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.
Article Directory
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
2. Approval template
3. Online process design
2.2. Staff side
1. Approval Center
2. Initiate approval and display dynamic form
3. Database table design
1. Approval type table: oa_process_type
2. Approval template table: oa_process_template
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
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
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
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:
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)
})
}