八、云尚办公系统-管理端-审批设置

news2024/11/25 0:52:16

云尚办公系统:管理端-审批设置

B站直达【为尚硅谷点赞】:
https://www.bilibili.com/video/BV1Ya411S7aT

本博文以课程相关为主发布,并且融入了自己的一些看法以及对学习过程中遇见的问题给出相关的解决方法。一起学习一起进步!!!

恭喜大家完成前面用户管理、菜单管理、权限管理的学习,这个博文笔记将详细解释管理端审批设置,需要思考并理解老师的思路,明确代码的目的和作用【没有遇到保错的地方,跟着步骤来就行】。

文章目录

  • 云尚办公系统:管理端-审批设置
    • 一、审批设置需求
      • 1、需求描述
      • 2、页面效果
        • 2.1、管理端
        • 2.2、员工端
      • 3、数据库表设计
    • 二、审批类型
      • 1、审批类型CRUD
        • 1.1、mapper
        • 1.2、service接口
        • 1.3、service接口实现
        • 1.4、controller接口
      • 2、前端页面
        • 2.1、动态添加路由
        • 2.2、定义api
        • 2.3、创建vue页面
    • 三、审批模板
      • 1、审批模板CRUD
        • 1.1、mapper
        • 1.2、service接口
        • 1.3、service接口实现
        • 1.4、controller接口
      • 2、列表页面
        • 2.1、动态添加路由
        • 2.2、定义api
        • 2.3、列表页面
      • 3、添加审批模板
        • 3.1、form-create
        • 3.2、集成form-create
        • 3.3、获取全部审批分类接口
        • 3.4、上传流程定义接口
        • 3.5、模板设置完整代码
      • 4、查看审批模板
        • 4.1、添加按钮
        • 4.2、定义data
        • 4.3、定义方法
        • 4.4、定义弹出层
      • 5、发布
        • 5.1、添加controller接口
        • 5.2、添加service接口及实现
        • 5.3、前端实现

一、审批设置需求

1、需求描述

公司日常办公,审批是必不可少的一个功能,例如常用的钉钉OA审批,今天我们就要做类似的审批功能。

审批设置模块包含:审批类型与审批模板

**审批类型:**审批类型即为审批的分类,如:出勤、人事、财务等

**审批模板:**设置具体审批的基本信息、表单信息与审批流程定义,审批流涉及工作流引擎Activiti,常见的审批模板如:加班、出差、请假、费用报销等,我们可以根据公司具体业务配置具体的审批模板

2、页面效果

2.1、管理端

1、审批类型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Nx2myXc-1688012848844)(assets/1671672543496.png)]

2、审批模板

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7MLv35SM-1688012848847)(assets/1671672578569.png)]

3、在线流程设计

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NhVs1DYq-1688012848848)(assets/1671672635610.png)]

2.2、员工端

1、审批中心

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JbV84AYL-1688012848850)(assets/1671672687292.png)]

2、发起审批,显示动态表单

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EGEpuobV-1688012848852)(assets/1671672747446.png)]

3、数据库表设计

1、审批类型表:oa_process_type

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K4rs85YF-1688012848854)(assets/1671672002455.png)]

2、审批模板表:oa_process_template

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a1YE6Don-1688012848856)(assets/1671672111040.png)]

重要字段说明:

​ form_props:动态表单的表单属性,后续入门form-create组件会详细讲解

​ form_options:动态表单的表单选项,后续入门form-create组件会详细讲解,这两项就是配置动态表单的

​ process_definition_key:流程定义key,前面Activiti入门已讲解,我们启动流程实例会使用它

​ process_definition_path:保存流程定义文件的路径

​ process_model_id:流程定义模型id,流程定义实现两种方式,一种:上传,第二种:在线制作,分别使用这两个字段保存记录

在这里插入图片描述

二、审批类型

1、审批类型CRUD

1.1、mapper

package com.atguigu.process.mapper;

import com.atguigu.model.process.ProcessType;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface ProcessTypeMapper extends BaseMapper<ProcessType> {

}

1.2、service接口

package com.atguigu.process.service;

import com.atguigu.model.process.ProcessType;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;

public interface ProcessTypeService extends IService<ProcessType> {

}

1.3、service接口实现

package com.atguigu.process.service.impl;

import com.atguigu.model.process.ProcessType;
import com.atguigu.process.mapper.ProcessTypeMapper;
import com.atguigu.process.service.ProcessTypeService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class ProcessTypeServiceImpl extends ServiceImpl<ProcessTypeMapper, ProcessType> implements ProcessTypeService {

}

1.4、controller接口

package com.atguigu.process.controller;

import com.atguigu.common.result.Result;
import com.atguigu.model.process.ProcessType;
import com.atguigu.process.service.ProcessTypeService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

@Api(value = "审批类型", tags = "审批类型")
@RestController
@RequestMapping(value = "/admin/process/processType")
@SuppressWarnings({"unchecked", "rawtypes"})
public class ProcessTypeController {

    @Autowired
    private ProcessTypeService processTypeService;

    @PreAuthorize("hasAuthority('bnt.processType.list')")
    @ApiOperation(value = "获取分页列表")
    @GetMapping("{page}/{limit}")
    public Result index(@PathVariable Long page,
                        @PathVariable Long limit) {
        Page<ProcessType> pageParam = new Page<>(page,limit);
        IPage<ProcessType> pageModel = processTypeService.page(pageParam);
        return Result.ok(pageModel);
    }

    @PreAuthorize("hasAuthority('bnt.processType.list')")
    @ApiOperation(value = "获取")
    @GetMapping("get/{id}")
    public Result get(@PathVariable Long id) {
        ProcessType processType = processTypeService.getById(id);
        return Result.ok(processType);
    }

    @PreAuthorize("hasAuthority('bnt.processType.add')")
    @ApiOperation(value = "新增")
    @PostMapping("save")
    public Result save(@RequestBody ProcessType processType) {
        processTypeService.save(processType);
        return Result.ok();
    }

    @PreAuthorize("hasAuthority('bnt.processType.update')")
    @ApiOperation(value = "修改")
    @PutMapping("update")
    public Result updateById(@RequestBody ProcessType processType) {
        processTypeService.updateById(processType);
        return Result.ok();
    }

    @PreAuthorize("hasAuthority('bnt.processType.remove')")
    @ApiOperation(value = "删除")
    @DeleteMapping("remove/{id}")
    public Result remove(@PathVariable Long id) {
        processTypeService.removeById(id);
        return Result.ok();
    }
}

2、前端页面

2.1、动态添加路由

在“系统管理”->“菜单管理”添加“审批设置”->“审批类型”

对于菜单信息,我们也可以直接导入菜单表初始化数据,后续不用再单独配置

2.2、定义api

创建src/api/process/processType.js

import request from '@/utils/request'

const api_name = '/admin/process/processType'

export default {

  getPageList(page, limit) {
    return request({
      url: `${api_name}/${page}/${limit}`,
      method: 'get'
    })
  },
  getById(id) {
    return request({
      url: `${api_name}/get/${id}`,
      method: 'get'
    })
  },
  save(role) {
    return request({
      url: `${api_name}/save`,
      method: 'post',
      data: role
    })
  },
  updateById(role) {
    return request({
      url: `${api_name}/update`,
      method: 'put',
      data: role
    })
  },
  removeById(id) {
    return request({
      url: `${api_name}/remove/${id}`,
      method: 'delete'
    })
  }
}

2.3、创建vue页面

创建views/processSet/processType/list.vue

<template>
  <div class="app-container">
    <!-- 工具条 -->
    <div class="tools-div">
      <el-button type="success" icon="el-icon-plus" size="mini" @click="add" :disabled="$hasBP('bnt.processType.add')  === false">添 加</el-button>
    </div>
    <!-- banner列表 -->
    <el-table
      v-loading="listLoading"
      :data="list"
      stripe
      border
      style="width: 100%;margin-top: 10px;"
    >
      <el-table-column
        type="selection"
        width="55"
      />
      <el-table-column
        label="序号"
        width="70"
        align="center"
      >
        <template slot-scope="scope">
          {{ (page - 1) * limit + scope.$index + 1 }}
        </template>
      </el-table-column>
      <el-table-column prop="name" label="类型名称"/>
      <el-table-column prop="description" label="描述"/>
      <el-table-column prop="createTime" label="创建时间"/>
      <el-table-column prop="updateTime" label="更新时间"/>
      <el-table-column label="操作" width="200" align="center">
        <template slot-scope="scope">
          <el-button type="text" size="mini" @click="edit(scope.row.id)" :disabled="$hasBP('bnt.processType.update')  === false">修改</el-button>
          <el-button type="text" size="mini" @click="removeDataById(scope.row.id)" :disabled="$hasBP('bnt.processType.remove')  === false">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    <!-- 分页组件 -->
    <el-pagination
      :current-page="page"
      :total="total"
      :page-size="limit"
      :page-sizes="[5, 10, 20, 30, 40, 50, 100]"
      style="padding: 30px 0; text-align: center;"
      layout="sizes, prev, pager, next, jumper, ->, total, slot"
      @current-change="fetchData"
      @size-change="changeSize"
    />
    <el-dialog title="添加/修改" :visible.sync="dialogVisible" width="40%">
      <el-form ref="flashPromotionForm" label-width="150px" size="small" style="padding-right: 40px;">
        <el-form-item label="类型名称">
          <el-input v-model="processType.name"/>
        </el-form-item>
        <el-form-item label="描述">
          <el-input v-model="processType.description"/>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false" size="small">取 消</el-button>
        <el-button type="primary" @click="saveOrUpdate()" size="small">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
import api from '@/api/process/processType'

const defaultForm = {
  id: '',
  name: '',
  description: ''
}
export default {
  data() {
    return {
      listLoading: true, // 数据是否正在加载
      list: null, // banner列表
      total: 0, // 数据库中的总记录数
      page: 1, // 默认页码
      limit: 10, // 每页记录数
      searchObj: {}, // 查询表单对象
      dialogVisible: false,
      processType: defaultForm,
      saveBtnDisabled: false
    }
  },
  // 生命周期函数:内存准备完毕,页面尚未渲染
  created() {
    this.fetchData()
  },
  // 生命周期函数:内存准备完毕,页面渲染成功
  mounted() {
  },
  methods: {
    // 当页码发生改变的时候
    changeSize(size) {
      console.log(size)
      this.limit = size
      this.fetchData(1)
    },
    // 加载列表数据
    fetchData(page = 1) {
      this.page = page
      api.getPageList(this.page, this.limit, this.searchObj).then(response => {
        this.list = response.data.records
        this.total = response.data.total
        // 数据加载并绑定成功
        this.listLoading = false
      })
    },
    // 重置查询表单
    resetData() {
      console.log('重置查询表单')
      this.searchObj = {}
      this.fetchData()
    },
    // 根据id删除数据
    removeDataById(id) {
      this.$confirm('此操作将永久删除该记录, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => { // promise
        // 点击确定,远程调用ajax
        return api.removeById(id)
      }).then((response) => {
        this.fetchData(this.page)
        this.$message.success(response.message)
      }).catch(() => {
        this.$message.info('取消删除')
      })
    },
    add() {
      this.dialogVisible = true
      this.processType = Object.assign({}, defaultForm)
    },
    edit(id) {
      this.dialogVisible = true
      this.fetchDataById(id)
    },
    fetchDataById(id) {
      api.getById(id).then(response => {
        this.processType = response.data
      })
    },
    saveOrUpdate() {
      this.saveBtnDisabled = true // 防止表单重复提交
      if (!this.processType.id) {
        this.saveData()
      } else {
        this.updateData()
      }
    },
    // 新增
    saveData() {
      api.save(this.processType).then(response => {
        this.$message.success(response.message || '操作成功')
        this.dialogVisible = false
        this.fetchData(this.page)
      })
    },
    // 根据id更新记录
    updateData() {
      api.updateById(this.processType).then(response => {
        this.$message.success(response.message || '操作成功')
        this.dialogVisible = false
        this.fetchData(this.page)
      })
    }
  }
}
</script>

三、审批模板

1、审批模板CRUD

1.1、mapper

package com.atguigu.process.mapper;

import com.atguigu.model.process.ProcessTemplate;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface ProcessTemplateMapper extends BaseMapper<ProcessTemplate> {

}

1.2、service接口

package com.atguigu.process.service;

import com.atguigu.model.process.ProcessTemplate;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;

public interface ProcessTemplateService extends IService<ProcessTemplate> {

    IPage<ProcessTemplate> selectPage(Page<ProcessTemplate> pageParam);

}

1.3、service接口实现

package com.atguigu.process.service.impl;

import com.atguigu.model.process.ProcessTemplate;
import com.atguigu.model.process.ProcessType;
import com.atguigu.process.mapper.ProcessTemplateMapper;
import com.atguigu.process.service.ProcessTemplateService;
import com.atguigu.process.service.ProcessTypeService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class ProcessTemplateServiceImpl extends ServiceImpl<ProcessTemplateMapper, ProcessTemplate> implements ProcessTemplateService {

   @Resource
   private ProcessTemplateMapper processTemplateMapper;

   @Resource
   private ProcessTypeService processTypeService;

   @Override
   public IPage<ProcessTemplate> selectPage(Page<ProcessTemplate> pageParam) {
      LambdaQueryWrapper<ProcessTemplate> queryWrapper = new LambdaQueryWrapper<ProcessTemplate>();
      queryWrapper.orderByDesc(ProcessTemplate::getId);
      IPage<ProcessTemplate> page = processTemplateMapper.selectPage(pageParam, queryWrapper);
      List<ProcessTemplate> processTemplateList = page.getRecords();
       
      List<Long> processTypeIdList = processTemplateList.stream().map(processTemplate -> processTemplate.getProcessTypeId()).collect(Collectors.toList());
       
      if(!CollectionUtils.isEmpty(processTypeIdList)) {
         Map<Long, ProcessType> processTypeIdToProcessTypeMap = processTypeService.list(new LambdaQueryWrapper<ProcessType>().in(ProcessType::getId, processTypeIdList)).stream().collect(Collectors.toMap(ProcessType::getId, ProcessType -> ProcessType));
         for(ProcessTemplate processTemplate : processTemplateList) {
            ProcessType processType = processTypeIdToProcessTypeMap.get(processTemplate.getProcessTypeId());
            if(null == processType) continue;
            processTemplate.setProcessTypeName(processType.getName());
         }
      }
      return page;
   }
}

1.4、controller接口

package com.atguigu.process.controller;

import com.atguigu.common.result.Result;
import com.atguigu.model.process.ProcessTemplate;
import com.atguigu.process.service.ProcessTemplateService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

@Api(value = "审批模板管理", tags = "审批模板管理")
@RestController
@RequestMapping(value = "/admin/process/processTemplate")
@SuppressWarnings({"unchecked", "rawtypes"})
public class ProcessTemplateController {

    @Autowired
    private ProcessTemplateService processTemplateService;

    //@PreAuthorize("hasAuthority('bnt.processTemplate.list')")
    @ApiOperation(value = "获取分页列表")
    @GetMapping("{page}/{limit}")
    public Result index(
            @ApiParam(name = "page", value = "当前页码", required = true)
            @PathVariable Long page,

            @ApiParam(name = "limit", value = "每页记录数", required = true)
            @PathVariable Long limit) {
        Page<ProcessTemplate> pageParam = new Page<>(page, limit);
        IPage<ProcessTemplate> pageModel = processTemplateService.selectPage(pageParam);
        return Result.ok(pageModel);
    }

    //@PreAuthorize("hasAuthority('bnt.processTemplate.list')")
    @ApiOperation(value = "获取")
    @GetMapping("get/{id}")
    public Result get(@PathVariable Long id) {
        ProcessTemplate processTemplate = processTemplateService.getById(id);
        return Result.ok(processTemplate);
    }

    //@PreAuthorize("hasAuthority('bnt.processTemplate.templateSet')")
    @ApiOperation(value = "新增")
    @PostMapping("save")
    public Result save(@RequestBody ProcessTemplate processTemplate) {
        processTemplateService.save(processTemplate);
        return Result.ok();
    }

    //@PreAuthorize("hasAuthority('bnt.processTemplate.templateSet')")
    @ApiOperation(value = "修改")
    @PutMapping("update")
    public Result updateById(@RequestBody ProcessTemplate processTemplate) {
        processTemplateService.updateById(processTemplate);
        return Result.ok();
    }

    //@PreAuthorize("hasAuthority('bnt.processTemplate.remove')")
    @ApiOperation(value = "删除")
    @DeleteMapping("remove/{id}")
    public Result remove(@PathVariable Long id) {
        processTemplateService.removeById(id);
        return Result.ok();
    }
}

2、列表页面

2.1、动态添加路由

在“系统管理”->“菜单管理”添加“审批设置”->“审批类型”

对于菜单信息,我们也可以直接导入菜单表初始化数据,后续不用再单独配置

说明:“审批模板设置”页面内容较多,因此单独打开一个独立页面

2.2、定义api

创建src/api/process/processTemplate.js

基本的增删改查接口

import request from '@/utils/request'

const api_name = '/admin/process/processTemplate'

export default {

  getPageList(page, limit) {
    return request({
      url: `${api_name}/${page}/${limit}`,
      method: 'get'
    })
  },
  getById(id) {
    return request({
      url: `${api_name}/get/${id}`,
      method: 'get'
    })
  },

  save(role) {
    return request({
      url: `${api_name}/save`,
      method: 'post',
      data: role
    })
  },

  updateById(role) {
    return request({
      url: `${api_name}/update`,
      method: 'put',
      data: role
    })
  },
  removeById(id) {
    return request({
      url: `${api_name}/remove/${id}`,
      method: 'delete'
    })
  }
}

2.3、列表页面

创建views/processSet/processTemplate/list.vue

<template>
  <div class="app-container">
    <!-- 工具条 -->
    <div class="tools-div">
      <el-button type="success" icon="el-icon-plus" size="mini" @click="add()" :disabled="$hasBP('bnt.processTemplate.templateSet')  === false">添加审批设置</el-button>
    </div>
    <!-- 列表 -->
    <el-table
      v-loading="listLoading"
      :data="list"
      stripe
      border
      style="width: 100%;margin-top: 10px;"
    >
      <el-table-column
        label="序号"
        width="70"
        align="center"
      >
        <template slot-scope="scope">
          {{ (page - 1) * limit + scope.$index + 1 }}
        </template>
      </el-table-column>iconPath
      <el-table-column prop="name" label="审批名称"/>
      <el-table-column label="图标">
        <template slot-scope="scope">
          <img :src="scope.row.iconUrl" style="width: 30px;height: 30px;vertical-align: text-bottom;">
        </template>
      </el-table-column>
      <el-table-column prop="processTypeName" label="审批类型"/>
      <el-table-column prop="description" label="描述"/>
      <el-table-column prop="createTime" label="创建时间"/>
      <el-table-column prop="updateTime" label="更新时间"/>
      <el-table-column label="操作" width="250" align="center">
        <template slot-scope="scope">
          <el-button type="text" size="mini" @click="edit(scope.row.id)" :disabled="$hasBP('bnt.processTemplate.templateSet')  === false">修改审批设置</el-button>
          <el-button type="text" size="mini" @click="removeDataById(scope.row.id)" :disabled="$hasBP('bnt.processTemplate.remove')  === false">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    <!-- 分页组件 -->
    <el-pagination
      :current-page="page"
      :total="total"
      :page-size="limit"
      :page-sizes="[5, 10, 20, 30, 40, 50, 100]"
      style="padding: 30px 0; text-align: center;"
      layout="sizes, prev, pager, next, jumper, ->, total, slot"
      @current-change="fetchData"
      @size-change="changeSize"
    />
  </div>
</template>
<script>
import api from '@/api/process/processTemplate'

export default {
  data() {
    return {
      listLoading: true, // 数据是否正在加载
      list: null, // banner列表
      total: 0, // 数据库中的总记录数
      page: 1, // 默认页码
      limit: 10, // 每页记录数
      searchObj: {} // 查询表单对象
    }
  },
  // 生命周期函数:内存准备完毕,页面尚未渲染
  created() {
    this.fetchData()
  },
  // 生命周期函数:内存准备完毕,页面渲染成功
  mounted() {
  },
  methods: {
    // 当页码发生改变的时候
    changeSize(size) {
      this.limit = size
      this.fetchData(1)
    },
    // 加载banner列表数据
    fetchData(page = 1) {
      // 异步获取远程数据(ajax)
      this.page = page
      api.getPageList(this.page, this.limit, this.searchObj).then(
        response => {
          this.list = response.data.records
          this.total = response.data.total
          // 数据加载并绑定成功
          this.listLoading = false
        }
      )
    },
    // 重置查询表单
    resetData() {
      this.searchObj = {}
      this.fetchData()
    },
    // 根据id删除数据
    removeDataById(id) {
      this.$confirm('此操作将永久删除该记录, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => { // promise
        // 点击确定,远程调用ajax
        return api.removeById(id)
      }).then((response) => {
        this.fetchData(this.page)
        this.$message.success(response.message)
      }).catch(() => {
        this.$message.info('取消删除')
      })
    },
    add() {
      this.$router.push('/processSet/templateSet')
    },
    edit(id) {
      this.$router.push('/processSet/templateSet?id=' + id)
    }
  }
}
</script>

3、添加审批模板

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m6jyPYRS-1688012848858)(assets/1672107038671.png)]

1、基本设置:一些基本信息

2、表单设置:动态表单

3、流程设置:本地设计流程定义,上传流程定义文件及流程定义图片(压缩上传)

涉及未实现接口:

1、获取全部审批分类

2、上传流程定义压缩文件

3.1、form-create

官网:http://www.form-create.com/v2/guide/

轻松搞定 form 表单,让你不再为表单而烦恼。

form-create 是一个可以通过 JSON 生成具有动态渲染、数据收集、验证和提交功能的表单生成组件。

form-create-designer 是基于 form-create实现的表单设计器组件。可以通过拖拽的方式快速创建表单,提高开发者对表单的开发效率,节省开发者的时间

表单设计器:

http://www.form-create.com/designer/?fr=home

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2jvGodxK-1688012848860)(assets/1672107092185.png)]

可以通过拖拽的方式快速配置动态表单,配置好的动态表单可以通过:生成JSON与生成Options获取数据,这两数据对于表字段:form_props与form_options,后续我们通过这两字段渲染动态表单。

大家可以根据表单设计器,查看数据格式

3.2、集成form-create

1、添加依赖

在package.json文件添加依赖,注意版本号,更高的版本号可能与本项目不兼容

"@form-create/element-ui": "^2.5.17",
"@form-create/designer": "^1.0.8",

2、在 main.js 中写入以下内容:

import formCreate from '@form-create/element-ui'
import FcDesigner from '@form-create/designer'
Vue.use(formCreate)
Vue.use(FcDesigner)

3、集成表单设计器

创建views/processSet/processTemplate/templateSet.vue

<template>
  <div class="app-container">
    <div id="app1">
      <fc-designer class="form-build" ref="designer"/>
      <el-button @click="save">获取数据</el-button>
    </div>
  </div>
</template>

<script>

export default {
  data() {
    return {
    }
  },

  created() {

  },

  methods: {
    save() {
      console.log(this.$refs.designer.getRule())
      console.log(this.$refs.designer.getOption())
    }
  }
}
</script>

显示效果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dDQ9KZBJ-1688012848862)(assets/1672107277356.png)]

随便拉几个表单项,点击“获取数据”,就是我们需要的动态表单数据格式了。

3.3、获取全部审批分类接口

1、在ProcessTypeController类添加接口

@ApiOperation(value = "获取全部审批分类")
@GetMapping("findAll")
public Result findAll() {
    return Result.ok(processTypeService.list());
}

2、在processType.js添加前端接口

findAll() {
  return request({
    url: `${api_name}/findAll`,
    method: 'get'
  })
}

3.4、上传流程定义接口

在ProcessTemplateController类添加接口

@PreAuthorize("hasAuthority('bnt.processTemplate.templateSet')")
@ApiOperation(value = "上传流程定义")
@PostMapping("/uploadProcessDefinition")
public Result uploadProcessDefinition(MultipartFile file) throws FileNotFoundException {
    String path = new File(ResourceUtils.getURL("classpath:").getPath()).getAbsolutePath();

    String fileName = file.getOriginalFilename();
    // 上传目录
    File tempFile = new File(path + "/processes/");
    // 判断目录是否存着
    if (!tempFile.exists()) {
        tempFile.mkdirs();//创建目录
    }
    // 创建空文件用于写入文件
    File imageFile = new File(path + "/processes/" + fileName);
    // 保存文件流到本地
    try {
        file.transferTo(imageFile);
    } catch (IOException e) {
        e.printStackTrace();
        return Result.fail("上传失败");
    }

    Map<String, Object> map = new HashMap<>();
    //根据上传地址后续部署流程定义,文件名称为流程定义的默认key
    map.put("processDefinitionPath", "processes/" + fileName);
    map.put("processDefinitionKey", fileName.substring(0, fileName.lastIndexOf(".")));
    return Result.ok(map);
}

3.5、模板设置完整代码

<template>
  <div class="app-container">
    <el-steps :active="stepIndex" finish-status="success">
      <el-step title="基本设置"></el-step>
      <el-step title="表单设置"></el-step>
      <el-step title="流程设置"></el-step>
    </el-steps>

    <div class="tools-div">
      <el-button v-if="stepIndex > 1" icon="el-icon-check" type="primary" size="small" @click="pre()" round>上一步
      </el-button>
      <el-button icon="el-icon-check" type="primary" size="small" @click="next()" round>{{
          stepIndex == 3 ? '提交保存' : '下一步'
        }}
      </el-button>
      <el-button type="primary" size="small" @click="back()">返回</el-button>
    </div>

    <!-- 第一步 -->
    <div v-show="stepIndex == 1" style="margin-top: 20px;">
      <el-form ref="flashPromotionForm" label-width="150px" size="small" style="padding-right: 40px;">
        <el-form-item label="审批类型">
          <el-select v-model="processTemplate.processTypeId" placeholder="请选择审批类型">
            <el-option v-for="item in processTypeList" :label="item.name" :value="item.id"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="审批名称">
          <el-input v-model="processTemplate.name"/>
        </el-form-item>
        <el-form-item label="审批图标">
          <el-select v-model="processTemplate.iconUrl" placeholder="请选择审批图标">
            <el-option v-for="item in iconUrlList" :label="item.iconUrl" :value="item.iconUrl">
              <img :src="item.iconUrl" style="width: 30px;height: 30px;vertical-align: text-bottom;">
            </el-option>
          </el-select>
        </el-form-item>

        <el-form-item label="描述">
          <el-input v-model="processTemplate.description"/>
        </el-form-item>
      </el-form>
    </div>

    <!-- 第二步 -->
    <div v-show="stepIndex == 2" style="margin-top: 20px;">
      <!--表单构建器-->
      <fc-designer class="form-build" ref="designer"/>
    </div>

    <!-- 第三步 -->
    <div v-show="stepIndex == 3" style="margin-top: 20px;">
      <el-upload
        class="upload-demo"
        drag
        action="/dev-api/admin/process/processTemplate/uploadProcessDefinition"
        :headers="uploadHeaders"
        multiple="false"
        :before-upload="beforeUpload"
        :on-success="onUploadSuccess"
        :file-list="fileList"
      >
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将Activiti流程设计文件拖到此处,或<em>点击上传</em></div>
        <div class="el-upload__tip" slot="tip">只能上传zip压缩文件,且不超过2048kb</div>
      </el-upload>
    </div>
  </div>
</template>

<script>
import api from '@/api/process/processTemplate'
import processTypeApi from '@/api/process/processType'
import store from '@/store'

const defaultForm = {
  id: '',
  name: '',
  iconUrl: '',
  formProps: '',
  formOptions: '',
  processDefinitionKey: '',
  processDefinitionPath: '',
  description: ''
}
export default {
  data() {
    return {
      stepIndex: 1,
      processTypeList: [],
      processTemplate: defaultForm,
      iconUrlList: [
        { iconUrl: 'https://gw.alicdn.com/tfs/TB1t695CFYqK1RjSZLeXXbXppXa-102-102.png', tag: '请假' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB1bHOWCSzqK1RjSZFjXXblCFXa-112-112.png', tag: '出差' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB1cbCYCPTpK1RjSZKPXXa3UpXa-112-112.png', tag: '机票出差' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB1cbCYCPTpK1RjSZKPXXa3UpXa-112-112.png', tag: '机票改签' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB1e76lCOLaK1RjSZFxXXamPFXa-112-112.png', tag: '外出' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB1Yfa0CG6qK1RjSZFmXXX0PFXa-112-112.png', tag: '补卡申请' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB1Y8PlCNjaK1RjSZKzXXXVwXXa-112-112.png', tag: '加班' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB11X99CNTpK1RjSZFKXXa2wXXa-102-102.png', tag: '居家隔离' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB1_YG.COrpK1RjSZFhXXXSdXXa-102-102.png', tag: '请假' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB13ca1CMDqK1RjSZSyXXaxEVXa-102-102.png', tag: '调岗' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB1U9iBCSzqK1RjSZPcXXbTepXa-102-102.png', tag: '离职' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB11pS_CFzqK1RjSZSgXXcpAVXa-102-102.png', tag: '费用申请' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB1t695CFYqK1RjSZLeXXbXppXa-102-102.png', tag: '用章申请' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB13f_aCQzoK1RjSZFlXXai4VXa-102-102.png', tag: '携章外出' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB1_YG.COrpK1RjSZFhXXXSdXXa-102-102.png', tag: '学期内分期' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB1_YG.COrpK1RjSZFhXXXSdXXa-102-102.png', tag: '特殊学费' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB1Yfa0CG6qK1RjSZFmXXX0PFXa-112-112.png', tag: '充值卡申领' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB1e76lCOLaK1RjSZFxXXamPFXa-112-112.png', tag: '礼品申领' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB1FNG.CMHqK1RjSZFgXXa7JXXa-102-102.png', tag: '邮寄快递申请' },
        { iconUrl: 'https://gw.alicdn.com/imgextra/i3/O1CN01LLn0YV1LhBXs7T2iO_!!6000000001330-2-tps-120-120.png', tag: '合同审批' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB1e76lCOLaK1RjSZFxXXamPFXa-112-112.png', tag: '合同借阅' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB1e76lCOLaK1RjSZFxXXamPFXa-112-112.png', tag: '魔点临时开门权限' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB1bHOWCSzqK1RjSZFjXXblCFXa-112-112.png', tag: '北京科技园车证审批' },
        { iconUrl: 'https://gw.alicdn.com/tfs/TB1e76lCOLaK1RjSZFxXXamPFXa-112-112.png', tag: '魔点访客提前预约审批' }
      ],

      uploadHeaders: {
        'token': store.getters.token
      },
      fileList: []
    }
  },

  created() {
    let id = this.$route.query.id
    console.log(id)
    if (id > 0) {
      this.fetchDataById(id)
    }
    this.fetchProcessTypeData()
  },

  methods: {
    pre() {
      this.stepIndex -= 1
    },

    next() {
      if (this.stepIndex === 2) {
        this.processTemplate.formProps = JSON.stringify(this.$refs.designer.getRule())
        this.processTemplate.formOptions = JSON.stringify(this.$refs.designer.getOption())
        console.log(JSON.stringify(this.processTemplate))
      }
      if (this.stepIndex === 3) {
        this.saveOrUpdate()
      }

      this.stepIndex += 1
    },

    fetchProcessTypeData() {
      processTypeApi.findAll().then(response => {
        this.processTypeList = response.data
      })
    },
    fetchDataById(id) {
      api.getById(id).then(response => {
        this.processTemplate = response.data
        // 给表单设计器赋值
        this.$refs.designer.setRule(JSON.parse(this.processTemplate.formProps))
        this.$refs.designer.setOption(JSON.parse(this.processTemplate.formOptions))
        this.fileList = [{
          name: this.processTemplate.processDefinitionPath,
          url: this.processTemplate.processDefinitionPath
        }]
      })
    },

    saveOrUpdate() {
      this.saveBtnDisabled = true // 防止表单重复提交
      if (!this.processTemplate.id) {
        this.saveData()
      } else {
        this.updateData()
      }
    },

    // 新增
    saveData() {
      api.save(this.processTemplate).then(response => {
        this.$router.push('/processSet/processTemplate')
      })
    },

    // 根据id更新记录
    updateData() {
      api.updateById(this.processTemplate).then(response => {
        this.$router.push('/processSet/processTemplate')
      })
    },

    // 文件上传限制条件
    beforeUpload(file) {
      const isZip = file.type === 'application/x-zip-compressed'
      const isLt2M = file.size / 1024 / 1024 < 2

      if (!isZip) {
        this.$message.error('文件格式不正确!')
        return false
      }
      if (!isLt2M) {
        this.$message.error('上传大小不能超过 2MB!')
        return false
      }
      return true
    },

    // 上传成功的回调
    onUploadSuccess(res, file) {
      // 填充上传文件列表
      this.processTemplate.processDefinitionPath = res.data.processDefinitionPath
      this.processTemplate.processDefinitionKey = res.data.processDefinitionKey
    },

    back() {
      this.$router.push('/processSet/processTemplate')
    }
  }
}
</script>

4、查看审批模板

查看审批模板基本信息、动态表单信息

4.1、添加按钮

<el-button type="text" size="mini" @click="show(scope.row)">查看审批设置</el-button>

4.2、定义data

rule: [],
option: {},
processTemplate: {},
formDialogVisible: false

4.3、定义方法

show(row) {
  this.rule = JSON.parse(row.formProps)
  this.option = JSON.parse(row.formOptions)
  this.processTemplate = row
  this.formDialogVisible = true
}

4.4、定义弹出层

<el-dialog title="查看审批设置" :visible.sync="formDialogVisible" width="35%">
  <h3>基本信息</h3>
  <el-divider/>
  <el-form ref="flashPromotionForm" label-width="150px" size="small" style="padding-right: 40px;">
    <el-form-item label="审批类型" style="margin-bottom: 0px;">{{ processTemplate.processTypeName }}</el-form-item>
    <el-form-item label="名称" style="margin-bottom: 0px;">{{ processTemplate.name }}</el-form-item>
    <el-form-item label="创建时间" style="margin-bottom: 0px;">{{ processTemplate.createTime }}</el-form-item>
  </el-form>
  <h3>表单信息</h3>
  <el-divider/>
  <div>
    <form-create
      :rule="rule"
      :option="option"
    ></form-create>
  </div>
  <span slot="footer" class="dialog-footer">
    <el-button @click="formDialogVisible = false" size="small">取 消</el-button>
  </span>
</el-dialog>

5、发布

发布后审批模板就不可以修改了,然后部署流程定义

5.1、添加controller接口

@PreAuthorize("hasAuthority('bnt.processTemplate.publish')")
@ApiOperation(value = "发布")
@GetMapping("/publish/{id}")
public Result publish(@PathVariable Long id) {
    processTemplateService.publish(id);
    return Result.ok();
}

5.2、添加service接口及实现

void publish(Long id);

接口实现:

@Transactional
@Override
public void publish(Long id) {
   ProcessTemplate processTemplate = this.getById(id);
   processTemplate.setStatus(1);
   processTemplateMapper.updateById(processTemplate);
    
   //TODO 部署流程定义,后续完善
}

5.3、前端实现

1、添加api接口

publish(id) {
  return request({
    url: `${api_name}/publish/${id}`,
    method: 'get'
  })
}

2、添加按钮

<el-button v-if="scope.row.status == 0" type="text" size="mini" @click="publish(scope.row.id)" :disabled="$hasBP('bnt.processTemplate.publish')  === false">发布</el-button>

3、添加按钮方法

publish(id) {
  api.publish(id).then(response => {
    this.$message.success('发布成功')
    this.fetchData(this.page)
  })
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/702919.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android处理内存泄漏

么是内存泄漏&#xff1a; 在Android开发过程中&#xff0c;当一个对象已经不需要再使用了&#xff0c;本该被回收时&#xff0c;而另个正在使用的对象持有它引用从而导致它不能被回收&#xff0c;这就导致本该被回收的对象不能被回收而停留在堆内存中&#xff0c;内存泄漏就产…

STM32外设系列—HC-05(蓝牙)

文章目录 一、蓝牙简介二、使用方法2.1 接线2.2 AT指令 三、蓝牙APP四、实战项目4.1 添加文件4.2 配置需要传递的参数4.3 获取返回值4.4 发送光照强度4.5 控制程序4.6 手机端页面设计4.6.1 新建调试工程4.6.2 设置通信变量4.6.3 编辑控件4.6.4 添加LED控制开关4.6.5 添加光照强…

Vue 时间转换

文章目录 将秒转换成简单时间格式方式一 表格渲染方式二 js转换 将时间转换为字符串方式一 年、月、日、时、分、秒、星期等信息方式二 返回多久之前的时间 将秒转换成简单时间格式 方式一 表格渲染 element-ui 表格为例&#xff0c;duration 单位为秒 <el-table-column …

Openresty原理概念篇(十一) 为什么要避免使用 NYI?

一 JIT编译器的死穴&#xff1a;为什么要避免使用 NYI ? ① 问题引入 1) 那么到底有哪些操作可以被 JIT,哪些不能呢?2) 怎样才可以避免写出不能被 JIT 的代码呢? ② 上节回顾 ③ 什么是 NYI&#xff1f; NYI函数 NYI完整的列表 ④ NYI列表中string库函数 说明&am…

sonarqube安装以及jenkins集成sonarqube

一、sonarqube安装 docker方式安装sonarqube docker 方式安装是最简便的&#xff0c;我选择了这个安装方式 1、下载镜像 docker pull postgres:latest docker pull sonarqube2、 创建挂载目录 #用于postgres的挂载目录 mkdir -p /opt/postgres/postgresql mkdir -p /opt/po…

慧博云通加入飞桨技术伙伴计划,共同推动企业AI应用创新

近日&#xff0c;慧博云通子公司慧博云通&#xff08;上海&#xff09;软件技术有限公司正式加入飞桨技术伙伴计划&#xff0c;双方将共同探索人工智能多场景创新应用&#xff0c;为企业提供智能化解决方案。 慧博云通 慧博云通科技股份有限公司&#xff08;股票代码&#x…

Pytorch分布式训练(一)

参考文献&#xff1a; 33、完整讲解PyTorch多GPU分布式训练代码编写_哔哩哔哩_bilibili pytorch进程间通信 - 文举的博客 (liwenju0.com) 前言 2023年&#xff0c;训练模型时&#xff0c;使用DDP&#xff08;DistributedDataParallel&#xff09;已经成为Pytorch炼丹师的标准…

sourcetree打开就闪退

1、问题分析 一直未出现如题描述情况&#xff0c;今早到公司可能是异常重启或者系统更新的愿意导致没有正常关机&#xff0c;出现了此种情况 2、问题解决 注&#xff1a;本文sourcetree安装在win11系统&#xff0c;win10等系统目录大同小异 ① (若快捷方式在桌面步骤①省略…

你的服务器还安全吗?用户数据是否面临泄露风险?

一系列严重的网络安全事件引起了广泛关注&#xff0c;多家知名公司的服务器遭到黑客挟持&#xff0c;用户的个人数据和敏感信息面临泄露的风险。这些事件揭示了网络安全的脆弱性和黑客攻击的威胁性&#xff0c;提醒着企业和个人加强对网络安全的重视。 一、入侵案例1.1 蔚来数据…

复习Javascript第二章

JavaScript 函数 JavaScript 函数是被设计为执行特定任务的代码块。 JavaScript 函数会在某代码调用它时被执行。 function myFunction(p1, p2) {return p1 * p2; // 该函数返回 p1 和 p2 的乘积 } JavaScript 函数语法 JavaScript 函数通过 function 关键词…

爆款视频生成器小程序源码搭建方案

爆款视频生成器是一种可以帮助用户快速制作出高质量视频的工具。它可以根据用户提供的素材、模板和音乐等要素&#xff0c;自动生成一个精美的视频。这种工具可以大大节省用户的时间和精力&#xff0c;同时还能够提高视频制作的效率和质量&#xff0c;使视频更易于被观众接受和…

开发一个商城小程序有哪些功能?

✔️近年来&#xff0c;随着微信小程序的不断优化和推出&#xff0c;越来越多的商家开始选择使用小程序作为销售渠道。商城小程序作为一种便捷、快速、高效的销售渠道&#xff0c;已经成为商家们打造线上商城的重要手段。商城小程序拥有着丰富的功能&#xff0c;可以满足不同商…

使用itextpdf填充表单域并生成pdf

文章目录 前言一、准备工作1.1 安装软件1.2 准备pdf1.3 设置表单域 二、创建项目三、编写代码3.1 编写工具类3.2 测试 四、测试结果 前言 最近手上有个任务&#xff0c;就是需要做一个pdf导出的功能。 可选择的技术点比较多&#xff0c;我这边综合考虑之后&#xff0c;使用的…

品牌推广的新路径:邀请歌手出席活动的独特策略“

在当今的市场竞争中&#xff0c;品牌推广和市场营销已经成为企业取得成功的重要因素之一。而邀请知名歌手出席活动则是一种备受瞩目的策略&#xff0c;可以为品牌带来巨大的优势和机遇。无论是与赵丽颖、迪丽热巴、张子枫、关晓彤、周冬雨还是孙俪等知名歌手合作&#xff0c;都…

WPF中Binding的数据转换—ValueConverters

WPF中Binding的数据转换—ValueConverters 在WPF中使用Binding经常会遇到需要转换的情况&#xff0c;如bool转为visibility&#xff0c;通常情况需要自己写一个类继承自IValueConverter接口&#xff0c;使用详情请参见Binding对数据的转换和校验&#xff0c;这种方法虽然不难&…

C 模拟包装机

一种自动包装机的结构如图 1 所示。首先机器中有 N 条轨道&#xff0c;放置了一些物品。轨道下面有一个筐。当某条轨道的按钮被按下时&#xff0c;活塞向左推动&#xff0c;将轨道尽头的一件物品推落筐中。当 0 号按钮被按下时&#xff0c;机械手将抓取筐顶部的一件物品&#x…

中间件漏洞解析

服务器解析漏洞算是历史比较悠久了&#xff0c;但如今依然广泛存在。在此记录汇总一些常见服务器&#xff08;WEB server&#xff09;的解析漏洞&#xff0c;比如IIS6.0、IIS7.5、apache、nginx等 2|0 二、IIS5.x-6.x解析漏洞&#xff08;针对asa/asp/cer&#xff09; 2|11、打…

学习笔记|盘点一些Linux 常用的命令

目录 1、apt-get Debian/Ubuntu系统包管理器 2、uname 获取 操作系统信息 3、date 查看/设置 系统时间 4、yum CentOS系统包管理器 5、mkdir 新建 文件夹 6、free 查看内存使用信息 7、wget 下载工具 8、cd 进入 文件夹 8、cp 复制或重命名 文件/文件夹 9、VI、VIM …

机器学习之支持向量机(SVM)

1 支持向量机介绍 支持向量机&#xff08;support vector machine&#xff0c;SVM&#xff09;是有监督学习中最有影响力的机器学习算法之一&#xff0c;该算法的诞生可追溯至上世纪 60 年代&#xff0c; 前苏联学者 Vapnik 在解决模式识别问题时提出这种算法模型&#xff0c;…

synchronized监视器锁

1、synchronized&监视器锁 1.1 synchronized 介绍 在 Java 中&#xff0c;synchronized 是一种关键字&#xff0c;用于实现线程的同步和互斥控制。它可以修饰方法或代码块&#xff0c;用于保护共享资源的访问&#xff0c;避免多个线程同时修改数据而引发的并发问题。 具…