8. Yunshang Office System - Management Terminal - Approval Settings

Yunshang Office System: Management Terminal - Approval Settings

Direct access to station B [like Silicon Valley] :
https://www.bilibili.com/video/BV1Ya411S7aT

This blog post is mainly published related to the course, and incorporates some of my own opinions and gives relevant solutions to the problems encountered in the learning process. Learn together and progress together! ! !

Congratulations to everyone who has completed the previous study of user management, menu management, and authority management. This blog post note will explain the approval settings of the management end in detail. You need to think about and understand the teacher's thinking, and clarify the purpose and function of the code.

1. Approval setting requirements

1. Requirements description

Approval is an indispensable function in the company's daily office work. For example, the commonly used DingTalk OA approval. Today we will implement a similar approval function.

The approval setting module includes: approval type and approval template

**Approval type: **Approval type is the classification of approval, such as: attendance, personnel, finance, etc.

**Approval template:** Set the basic information, form information and approval process definition of specific approval. The approval flow involves the workflow engine Activiti. Common approval templates such as: overtime, business trip, leave, expense reimbursement, etc. We can configure specific approval templates according to the company's specific business

2. Page effect

2.1. Management terminal

1. Approval type

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-3Nx2myXc-1688012848844)(assets/1671672543496.png)]

2. Approval template

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-7MLv35SM-1688012848847)(assets/1671672578569.png)]

3. Online process design

[External link image transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the image and upload it directly (img-NhVs1DYq-1688012848848)(assets/1671672635610.png)]

2.2. Staff side

1. Approval Center

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-JbV84AYL-1688012848850)(assets/1671672687292.png)]

2. Initiate approval and display dynamic form

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-EGEpuobV-1688012848852)(assets/1671672747446.png)]

3. Database table design

1. Approval type table: oa_process_type

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-K4rs85YF-1688012848854)(assets/1671672002455.png)]

2. Approval template table: oa_process_template

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-a1YE6Don-1688012848856)(assets/1671672111040.png)]

Description of important fields:

​ form_props: The form properties of the dynamic form, which will be explained in detail in the follow-up entry form-create component

​ form_options: The form options of the dynamic form, which will be explained in detail in the follow-up entry form-create component. These two items are used to configure the dynamic form

​ process_definition_key: Process definition key, which has been explained before getting started with Activiti, and we will use it to start the process instance

​ process_definition_path: save the path of the process definition file

​ process_model_id: process definition model id, there are two ways to implement process definition, one: upload, the second: online production, use these two fields to save records respectively

insert image description here

2. Approval type

1. Approval type 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 interface

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. Implementation of service interface

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 interface

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. Front-end page

2.1. Dynamically add routes

Add "Approval Settings" -> "Approval Type" in "System Management" -> "Menu Management"

For the menu information, we can also directly import the menu table initialization data, and then do not need to configure it separately

2.2. Define api

Create 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. Create a vue page

Create 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>

3. Approval template

1. Approval template 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 interface

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. Implementation of service interface

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 interface

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. List page

2.1. Dynamically add routes

Add "Approval Settings" -> "Approval Type" in "System Management" -> "Menu Management"

For the menu information, we can also directly import the menu table initialization data, and then do not need to configure it separately

Note: The "Approval Template Settings" page has a lot of content, so open an independent page separately

2.2. Define api

Create src/api/process/processTemplate.js

Basic CRUD interface

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. List page

Create 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. Add approval template

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-m6jyPYRS-1688012848858)(assets/1672107038671.png)]

1. Basic settings: some basic information

2. Form settings: dynamic form

3. Process setting: local design process definition, upload process definition file and process definition picture (compressed upload)

Involves unimplemented interfaces:

1. Obtain all approval categories

2. Upload process definition compressed file

3.1、form-create

Official website: http://www.form-create.com/v2/guide/

Get the form form easily, so that you don't have to worry about the form anymore.

form-create is a form generation component that can generate dynamic rendering, data collection, validation and submission through JSON.

form-create-designer is a form designer component implemented based on form-create. Forms can be quickly created by dragging and dropping, improving developers' efficiency in developing forms and saving developers' time

Form Designer:

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

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-2jvGodxK-1688012848860)(assets/1672107092185.png)]

The dynamic form can be quickly configured by dragging and dropping. The configured dynamic form can obtain data by: generating JSON and generating Options. These two data are for the table fields: form_props and form_options. Later, we will render the dynamic form through these two fields.

You can view the data format according to the form designer

3.2. Integrated form-create

1. Add dependencies

Add dependencies to the package.json file, pay attention to the version number, a higher version number may not be compatible with this project

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

2. Write the following content in main.js:

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

3. Integrated form designer

创建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>

display effect:

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-dDQ9KZBJ-1688012848862)(assets/1672107277356.png)]

Just pull a few form items and click "Get Data", which is the dynamic form data format we need.

3.3. Obtain all approval classification interfaces

1. Add an interface to the ProcessTypeController class

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

2. Add a front-end interface to processType.js

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

3.4. Upload process definition interface

Add an interface to the ProcessTemplateController class

@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 setting complete code

<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. View the approval template

View the basic information of the approval template and dynamic form information

4.1. Add button

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

4.2. Define data

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

4.3. Definition method

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

4.4. Define the pop-up layer

<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. Release

After the release, the approval template cannot be modified, and then deploy the process definition

5.1. Add controller interface

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

5.2. Add service interface and implementation

void publish(Long id);

Interface implementation:

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

5.3. Front-end implementation

1. Add API interface

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

2. Add button

<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. Add button method

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

Guess you like

Origin blog.csdn.net/AN_NI_112/article/details/131453978