!88 合并flowable工作流功能
* merge 合并dev
* add 添加抄送查询
* add 添加我的已办
* add 添加抄送
* add 添加附件下载
* update 优化类型
* Merge remote-tracking branch 'origin/future/flowable' into future/flowable
* fix 修复 流程设计器打包部署报错问题
* add 添加审批附件上传
* update 修复固定值未在xml显示问题
* update 修复跳转条件回显Object问题
* update 优化面板文件名称
* update 调整key
* remove 移除旧设计器,添加xml保存
* update 增加任务面板提示
* update 优化xml预览和svg预览
* update 优化xml预览和svg预览
* update 优化模型设计
* update 优化设计器
* update 优化设计器
* update 优化设计器
* update 删除旧设计器
* update 删除console.log
* add 添加模型接口
* update 优化预览xml和svg样式被修改问题
* update 优化属性面板,增加展开动画
* update 去除开发模式
* update 优化任务栏样式
* update 优化图标渲染样式
* update 增加BpmnFactory类型
* update 增加BpmnFactory
* update 移除users和group
* update 移除无用类型
* update 优化页面类型
* update 去除多余属性
* update 完善流程线
* update 增加复杂网关
* update 完善流程
* update 完善网关
* update 优化网关汉化
* update 优化过期时间选择
* update 支持多实例
* update 增加类容提示
* update 支持选择组
* update 新增角色api
* update 优化roleSelect 选中未确定,再次打开还保留选中的问题
* update 优化userSelect 选中未确定,再次打开还保留选中的问题
* update 优化userSelect 选中未确定,再次打开还保留选中的问题
* update 去掉modeler store多余属性 bpmnModel
* update 优化属性面板,当面板未选中时默认展示流程面板
* update 优化TaskPanel类型,去掉roles属性
* update 优化用户api
* update 优化用户选择器
* update 优化执行监听器
* update 优化任务监听器
* update 优化usePanel方法
* update 选人优化
* update 增加扩展节点信息
* update 增加usePanel默认方法
* update 去除处理事件
* update 扩展flowable userinfo属性
* update 全局modeler 改为非响应式
* update 增加hooks方法
* update 修改命名
* update 修改面板formData来源
* update 重写用户任务面板选择逻辑
* update 重写用户任务面板选择逻辑
* update 修改用户选择组件获取数据逻辑
* update 修改枚举类型
* update 修改默认配置列
* update 增加修改节点方法
* update 调整预览窗口大小
* update 优化用户选择组件 返回值
* update 优化用户选择组件
* update 新增通过ids 获取用户信息
* update 重写task面板选人 未完成
* update 升级用户选择 支持多选配置
* update 升级bpmnjs依赖版本
* update 增加useDialog类型
* update 调整全局样式
* update 代码高亮设置
* update 优化领用,归还加载
* update 增加选择角色
* update 新增角色选择组件
* update 新增过期时间选择组件
* update 调整任务面板样式
* update 调整全局dialog header 增加分割线
* update 代码高亮设置
* update 调整面板位置
* update 封装用户选择组件
* update 移除所有的节点描述
* update 删除分类
* update 调整面板位置
* update 修改命名,增加自定义渲染
* update 修改命名,增加自定义渲染
* update 增加 Element类型定义
* update 调整样式
* update 移除bpmn panel依赖,升级bpmn.js依赖到最新,修改汉化包
* update 调整类型声明文件
* update 调整类型声明文件
* update 优化面板工具
* update 优化面板工具
* Merge remote-tracking branch 'origin/future/flowable' into future/flowable
* update 优化面板工具
* Merge branch 'future/flowable' of https://gitee.com/JavaLionLi/plus-ui…
* add 添加修改办理人
* update 优化面板工具
* update 初始化流程数据
* Merge remote-tracking branch 'origin/future/flowable' into future/flowable
* add 流程设计面板
* update 调整初始化xml
* add 任务面板
* add 新增bpmn.js
* update 优化request请求类判断请求头方式
* update 流程定义预览 优化
* update 流程定义预览 优化
* update 去掉console.log
* update 优化工作流代码
* fix 修复待办任务 重置查询条件失效问题
* add 增加待办任务 接口类型,优化页面
* add 增加vite 启动预编译css
* fix 修复i18n无感刷新问题
* Merge branch 'dev' into future/flowable
* update 调整选择请假事件
* Merge branch 'dev' into future/flowable
* 同步dev代码
* Merge branch 'dev' into future/flowable
* 合并dev
* remove 设计器无用代码 调整请假查询
* update 调整请假申请
* update 移动请假表单包结构,调整设计器选择引用表单请求错误
* remove 移除动态表单
* update 调整流程办理
* Merge branch 'dev' into future/flowable
* Merge branch 'dev' into future/flowable
* Merge branch 'dev' into future/flowable
* Merge branch 'dev' into future/flowable
* 合并
* update 调整请假申请流程提交
* update 修改业务单据流程提交
* update 调整业务单据流程提交
* 优化代码
* 优化工作流代码缩进
* 项目格式化配置修改
* 调整代码缩进
* Merge branch 'ts' into future/flowable
* add 添加动态表单提交流程
* add 添加动态表单单据
* add 新增流程定义与表单关联
* update 调整点击左侧部门查询人员,部门刷新问题
* update 调整按钮图标
* 调整错别字
* update 调整流程定义图片预览
* add 添加流程实例迁移版本
* fix 修复我的单据无法提交问题
* Merge branch 'ts' into future/flowable
* remove 还原代码后端解决
* update 流程设计器中分配发起人变量错误,先移除
* fix 修复设计器无法编辑问题
* update 调整设计器请求头
* Merge branch 'ts' into future/flowable
* Merge branch 'ts' into future/flowable
* add 添加流程定义历史列表
* update 审批记录v2改为v3
* update 调整请假必填项
* add 添加请假申请示例,添加流程定义文件部署
* update 移除流程表单 formConfig 属性,表单配置信息都放一起便于使用。
* add 添加任务加签,减签
* update 调整流程作废
* update 优化流程状态
* add 添加任务驳回
* add 添加查询当前租户所有待办,已办任务
* add 增加审批意见
* add 添加流程办理弹窗确认组件
* add 添加任务作废理由
* update 调整流程实例,流程定义检索
* add 添加我的单据页面
* add 添加任务归还认领
* add 添加流程实例,流程定义分类查询
* add 添加模型分类查询
* add 添加流程分类
* Merge remote-tracking branch 'origin/future/flowable' into future/flowable
* add 添加流程表单管理页面
* add 集成vForm动态表单组件
* update xml调整超出滚动
* add 添加已办列表
* add 添加单据状态
* update 优化流程实例删除
* fix 修复流程实例查询挂起状态错误
* update 调整流程实例挂起激活状态
* add 添加流程实例列表
* update 调整流程定义弹窗提示
* add 添加流程定义列表,添加流程图,xml预览,添加简单流程启动,办理
* 调整审批记录悬浮逻辑
* 删除无用代码
* add 添加节点悬浮信息
* 调整流程预览
* 调整流程追踪
* add 添加审批记录
* add 模型设计的types
* update 修改排版
* add lang=ts
* update 修改ele的废弃api
* fix调整审批记录图片不显示问题
* add 添加任务待办,流程图
* 调整设计器关闭
* add 添加待办
* remove 删除无用代码
* update types
* 添加模型token验证
* 隐藏设计器验证按钮,隐藏表单,案例,应用程序等
* 添加模型部署
* 添加画图接口token,优化画图接口
* 添加工作流模型新增,修改,查询,删除,画图工具
| | |
| | | }, |
| | | "dependencies": { |
| | | "@element-plus/icons-vue": "2.3.1", |
| | | "@highlightjs/vue-plugin": "2.1.0", |
| | | "@lezer/common": "1.2.1", |
| | | "@vueup/vue-quill": "1.2.0", |
| | | "@vueuse/core": "10.7.2", |
| | | "animate.css": "4.1.1", |
| | | "await-to-js": "3.0.0", |
| | | "axios": "1.6.5", |
| | | "bpmn-js": "16.4.0", |
| | | "camunda-bpmn-js-behaviors": "1.2.2", |
| | | "camunda-bpmn-moddle": "7.0.1", |
| | | "crypto-js": "4.2.0", |
| | | "diagram-js": "12.3.0", |
| | | "didi": "9.0.2", |
| | | "echarts": "5.4.3", |
| | | "element-plus": "2.4.4", |
| | | "file-saver": "2.0.5", |
| | | "fuse.js": "7.0.0", |
| | | "highlight.js": "11.9.0", |
| | | "image-conversion": "^2.1.1", |
| | | "js-cookie": "3.0.5", |
| | | "jsencrypt": "3.3.2", |
| | | "moddle": "6.2.3", |
| | | "nprogress": "0.2.0", |
| | | "path-browserify": "1.0.1", |
| | | "path-to-regexp": "6.2.1", |
| | | "pinia": "2.1.7", |
| | | "preact": "10.19.3", |
| | | "screenfull": "6.0.2", |
| | | "vform3-builds": "3.0.10", |
| | | "vue": "3.4.13", |
| | |
| | | "vue-i18n": "9.9.0", |
| | | "vue-router": "4.2.5", |
| | | "vue-types": "5.1.1", |
| | | "vxe-table": "4.5.18" |
| | | "vxe-table": "4.5.18", |
| | | "zeebe-bpmn-moddle": "1.0.0" |
| | | }, |
| | | "devDependencies": { |
| | | "@iconify/json": "2.2.168", |
| | |
| | | "@unocss/preset-attributify": "0.58.3", |
| | | "@unocss/preset-icons": "0.58.3", |
| | | "@unocss/preset-uno": "0.58.3", |
| | | "@vue/compiler-sfc": "3.4.13", |
| | | "@vitejs/plugin-vue": "5.0.3", |
| | | "@vue/compiler-sfc": "3.4.13", |
| | | "autoprefixer": "10.4.16", |
| | | "eslint": "8.56.0", |
| | | "eslint-config-prettier": "9.1.0", |
| | |
| | | "unplugin-icons": "0.18.2", |
| | | "unplugin-vue-components": "0.26.0", |
| | | "unplugin-vue-setup-extend-plus": "1.0.0", |
| | | "vite": "5.0.11", |
| | | "vite-plugin-compression": "0.5.1", |
| | | "vite-plugin-svg-icons": "2.0.1", |
| | | "vitest": "1.2.0", |
| | | "vue-eslint-parser": "9.4.0", |
| | | "vue-tsc": "1.8.27", |
| | | "vite": "5.0.11" |
| | | "vue-tsc": "1.8.27" |
| | | } |
| | | } |
| | |
| | | }; |
| | | |
| | | /** |
| | | * éè¿roleIdsæ¥è¯¢è§è² |
| | | * @param roleIds |
| | | */ |
| | | export const optionSelect = (roleIds: (number | string)[]): AxiosPromise<RoleVO[]> => { |
| | | return request({ |
| | | url: '/system/role/optionselect?roleIds=' + roleIds, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢è§è²è¯¦ç» |
| | | */ |
| | | export const getRole = (roleId: string | number): AxiosPromise<RoleVO> => { |
| | |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | export default { |
| | | optionSelect, |
| | | listRole |
| | | }; |
| | |
| | | }; |
| | | |
| | | /** |
| | | * éè¿ç¨æ·idsæ¥è¯¢ç¨æ· |
| | | * @param userIds |
| | | */ |
| | | export const optionSelect = (userIds: (number | string)[]): AxiosPromise<UserVO[]> => { |
| | | return request({ |
| | | url: '/system/user/optionselect?userIds=' + userIds, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * è·åç¨æ·è¯¦æ
|
| | | * @param userId |
| | | */ |
| | |
| | | export default { |
| | | listUser, |
| | | getUser, |
| | | optionSelect, |
| | | addUser, |
| | | updateUser, |
| | | delUser, |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | import { AxiosPromise } from 'axios'; |
| | | import { CategoryVO, CategoryForm, CategoryQuery } from '@/api/workflow/category/types'; |
| | | |
| | | /** |
| | | * æ¥è¯¢æµç¨åç±»å表 |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | |
| | | export const listCategory = (query?: CategoryQuery): AxiosPromise<CategoryVO[]> => { |
| | | return request({ |
| | | url: '/workflow/category/list', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢æµç¨åç±»è¯¦ç» |
| | | * @param id |
| | | */ |
| | | export const getCategory = (id: string | number): AxiosPromise<CategoryVO> => { |
| | | return request({ |
| | | url: '/workflow/category/' + id, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ°å¢æµç¨åç±» |
| | | * @param data |
| | | */ |
| | | export const addCategory = (data: CategoryForm) => { |
| | | return request({ |
| | | url: '/workflow/category', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * ä¿®æ¹æµç¨åç±» |
| | | * @param data |
| | | */ |
| | | export const updateCategory = (data: CategoryForm) => { |
| | | return request({ |
| | | url: '/workflow/category', |
| | | method: 'put', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å 餿µç¨åç±» |
| | | * @param id |
| | | */ |
| | | export const delCategory = (id: string | number | Array<string | number>) => { |
| | | return request({ |
| | | url: '/workflow/category/' + id, |
| | | method: 'delete' |
| | | }); |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export interface CategoryVO { |
| | | /** |
| | | * ä¸»é® |
| | | */ |
| | | id: string; |
| | | |
| | | /** |
| | | * åç±»åç§° |
| | | */ |
| | | categoryName: string; |
| | | |
| | | /** |
| | | * åç±»ç¼ç |
| | | */ |
| | | categoryCode: string; |
| | | |
| | | /** |
| | | * ç¶çº§id |
| | | */ |
| | | parentId: string | number; |
| | | |
| | | /** |
| | | * æåº |
| | | */ |
| | | sortNum: number; |
| | | |
| | | children?: CategoryVO[]; |
| | | } |
| | | |
| | | export interface CategoryForm extends BaseEntity { |
| | | /** |
| | | * ä¸»é® |
| | | */ |
| | | id?: string | number; |
| | | |
| | | /** |
| | | * åç±»åç§° |
| | | */ |
| | | categoryName?: string; |
| | | |
| | | /** |
| | | * åç±»ç¼ç |
| | | */ |
| | | categoryCode?: string; |
| | | |
| | | /** |
| | | * ç¶çº§id |
| | | */ |
| | | parentId?: string | number; |
| | | |
| | | /** |
| | | * æåº |
| | | */ |
| | | sortNum?: number; |
| | | } |
| | | |
| | | export interface CategoryQuery extends PageQuery { |
| | | /** |
| | | * åç±»åç§° |
| | | */ |
| | | categoryName?: string; |
| | | |
| | | /** |
| | | * åç±»ç¼ç |
| | | */ |
| | | categoryCode?: string; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | import { AxiosPromise } from 'axios'; |
| | | import { LeaveVO, LeaveQuery, LeaveForm } from '@/api/workflow/leave/types'; |
| | | |
| | | /** |
| | | * æ¥è¯¢è¯·åå表 |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | |
| | | export const listLeave = (query?: LeaveQuery): AxiosPromise<LeaveVO[]> => { |
| | | return request({ |
| | | url: '/demo/leave/list', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢è¯·åè¯¦ç» |
| | | * @param id |
| | | */ |
| | | export const getLeave = (id: string | number): AxiosPromise<LeaveVO> => { |
| | | return request({ |
| | | url: '/demo/leave/' + id, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ°å¢è¯·å |
| | | * @param data |
| | | */ |
| | | export const addLeave = (data: LeaveForm): AxiosPromise<LeaveVO> => { |
| | | return request({ |
| | | url: '/demo/leave', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * ä¿®æ¹è¯·å |
| | | * @param data |
| | | */ |
| | | export const updateLeave = (data: LeaveForm): AxiosPromise<LeaveVO> => { |
| | | return request({ |
| | | url: '/demo/leave', |
| | | method: 'put', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å é¤è¯·å |
| | | * @param id |
| | | */ |
| | | export const delLeave = (id: string | number | Array<string | number>) => { |
| | | return request({ |
| | | url: '/demo/leave/' + id, |
| | | method: 'delete' |
| | | }); |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export interface LeaveVO { |
| | | id: string | number; |
| | | leaveType: string; |
| | | startDate: string; |
| | | endDate: string; |
| | | leaveDays: number; |
| | | remark: string; |
| | | } |
| | | |
| | | export interface LeaveForm extends BaseEntity { |
| | | id?: string | number; |
| | | leaveType?: string; |
| | | startDate?: string; |
| | | endDate?: string; |
| | | leaveDays?: number; |
| | | remark?: string; |
| | | } |
| | | |
| | | export interface LeaveQuery extends PageQuery { |
| | | startLeaveDays?: number; |
| | | endLeaveDays?: number; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | import { AxiosPromise } from 'axios'; |
| | | import { ModelForm, ModelQuery, ModelVO } from '@/api/workflow/model/types'; |
| | | |
| | | /** |
| | | * æ¥è¯¢æ¨¡åå表 |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const listModel = (query: ModelQuery): AxiosPromise<ModelVO[]> => { |
| | | return request({ |
| | | url: '/workflow/model/list', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢æ¨¡åä¿¡æ¯ |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getInfo = (id: string): AxiosPromise<ModelForm> => { |
| | | return request({ |
| | | url: '/workflow/model/getInfo/'+id, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ°å¢æ¨¡å |
| | | * @param data |
| | | * @returns {*} |
| | | */ |
| | | export const addModel = (data: ModelForm): AxiosPromise<void> => { |
| | | return request({ |
| | | url: '/workflow/model/save', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * ä¿®æ¹æ¨¡åä¿¡æ¯ |
| | | * @param data |
| | | * @returns {*} |
| | | */ |
| | | export function update(data: ModelForm): AxiosPromise<void> { |
| | | return request({ |
| | | url: '/workflow/model/update', |
| | | method: 'put', |
| | | data: data |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * ä¿®æ¹æ¨¡åä¿¡æ¯ |
| | | * @param data |
| | | * @returns {*} |
| | | */ |
| | | export function editModelXml(data: ModelForm): AxiosPromise<void> { |
| | | return request({ |
| | | url: '/workflow/model/editModelXml', |
| | | method: 'put', |
| | | data: data |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * æidå 餿¨¡å |
| | | * @returns {*} |
| | | * @param id 模åid |
| | | */ |
| | | export function delModel(id: string | string[]): AxiosPromise<void> { |
| | | return request({ |
| | | url: '/workflow/model/' + id, |
| | | method: 'delete' |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * 模åé¨ç½² |
| | | * @returns {*} |
| | | * @param id 模åid |
| | | */ |
| | | export const modelDeploy = (id: string): AxiosPromise<void> => { |
| | | return request({ |
| | | url: `/workflow/model/modelDeploy/${id}`, |
| | | method: 'post' |
| | | }); |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export interface ModelForm { |
| | | id: string, |
| | | name: string; |
| | | key: string; |
| | | categoryCode: string; |
| | | xml:string, |
| | | svg:string, |
| | | description: string; |
| | | } |
| | | |
| | | export interface ModelQuery extends PageQuery { |
| | | name?: string; |
| | | key?: string; |
| | | categoryCode?: string; |
| | | } |
| | | |
| | | export interface OriginalPersistentState { |
| | | metaInfo: string; |
| | | editorSourceValueId: string; |
| | | createTime: string; |
| | | deploymentId?: string; |
| | | name: string; |
| | | tenantId: string; |
| | | category?: string; |
| | | version: number; |
| | | editorSourceExtraValueId?: string; |
| | | key: string; |
| | | lastUpdateTime: string; |
| | | } |
| | | |
| | | export interface PersistentState { |
| | | metaInfo: string; |
| | | editorSourceValueId: string; |
| | | createTime: string; |
| | | deploymentId?: string; |
| | | name: string; |
| | | tenantId: string; |
| | | category?: string; |
| | | version: number; |
| | | editorSourceExtraValueId?: string; |
| | | key: string; |
| | | lastUpdateTime: string; |
| | | } |
| | | |
| | | export interface ModelVO { |
| | | id: string; |
| | | revision: number; |
| | | originalPersistentState: OriginalPersistentState; |
| | | name: string; |
| | | key: string; |
| | | category?: string; |
| | | createTime: string; |
| | | lastUpdateTime: string; |
| | | version: number; |
| | | metaInfo: string; |
| | | deploymentId?: string; |
| | | editorSourceValueId: string; |
| | | editorSourceExtraValueId?: string; |
| | | tenantId: string; |
| | | persistentState: PersistentState; |
| | | revisionNext: number; |
| | | idPrefix: string; |
| | | inserted: boolean; |
| | | updated: boolean; |
| | | deleted: boolean; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | import { ProcessDefinitionQuery, ProcessDefinitionVO, ProcessDefinitionXmlVO } from '@/api/workflow/processDefinition/types'; |
| | | import { AxiosPromise } from 'axios'; |
| | | const baseUrl = import.meta.env.VITE_APP_BASE_API; |
| | | |
| | | /** |
| | | * è·åæµç¨å®ä¹å表 |
| | | * @param query æµç¨å®ä¾id |
| | | * @returns |
| | | */ |
| | | export const listProcessDefinition = (query: ProcessDefinitionQuery): AxiosPromise<ProcessDefinitionVO[]> => { |
| | | return request({ |
| | | url: `/workflow/processDefinition/list`, |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | /** |
| | | * æç
§æµç¨å®ä¹keyè·åæµç¨å®ä¹ |
| | | * @param processInstanceId æµç¨å®ä¾id |
| | | * @returns |
| | | */ |
| | | export const getProcessDefinitionListByKey = (key: string) => { |
| | | return request({ |
| | | url: `/workflow/processDefinition/getProcessDefinitionListByKey/${key}`, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * éè¿æµç¨å®ä¹idè·åæµç¨å¾ |
| | | */ |
| | | export const processDefinitionImage = (processDefinitionId: string): AxiosPromise<any> => { |
| | | return request({ |
| | | url: `/workflow/processDefinition/processDefinitionImage/${processDefinitionId}` + '?t' + Math.random(), |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * éè¿æµç¨å®ä¹idè·åxml |
| | | * @param processDefinitionId æµç¨å®ä¹id |
| | | * @returns |
| | | */ |
| | | export const processDefinitionXml = (processDefinitionId: string): AxiosPromise<ProcessDefinitionXmlVO> => { |
| | | return request({ |
| | | url: `/workflow/processDefinition/processDefinitionXml/${processDefinitionId}`, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å 餿µç¨å®ä¹ |
| | | * @param processDefinitionId æµç¨å®ä¹id |
| | | * @param deploymentId é¨ç½²id |
| | | * @returns |
| | | */ |
| | | export const deleteProcessDefinition = (deploymentId: string, processDefinitionId: string) => { |
| | | return request({ |
| | | url: `/workflow/processDefinition/${deploymentId}/${processDefinitionId}`, |
| | | method: 'delete' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æèµ·/æ¿æ´» |
| | | * @param processDefinitionId æµç¨å®ä¹id |
| | | * @returns |
| | | */ |
| | | export const updateProcessDefState = (processDefinitionId: string) => { |
| | | return request({ |
| | | url: `/workflow/processDefinition/updateProcessDefState/${processDefinitionId}`, |
| | | method: 'put' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æµç¨å®ä¹è½¬æ¢ä¸ºæ¨¡å |
| | | * @param processDefinitionId æµç¨å®ä¹id |
| | | * @returns |
| | | */ |
| | | export const convertToModel = (processDefinitionId: string) => { |
| | | return request({ |
| | | url: `/workflow/processDefinition/convertToModel/${processDefinitionId}`, |
| | | method: 'put' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * éè¿zipæxmlé¨ç½²æµç¨å®ä¹ |
| | | * @returns |
| | | */ |
| | | export function deployProcessFile(data: any) { |
| | | return request({ |
| | | url: '/workflow/processDefinition/deployByFile', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * è¿ç§»æµç¨ |
| | | * @param currentProcessDefinitionId |
| | | * @param fromProcessDefinitionId |
| | | * @returns |
| | | */ |
| | | export const migrationProcessDefinition = (currentProcessDefinitionId: string, fromProcessDefinitionId: string) => { |
| | | return request({ |
| | | url: `/workflow/processDefinition/migrationProcessDefinition/${currentProcessDefinitionId}/${fromProcessDefinitionId}`, |
| | | method: 'put' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢æµç¨å®ä¹å表 |
| | | * @returns |
| | | */ |
| | | export const getProcessDefinitionList = () => { |
| | | return request({ |
| | | url: `/workflow/processDefinition/getProcessDefinitionList`, |
| | | method: 'get' |
| | | }); |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export interface ProcessDefinitionQuery extends PageQuery { |
| | | key?: string; |
| | | name?: string; |
| | | categoryCode?: string; |
| | | } |
| | | |
| | | export interface ProcessDefinitionVO extends BaseEntity { |
| | | id: string; |
| | | name: string; |
| | | key: string; |
| | | version: number; |
| | | suspensionState: number; |
| | | resourceName: string; |
| | | diagramResourceName: string; |
| | | deploymentId: string; |
| | | deploymentTime: string; |
| | | } |
| | | |
| | | export interface ProcessDefinitionXmlVO { |
| | | xml: string[]; |
| | | xmlStr: string; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | import { ProcessInstanceQuery, ProcessInstanceVO } from '@/api/workflow/processInstance/types'; |
| | | import { AxiosPromise } from 'axios'; |
| | | import { string } from 'vue-types'; |
| | | const baseUrl = import.meta.env.VITE_APP_BASE_API; |
| | | |
| | | /** |
| | | * æ¥è¯¢è¿è¡ä¸å®ä¾å表 |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getProcessInstanceRunningByPage = (query: ProcessInstanceQuery): AxiosPromise<ProcessInstanceVO[]> => { |
| | | return request({ |
| | | url: '/workflow/processInstance/getProcessInstanceRunningByPage', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢å·²å®æå®ä¾å表 |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getProcessInstanceFinishByPage = (query: ProcessInstanceQuery): AxiosPromise<ProcessInstanceVO[]> => { |
| | | return request({ |
| | | url: '/workflow/processInstance/getProcessInstanceFinishByPage', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * éè¿æµç¨å®ä¾idè·åå岿µç¨å¾ |
| | | */ |
| | | export const getHistoryProcessImage = (processInstanceId: string) => { |
| | | return request({ |
| | | url: `/workflow/processInstance/getHistoryProcessImage/${processInstanceId}` + '?t' + Math.random(), |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * è·å审æ¹è®°å½ |
| | | * @param processInstanceId æµç¨å®ä¾id |
| | | * @returns |
| | | */ |
| | | export const getHistoryRecord = (processInstanceId: string) => { |
| | | return request({ |
| | | url: `/workflow/processInstance/getHistoryRecord/${processInstanceId}`, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * ä½åº |
| | | * @param data åæ° |
| | | * @returns |
| | | */ |
| | | export const deleteRuntimeProcessInst = (data: object) => { |
| | | return request({ |
| | | url: `/workflow/processInstance/deleteRuntimeProcessInst`, |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * è¿è¡ä¸çå®ä¾ å é¤ç¨å®ä¾ï¼å é¤åå²è®°å½ï¼å é¤ä¸å¡ä¸æµç¨å
³èä¿¡æ¯ |
| | | * @param processInstanceId æµç¨å®ä¾id |
| | | * @returns |
| | | */ |
| | | export const deleteRuntimeProcessAndHisInst = (processInstanceId: string | string[]) => { |
| | | return request({ |
| | | url: `/workflow/processInstance/deleteRuntimeProcessAndHisInst/${processInstanceId}`, |
| | | method: 'delete' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * 已宿çå®ä¾ å é¤ç¨å®ä¾ï¼å é¤åå²è®°å½ï¼å é¤ä¸å¡ä¸æµç¨å
³èä¿¡æ¯ |
| | | * @param processInstanceId æµç¨å®ä¾id |
| | | * @returns |
| | | */ |
| | | export const deleteFinishProcessAndHisInst = (processInstanceId: string | string[]) => { |
| | | return request({ |
| | | url: `/workflow/processInstance/deleteFinishProcessAndHisInst/${processInstanceId}`, |
| | | method: 'delete' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å页æ¥è¯¢å½åç»å½äººåæ® |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getCurrentSubmitByPage = (query: ProcessInstanceQuery): AxiosPromise<ProcessInstanceVO[]> => { |
| | | return request({ |
| | | url: '/workflow/processInstance/getCurrentSubmitByPage', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¤éæµç¨ |
| | | * @param processInstanceId æµç¨å®ä¾id |
| | | * @returns |
| | | */ |
| | | export const cancelProcessApply = (processInstanceId: string) => { |
| | | return request({ |
| | | url: `/workflow/processInstance/cancelProcessApply/${processInstanceId}`, |
| | | method: 'post' |
| | | }); |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { TaskVO } from '@/api/workflow/task/types'; |
| | | |
| | | export interface ProcessInstanceQuery extends PageQuery { |
| | | categoryCode?: string; |
| | | name?: string; |
| | | key?: string; |
| | | startUserId?: string; |
| | | businessKey?: string; |
| | | } |
| | | |
| | | export interface ProcessInstanceVO extends BaseEntity { |
| | | id: string; |
| | | processDefinitionId: string; |
| | | processDefinitionName: string; |
| | | processDefinitionKey: string; |
| | | processDefinitionVersion: string; |
| | | deploymentId: string; |
| | | businessKey: string; |
| | | isSuspended?: any; |
| | | tenantId: string; |
| | | startTime: string; |
| | | endTime?: string; |
| | | startUserId: string; |
| | | businessStatus: string; |
| | | businessStatusName: string; |
| | | taskVoList: TaskVO[]; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | import { AxiosPromise } from 'axios'; |
| | | import { TaskQuery, TaskVO } from '@/api/workflow/task/types'; |
| | | /** |
| | | * æ¥è¯¢å¾
åå表 |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getTaskWaitByPage = (query: TaskQuery): AxiosPromise<TaskVO[]> => { |
| | | return request({ |
| | | url: '/workflow/task/getTaskWaitByPage', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢å·²åå表 |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getTaskFinishByPage = (query: TaskQuery): AxiosPromise<TaskVO[]> => { |
| | | return request({ |
| | | url: '/workflow/task/getTaskFinishByPage', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢å½åç¨æ·çæéå表 |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getTaskCopyByPage = (query: TaskQuery): AxiosPromise<TaskVO[]> => { |
| | | return request({ |
| | | url: '/workflow/task/getTaskCopyByPage', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å½åç§æ·ææå¾
åä»»å¡ |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getAllTaskWaitByPage = (query: TaskQuery): AxiosPromise<TaskVO[]> => { |
| | | return request({ |
| | | url: '/workflow/task/getAllTaskWaitByPage', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å½åç§æ·ææå·²åä»»å¡ |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getAllTaskFinishByPage = (query: TaskQuery): AxiosPromise<TaskVO[]> => { |
| | | return request({ |
| | | url: '/workflow/task/getAllTaskFinishByPage', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å¯å¨æµç¨ |
| | | * @param data |
| | | * @returns {*} |
| | | */ |
| | | export const startWorkFlow = (data: object) => { |
| | | return request({ |
| | | url: '/workflow/task/startWorkFlow', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * åçæµç¨ |
| | | * @param data |
| | | * @returns {*} |
| | | */ |
| | | export const completeTask = (data: object) => { |
| | | return request({ |
| | | url: '/workflow/task/completeTask', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * 认é¢ä»»å¡ |
| | | * @param taskId |
| | | * @returns {*} |
| | | */ |
| | | export const claim = (taskId: string) => { |
| | | return request({ |
| | | url: '/workflow/task/claim/' + taskId, |
| | | method: 'post' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å½è¿ä»»å¡ |
| | | * @param taskId |
| | | * @returns {*} |
| | | */ |
| | | export const returnTask = (taskId: string) => { |
| | | return request({ |
| | | url: '/workflow/task/returnTask/' + taskId, |
| | | method: 'post' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * ä»»å¡é©³å |
| | | * @param taskId |
| | | * @returns {*} |
| | | */ |
| | | export const backProcess = (data: object) => { |
| | | return request({ |
| | | url: '/workflow/task/backProcess', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * è·åæµç¨ç¶æ |
| | | * @param taskId |
| | | * @returns |
| | | */ |
| | | export const getBusinessStatus = (taskId: string) => { |
| | | return request({ |
| | | url: '/workflow/task/getBusinessStatus/' + taskId, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å ç¾ |
| | | * @param data |
| | | * @returns |
| | | */ |
| | | export const addMultiInstanceExecution = (data: object) => { |
| | | return request({ |
| | | url: '/workflow/task/addMultiInstanceExecution', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * åç¾ |
| | | * @param data |
| | | * @returns |
| | | */ |
| | | export const deleteMultiInstanceExecution = (data: object) => { |
| | | return request({ |
| | | url: '/workflow/task/deleteMultiInstanceExecution', |
| | | method: 'post', |
| | | data: data |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * ä¿®æ¹ä»»å¡åç人 |
| | | * @param taskIds |
| | | * @param userId |
| | | * @returns |
| | | */ |
| | | export const updateAssignee = (taskIds: Array<string>,userId: string) => { |
| | | return request({ |
| | | url: `/workflow/task/updateAssignee/${taskIds}/${userId}`, |
| | | method: 'put' |
| | | }); |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export interface TaskQuery extends PageQuery { |
| | | name?: string; |
| | | processDefinitionKey?: string; |
| | | processDefinitionName?: string; |
| | | } |
| | | |
| | | export interface ParticipantVo { |
| | | groupIds?: string[] | number[]; |
| | | candidate: string[] | number[]; |
| | | candidateName: string[]; |
| | | claim: boolean; |
| | | } |
| | | |
| | | export interface TaskVO extends BaseEntity { |
| | | id: string; |
| | | name: string; |
| | | description?: string; |
| | | priority: number; |
| | | owner?: string; |
| | | assignee?: string | number; |
| | | assigneeName?: string; |
| | | processInstanceId: string; |
| | | executionId: string; |
| | | taskDefinitionId?: any; |
| | | processDefinitionId: string; |
| | | endTime?: string; |
| | | taskDefinitionKey: string; |
| | | dueDate?: string; |
| | | category?: any; |
| | | parentTaskId?: any; |
| | | tenantId: string; |
| | | claimTime?: string; |
| | | businessStatus: string; |
| | | businessStatusName: string; |
| | | processDefinitionName: string; |
| | | processDefinitionKey: string; |
| | | participantVo: ParticipantVo; |
| | | multiInstance: boolean; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | import { AxiosPromise } from 'axios'; |
| | | import { UserVO } from '@/api/system/user/types'; |
| | | |
| | | /** |
| | | * å页æ¥è¯¢å·¥ä½æµéæ©å ç¾äººå |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getWorkflowAddMultiListByPage = (query: object) => { |
| | | return request({ |
| | | url: '/workflow/user/getWorkflowAddMultiListByPage', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æ¥è¯¢å·¥ä½æµéæ©åç¾äººå |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getWorkflowDeleteMultiInstanceList = (taskId: string) => { |
| | | return request({ |
| | | url: '/workflow/user/getWorkflowDeleteMultiInstanceList/' + taskId, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * æç
§ç¨æ·idæ¥è¯¢ç¨æ· |
| | | * @param userIdList |
| | | * @returns {*} |
| | | */ |
| | | export const getUserListByIds = (userIdList: any[]): AxiosPromise<UserVO[]> => { |
| | | return request({ |
| | | url: '/workflow/user/getUserListByIds/' + userIdList, |
| | | method: 'get' |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * å页æ¥è¯¢ç¨æ· |
| | | * @param query |
| | | * @returns {*} |
| | | */ |
| | | export const getUserListByPage = (query: object) => { |
| | | return request({ |
| | | url: '/workflow/user/getUserListByPage', |
| | | method: 'get', |
| | | params: query |
| | | }); |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><path d="M321.94 98L158.82 237.78a24 24 0 000 36.44L321.94 414c15.57 13.34 39.62 2.28 39.62-18.22v-279.6c0-20.5-24.05-31.56-39.62-18.18z"/></svg> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><path d="M190.06 414l163.12-139.78a24 24 0 000-36.44L190.06 98c-15.57-13.34-39.62-2.28-39.62 18.22v279.6c0 20.5 24.05 31.56 39.62 18.18z"/></svg> |
| | |
| | | // cover some element-ui styles |
| | | |
| | | .el-collapse { |
| | | .collapse__title { |
| | | font-weight: 600; |
| | | padding: 0 8px; |
| | | font-size: 1.2em; |
| | | line-height: 1.1em; |
| | | } |
| | | .el-collapse-item__content { |
| | | padding: 0 8px; |
| | | } |
| | | } |
| | | |
| | | .el-divider--horizontal { |
| | | margin-bottom: 10px; |
| | |
| | | .el-dialog__body { |
| | | padding: 15px !important; |
| | | } |
| | | .el-dialog__header { |
| | | padding: 16px 16px 8px 16px; |
| | | box-sizing: border-box; |
| | | border-bottom: 1px solid #e8e8e8; |
| | | margin-right: 0; |
| | | } |
| | | } |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | function generateRandomValue() { |
| | | // çæä¸ä¸ªéæºæ° |
| | | const randomValue = Math.random().toString(36).slice(2, 12); |
| | | return `Process_${randomValue}`; |
| | | } |
| | | |
| | | const cartage: string = 'default'; |
| | | export default `<?xml version="1.0" encoding="UTF-8"?> |
| | | <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:bioc="http://bpmn.io/schema/bpmn/biocolor/1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.org/bpmn" targetNamespace="http://www.flowable.org/processdef"> |
| | | <process id="process_${generateRandomValue()}" name="name_${generateRandomValue()}"> |
| | | <startEvent id="startNode1" name="å¼å§" /> |
| | | </process> |
| | | <bpmndi:BPMNDiagram id="BPMNDiagram_flow"> |
| | | <bpmndi:BPMNPlane id="BPMNPlane_flow" bpmnElement="T-2d89e7a3-ba79-4abd-9f64-ea59621c258c"> |
| | | <bpmndi:BPMNShape id="BPMNShape_startNode1" bpmnElement="startNode1" bioc:stroke=""> |
| | | <omgdc:Bounds x="240" y="200" width="30" height="30" /> |
| | | <bpmndi:BPMNLabel> |
| | | <omgdc:Bounds x="242" y="237" width="23" height="14" /> |
| | | </bpmndi:BPMNLabel> |
| | | </bpmndi:BPMNShape> |
| | | </bpmndi:BPMNPlane> |
| | | </bpmndi:BPMNDiagram> |
| | | </definitions>`; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export const NodeName = { |
| | | 'bpmn:Process': 'æµç¨', |
| | | 'bpmn:StartEvent': 'å¼å§äºä»¶', |
| | | 'bpmn:IntermediateThrowEvent': 'ä¸é´äºä»¶', |
| | | 'bpmn:Task': 'ä»»å¡', |
| | | 'bpmn:SendTask': 'åéä»»å¡', |
| | | 'bpmn:ReceiveTask': 'æ¥æ¶ä»»å¡', |
| | | 'bpmn:UserTask': 'ç¨æ·ä»»å¡', |
| | | 'bpmn:ManualTask': 'æå·¥ä»»å¡', |
| | | 'bpmn:BusinessRuleTask': 'ä¸å¡è§åä»»å¡', |
| | | 'bpmn:ServiceTask': 'æå¡ä»»å¡', |
| | | 'bpmn:ScriptTask': 'èæ¬ä»»å¡', |
| | | 'bpmn:EndEvent': 'ç»æäºä»¶', |
| | | 'bpmn:SequenceFlow': 'æµç¨çº¿', |
| | | 'bpmn:ExclusiveGateway': 'äºæ¥ç½å
³', |
| | | 'bpmn:ParallelGateway': 'å¹¶è¡ç½å
³', |
| | | 'bpmn:InclusiveGateway': 'ç¸å®¹ç½å
³', |
| | | 'bpmn:ComplexGateway': '夿ç½å
³', |
| | | 'bpmn:EventBasedGateway': 'äºä»¶ç½å
³' |
| | | }; |
| | | |
| | | export default { |
| | | 'Activate hand tool': 'å¯å¨æå¨å·¥å
·', |
| | | 'Activate lasso tool': 'å¯å¨ Lasso å·¥å
·', |
| | | 'Activate create/remove space tool': 'å¯å¨å建/å é¤ç©ºé´å·¥å
·', |
| | | 'Activate global connect tool': 'å¯å¨å
¨å±è¿æ¥å·¥å
·', |
| | | 'Ad-hoc': 'Ad-hoc', |
| | | 'Add lane above': 'å¨ä¸æ¹æ·»å æ³³é', |
| | | 'Add lane below': 'å¨ä¸æ¹æ·»å æ³³é', |
| | | 'Business rule task': 'è§åä»»å¡', |
| | | 'Call activity': 'å¼ç¨æµç¨', |
| | | 'Compensation end event': 'ç»æè¡¥å¿äºä»¶', |
| | | 'Compensation intermediate throw event': 'ä¸é´è¡¥å¿æåºäºä»¶', |
| | | 'Complex gateway': '夿ç½å
³', |
| | | 'Conditional intermediate catch event': 'ä¸é´æ¡ä»¶æè·äºä»¶', |
| | | 'Conditional start event (non-interrupting)': 'æ¡ä»¶å¯å¨äºä»¶ (é䏿)', |
| | | 'Conditional start event': 'æ¡ä»¶å¯å¨äºä»¶', |
| | | 'Connect using association': 'ææ¬å
³è', |
| | | 'Connect using sequence/message flow or association': 'æ¶æ¯å
³è', |
| | | 'Change element': 'æ´æ¹å
ç´ ', |
| | | 'Change type': 'æ´æ¹ç±»å', |
| | | 'Create data object reference': 'åå»ºæ°æ®å¯¹è±¡å¼ç¨', |
| | | 'Create data store reference': 'åå»ºæ°æ®åå¨å¼ç¨', |
| | | 'Create expanded sub-process': 'åå»ºå¯æå åæµç¨', |
| | | 'Create pool/participant': 'åå»ºæ± /åä¸è
', |
| | | 'Collection': 'éå', |
| | | 'Connect using data input association': 'æ°æ®è¾å
¥å
³è', |
| | | 'Data store reference': 'æ°æ®åå¨å¼ç¨', |
| | | 'Data object reference': 'æ°æ®å¯¹è±¡å¼ç¨', |
| | | 'Divide into two lanes': 'åæä¸¤ä¸ªæ³³é', |
| | | 'Divide into three lanes': 'åæä¸ä¸ªæ³³é', |
| | | 'End event': 'ç»æäºä»¶', |
| | | 'Error end event': 'ç»æé误äºä»¶', |
| | | 'Escalation end event': 'ç»æå级äºä»¶', |
| | | 'Escalation intermediate throw event': 'ä¸é´å级æåºäºä»¶', |
| | | 'Event sub-process': 'äºä»¶åæµç¨', |
| | | 'Event-based gateway': 'äºä»¶ç½å
³', |
| | | 'Exclusive gateway': 'äºæ¥ç½å
³', |
| | | 'Empty pool/participant (removes content)': 'æ¸
ç©ºæ± /åä¸è
(å é¤å
容)', |
| | | 'Inclusive gateway': 'ç¸å®¹ç½å
³', |
| | | 'Intermediate throw event': 'ä¸é´æåºäºä»¶', |
| | | 'Loop': '循ç¯', |
| | | 'Link intermediate catch event': 'ä¸é´é¾æ¥æè·äºä»¶', |
| | | 'Link intermediate throw event': 'ä¸é´é¾æ¥æåºäºä»¶', |
| | | 'Manual task': 'æå¨ä»»å¡', |
| | | 'Message end event': 'ç»ææ¶æ¯äºä»¶', |
| | | 'Message intermediate catch event': 'ä¸é´æ¶æ¯æè·äºä»¶', |
| | | 'Message intermediate throw event': 'ä¸é´æ¶æ¯æåºäºä»¶', |
| | | 'Message start event': 'æ¶æ¯å¯å¨äºä»¶', |
| | | 'Parallel gateway': 'å¹¶è¡ç½å
³', |
| | | 'Parallel multi-instance': 'å¹¶è¡å¤å®ä¾', |
| | | 'Participant multiplicity': 'åä¸è
å¤éæ§', |
| | | 'Receive task': 'æ¥åä»»å¡', |
| | | 'Remove': 'ç§»é¤', |
| | | 'Script task': 'èæ¬ä»»å¡', |
| | | 'Send task': 'åéä»»å¡', |
| | | 'Sequential multi-instance': '串è¡å¤å®ä¾', |
| | | 'Service task': 'æå¡ä»»å¡', |
| | | 'Signal end event': 'ç»æä¿¡å·äºä»¶', |
| | | 'Signal intermediate catch event': 'ä¸é´ä¿¡å·æè·äºä»¶', |
| | | 'Signal intermediate throw event': 'ä¸é´ä¿¡å·æåºäºä»¶', |
| | | 'Signal start event (non-interrupting)': 'ä¿¡å·å¯å¨äºä»¶ (é䏿)', |
| | | 'Signal start event': 'ä¿¡å·å¯å¨äºä»¶', |
| | | 'Start event': 'å¼å§äºä»¶', |
| | | 'Sub-process (collapsed)': '坿å åæµç¨', |
| | | 'Sub-process (expanded)': 'å¯å±å¼åæµç¨', |
| | | 'Sub rocess': 'åæµç¨', |
| | | 'Task': 'ä»»å¡', |
| | | 'Transaction': 'äºå¡', |
| | | 'Terminate end event': 'ç»æ¢è¾¹çäºä»¶', |
| | | 'Timer intermediate catch event': 'ä¸é´å®æ¶æè·äºä»¶', |
| | | 'Timer start event (non-interrupting)': '宿¶å¯å¨äºä»¶ (é䏿)', |
| | | 'Timer start event': '宿¶å¯å¨äºä»¶', |
| | | 'User task': 'ç¨æ·ä»»å¡', |
| | | 'Create start event': 'å建å¼å§äºä»¶', |
| | | 'Create gateway': 'å建ç½å
³', |
| | | 'Create intermediate/boundary event': 'å建ä¸é´/è¾¹çäºä»¶', |
| | | 'Create end event': 'åå»ºç»æäºä»¶', |
| | | 'Create group': 'å建ç»', |
| | | 'Create startEvent': 'å¼å§èç¹', |
| | | 'Create endEvent': 'ç»æèç¹', |
| | | 'Create exclusiveGateway': 'äºæ¥ç½å
³', |
| | | 'Create parallelGateway': 'å¹¶è¡ç½å
³', |
| | | 'Create task': 'ä»»å¡èç¹', |
| | | 'Create userTask': 'ç¨æ·ä»»å¡èç¹', |
| | | 'Condition type': 'æ¡ä»¶ç±»å', |
| | | 'Append end event': '追å ç»æäºä»¶èç¹', |
| | | 'Append gateway': '追å ç½å
³èç¹', |
| | | 'Append task': '追å ä»»å¡', |
| | | 'Append user task': '追å ç¨æ·ä»»å¡èç¹', |
| | | 'Append text annotation': 'è¿½å ææ¬æ³¨é', |
| | | 'Append intermediate/boundary event': '追å ä¸é´æè¾¹çäºä»¶', |
| | | 'Append receive task': 'è¿½å æ¥æ¶ä»»å¡èç¹', |
| | | 'Append message intermediate catch event': '追å ä¸é´æ¶æ¯æè·äºä»¶', |
| | | 'Append timer intermediate catch event': '追å ä¸é´å®æ¶æè·äºä»¶', |
| | | 'Append conditional intermediate catch event': '追å ä¸é´æ¡ä»¶æè·äºä»¶', |
| | | 'Append signal intermediate catch event': '追å ä¸é´ä¿¡å·æè·äºä»¶' |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export default { |
| | | 'name': 'Flowable', |
| | | 'uri': 'http://flowable.org/bpmn', |
| | | 'prefix': 'flowable', |
| | | 'xml': { |
| | | 'tagAlias': 'lowerCase' |
| | | }, |
| | | 'associations': [], |
| | | 'types': [ |
| | | { |
| | | 'name': 'flowable:extCandidateUsers', |
| | | 'isAbstract': true, |
| | | 'extends': [], |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['*'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'body', |
| | | 'type': 'String', |
| | | 'isBody': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'flowable:extAssignee', |
| | | 'isAbstract': true, |
| | | 'extends': [], |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['*'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'body', |
| | | 'type': 'String', |
| | | 'isBody': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'flowable:property', |
| | | 'superClass': ['Element'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'id', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'name', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'value', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'flowable:properties', |
| | | 'isAbstract': true, |
| | | 'extends': [], |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['*'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'values', |
| | | 'type': 'flowable:property', |
| | | 'isMany': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'InOutBinding', |
| | | 'superClass': ['Element'], |
| | | 'isAbstract': true, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'source', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'sourceExpression', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'target', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'businessKey', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'local', |
| | | 'isAttr': true, |
| | | 'type': 'Boolean', |
| | | 'default': false |
| | | }, |
| | | { |
| | | 'name': 'variables', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'In', |
| | | 'superClass': ['InOutBinding'], |
| | | 'meta': { |
| | | 'allowedIn': ['bpmn:CallActivity'] |
| | | } |
| | | }, |
| | | { |
| | | 'name': 'Out', |
| | | 'superClass': ['InOutBinding'], |
| | | 'meta': { |
| | | 'allowedIn': ['bpmn:CallActivity'] |
| | | } |
| | | }, |
| | | { |
| | | 'name': 'AsyncCapable', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:Activity', 'bpmn:Gateway', 'bpmn:Event'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'async', |
| | | 'isAttr': true, |
| | | 'type': 'Boolean', |
| | | 'default': false |
| | | }, |
| | | { |
| | | 'name': 'asyncBefore', |
| | | 'isAttr': true, |
| | | 'type': 'Boolean', |
| | | 'default': false |
| | | }, |
| | | { |
| | | 'name': 'asyncAfter', |
| | | 'isAttr': true, |
| | | 'type': 'Boolean', |
| | | 'default': false |
| | | }, |
| | | { |
| | | 'name': 'exclusive', |
| | | 'isAttr': true, |
| | | 'type': 'Boolean', |
| | | 'default': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'flowable:in', |
| | | 'superClass': ['Element'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'source', |
| | | 'type': 'string', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'target', |
| | | 'type': 'string', |
| | | 'isAttr': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'flowable:out', |
| | | 'superClass': ['Element'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'source', |
| | | 'type': 'string', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'target', |
| | | 'type': 'string', |
| | | 'isAttr': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'BoundaryEvent', |
| | | 'superClass': ['CatchEvent'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'cancelActivity', |
| | | 'default': true, |
| | | 'isAttr': true, |
| | | 'type': 'Boolean' |
| | | }, |
| | | { |
| | | 'name': 'attachedToRef', |
| | | 'type': 'Activity', |
| | | 'isAttr': true, |
| | | 'isReference': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'JobPriorized', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:Process', 'flowable:AsyncCapable'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'jobPriority', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'SignalEventDefinition', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:SignalEventDefinition'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'async', |
| | | 'isAttr': true, |
| | | 'type': 'Boolean', |
| | | 'default': false |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'ErrorEventDefinition', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:ErrorEventDefinition'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'errorCodeVariable', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'errorMessageVariable', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Error', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:Error'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'flowable:errorMessage', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'PotentialStarter', |
| | | 'superClass': ['Element'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'resourceAssignmentExpression', |
| | | 'type': 'bpmn:ResourceAssignmentExpression' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'UserTask', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:UserTask'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'timerEventDefinition', |
| | | 'type': 'Expression' |
| | | }, |
| | | { |
| | | 'name': 'multiInstanceLoopCharacteristics', |
| | | 'type': 'MultiInstanceLoopCharacteristics' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'StartEvent', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:StartEvent'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'timerEventDefinition', |
| | | 'type': 'Expression' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'FormSupported', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:StartEvent', 'bpmn:UserTask'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'formHandlerClass', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'formKey', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'TemplateSupported', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:Process', 'bpmn:FlowElement'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'modelerTemplate', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Initiator', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:StartEvent'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'initiator', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'ScriptTask', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:ScriptTask'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'resultVariable', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'resource', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Process', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:Process'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'candidateStarterGroups', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'candidateStarterUsers', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'versionTag', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'historyTimeToLive', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'isStartableInTasklist', |
| | | 'isAttr': true, |
| | | 'type': 'Boolean', |
| | | 'default': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'EscalationEventDefinition', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:EscalationEventDefinition'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'escalationCodeVariable', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'FormalExpression', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:FormalExpression'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'resource', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Assignable', |
| | | 'extends': ['bpmn:UserTask'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'candidateGroups', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'dueDate', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'followUpDate', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'priority', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'CallActivity', |
| | | 'extends': ['bpmn:CallActivity'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'calledElementBinding', |
| | | 'isAttr': true, |
| | | 'type': 'String', |
| | | 'default': 'latest' |
| | | }, |
| | | { |
| | | 'name': 'calledElementVersion', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'calledElementVersionTag', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'calledElementTenantId', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'caseRef', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'caseBinding', |
| | | 'isAttr': true, |
| | | 'type': 'String', |
| | | 'default': 'latest' |
| | | }, |
| | | { |
| | | 'name': 'caseVersion', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'caseTenantId', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'variableMappingClass', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'variableMappingDelegateExpression', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'ServiceTaskLike', |
| | | 'extends': ['bpmn:ServiceTask', 'bpmn:BusinessRuleTask', 'bpmn:SendTask', 'bpmn:MessageEventDefinition'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'expression', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'class', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'delegateExpression', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'resultVariable', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'ExclusiveGateway', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:ExclusiveGateway'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'serviceClass', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'DmnCapable', |
| | | 'extends': ['bpmn:BusinessRuleTask'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'decisionRef', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'decisionRefBinding', |
| | | 'isAttr': true, |
| | | 'type': 'String', |
| | | 'default': 'latest' |
| | | }, |
| | | { |
| | | 'name': 'decisionRefVersion', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'mapDecisionResult', |
| | | 'isAttr': true, |
| | | 'type': 'String', |
| | | 'default': 'resultList' |
| | | }, |
| | | { |
| | | 'name': 'decisionRefTenantId', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'ExternalCapable', |
| | | 'extends': ['flowable:ServiceTaskLike'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'type', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'topic', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'TaskPriorized', |
| | | 'extends': ['bpmn:Process', 'flowable:ExternalCapable'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'taskPriority', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Properties', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['*'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'values', |
| | | 'type': 'Property', |
| | | 'isMany': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Property', |
| | | 'superClass': ['Element'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'id', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'name', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'value', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Connector', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['flowable:ServiceTaskLike'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'inputOutput', |
| | | 'type': 'InputOutput' |
| | | }, |
| | | { |
| | | 'name': 'connectorId', |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'InputOutput', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['bpmn:FlowNode', 'flowable:Connector'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'inputOutput', |
| | | 'type': 'InputOutput' |
| | | }, |
| | | { |
| | | 'name': 'connectorId', |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'inputParameters', |
| | | 'isMany': true, |
| | | 'type': 'InputParameter' |
| | | }, |
| | | { |
| | | 'name': 'outputParameters', |
| | | 'isMany': true, |
| | | 'type': 'OutputParameter' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'InputOutputParameter', |
| | | 'properties': [ |
| | | { |
| | | 'name': 'name', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'value', |
| | | 'isBody': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'definition', |
| | | 'type': 'InputOutputParameterDefinition' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'InputOutputParameterDefinition', |
| | | 'isAbstract': true |
| | | }, |
| | | { |
| | | 'name': 'List', |
| | | 'superClass': ['InputOutputParameterDefinition'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'items', |
| | | 'isMany': true, |
| | | 'type': 'InputOutputParameterDefinition' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Map', |
| | | 'superClass': ['InputOutputParameterDefinition'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'entries', |
| | | 'isMany': true, |
| | | 'type': 'Entry' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Entry', |
| | | 'properties': [ |
| | | { |
| | | 'name': 'key', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'value', |
| | | 'isBody': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'definition', |
| | | 'type': 'InputOutputParameterDefinition' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Value', |
| | | 'superClass': ['InputOutputParameterDefinition'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'id', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'name', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'value', |
| | | 'isBody': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Script', |
| | | 'superClass': ['InputOutputParameterDefinition'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'scriptFormat', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'resource', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'value', |
| | | 'isBody': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Field', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['flowable:ServiceTaskLike', 'flowable:ExecutionListener', 'flowable:TaskListener'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'name', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'expression', |
| | | 'isAttr': true, |
| | | 'type': 'expression' |
| | | }, |
| | | { |
| | | 'name': 'string', |
| | | 'type': 'string' |
| | | }, |
| | | { |
| | | 'name': 'stringValue', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'string', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['flowable:Field'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'body', |
| | | 'isBody': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'expression', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['flowable:Field'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'body', |
| | | 'isBody': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'InputParameter', |
| | | 'superClass': ['InputOutputParameter'] |
| | | }, |
| | | { |
| | | 'name': 'OutputParameter', |
| | | 'superClass': ['InputOutputParameter'] |
| | | }, |
| | | { |
| | | 'name': 'Collectable', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:MultiInstanceLoopCharacteristics'], |
| | | 'superClass': ['flowable:AsyncCapable'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'collection', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'elementVariable', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'SequenceFlow', |
| | | 'superClass': ['FlowElement'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'isImmediate', |
| | | 'isAttr': true, |
| | | 'type': 'Boolean' |
| | | }, |
| | | { |
| | | 'name': 'conditionExpression', |
| | | 'type': 'Expression' |
| | | }, |
| | | { |
| | | 'name': 'sourceRef', |
| | | 'type': 'FlowNode', |
| | | 'isAttr': true, |
| | | 'isReference': true |
| | | }, |
| | | { |
| | | 'name': 'targetRef', |
| | | 'type': 'FlowNode', |
| | | 'isAttr': true, |
| | | 'isReference': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'MultiInstanceLoopCharacteristics', |
| | | 'superClass': ['LoopCharacteristics'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'isSequential', |
| | | 'default': false, |
| | | 'isAttr': true, |
| | | 'type': 'Boolean' |
| | | }, |
| | | { |
| | | 'name': 'behavior', |
| | | 'type': 'MultiInstanceBehavior', |
| | | 'default': 'All', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'loopCardinality', |
| | | 'type': 'Expression', |
| | | 'xml': { |
| | | 'serialize': 'xsi:type' |
| | | } |
| | | }, |
| | | { |
| | | 'name': 'loopDataInputRef', |
| | | 'type': 'ItemAwareElement', |
| | | 'isReference': true |
| | | }, |
| | | { |
| | | 'name': 'loopDataOutputRef', |
| | | 'type': 'ItemAwareElement', |
| | | 'isReference': true |
| | | }, |
| | | { |
| | | 'name': 'inputDataItem', |
| | | 'type': 'DataInput', |
| | | 'xml': { |
| | | 'serialize': 'property' |
| | | } |
| | | }, |
| | | { |
| | | 'name': 'outputDataItem', |
| | | 'type': 'DataOutput', |
| | | 'xml': { |
| | | 'serialize': 'property' |
| | | } |
| | | }, |
| | | { |
| | | 'name': 'complexBehaviorDefinition', |
| | | 'type': 'ComplexBehaviorDefinition', |
| | | 'isMany': true |
| | | }, |
| | | { |
| | | 'name': 'completionCondition', |
| | | 'type': 'Expression', |
| | | 'xml': { |
| | | 'serialize': 'xsi:type' |
| | | } |
| | | }, |
| | | { |
| | | 'name': 'oneBehaviorEventRef', |
| | | 'type': 'EventDefinition', |
| | | 'isAttr': true, |
| | | 'isReference': true |
| | | }, |
| | | { |
| | | 'name': 'noneBehaviorEventRef', |
| | | 'type': 'EventDefinition', |
| | | 'isAttr': true, |
| | | 'isReference': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'FailedJobRetryTimeCycle', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['flowable:AsyncCapable', 'bpmn:MultiInstanceLoopCharacteristics'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'body', |
| | | 'isBody': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'ExecutionListener', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': [ |
| | | 'bpmn:Task', |
| | | 'bpmn:ServiceTask', |
| | | 'bpmn:UserTask', |
| | | 'bpmn:BusinessRuleTask', |
| | | 'bpmn:ScriptTask', |
| | | 'bpmn:ReceiveTask', |
| | | 'bpmn:ManualTask', |
| | | 'bpmn:ExclusiveGateway', |
| | | 'bpmn:SequenceFlow', |
| | | 'bpmn:ParallelGateway', |
| | | 'bpmn:InclusiveGateway', |
| | | 'bpmn:EventBasedGateway', |
| | | 'bpmn:StartEvent', |
| | | 'bpmn:IntermediateCatchEvent', |
| | | 'bpmn:IntermediateThrowEvent', |
| | | 'bpmn:EndEvent', |
| | | 'bpmn:BoundaryEvent', |
| | | 'bpmn:CallActivity', |
| | | 'bpmn:SubProcess', |
| | | 'bpmn:Process' |
| | | ] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'expression', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'class', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'delegateExpression', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'event', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'script', |
| | | 'type': 'Script' |
| | | }, |
| | | { |
| | | 'name': 'fields', |
| | | 'type': 'Field', |
| | | 'isMany': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'TaskListener', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['bpmn:UserTask'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'expression', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'class', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'delegateExpression', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'event', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'script', |
| | | 'type': 'Script' |
| | | }, |
| | | { |
| | | 'name': 'fields', |
| | | 'type': 'Field', |
| | | 'isMany': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'FormProperty', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['bpmn:StartEvent', 'bpmn:UserTask'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'id', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'name', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'type', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'required', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'readable', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'writable', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'variable', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'expression', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'datePattern', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'default', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'values', |
| | | 'type': 'Value', |
| | | 'isMany': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'FormData', |
| | | 'superClass': ['Element'], |
| | | 'meta': { |
| | | 'allowedIn': ['bpmn:StartEvent', 'bpmn:UserTask'] |
| | | }, |
| | | 'properties': [ |
| | | { |
| | | 'name': 'fields', |
| | | 'type': 'FormField', |
| | | 'isMany': true |
| | | }, |
| | | { |
| | | 'name': 'businessKey', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'FormField', |
| | | 'superClass': ['Element'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'id', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'label', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'type', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'datePattern', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'defaultValue', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'properties', |
| | | 'type': 'Properties' |
| | | }, |
| | | { |
| | | 'name': 'validation', |
| | | 'type': 'Validation' |
| | | }, |
| | | { |
| | | 'name': 'values', |
| | | 'type': 'Value', |
| | | 'isMany': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Validation', |
| | | 'superClass': ['Element'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'constraints', |
| | | 'type': 'Constraint', |
| | | 'isMany': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'Constraint', |
| | | 'superClass': ['Element'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'name', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | }, |
| | | { |
| | | 'name': 'config', |
| | | 'type': 'String', |
| | | 'isAttr': true |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | 'name': 'ConditionalEventDefinition', |
| | | 'isAbstract': true, |
| | | 'extends': ['bpmn:ConditionalEventDefinition'], |
| | | 'properties': [ |
| | | { |
| | | 'name': 'variableName', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | }, |
| | | { |
| | | 'name': 'variableEvent', |
| | | 'isAttr': true, |
| | | 'type': 'String' |
| | | } |
| | | ] |
| | | } |
| | | ], |
| | | 'emumerations': [] |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import ContextPadProvider from 'bpmn-js/lib/features/context-pad/ContextPadProvider'; |
| | | import { Injector } from 'didi'; |
| | | import EventBus from 'diagram-js/lib/core/EventBus'; |
| | | import ContextPad from 'diagram-js/lib/features/context-pad/ContextPad'; |
| | | import Modeling from 'bpmn-js/lib/features/modeling/Modeling.js'; |
| | | import ElementFactory from 'bpmn-js/lib/features/modeling/ElementFactory'; |
| | | import Connect from 'diagram-js/lib/features/connect/Connect'; |
| | | import Create from 'diagram-js/lib/features/create/Create'; |
| | | import PopupMenu from 'diagram-js/lib/features/popup-menu/PopupMenu'; |
| | | import Canvas from 'diagram-js/lib/core/Canvas'; |
| | | import Rules from 'diagram-js/lib/features/rules/Rules'; |
| | | import { Element, Shape } from 'diagram-js/lib/model/Types'; |
| | | import BpmnFactory from 'bpmn-js/lib/features/modeling/BpmnFactory'; |
| | | import modeler from '@/store/modules/modeler'; |
| | | |
| | | // @Description: å¢å¼ºå
ç´ è¿çº¿äºä»¶ |
| | | |
| | | class CustomContextPadProvider extends ContextPadProvider { |
| | | private _contextPad: ContextPad; |
| | | private _modeling: Modeling; |
| | | private _elementFactory: ElementFactory; |
| | | private _autoPlace: any; |
| | | private _connect: Connect; |
| | | private _create: Create; |
| | | private _popupMenu: PopupMenu; |
| | | private _canvas: Canvas; |
| | | private _rules: Rules; |
| | | |
| | | constructor( |
| | | config: any, |
| | | injector: Injector, |
| | | eventBus: EventBus, |
| | | contextPad: ContextPad, |
| | | modeling: Modeling, |
| | | elementFactory: ElementFactory, |
| | | connect: Connect, |
| | | create: Create, |
| | | popupMenu: PopupMenu, |
| | | canvas: Canvas, |
| | | rules: Rules, |
| | | translate |
| | | ) { |
| | | // @ts-ignore |
| | | super(config, injector, eventBus, contextPad, modeling, elementFactory, connect, create, popupMenu, canvas, rules, translate); |
| | | |
| | | this._contextPad = contextPad; |
| | | this._modeling = modeling; |
| | | this._elementFactory = elementFactory; |
| | | this._connect = connect; |
| | | this._create = create; |
| | | this._popupMenu = popupMenu; |
| | | this._canvas = canvas; |
| | | this._rules = rules; |
| | | |
| | | this._autoPlace = injector.get('autoPlace', false); |
| | | } |
| | | |
| | | getContextPadEntries(element: Element) { |
| | | const actions: Record<string, any> = {}; |
| | | |
| | | const appendUserTask = (event: Event, element: Shape) => { |
| | | const shape = this._elementFactory.createShape({ type: 'bpmn:UserTask' }); |
| | | this._create.start(event, shape, { |
| | | source: element |
| | | }); |
| | | }; |
| | | |
| | | const appendMultiInstanceUserTask = (event: Event, element: Shape) => { |
| | | const store = modeler(); |
| | | const bpmnFactory = store.getModeler().get('bpmnFactory') as BpmnFactory; |
| | | const businessObject = bpmnFactory.create('bpmn:UserTask', { |
| | | // name: 'å¤å®ä¾ç¨æ·ä»»å¡', |
| | | isForCompensation: false |
| | | }); |
| | | businessObject.loopCharacteristics = bpmnFactory.create('bpmn:MultiInstanceLoopCharacteristics'); |
| | | // å建 Shape |
| | | const shape = this._elementFactory.createShape({ |
| | | type: 'bpmn:UserTask', |
| | | businessObject: businessObject |
| | | }); |
| | | this._create.start(event, shape, { source: element }); |
| | | }; |
| | | |
| | | const appendTask = this._autoPlace |
| | | ? (event, element) => { |
| | | const bpmnFactory: BpmnFactory | undefined = modeler().getModeler().get('bpmnFactory'); |
| | | const businessObject = bpmnFactory.create('bpmn:UserTask', { |
| | | // name: 'å¤å®ä¾ç¨æ·ä»»å¡',// å³é®å建æ¾ç¤º |
| | | isForCompensation: false |
| | | }); |
| | | |
| | | // å建å¤å®ä¾å±æ§å¹¶åé
ç»ç¨æ·ä»»å¡ç loopCharacteristics |
| | | businessObject.loopCharacteristics = bpmnFactory.create('bpmn:MultiInstanceLoopCharacteristics'); |
| | | |
| | | // å建 Shape |
| | | const shape = this._elementFactory.createShape({ |
| | | type: 'bpmn:UserTask', |
| | | businessObject: businessObject |
| | | }); |
| | | |
| | | this._autoPlace.append(element, shape); |
| | | } |
| | | : appendMultiInstanceUserTask; |
| | | |
| | | const append = this._autoPlace |
| | | ? (event: Event, element: Shape) => { |
| | | const shape = this._elementFactory.createShape({ type: 'bpmn:UserTask' }); |
| | | this._autoPlace.append(element, shape); |
| | | } |
| | | : appendUserTask; |
| | | |
| | | // // æ·»å åå»ºç¨æ·ä»»å¡æé® |
| | | actions['append.append-user-task'] = { |
| | | group: 'model', |
| | | className: 'bpmn-icon-user-task', |
| | | title: 'ç¨æ·ä»»å¡', |
| | | action: { |
| | | dragstart: appendUserTask, |
| | | click: append |
| | | } |
| | | }; |
| | | |
| | | // æ·»å å建å¤å®ä¾ç¨æ·ä»»å¡æé® |
| | | actions['append.append-multi-instance-user-task'] = { |
| | | group: 'model', |
| | | className: 'bpmn-icon-user', // ä½ å¯ä»¥ä½¿ç¨å¤å®ä¾ç¨æ·ä»»å¡ç徿 bpmn-icon-user bpmn-icon-user-task |
| | | title: 'å¤å®ä¾ç¨æ·ä»»å¡', |
| | | action: { |
| | | dragstart: appendMultiInstanceUserTask, |
| | | click: appendTask |
| | | } |
| | | }; |
| | | |
| | | return actions; |
| | | } |
| | | } |
| | | |
| | | export default CustomContextPadProvider; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { assign } from 'min-dash'; |
| | | import PaletteProvider from 'bpmn-js/lib/features/palette/PaletteProvider'; |
| | | import ElementFactory from 'bpmn-js/lib/features/modeling/ElementFactory'; |
| | | import Create from 'diagram-js/lib/features/create/Create'; |
| | | import SpaceTool from 'diagram-js/lib/features/space-tool/SpaceTool'; |
| | | import LassoTool from 'diagram-js/lib/features/lasso-tool/LassoTool'; |
| | | import HandTool from 'diagram-js/lib/features/hand-tool/HandTool'; |
| | | import GlobalConnect from 'diagram-js/lib/features/global-connect/GlobalConnect'; |
| | | import Palette from 'diagram-js/lib/features/palette/Palette'; |
| | | import modeler from '@/store/modules/modeler'; |
| | | import BpmnFactory from 'bpmn-js/lib/features/modeling/BpmnFactory'; |
| | | |
| | | // @Description: å¢å¼ºå·¦ä¾§é¢æ¿ |
| | | class CustomPaletteProvider extends PaletteProvider { |
| | | private readonly _palette: Palette; |
| | | private readonly _create: Create; |
| | | private readonly _elementFactory: ElementFactory; |
| | | private readonly _spaceTool: SpaceTool; |
| | | private readonly _lassoTool: LassoTool; |
| | | private readonly _handTool: HandTool; |
| | | private readonly _globalConnect: GlobalConnect; |
| | | private readonly _translate: any; |
| | | |
| | | constructor(palette, create, elementFactory, spaceTool, lassoTool, handTool, globalConnect, translate) { |
| | | super( |
| | | palette, |
| | | create, |
| | | elementFactory, |
| | | spaceTool, |
| | | lassoTool, |
| | | handTool, |
| | | globalConnect, |
| | | translate |
| | | // 2000 |
| | | ); |
| | | this._palette = palette; |
| | | this._create = create; |
| | | this._elementFactory = elementFactory; |
| | | this._spaceTool = spaceTool; |
| | | this._lassoTool = lassoTool; |
| | | this._handTool = handTool; |
| | | this._globalConnect = globalConnect; |
| | | this._translate = translate; |
| | | } |
| | | |
| | | getPaletteEntries() { |
| | | const actions = {}, |
| | | create = this._create, |
| | | elementFactory = this._elementFactory, |
| | | translate = this._translate; |
| | | |
| | | function createAction(type: string, group: string, className: string, title: string, options?: object) { |
| | | function createListener(event) { |
| | | const shape = elementFactory.createShape(assign({ type: type }, options)); |
| | | if (options) { |
| | | !shape.businessObject.di && (shape.businessObject.di = {}); |
| | | shape.businessObject.di.isExpanded = (options as { [key: string]: any }).isExpanded; |
| | | } |
| | | create.start(event, shape, null); |
| | | } |
| | | const shortType = type.replace(/^bpmn:/, ''); |
| | | return { |
| | | group: group, |
| | | className: className, |
| | | title: title || translate('Create {type}', { type: shortType }), |
| | | action: { |
| | | dragstart: createListener, |
| | | click: createListener |
| | | } |
| | | }; |
| | | } |
| | | |
| | | function createMultiInstanceUserTask(event) { |
| | | const bpmnFactory: BpmnFactory | undefined = modeler().getBpmnFactory(); |
| | | // å建ä¸ä¸ª bpmn:UserTask |
| | | const userTask = bpmnFactory.create('bpmn:UserTask', { |
| | | // name: 'å¤å®ä¾ç¨æ·ä»»å¡', // å¨ç»æ¿ä¸æ¾ç¤ºå段 |
| | | isForCompensation: false |
| | | }); |
| | | // å°å¤å®ä¾å±æ§åé
ç» bpmn:UserTask ç loopCharacteristics |
| | | userTask.loopCharacteristics = bpmnFactory.create('bpmn:MultiInstanceLoopCharacteristics'); |
| | | const customUserTask = elementFactory.createShape({ |
| | | type: 'bpmn:UserTask', |
| | | businessObject: userTask // åé
å建ç userTask å° businessObject |
| | | }); |
| | | create.start(event, customUserTask, {}); |
| | | } |
| | | |
| | | assign(actions, { |
| | | 'create.parallel-gateway': createAction('bpmn:ParallelGateway', 'gateway', 'bpmn-icon-gateway-parallel', 'å¹¶è¡ç½å
³'), |
| | | 'create.event-base-gateway': createAction('bpmn:EventBasedGateway', 'gateway', 'bpmn-icon-gateway-eventbased', 'äºä»¶ç½å
³'), |
| | | // åç»çº¿ |
| | | 'gateway-separator': { |
| | | group: 'gateway', |
| | | separator: true |
| | | }, |
| | | 'create.user-task': createAction('bpmn:UserTask', 'activity', 'bpmn-icon-user-task', 'åå»ºç¨æ·ä»»å¡'), |
| | | 'create.multi-instance-user-task': { |
| | | group: 'activity', |
| | | type: 'bpmn:UserTask', |
| | | className: 'bpmn-icon-user task-multi-instance', |
| | | title: 'å建å¤å®ä¾ç¨æ·ä»»å¡', |
| | | action: { |
| | | click: createMultiInstanceUserTask, |
| | | dragstart: createMultiInstanceUserTask |
| | | } |
| | | }, |
| | | 'task-separator': { |
| | | group: 'activity', |
| | | separator: true |
| | | } |
| | | }); |
| | | return actions; |
| | | } |
| | | } |
| | | |
| | | CustomPaletteProvider['$inject'] = ['palette', 'create', 'elementFactory', 'spaceTool', 'lassoTool', 'handTool', 'globalConnect', 'translate']; |
| | | |
| | | export default CustomPaletteProvider; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import BaseRenderer from 'diagram-js/lib/draw/BaseRenderer'; |
| | | import { |
| | | append as svgAppend, |
| | | attr as svgAttr, |
| | | create as svgCreate, |
| | | select as svgSelect, |
| | | selectAll as svgSelectAll, |
| | | clone as svgClone, |
| | | clear as svgClear, |
| | | remove as svgRemove |
| | | } from 'tiny-svg'; |
| | | |
| | | const HIGH_PRIORITY = 1500; |
| | | export default class CustomRenderer extends BaseRenderer { |
| | | bpmnRenderer: BaseRenderer; |
| | | modeling: any; |
| | | constructor(eventBus, bpmnRenderer, modeling) { |
| | | super(eventBus, HIGH_PRIORITY); |
| | | this.bpmnRenderer = bpmnRenderer; |
| | | this.modeling = modeling; |
| | | } |
| | | canRender(element) { |
| | | // ignore labels |
| | | return !element.labelTarget; |
| | | } |
| | | |
| | | /** |
| | | * èªå®ä¹èç¹å¾å½¢ |
| | | * @param {*} parentNode å½åå
ç´ çsvgNode |
| | | * @param {*} element |
| | | * @returns |
| | | */ |
| | | drawShape(parentNode, element) { |
| | | const shape = this.bpmnRenderer.drawShape(parentNode, element); |
| | | const { type, width, height } = element; |
| | | // å¼å§ å¡«å
ç»¿è² |
| | | if (type === 'bpmn:StartEvent') { |
| | | svgAttr(shape, { fill: '#77DF6D' }); |
| | | return shape; |
| | | } |
| | | if (type === 'bpmn:EndEvent') { |
| | | svgAttr(shape, { fill: '#EE7B77' }); |
| | | return shape; |
| | | } |
| | | if (type === 'bpmn:UserTask') { |
| | | svgAttr(shape, { fill: '#A9C4F8' }); |
| | | return shape; |
| | | } |
| | | return shape; |
| | | } |
| | | |
| | | getShapePath(shape) { |
| | | return this.bpmnRenderer.getShapePath(shape); |
| | | } |
| | | } |
| | | CustomRenderer['$inject'] = ['eventBus', 'bpmnRenderer']; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import zh from '@/components/BpmnDesign/assets/lang/zh'; |
| | | |
| | | const customTranslate = (template: any, replacements: any) => { |
| | | replacements = replacements || {}; |
| | | template = zh[template] || template; |
| | | return template.replace(/{([^}]+)}/g, function (_: any, key: any) { |
| | | return replacements[key] || '{' + key + '}'; |
| | | }); |
| | | }; |
| | | |
| | | export const translateModule = { |
| | | translate: ['value', customTranslate] |
| | | }; |
| | | |
| | | export default translateModule; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | // ç¿»è¯æ¨¡å |
| | | import TranslationModule from './Translate'; |
| | | import { ModuleDeclaration } from 'didi'; |
| | | import CustomPaletteProvider from './Palette/CustomPaletteProvider'; |
| | | import CustomRenderer from './Renderer/CustomRenderer'; |
| | | import CustomContextPadProvider from './ContextPad/CustomContextPadProvider'; |
| | | |
| | | const Module: ModuleDeclaration[] = [ |
| | | { |
| | | __init__: ['customPaletteProvider', 'customContextPadProvider', 'customRenderer'], |
| | | customPaletteProvider: ['type', CustomPaletteProvider], |
| | | customRenderer: ['type', CustomRenderer], |
| | | customContextPadProvider: ['type', CustomContextPadProvider] |
| | | }, |
| | | TranslationModule |
| | | ]; |
| | | export default Module; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export default { |
| | | 'bpmn:EndEvent': {}, |
| | | 'bpmn:StartEvent': { |
| | | initiator: true, |
| | | formKey: true |
| | | }, |
| | | 'bpmn:UserTask': { |
| | | allocationType: true, |
| | | specifyDesc: true, |
| | | multipleUserAuditType: true, |
| | | async: true, |
| | | priority: true, |
| | | skipExpression: true, |
| | | dueDate: true, |
| | | taskListener: true, |
| | | executionListener: true |
| | | }, |
| | | 'bpmn:ServiceTask': { |
| | | async: true, |
| | | skipExpression: true, |
| | | isForCompensation: true, |
| | | triggerable: true, |
| | | class: true |
| | | }, |
| | | 'bpmn:ScriptTask': { |
| | | async: true, |
| | | isForCompensation: true, |
| | | autoStoreVariables: true |
| | | }, |
| | | 'bpmn:ManualTask': { |
| | | async: true, |
| | | isForCompensation: true |
| | | }, |
| | | 'bpmn:ReceiveTask': { |
| | | async: true, |
| | | isForCompensation: true |
| | | }, |
| | | 'bpmn:SendTask': { |
| | | async: true, |
| | | isForCompensation: true |
| | | }, |
| | | 'bpmn:BusinessRuleTask': { |
| | | async: true, |
| | | isForCompensation: true, |
| | | ruleVariablesInput: true, |
| | | rules: true, |
| | | resultVariable: true, |
| | | exclude: true |
| | | } |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | .djs-palette { |
| | | width: 300px; |
| | | |
| | | .bpmn-icon-hand-tool:hover { |
| | | &:after { |
| | | content: 'å¯å¨æå¨å·¥å
·'; |
| | | position: absolute; |
| | | left: 45px; |
| | | width: 120px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-lasso-tool:hover { |
| | | &:after { |
| | | content: 'å¯å¨å¥ç´¢å·¥å
·'; |
| | | position: absolute; |
| | | left: 100px; |
| | | width: 120px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-space-tool:hover { |
| | | &:after { |
| | | content: 'å¯å¨å建/å é¤ç©ºé´å·¥å
·'; |
| | | position: absolute; |
| | | left: 45px; |
| | | width: 170px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-connection-multi:hover { |
| | | &:after { |
| | | content: 'å¯å¨å
¨å±è¿æ¥å·¥å
·'; |
| | | position: absolute; |
| | | left: 100px; |
| | | width: 140px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-start-event-none:hover { |
| | | &:after { |
| | | content: 'å建å¼å§äºä»¶'; |
| | | position: absolute; |
| | | left: 45px; |
| | | width: 120px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-intermediate-event-none:hover { |
| | | &:after { |
| | | content: 'å建ä¸é´/è¾¹çäºä»¶'; |
| | | position: absolute; |
| | | left: 100px; |
| | | width: 140px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-end-event-none:hover { |
| | | &:after { |
| | | content: 'åå»ºç»æäºä»¶'; |
| | | position: absolute; |
| | | left: 45px; |
| | | width: 120px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-gateway-none:hover { |
| | | &:after { |
| | | content: 'å建ç½å
³'; |
| | | position: absolute; |
| | | left: 100px; |
| | | width: 90px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-gateway-parallel:hover { |
| | | &:after { |
| | | content: 'å建并è¡ç½å
³'; |
| | | position: absolute; |
| | | left: 45px; |
| | | width: 120px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-gateway-eventbased:hover { |
| | | &:after { |
| | | content: 'å建äºä»¶ç½å
³'; |
| | | position: absolute; |
| | | left: 100px; |
| | | width: 120px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-task:hover { |
| | | &:after { |
| | | content: 'å建任å¡'; |
| | | position: absolute; |
| | | left: 45px; |
| | | width: 80px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-subprocess-expanded:hover { |
| | | &:after { |
| | | content: 'åå»ºå¯æå åæµç¨'; |
| | | position: absolute; |
| | | left: 100px; |
| | | width: 140px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-user-task:hover { |
| | | &:after { |
| | | content: 'åå»ºç¨æ·ä»»å¡'; |
| | | position: absolute; |
| | | left: 45px; |
| | | width: 120px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | |
| | | .task-multi-instance:hover { |
| | | &:after { |
| | | content: 'å建å¤å®ä¾ç¨æ·ä»»å¡'; |
| | | position: absolute; |
| | | left: 100px; |
| | | width: 160px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | .bpmn-icon-participant:hover { |
| | | &:after { |
| | | content: 'åå»ºæ³³æ± /æ³³é'; |
| | | position: absolute; |
| | | left: 45px; |
| | | width: 120px; |
| | | font-size: 15px; |
| | | font-weight: bold; |
| | | color: #3a84de; |
| | | border-radius: 2px; |
| | | border: 1px solid #cccccc; |
| | | background-color: #fafafa; |
| | | opacity: 0.8; |
| | | } |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import showConfig from '@/components/BpmnDesign/assets/showConfig'; |
| | | import { ModdleElement } from 'bpmn'; |
| | | import useModelerStore from '@/store/modules/modeler'; |
| | | interface Options { |
| | | element: ModdleElement; |
| | | } |
| | | |
| | | export default (ops: Options) => { |
| | | const { element } = ops; |
| | | const { getModeling, getModdle } = useModelerStore(); |
| | | const modeling = getModeling(); |
| | | const moddle = getModdle(); |
| | | |
| | | /** |
| | | * å½åèç¹ç±»å |
| | | */ |
| | | const elementType = computed(() => { |
| | | const bizObj = element.businessObject; |
| | | return bizObj.eventDefinitions ? bizObj.eventDefinitions[0].$type : bizObj.$type; |
| | | }); |
| | | |
| | | /** |
| | | * ç¨äºæ§å¶é¢æ¿å段æ¾ç¤ºä¸éèçé
ç½® |
| | | */ |
| | | const config = computed(() => showConfig[elementType.value] || {}); |
| | | |
| | | /** |
| | | * å建ä¸ä¸ªèç¹ |
| | | * @param elementType èç¹ç±»å |
| | | * @param properties 屿§ |
| | | * @param parent ç¶èç¹ |
| | | */ |
| | | const createModdleElement = (elementType: string, properties: any, parent: ModdleElement) => { |
| | | const element = moddle.create(elementType, properties); |
| | | parent && (element.$parent = parent); |
| | | return element; |
| | | }; |
| | | |
| | | /** |
| | | * è·åæ©å±å±æ§ï¼å¦æä¸åå¨ä¼èªå¨å建 |
| | | */ |
| | | const getExtensionElements = (create = true) => { |
| | | let extensionElements = element.businessObject.get<ModdleElement>('extensionElements'); |
| | | if (!extensionElements && create) { |
| | | extensionElements = createModdleElement('bpmn:ExtensionElements', { values: [] }, element.businessObject); |
| | | modeling.updateModdleProperties(element, element.businessObject, { extensionElements }); |
| | | } |
| | | return extensionElements; |
| | | }; |
| | | |
| | | /** |
| | | * è·åextensionElementsä¸çproperties |
| | | * @param extensionElements å¯éåæ°ï¼é»è®¤è·åå½åElementä¸çextensionElementsä¸çProperties |
| | | */ |
| | | const getPropertiesElements = (extensionElements?: ModdleElement) => { |
| | | if (!extensionElements) { |
| | | extensionElements = getExtensionElements(); |
| | | } |
| | | let propertiesElements = extensionElements.values.find((item) => item.$type === 'flowable:properties'); |
| | | if (!propertiesElements) { |
| | | propertiesElements = createModdleElement('flowable:properties', { values: [] }, extensionElements); |
| | | modeling.updateModdleProperties(element, extensionElements, { |
| | | values: [...extensionElements.get<[]>('values'), propertiesElements] |
| | | }); |
| | | } |
| | | return propertiesElements; |
| | | }; |
| | | |
| | | /** |
| | | * æ´æ°èç¹å±æ§ |
| | | * @param properties 屿§å¼ |
| | | */ |
| | | const updateProperties = (properties: any) => { |
| | | modeling.updateProperties(element, properties); |
| | | }; |
| | | |
| | | /** |
| | | * æ´æ°èç¹ä¿¡æ¯ |
| | | * @param updateElement éè¦æ´æ°çèç¹ |
| | | * @param properties 屿§ |
| | | */ |
| | | const updateModdleProperties = (updateElement, properties: any) => { |
| | | modeling.updateModdleProperties(element, updateElement, properties); |
| | | }; |
| | | |
| | | /** |
| | | * æ´æ°Property屿§ |
| | | * @param name keyå¼ |
| | | * @param value å¼ |
| | | */ |
| | | const updateProperty = (name: string, value: string) => { |
| | | const propertiesElements = getPropertiesElements(); |
| | | |
| | | let propertyElements = propertiesElements.values.find((item) => item.name === name); |
| | | if (!propertyElements) { |
| | | propertyElements = createModdleElement('flowable:property', { name: name, value: value }, propertiesElements); |
| | | modeling.updateModdleProperties(element, propertiesElements, { |
| | | values: [...propertiesElements.get('values'), propertyElements] |
| | | }); |
| | | } else { |
| | | propertyElements.name = name; |
| | | propertyElements.value = value; |
| | | } |
| | | return propertyElements; |
| | | }; |
| | | |
| | | const idChange = (newVal: string) => { |
| | | if (newVal) { |
| | | updateProperties({ id: newVal }); |
| | | } |
| | | }; |
| | | const nameChange = (newVal: string) => { |
| | | if (newVal) { |
| | | updateProperties({ name: newVal }); |
| | | } |
| | | }; |
| | | return { |
| | | elementType, |
| | | showConfig: config, |
| | | |
| | | updateProperties, |
| | | updateProperty, |
| | | updateModdleProperties, |
| | | |
| | | createModdleElement, |
| | | idChange, |
| | | nameChange, |
| | | |
| | | getExtensionElements, |
| | | getPropertiesElements |
| | | }; |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { ModdleElement } from 'bpmn'; |
| | | |
| | | interface Options { |
| | | element: ModdleElement; |
| | | } |
| | | |
| | | interface Data { |
| | | id: string; |
| | | } |
| | | |
| | | export default (ops: Options) => { |
| | | const { element } = ops; |
| | | |
| | | const parseData = <T>(): T => { |
| | | const result = { |
| | | ...element.businessObject, |
| | | ...element.businessObject.$attrs |
| | | }; |
| | | |
| | | // ç§»é¤flowableåç¼ï¼æ ¼å¼åæ°ç» |
| | | for (const key in result) { |
| | | if (key.indexOf('flowable:') === 0) { |
| | | const newKey = key.replace('flowable:', ''); |
| | | result[newKey] = result[key]; |
| | | delete result[key]; |
| | | } |
| | | } |
| | | return { ...result } as T; |
| | | }; |
| | | |
| | | return { |
| | | parseData |
| | | }; |
| | | }; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="containers"> |
| | | <div class="app-containers"> |
| | | <el-container class="h-full"> |
| | | <el-container style="align-items: stretch"> |
| | | <el-header> |
| | | <div class="process-toolbar"> |
| | | <el-space wrap :size="10"> |
| | | <el-button size="small" type="primary" @click="saveXml">ä¿ å</el-button> |
| | | <el-dropdown size="small"> |
| | | <el-button size="small" type="primary"> é¢ è§ </el-button> |
| | | <template #dropdown> |
| | | <el-dropdown-menu> |
| | | <el-dropdown-item icon="Document" @click="previewXML">XMLé¢è§</el-dropdown-item> |
| | | <el-dropdown-item icon="View" @click="previewSVG"> SVGé¢è§</el-dropdown-item> |
| | | </el-dropdown-menu> |
| | | </template> |
| | | </el-dropdown> |
| | | |
| | | <el-dropdown size="small"> |
| | | <el-button size="small" type="primary"> ä¸ è½½ </el-button> |
| | | <template #dropdown> |
| | | <el-dropdown-menu> |
| | | <el-dropdown-item icon="Download" @click="downloadXML">ä¸è½½XML</el-dropdown-item> |
| | | <el-dropdown-item icon="Download" @click="downloadSVG"> ä¸è½½SVG</el-dropdown-item> |
| | | </el-dropdown-menu> |
| | | </template> |
| | | </el-dropdown> |
| | | <el-tooltip effect="dark" content="æ°å»º" placement="bottom"> |
| | | <el-button size="small" icon="CirclePlus" @click="newDiagram" /> |
| | | </el-tooltip> |
| | | <el-tooltip effect="dark" content="èªéåºå±å¹" placement="bottom"> |
| | | <el-button size="small" icon="Rank" @click="fitViewport" /> |
| | | </el-tooltip> |
| | | <el-tooltip effect="dark" content="æ¾å¤§" placement="bottom"> |
| | | <el-button size="small" icon="ZoomIn" @click="zoomViewport(true)" /> |
| | | </el-tooltip> |
| | | <el-tooltip effect="dark" content="缩å°" placement="bottom"> |
| | | <el-button size="small" icon="ZoomOut" @click="zoomViewport(false)" /> |
| | | </el-tooltip> |
| | | <el-tooltip effect="dark" content="åé" placement="bottom"> |
| | | <el-button size="small" icon="Back" @click="bpmnModeler.get('commandStack').undo()" /> |
| | | </el-tooltip> |
| | | <el-tooltip effect="dark" content="åè¿" placement="bottom"> |
| | | <el-button size="small" icon="Right" @click="bpmnModeler.get('commandStack').redo()" /> |
| | | </el-tooltip> |
| | | </el-space> |
| | | </div> |
| | | </el-header> |
| | | <div ref="canvas" class="canvas" /> |
| | | </el-container> |
| | | <div :class="{ 'process-panel': true, 'hide': panelFlag }"> |
| | | <div class="process-panel-bar" @click="panelBarClick"> |
| | | <div class="open-bar"> |
| | | <el-link type="default" :underline="false"> |
| | | <svg-icon class-name="open-bar" :icon-class="panelFlag ? 'caret-back' : 'caret-forward'"></svg-icon> |
| | | </el-link> |
| | | </div> |
| | | </div> |
| | | <transition enter-active-class="animate__animated animate__fadeIn"> |
| | | <div v-show="showPanel" v-if="bpmnModeler" class="panel-content"> |
| | | <PropertyPanel :modeler="bpmnModeler" /> |
| | | </div> |
| | | </transition> |
| | | </div> |
| | | </el-container> |
| | | </div> |
| | | </div> |
| | | <div> |
| | | <el-dialog v-model="perviewXMLShow" title="XMLé¢è§" width="80%" append-to-body> |
| | | <highlightjs :code="xmlStr" language="XML" /> |
| | | </el-dialog> |
| | | </div> |
| | | <div> |
| | | <el-dialog v-model="perviewSVGShow" title="SVGé¢è§" width="80%" append-to-body> |
| | | <div style="text-align: center" v-html="svgData" /> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup name="BpmnDesign"> |
| | | import 'bpmn-js/dist/assets/diagram-js.css'; |
| | | import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css'; |
| | | import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css'; |
| | | import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'; |
| | | import './assets/style/index.scss'; |
| | | import { Canvas, Modeler } from 'bpmn'; |
| | | import PropertyPanel from './panel/index.vue'; |
| | | import BpmnModeler from 'bpmn-js/lib/Modeler.js'; |
| | | import defaultXML from '@/components/BpmnDesign/assets/defaultXML'; |
| | | import flowableModdle from '@/components/BpmnDesign/assets/moddle/flowable'; |
| | | import Modules from './assets/module/index'; |
| | | import useModelerStore from '@/store/modules/modeler'; |
| | | import useDialog from '@/hooks/useDialog'; |
| | | |
| | | const emit = defineEmits(['closeCallBack', 'saveCallBack']); |
| | | |
| | | const { visible, title, openDialog, closeDialog } = useDialog({ |
| | | title: 'ç¼è¾æµç¨' |
| | | }); |
| | | const modelerStore = useModelerStore(); |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | const panelFlag = ref(false); |
| | | const showPanel = ref(true); |
| | | const canvas = ref<HTMLDivElement>(); |
| | | const panel = ref<HTMLDivElement>(); |
| | | const bpmnModeler = ref<Modeler>(); |
| | | const zoom = ref(1); |
| | | const perviewXMLShow = ref(false); |
| | | const perviewSVGShow = ref(false); |
| | | const xmlStr = ref(''); |
| | | const svgData = ref(''); |
| | | |
| | | const panelBarClick = () => { |
| | | // å»¶è¿æ§è¡ï¼å¦åä¼å¯¼è´é¢æ¿æ¶èµ·æ¶ï¼å±æ§é¢æ¿ä¸æ¾ç¤º |
| | | panelFlag.value = !panelFlag.value; |
| | | setTimeout(() => { |
| | | showPanel.value = !panelFlag.value; |
| | | }, 100); |
| | | }; |
| | | |
| | | /** |
| | | * åå§åCanvas |
| | | */ |
| | | const initCanvas = () => { |
| | | bpmnModeler.value = new BpmnModeler({ |
| | | container: canvas.value, |
| | | // é®ç |
| | | keyboard: { |
| | | bindTo: window // æè
windowï¼æ³¨æä¸å¤é¨è¡¨åçé®ççå¬äºä»¶æ¯å¦å²çª |
| | | }, |
| | | propertiesPanel: { |
| | | parent: panel.value |
| | | }, |
| | | additionalModules: Modules, |
| | | moddleExtensions: { |
| | | flowable: flowableModdle |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * åå§åModel |
| | | */ |
| | | const initModel = () => { |
| | | if (modelerStore.getModeler()) { |
| | | modelerStore.getModeler().destroy(); |
| | | modelerStore.setModeler(undefined); |
| | | } |
| | | modelerStore.setModeler(bpmnModeler.value); |
| | | }; |
| | | |
| | | /** |
| | | * æ°å»º |
| | | */ |
| | | const newDiagram = async () => { |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤æ°å»º'); |
| | | initDiagram(); |
| | | }; |
| | | |
| | | /** |
| | | * åå§å |
| | | */ |
| | | const initDiagram = (xml?: string) => { |
| | | if (!xml) xml = defaultXML; |
| | | bpmnModeler.value.importXML(xml); |
| | | }; |
| | | |
| | | /** |
| | | * èªéåºå±å¹ |
| | | */ |
| | | const fitViewport = () => { |
| | | zoom.value = bpmnModeler.value.get<Canvas>('canvas').zoom('fit-viewport'); |
| | | const bbox = document.querySelector<SVGGElement>('.app-containers .viewport').getBBox(); |
| | | const currentViewBox = bpmnModeler.value.get<Canvas>('canvas').viewbox(); |
| | | const elementMid = { |
| | | x: bbox.x + bbox.width / 2 - 65, |
| | | y: bbox.y + bbox.height / 2 |
| | | }; |
| | | bpmnModeler.value.get<Canvas>('canvas').viewbox({ |
| | | x: elementMid.x - currentViewBox.width / 2, |
| | | y: elementMid.y - currentViewBox.height / 2, |
| | | width: currentViewBox.width, |
| | | height: currentViewBox.height |
| | | }); |
| | | zoom.value = (bbox.width / currentViewBox.width) * 1.8; |
| | | }; |
| | | /** |
| | | * æ¾å¤§æè
ç¼©å° |
| | | * @param zoomIn true æ¾å¤§ | false ç¼©å° |
| | | */ |
| | | const zoomViewport = (zoomIn = true) => { |
| | | zoom.value = bpmnModeler.value.get<Canvas>('canvas').zoom(); |
| | | zoom.value += zoomIn ? 0.1 : -0.1; |
| | | bpmnModeler.value.get<Canvas>('canvas').zoom(zoom.value); |
| | | }; |
| | | |
| | | /** |
| | | * ä¸è½½XML |
| | | */ |
| | | const downloadXML = async () => { |
| | | try { |
| | | const { xml } = await bpmnModeler.value.saveXML({ format: true }); |
| | | downloadFile(`${getProcessElement().name}.bpmn20.xml`, xml, 'application/xml'); |
| | | } catch (e) { |
| | | proxy?.$modal.msgError(e); |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * ä¸è½½SVG |
| | | */ |
| | | const downloadSVG = async () => { |
| | | try { |
| | | const { svg } = await bpmnModeler.value.saveSVG(); |
| | | downloadFile(getProcessElement().name, svg, 'image/svg+xml'); |
| | | } catch (e) { |
| | | proxy?.$modal.msgError(e); |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * XMLé¢è§ |
| | | */ |
| | | const previewXML = async () => { |
| | | try { |
| | | const { xml } = await bpmnModeler.value.saveXML({ format: true }); |
| | | xmlStr.value = xml; |
| | | perviewXMLShow.value = true; |
| | | } catch (e) { |
| | | proxy?.$modal.msgError(e); |
| | | } |
| | | }; |
| | | |
| | | /** |
| | | * SVGé¢è§ |
| | | */ |
| | | const previewSVG = async () => { |
| | | try { |
| | | const { svg } = await bpmnModeler.value.saveSVG(); |
| | | svgData.value = svg; |
| | | perviewSVGShow.value = true; |
| | | } catch (e) { |
| | | proxy?.$modal.msgError(e); |
| | | } |
| | | }; |
| | | |
| | | const curNodeInfo = reactive({ |
| | | curType: '', // ä»»å¡ç±»å ç¨æ·ä»»å¡ |
| | | curNode: '', |
| | | expValue: '' //å¤ç¨æ·åé¨é¨è§è²å®ç° |
| | | }); |
| | | |
| | | const downloadFile = (fileName: string, data: any, type: string) => { |
| | | const a = document.createElement('a'); |
| | | const url = window.URL.createObjectURL(new Blob([data], { type: type })); |
| | | a.href = url; |
| | | a.download = fileName; |
| | | a.click(); |
| | | window.URL.revokeObjectURL(url); |
| | | }; |
| | | |
| | | const getProcessElement = () => { |
| | | const rootElements = bpmnModeler.value?.getDefinitions().rootElements; |
| | | for (let i = 0; i < rootElements.length; i++) { |
| | | if (rootElements[i].$type === 'bpmn:Process') return rootElements[i]; |
| | | } |
| | | }; |
| | | |
| | | const getProcess = () => { |
| | | const element = getProcessElement(); |
| | | return { |
| | | id: element.id, |
| | | name: element.name |
| | | }; |
| | | }; |
| | | |
| | | const saveXml = async () => { |
| | | const { xml } = await bpmnModeler.value.saveXML({ format: true }); |
| | | const { svg } = await bpmnModeler.value.saveSVG(); |
| | | const process = getProcess(); |
| | | let data = { |
| | | xml: xml, |
| | | svg: svg, |
| | | key: process.id, |
| | | name: process.name |
| | | }; |
| | | emit('saveCallBack', data); |
| | | }; |
| | | |
| | | const open = (xml?: string) => { |
| | | openDialog(); |
| | | nextTick(() => { |
| | | initDiagram(xml); |
| | | }); |
| | | }; |
| | | const close = () => { |
| | | closeDialog(); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | nextTick(() => { |
| | | initCanvas(); |
| | | initModel(); |
| | | }); |
| | | }); |
| | | |
| | | /** |
| | | * 坹夿´é²åç»ä»¶æ¹æ³ |
| | | */ |
| | | defineExpose({ |
| | | initDiagram, |
| | | saveXml, |
| | | open, |
| | | close |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .containers { |
| | | height: 100%; |
| | | .app-containers { |
| | | width: 100%; |
| | | height: 100%; |
| | | .canvas { |
| | | width: 100%; |
| | | height: 100%; |
| | | background: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PHBhdHRlcm4gaWQ9ImEiIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgcGF0dGVyblVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGggZD0iTTAgMTBoNDBNMTAgMHY0ME0wIDIwaDQwTTIwIDB2NDBNMCAzMGg0ME0zMCAwdjQwIiBmaWxsPSJub25lIiBzdHJva2U9IiNlMGUwZTAiIG9wYWNpdHk9Ii4yIi8+PHBhdGggZD0iTTQwIDBIMHY0MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZTBlMGUwIi8+PC9wYXR0ZXJuPjwvZGVmcz48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2EpIi8+PC9zdmc+'); |
| | | } |
| | | .el-header { |
| | | height: 35px; |
| | | padding: 0; |
| | | } |
| | | |
| | | .process-panel { |
| | | transition: width 0.25s ease-in; |
| | | .process-panel-bar { |
| | | width: 34px; |
| | | height: 40px; |
| | | .open-bar { |
| | | width: 34px; |
| | | line-height: 40px; |
| | | } |
| | | } |
| | | // æ¶èµ·é¢æ¿æ ·å¼ |
| | | &.hide { |
| | | width: 34px; |
| | | overflow: hidden; |
| | | padding: 0; |
| | | .process-panel-bar { |
| | | width: 34px; |
| | | height: 100%; |
| | | box-sizing: border-box; |
| | | display: block; |
| | | text-align: left; |
| | | line-height: 34px; |
| | | } |
| | | .process-panel-bar:hover { |
| | | background-color: #f5f7fa; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | pre { |
| | | margin: 0; |
| | | height: 100%; |
| | | max-height: calc(80vh - 32px); |
| | | overflow-x: hidden; |
| | | overflow-y: auto; |
| | | :deep(.hljs) { |
| | | word-break: break-word; |
| | | white-space: pre-wrap; |
| | | padding: 0.5em; |
| | | } |
| | | } |
| | | |
| | | .open-bar { |
| | | font-size: 20px; |
| | | cursor: pointer; |
| | | text-align: center; |
| | | } |
| | | .process-panel { |
| | | box-sizing: border-box; |
| | | padding: 0 8px 0 8px; |
| | | border-left: 1px solid #eeeeee; |
| | | box-shadow: #cccccc 0 0 8px; |
| | | max-height: 100%; |
| | | width: 480px; |
| | | height: calc(100vh - 80px); |
| | | :deep(.el-collapse) { |
| | | height: calc(100vh - 162px); |
| | | overflow: auto; |
| | | } |
| | | } |
| | | |
| | | // 任塿 éæåº¦ |
| | | //:deep(.djs-palette) { |
| | | // opacity: 0.3; |
| | | // transition: all 1s; |
| | | //} |
| | | // |
| | | //:deep(.djs-palette:hover) { |
| | | // opacity: 1; |
| | | // transition: all 1s; |
| | | //} |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-collapse v-model="currentCollapseItem"> |
| | | <el-collapse-item name="1"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <InfoFilled /> |
| | | </el-icon> |
| | | å¸¸è§ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <el-form ref="formRef" :model="formData" :rules="formRules" label-width="80px"> |
| | | <el-form-item prop="id" label="èç¹ ID"> |
| | | <el-input v-model="formData.id" @change="idChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="name" label="èç¹åç§°"> |
| | | <el-input v-model="formData.name" @change="nameChange"> </el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </el-collapse-item> |
| | | |
| | | <el-collapse-item name="2"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <BellFilled /> |
| | | </el-icon> |
| | | æ§è¡çå¬å¨ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <ExecutionListener :element="element"></ExecutionListener> |
| | | </div> |
| | | </el-collapse-item> |
| | | </el-collapse> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import useParseElement from '@/components/BpmnDesign/hooks/useParseElement'; |
| | | import usePanel from '@/components/BpmnDesign/hooks/usePanel'; |
| | | import { Modeler, ModdleElement } from 'bpmn'; |
| | | import { GatewayPanel } from 'bpmnDesign'; |
| | | import ExecutionListener from '@/components/BpmnDesign/panel/property/ExecutionListener.vue'; |
| | | |
| | | interface PropType { |
| | | element: ModdleElement; |
| | | } |
| | | const props = withDefaults(defineProps<PropType>(), {}); |
| | | const { nameChange, idChange } = usePanel({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const { parseData } = useParseElement({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const currentCollapseItem = ref(['1', '2']); |
| | | const formData = ref(parseData<GatewayPanel>()); |
| | | |
| | | const formRules = ref<ElFormRules>({ |
| | | processCategory: [{ required: true, message: 'è¯·éæ©', trigger: 'blur' }], |
| | | id: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }], |
| | | name: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }] |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped></style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-collapse v-model="currentCollapseItem"> |
| | | <el-collapse-item name="1"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <InfoFilled /> |
| | | </el-icon> |
| | | å¸¸è§ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <el-form ref="formRef" :model="formData" :rules="formRules" label-width="80px"> |
| | | <el-form-item label="æµç¨æ è¯" prop="id"> |
| | | <el-input v-model="formData.id" @change="idChange"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="æµç¨åç§°" prop="name"> |
| | | <el-input v-model="formData.name" @change="nameChange"></el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </el-collapse-item> |
| | | |
| | | <el-collapse-item name="2"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <BellFilled /> |
| | | </el-icon> |
| | | æ§è¡çå¬å¨ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <ExecutionListener :element="element"></ExecutionListener> |
| | | </div> |
| | | </el-collapse-item> |
| | | </el-collapse> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import ExecutionListener from './property/ExecutionListener.vue'; |
| | | import useParseElement from '@/components/BpmnDesign/hooks/useParseElement'; |
| | | import usePanel from '@/components/BpmnDesign/hooks/usePanel'; |
| | | import { Modeler, ModdleElement } from 'bpmn'; |
| | | import { ProcessPanel } from 'bpmnDesign'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | interface PropType { |
| | | element: ModdleElement; |
| | | } |
| | | const props = withDefaults(defineProps<PropType>(), {}); |
| | | |
| | | const { parseData } = useParseElement({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const { idChange, nameChange } = usePanel({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const currentCollapseItem = ref(['1', '2']); |
| | | const formData = ref<ProcessPanel>(parseData<ProcessPanel>()); |
| | | |
| | | const formRules = ref<ElFormRules>({ |
| | | id: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }], |
| | | name: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }] |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"></style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-collapse v-model="currentCollapseItem"> |
| | | <el-collapse-item name="1"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <InfoFilled /> |
| | | </el-icon> |
| | | å¸¸è§ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <el-form ref="formRef" :model="formData" :rules="formRules" label-width="90px"> |
| | | <el-form-item prop="id" label="èç¹ ID"> |
| | | <el-input v-model="formData.id" @change="idChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="name" label="èç¹åç§°"> |
| | | <el-input v-model="formData.name" @change="nameChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="conditionExpression" label="跳转æ¡ä»¶"> |
| | | <el-input v-model="formData.conditionExpressionValue" @change="conditionExpressionChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="skipExpression" label="è·³è¿è¡¨è¾¾å¼"> |
| | | <el-input v-model="formData.skipExpression" @change="skipExpressionChange"> </el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </el-collapse-item> |
| | | |
| | | <el-collapse-item name="2"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <BellFilled /> |
| | | </el-icon> |
| | | æ§è¡çå¬å¨ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <ExecutionListener :element="element"></ExecutionListener> |
| | | </div> |
| | | </el-collapse-item> |
| | | </el-collapse> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import useParseElement from '@/components/BpmnDesign/hooks/useParseElement'; |
| | | import usePanel from '@/components/BpmnDesign/hooks/usePanel'; |
| | | import { Modeler, ModdleElement } from 'bpmn'; |
| | | import { SequenceFlowPanel } from 'bpmnDesign'; |
| | | import useModelerStore from '@/store/modules/modeler'; |
| | | |
| | | interface PropType { |
| | | element: ModdleElement; |
| | | } |
| | | const props = withDefaults(defineProps<PropType>(), {}); |
| | | const { nameChange, idChange, updateProperties } = usePanel({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const { parseData } = useParseElement({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const moddle = useModelerStore().getModdle(); |
| | | const currentCollapseItem = ref(['1', '2']); |
| | | const formData = ref(parseData<SequenceFlowPanel>()); |
| | | |
| | | const formRules = ref<ElFormRules>({ |
| | | processCategory: [{ required: true, message: 'è¯·éæ©', trigger: 'blur' }], |
| | | id: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }], |
| | | name: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }] |
| | | }); |
| | | |
| | | const conditionExpressionChange = (val: string) => { |
| | | if (val) { |
| | | const newCondition = moddle.create('bpmn:FormalExpression', { body: val }); |
| | | updateProperties({ conditionExpression: newCondition }); |
| | | } else { |
| | | updateProperties({ conditionExpression: null }); |
| | | } |
| | | }; |
| | | |
| | | const skipExpressionChange = (val: string) => { |
| | | updateProperties({ 'flowable:skipExpression': val }); |
| | | }; |
| | | |
| | | onBeforeMount(() => { |
| | | if (formData.value.conditionExpression) { |
| | | formData.value.conditionExpressionValue = formData.value.conditionExpression.body; |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped></style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-form ref="formRef" :model="formData" :rules="formRules" label-width="80px"> |
| | | <el-form-item prop="id" label="èç¹ ID"> |
| | | <el-input v-model="formData.id" @change="idChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="name" label="èç¹åç§°"> |
| | | <el-input v-model="formData.name" @change="nameChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item label="æ§è¡çå¬å¨" style="margin-bottom: 0"> </el-form-item> |
| | | <ExecutionListener :element="element"></ExecutionListener> |
| | | </el-form> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import useParseElement from '@/components/BpmnDesign/hooks/useParseElement'; |
| | | import usePanel from '@/components/BpmnDesign/hooks/usePanel'; |
| | | import { Modeler, ModdleElement } from 'bpmn'; |
| | | import { StartEndPanel } from 'bpmnDesign'; |
| | | |
| | | interface PropType { |
| | | element: ModdleElement; |
| | | } |
| | | const props = withDefaults(defineProps<PropType>(), {}); |
| | | const { nameChange, idChange } = usePanel({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const { parseData } = useParseElement({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | |
| | | const formData = ref(parseData<StartEndPanel>()); |
| | | |
| | | const formRules = ref<ElFormRules>({ |
| | | id: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }], |
| | | name: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }] |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped></style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-form ref="formRef" size="default" :model="formData" :rules="formRules" label-width="100px"> |
| | | <el-collapse v-model="currentCollapseItem"> |
| | | <el-collapse-item name="1"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <InfoFilled /> |
| | | </el-icon> |
| | | å¸¸è§ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <el-form-item prop="id" label="èç¹ ID"> |
| | | <el-input v-model="formData.id" @change="idChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item prop="name" label="èç¹åç§°"> |
| | | <el-input v-model="formData.name" @change="nameChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item v-if="showConfig.skipExpression" prop="skipExpression" label="è·³è¿è¡¨è¾¾å¼"> |
| | | <el-input v-model="formData.skipExpression" @change="skipExpressionChange"> </el-input> |
| | | </el-form-item> |
| | | </div> |
| | | </el-collapse-item> |
| | | <el-collapse-item name="2"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <Checked /> |
| | | </el-icon> |
| | | ä»»å¡ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <el-form-item v-if="showConfig.async" prop="sync" label="æ¯å¦å¼æ¥"> |
| | | <el-switch v-model="formData.async" inline-prompt active-text="æ¯" inactive-text="å¦" @change="syncChange" /> |
| | | </el-form-item> |
| | | |
| | | <el-tabs tab-position="left" class="demo-tabs" @tab-click="taskTabClick"> |
| | | <el-tab-pane label="身份åå¨"> |
| | | <el-form-item label="åé
人å"> |
| | | <el-input v-model="assignee.userName" disabled> |
| | | <template #append> |
| | | <el-button icon="Search" type="primary" @click="openSingleUserSelect" /> |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item label="åé人å"> |
| | | <el-badge :value="selectUserLength" :max="99"> |
| | | <el-button size="small" type="primary" @click="openUserSelect">éæ©äººå</el-button> |
| | | </el-badge> |
| | | </el-form-item> |
| | | <el-form-item label="åéç»"> |
| | | <el-badge :value="selectRoleLength" :max="99"> |
| | | <el-button size="small" type="primary" @click="openRoleSelect">éæ©ç»</el-button> |
| | | </el-badge> |
| | | </el-form-item> |
| | | </el-tab-pane> |
| | | |
| | | <el-tab-pane label="åºå®å¼"> |
| | | <el-form-item prop="auditUserType" label="åé
ç±»å"> |
| | | <el-select v-model="formData.allocationType"> |
| | | <el-option v-for="item in AllocationTypeSelect" :key="item.id" :value="item.value" :label="item.label"> </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item v-if="formData.allocationType === AllocationTypeEnum.USER" label="åé
人å"> |
| | | <el-input v-model="formData.fixedAssignee" @change="fixedAssigneeChange"> |
| | | <template #append> |
| | | <el-button icon="Search" size="small" type="primary" @click="proxy.$modal.msgWarning('å¼åä¸ãããããã')" /> |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <div v-if="formData.allocationType === AllocationTypeEnum.CANDIDATE"> |
| | | <el-form-item label="åé人å"> |
| | | <el-badge :value="selectUserLength" :max="99"> |
| | | <el-button size="small" type="primary" @click="openUserSelect">éæ©äººå</el-button> |
| | | </el-badge> |
| | | </el-form-item> |
| | | <el-form-item label="åéç»"> |
| | | <el-badge :value="selectRoleLength" :max="99"> |
| | | <el-button size="small" type="primary" @click="openRoleSelect">éæ©ç»</el-button> |
| | | </el-badge> |
| | | </el-form-item> |
| | | </div> |
| | | <el-form-item v-if="formData.allocationType === AllocationTypeEnum.SPECIFY && showConfig.specifyDesc" style=""> |
| | | <el-radio-group v-model="formData.specifyDesc" class="ml-4"> |
| | | <el-radio v-for="item in SpecifyDesc" :key="item.id" :label="item.value" size="large">{{ item.label }}</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | |
| | | <el-form-item v-if="showConfig.dueDate" prop="dueDate" label="å°ææ¶é´"> |
| | | <el-input v-model="formData.dueDate" clearable @change="dueDateChange" @click="openDueDate"> |
| | | <template #append> |
| | | <el-button icon="Search" type="primary" @click="openDueDate" /> |
| | | </template> |
| | | </el-input> |
| | | </el-form-item> |
| | | <el-form-item v-if="showConfig.priority" prop="priority" label="ä¼å
级"> |
| | | <el-input-number v-model="formData.priority" :min="0" @change="priorityChange"> </el-input-number> |
| | | </el-form-item> |
| | | </div> |
| | | </el-collapse-item> |
| | | <el-collapse-item name="3"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <HelpFilled /> |
| | | </el-icon> |
| | | å¤å®ä¾ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <el-form-item label="å¤å®ä¾ç±»å"> |
| | | <el-select v-model="formData.multiInstanceType" @change="multiInstanceTypeChange"> |
| | | <el-option v-for="item in MultiInstanceType" :key="item.id" :value="item.value" :label="item.label"> </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <div v-if="formData.multiInstanceType !== MultiInstanceTypeEnum.NONE"> |
| | | <el-form-item label="éå"> |
| | | <template #label> |
| | | <span> |
| | | éå |
| | | <el-tooltip placement="top"> |
| | | <el-icon><QuestionFilled /></el-icon> |
| | | <template #content> |
| | | 屿§ä¼ä½ä¸ºè¡¨è¾¾å¼è¿è¡è§£æãå¦æè¡¨è¾¾å¼è§£æä¸ºå符串è䏿¯ä¸ä¸ªéåï¼<br /> |
| | | ä¸è®ºæ¯å 为æ¬èº«é
ç½®çå°±æ¯éæå符串å¼ï¼è¿æ¯è¡¨è¾¾å¼è®¡ç®ç»æä¸ºå符串ï¼<br /> |
| | | è¿ä¸ªå符串é½ä¼è¢«å½ååéåï¼å¹¶ä»æµç¨åéä¸ç¨äºè·åå®é
çéåã |
| | | </template> |
| | | </el-tooltip> |
| | | </span> |
| | | </template> |
| | | <el-input v-model="formData.collection" @change="collectionChange"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="å
ç´ åé"> |
| | | <template #label> |
| | | <span> |
| | | å
ç´ åé |
| | | <el-tooltip placement="top"> |
| | | <el-icon><QuestionFilled /></el-icon> |
| | | <template #content> |
| | | æ¯å建ä¸ä¸ªç¨æ·ä»»å¡åï¼å
以该å
ç´ åé为labelï¼éåä¸çä¸é¡¹ä¸ºvalueï¼<br /> |
| | | å建ï¼å±é¨ï¼æµç¨åéï¼è¯¥å±é¨æµç¨åé被ç¨äºææ´¾ç¨æ·ä»»å¡ã<br /> |
| | | ä¸è¬æ¥è¯´ï¼è¯¥å符串åºä¸æå®äººååéç¸åã |
| | | </template> |
| | | </el-tooltip> |
| | | </span> |
| | | </template> |
| | | <el-input v-model="formData.elementVariable" @change="elementVariableChange"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item label="宿æ¡ä»¶"> |
| | | <template #label> |
| | | <span> |
| | | 宿æ¡ä»¶ |
| | | <el-tooltip placement="top"> |
| | | <el-icon><QuestionFilled /></el-icon> |
| | | <template #content> |
| | | å¤å®ä¾æ´»å¨å¨ææå®ä¾é½å®ææ¶ç»æï¼ç¶èä¹å¯ä»¥æå®ä¸ä¸ªè¡¨è¾¾å¼ï¼å¨æ¯ä¸ªå®ä¾<br /> |
| | | ç»ææ¶è¿è¡è®¡ç®ãå½è¡¨è¾¾å¼è®¡ç®ä¸ºtrueæ¶ï¼å°éæ¯ææå©ä½çå®ä¾ï¼å¹¶ç»æå¤å®ä¾<br /> |
| | | æ´»å¨ï¼ç»§ç»æ§è¡æµç¨ãä¾å¦ ${nrOfCompletedInstances/nrOfInstances >= 0.6 }ï¼<br /> |
| | | 表示å½ä»»å¡å®æ60%æ¶ï¼è¯¥èç¹å°±ç®å®æ |
| | | </template> |
| | | </el-tooltip> |
| | | </span> |
| | | </template> |
| | | <el-input v-model="formData.completionCondition" @change="completionConditionChange"> </el-input> |
| | | </el-form-item> |
| | | </div> |
| | | </div> |
| | | </el-collapse-item> |
| | | <el-collapse-item v-if="showConfig.taskListener" name="4"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <BellFilled /> |
| | | </el-icon> |
| | | ä»»å¡çå¬å¨ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <TaskListener v-if="showConfig.taskListener" :element="element"></TaskListener> |
| | | </div> |
| | | </el-collapse-item> |
| | | <el-collapse-item v-if="showConfig.executionListener" name="5"> |
| | | <template #title> |
| | | <div class="collapse__title"> |
| | | <el-icon> |
| | | <BellFilled /> |
| | | </el-icon> |
| | | æ§è¡çå¬å¨ |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <ExecutionListener v-if="showConfig.executionListener" :element="element"></ExecutionListener> |
| | | </div> |
| | | </el-collapse-item> |
| | | |
| | | <el-form-item v-if="showConfig.isForCompensation" prop="isForCompensation" label="æ¯å¦ä¸ºè¡¥å¿"> |
| | | <el-switch v-model="formData.isForCompensation" inline-prompt active-text="æ¯" inactive-text="å¦" /> |
| | | </el-form-item> |
| | | <el-form-item v-if="showConfig.triggerServiceTask" prop="triggerServiceTask" label="æå¡ä»»å¡å¯è§¦å"> |
| | | <el-switch v-model="formData.triggerServiceTask" inline-prompt active-text="æ¯" inactive-text="å¦" /> |
| | | </el-form-item> |
| | | <el-form-item v-if="showConfig.autoStoreVariables" prop="autoStoreVariables" label="èªå¨åå¨åé"> |
| | | <el-switch v-model="formData.autoStoreVariables" inline-prompt active-text="æ¯" inactive-text="å¦" /> |
| | | </el-form-item> |
| | | <el-form-item v-if="showConfig.ruleVariablesInput" prop="skipExpression" label="è¾å
¥åé"> |
| | | <el-input v-model="formData.ruleVariablesInput"> </el-input> |
| | | </el-form-item> |
| | | <el-form-item v-if="showConfig.exclude" prop="exclude" label="æé¤"> |
| | | <el-switch v-model="formData.exclude" inline-prompt active-text="æ¯" inactive-text="å¦" /> |
| | | </el-form-item> |
| | | <el-form-item v-if="showConfig.class" prop="class" label="ç±»"> |
| | | <el-input v-model="formData.class"> </el-input> |
| | | </el-form-item> |
| | | </el-collapse> |
| | | </el-form> |
| | | <UserSelect ref="userSelectRef" :data="formData.candidateUsers" @confirm-call-back="userSelectCallBack"></UserSelect> |
| | | <UserSelect ref="singleUserSelectRef" :data="formData.assignee" :multiple="false" @confirm-call-back="singleUserSelectCallBack"></UserSelect> |
| | | <RoleSelect ref="roleSelectRef" :data="formData.candidateGroups" @confirm-call-back="roleSelectCallBack"></RoleSelect> |
| | | <DueDate ref="dueDateRef" v-model="formData.dueDate" :data="formData.dueDate" @confirm-call-back="dueDateCallBack"></DueDate> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import useParseElement from '@/components/BpmnDesign/hooks/useParseElement'; |
| | | import usePanel from '@/components/BpmnDesign/hooks/usePanel'; |
| | | import UserSelect from '@/components/UserSelect'; |
| | | import RoleSelect from '@/components/RoleSelect'; |
| | | import DueDate from '@/components/BpmnDesign/panel/property/DueDate.vue'; |
| | | import { ModdleElement } from 'bpmn'; |
| | | import { TaskPanel } from 'bpmnDesign'; |
| | | import { AllocationTypeEnum, MultiInstanceTypeEnum, SpecifyDescEnum } from '@/enums/bpmn/IndexEnums'; |
| | | import { UserVO } from '@/api/system/user/types'; |
| | | import { RoleVO } from '@/api/system/role/types'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | interface PropType { |
| | | element: ModdleElement; |
| | | } |
| | | const props = withDefaults(defineProps<PropType>(), {}); |
| | | const { showConfig, nameChange, idChange, updateProperties, getExtensionElements, createModdleElement } = usePanel({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const { parseData } = useParseElement({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | |
| | | const initFormData = { |
| | | id: '', |
| | | name: '', |
| | | dueDate: '', |
| | | multiInstanceType: MultiInstanceTypeEnum.NONE, |
| | | allocationType: AllocationTypeEnum.USER, |
| | | specifyDesc: SpecifyDescEnum.SPECIFY_SINGLE |
| | | }; |
| | | const formData = ref({ ...initFormData, ...parseData<TaskPanel>() }); |
| | | const assignee = ref<Partial<UserVO>>({ |
| | | userName: '' |
| | | }); |
| | | const currentCollapseItem = ref(['1', '2']); |
| | | const userSelectRef = ref<InstanceType<typeof UserSelect>>(); |
| | | const singleUserSelectRef = ref<InstanceType<typeof UserSelect>>(); |
| | | const roleSelectRef = ref<InstanceType<typeof RoleSelect>>(); |
| | | const dueDateRef = ref<InstanceType<typeof DueDate>>(); |
| | | |
| | | const isMultiple = ref(true); |
| | | const openUserSelect = () => { |
| | | userSelectRef.value.open(); |
| | | }; |
| | | const openSingleUserSelect = () => { |
| | | singleUserSelectRef.value.open(); |
| | | }; |
| | | const openRoleSelect = () => { |
| | | roleSelectRef.value.open(); |
| | | }; |
| | | const openDueDate = (e) => { |
| | | dueDateRef.value.openDialog(); |
| | | }; |
| | | |
| | | const singleUserSelectCallBack = (data: UserVO[]) => { |
| | | const user: UserVO = data.length !== 0 ? data[0] : undefined; |
| | | updateProperties({ 'flowable:assignee': user?.userId }); |
| | | assignee.value = user ? user : { userName: '' }; |
| | | formData.value.assignee = String(user?.userId); |
| | | let extensionElements = getExtensionElements(); |
| | | extensionElements.values = extensionElements.get('values').filter((item) => item.$type !== 'flowable:extAssignee'); |
| | | if (user) { |
| | | const extAssigneeElement = createModdleElement('flowable:extAssignee', { body: '' }, extensionElements); |
| | | extensionElements.get('values').push(extAssigneeElement); |
| | | extAssigneeElement.body = JSON.stringify({ userName: user.userName, userId: user.userId }); |
| | | } |
| | | if (extensionElements.values.length === 0) { |
| | | extensionElements = undefined; |
| | | } |
| | | updateProperties({ extensionElements: extensionElements }); |
| | | }; |
| | | const userSelectCallBack = (data: UserVO[]) => { |
| | | let extensionElements = getExtensionElements(); |
| | | extensionElements.values = extensionElements.values.filter((item) => item.$type !== 'flowable:extCandidateUsers'); |
| | | if (data.length === 0) { |
| | | formData.value.candidateUsers = undefined; |
| | | updateProperties({ 'flowable:candidateUsers': undefined }); |
| | | } else { |
| | | const userIds = data.map((item) => item.userId).join(','); |
| | | formData.value.candidateUsers = userIds; |
| | | updateProperties({ 'flowable:candidateUsers': userIds }); |
| | | const extCandidateUsersElement = createModdleElement('flowable:extCandidateUsers', { body: '' }, extensionElements); |
| | | extensionElements.values.push(extCandidateUsersElement); |
| | | const users = data.map((item) => { |
| | | return { |
| | | userId: item.userId, |
| | | userName: item.userName |
| | | }; |
| | | }); |
| | | extCandidateUsersElement.body = JSON.stringify(users); |
| | | } |
| | | if (extensionElements.values.length === 0) { |
| | | extensionElements = undefined; |
| | | } |
| | | updateProperties({ extensionElements: extensionElements }); |
| | | }; |
| | | const roleSelectCallBack = (data: RoleVO[]) => { |
| | | if (data.length === 0) { |
| | | formData.value.candidateGroups = ''; |
| | | updateProperties({ 'flowable:candidateGroups': undefined }); |
| | | } else { |
| | | const roleIds = data.map((item) => item.roleId).join(','); |
| | | formData.value.candidateGroups = roleIds; |
| | | updateProperties({ 'flowable:candidateGroups': roleIds }); |
| | | } |
| | | }; |
| | | const dueDateCallBack = (data: string) => { |
| | | updateProperties({ 'flowable:dueDate': data }); |
| | | }; |
| | | |
| | | const taskTabClick = (e) => { |
| | | formData.value.candidateGroups = ''; |
| | | formData.value.candidateUsers = ''; |
| | | formData.value.assignee = ''; |
| | | assignee.value = {}; |
| | | }; |
| | | |
| | | const syncChange = (newVal) => { |
| | | updateProperties({ 'flowable:async': newVal }); |
| | | }; |
| | | const skipExpressionChange = (newVal) => { |
| | | updateProperties({ 'flowable:skipExpression': newVal && newVal.length > 0 ? newVal : undefined }); |
| | | }; |
| | | const priorityChange = (newVal) => { |
| | | updateProperties({ 'flowable:priority': newVal }); |
| | | }; |
| | | const fixedAssigneeChange = (newVal) => { |
| | | updateProperties({ 'flowable:assignee': newVal && newVal.length > 0 ? newVal : undefined }); |
| | | }; |
| | | const multiInstanceTypeChange = (newVal) => { |
| | | if (newVal !== MultiInstanceTypeEnum.NONE) { |
| | | let loopCharacteristics = props.element.businessObject.get('loopCharacteristics'); |
| | | if (!loopCharacteristics) { |
| | | loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject); |
| | | } |
| | | loopCharacteristics.isSequential = newVal === MultiInstanceTypeEnum.SERIAL; |
| | | updateProperties({ loopCharacteristics: loopCharacteristics }); |
| | | } else { |
| | | updateProperties({ loopCharacteristics: undefined }); |
| | | } |
| | | }; |
| | | const collectionChange = (newVal) => { |
| | | let loopCharacteristics = props.element.businessObject.get('loopCharacteristics'); |
| | | if (!loopCharacteristics) { |
| | | loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject); |
| | | } |
| | | loopCharacteristics.collection = newVal && newVal.length > 0 ? newVal : undefined; |
| | | updateProperties({ loopCharacteristics: loopCharacteristics }); |
| | | }; |
| | | const elementVariableChange = (newVal) => { |
| | | let loopCharacteristics = props.element.businessObject.get('loopCharacteristics'); |
| | | if (!loopCharacteristics) { |
| | | loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject); |
| | | } |
| | | loopCharacteristics.elementVariable = newVal && newVal.length > 0 ? newVal : undefined; |
| | | updateProperties({ loopCharacteristics: loopCharacteristics }); |
| | | }; |
| | | const completionConditionChange = (newVal) => { |
| | | let loopCharacteristics = props.element.businessObject.get<ModdleElement>('loopCharacteristics'); |
| | | if (!loopCharacteristics) { |
| | | loopCharacteristics = createModdleElement('bpmn:MultiInstanceLoopCharacteristics', {}, props.element.businessObject); |
| | | } |
| | | if (newVal && newVal.length > 0) { |
| | | if (!loopCharacteristics.completionCondition) { |
| | | loopCharacteristics.completionCondition = createModdleElement('bpmn:Expression', { body: newVal }, loopCharacteristics); |
| | | } else { |
| | | loopCharacteristics.completionCondition.body = newVal; |
| | | } |
| | | } else { |
| | | loopCharacteristics.completionCondition = undefined; |
| | | } |
| | | updateProperties({ loopCharacteristics: loopCharacteristics }); |
| | | }; |
| | | const dueDateChange = (newVal) => { |
| | | updateProperties({ 'flowable:dueDate': newVal && newVal.length > 0 ? newVal : undefined }); |
| | | }; |
| | | const selectUserLength = computed(() => { |
| | | if (formData.value.candidateUsers) { |
| | | return formData.value.candidateUsers.split(',').length; |
| | | } else { |
| | | return 0; |
| | | } |
| | | }); |
| | | const selectRoleLength = computed(() => { |
| | | if (formData.value.candidateGroups) { |
| | | return formData.value.candidateGroups.split(',').length; |
| | | } else { |
| | | return 0; |
| | | } |
| | | }); |
| | | |
| | | onBeforeMount(() => { |
| | | const extensionElements = getExtensionElements(false); |
| | | if (extensionElements && extensionElements.get('values')) { |
| | | let extAssigneeElement = extensionElements.get('values').find((item) => item.$type === 'flowable:extAssignee'); |
| | | if (extAssigneeElement) { |
| | | assignee.value = JSON.parse(extAssigneeElement.body); |
| | | } |
| | | } |
| | | |
| | | if (formData.value.loopCharacteristics) { |
| | | const loopCharacteristics = formData.value.loopCharacteristics; |
| | | formData.value.collection = loopCharacteristics.collection || ''; |
| | | formData.value.elementVariable = loopCharacteristics.elementVariable || ''; |
| | | formData.value.completionCondition = loopCharacteristics.completionCondition?.body || ''; |
| | | formData.value.multiInstanceType = loopCharacteristics.isSequential ? MultiInstanceTypeEnum.SERIAL : MultiInstanceTypeEnum.PARALLEL; |
| | | } |
| | | |
| | | if (formData.value.assignee) { |
| | | formData.value.fixedAssignee = formData.value.assignee; |
| | | } |
| | | }); |
| | | |
| | | const formRules = ref<ElFormRules>({ |
| | | id: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }], |
| | | name: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }] |
| | | }); |
| | | |
| | | const AllocationTypeSelect = [ |
| | | { id: 'b9cdf970-dd91-47c0-819f-42a7010ca2a6', label: 'æå®äººå', value: AllocationTypeEnum.USER }, |
| | | { id: '3f7ccbcd-c464-4602-bb9d-e96649d10585', label: 'åé人å', value: AllocationTypeEnum.CANDIDATE }, |
| | | { id: 'c49065e0-7f2d-4c09-aedb-ab2d47d9a454', label: 'å起人èªå·±', value: AllocationTypeEnum.YOURSELF }, |
| | | { id: '6ef40a03-7e9a-4898-89b2-c88fe9064542', label: 'å起人æå®', value: AllocationTypeEnum.SPECIFY } |
| | | ]; |
| | | const SpecifyDesc = [ |
| | | { id: 'fa253b34-4335-458c-b1bc-b039e2a2b7a6', label: 'æå®ä¸ä¸ªäºº', value: 'specifySingle' }, |
| | | { id: '7365ff54-2e05-4312-9bfb-0b8edd779c5b', label: 'æå®å¤ä¸ªäºº', value: 'specifyMultiple' } |
| | | ]; |
| | | |
| | | const MultiInstanceType = [ |
| | | { id: '373d4b81-a0d1-4eb8-8685-0d2fb1b468e2', label: 'æ ', value: MultiInstanceTypeEnum.NONE }, |
| | | { id: 'b5acea7c-b7e5-46b0-8778-390db091bdab', label: '串è¡', value: MultiInstanceTypeEnum.SERIAL }, |
| | | { id: 'b4f0c683-1ccc-43c4-8380-e1b998986caf', label: 'å¹¶è¡', value: MultiInstanceTypeEnum.PARALLEL } |
| | | ]; |
| | | </script> |
| | | |
| | | <style lang="scss" scoped></style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div ref="propertyPanel"> |
| | | <div v-if="nodeName" class="node-name">{{ nodeName }}</div> |
| | | <component :is="component" v-if="element" :element="element" /> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts" name="PropertyPanel"> |
| | | import { NodeName } from '../assets/lang/zh'; |
| | | import TaskPanel from './TaskPanel.vue'; |
| | | import ProcessPanel from './ProcessPanel.vue'; |
| | | import StartEndPanel from './StartEndPanel.vue'; |
| | | import GatewayPanel from './GatewayPanel.vue'; |
| | | import SequenceFlowPanel from './SequenceFlowPanel.vue'; |
| | | import { Modeler, ModdleElement } from 'bpmn'; |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | interface propsType { |
| | | modeler: Modeler; |
| | | } |
| | | const props = withDefaults(defineProps<propsType>(), {}); |
| | | |
| | | const element = ref<ModdleElement>(); |
| | | const processElement = ref<ModdleElement>(); |
| | | |
| | | const startEndType = ['bpmn:IntermediateThrowEvent', 'bpmn:StartEvent', 'bpmn:EndEvent']; |
| | | const taskType = [ |
| | | 'bpmn:UserTask', |
| | | 'bpmn:Task', |
| | | 'bpmn:SendTask', |
| | | 'bpmn:ReceiveTask', |
| | | 'bpmn:ManualTask', |
| | | 'bpmn:BusinessRuleTask', |
| | | 'bpmn:ServiceTask', |
| | | 'bpmn:ScriptTask' |
| | | ]; |
| | | const sequenceType = ['bpmn:SequenceFlow']; |
| | | const gatewayType = ['bpmn:InclusiveGateway', 'bpmn:ExclusiveGateway', 'bpmn:ParallelGateway', 'bpmn:EventBasedGateway', 'bpmn:ComplexGateway']; |
| | | const processType = ['bpmn:Process']; |
| | | |
| | | // ç»ä»¶è®¡ç® |
| | | const component = computed(() => { |
| | | if (!element.value) return null; |
| | | const type = element.value.type; |
| | | if (startEndType.includes(type)) return StartEndPanel; |
| | | if (taskType.includes(type)) return TaskPanel; |
| | | if (sequenceType.includes(type)) return SequenceFlowPanel; |
| | | if (gatewayType.includes(type)) return GatewayPanel; |
| | | if (processType.includes(type)) return ProcessPanel; |
| | | return proxy?.$modal.msgWarning('颿¿å¼åä¸....'); |
| | | }); |
| | | |
| | | const nodeName = computed(() => { |
| | | if (element.value) { |
| | | const bizObj = element.value.businessObject; |
| | | const type = bizObj?.eventDefinitions && bizObj?.eventDefinitions.length > 0 ? bizObj.eventDefinitions[0].$type : bizObj.$type; |
| | | return NodeName[type] || type; |
| | | } |
| | | }); |
| | | |
| | | const handleModeler = () => { |
| | | props.modeler.on('root.added', (e: any) => { |
| | | element.value = null; |
| | | if (e.element.type === 'bpmn:Process') { |
| | | nextTick(() => { |
| | | element.value = e.element; |
| | | processElement.value = e.element; |
| | | }); |
| | | } |
| | | }); |
| | | props.modeler.on('element.click', (e: any) => { |
| | | if (e.element.type === 'bpmn:Process') { |
| | | nextTick(() => { |
| | | element.value = e.element; |
| | | processElement.value = e.element; |
| | | }); |
| | | } |
| | | }); |
| | | props.modeler.on('selection.changed', (e: any) => { |
| | | // å
ç»null为äºè®©vueå·æ° |
| | | element.value = null; |
| | | const newElement = e.newSelection[0]; |
| | | if (newElement) { |
| | | nextTick(() => { |
| | | element.value = newElement; |
| | | }); |
| | | } else { |
| | | nextTick(() => { |
| | | element.value = processElement.value; |
| | | }); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | handleModeler(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .node-name { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | padding: 10px; |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-dialog v-model="visible" :title="title" width="600px" append-to-body> |
| | | <el-form label-width="100px"> |
| | | <el-form-item label="å°æ¶"> |
| | | <el-radio-group v-model="hourValue" @change="hourChange"> |
| | | <el-radio-button label="4" /> |
| | | <el-radio-button label="8" /> |
| | | <el-radio-button label="12" /> |
| | | <el-radio-button label="24" /> |
| | | <el-radio-button label="èªå®ä¹" /> |
| | | <el-input-number v-show="hourValue === 'èªå®ä¹'" v-model="customHourValue" :min="1" @change="customHourValueChange"></el-input-number> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="天"> |
| | | <el-radio-group v-model="dayValue" @change="dayChange"> |
| | | <el-radio-button label="1" /> |
| | | <el-radio-button label="2" /> |
| | | <el-radio-button label="3" /> |
| | | <el-radio-button label="4" /> |
| | | <el-radio-button label="èªå®ä¹" /> |
| | | <el-input-number v-show="dayValue === 'èªå®ä¹'" v-model="customDayValue" :min="1" @change="customDayValueChange"></el-input-number> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="å¨"> |
| | | <el-radio-group v-model="weekValue" @change="weekChange"> |
| | | <el-radio-button label="1" /> |
| | | <el-radio-button label="2" /> |
| | | <el-radio-button label="3" /> |
| | | <el-radio-button label="4" /> |
| | | <el-radio-button label="èªå®ä¹" /> |
| | | <el-input-number v-show="weekValue === 'èªå®ä¹'" v-model="customWeekValue" :min="1" @change="customWeekValueChange"></el-input-number> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="æ"> |
| | | <el-radio-group v-model="monthValue" @change="monthChange"> |
| | | <el-radio-button label="1" /> |
| | | <el-radio-button label="2" /> |
| | | <el-radio-button label="3" /> |
| | | <el-radio-button label="4" /> |
| | | <el-radio-button label="èªå®ä¹" /> |
| | | <el-input-number v-show="monthValue === 'èªå®ä¹'" v-model="customMonthValue" :min="1" @change="customMonthValueChange"></el-input-number> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <template #footer> |
| | | <div> |
| | | <el-button @click="closeDialog">åæ¶</el-button> |
| | | <el-button type="primary" @click="confirm">ç¡®å®</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import useDialog from '@/hooks/useDialog'; |
| | | |
| | | interface PropType { |
| | | modelValue?: string; |
| | | data?: string; |
| | | } |
| | | const prop = withDefaults(defineProps<PropType>(), { |
| | | modelValue: '', |
| | | data: '' |
| | | }); |
| | | const emit = defineEmits(['update:modelValue', 'confirmCallBack']); |
| | | |
| | | const { title, visible, openDialog, closeDialog } = useDialog({ |
| | | title: '设置任å¡å°ææ¶é´' |
| | | }); |
| | | const formValue = ref(); |
| | | const valueType = ref(); |
| | | |
| | | const hourValue = ref(''); |
| | | const dayValue = ref(''); |
| | | const weekValue = ref(''); |
| | | const monthValue = ref(''); |
| | | |
| | | const customHourValue = ref(1); |
| | | const customDayValue = ref(1); |
| | | const customWeekValue = ref(1); |
| | | const customMonthValue = ref(1); |
| | | |
| | | const hourValueConst = ['4', '8', '12', '24']; |
| | | const dayAndWeekAndMonthValueConst = ['1', '2', '3', '4']; |
| | | |
| | | const initValue = () => { |
| | | formValue.value = prop.data; |
| | | if (prop.data) { |
| | | const lastStr = prop.data.substring(prop.data.length - 1); |
| | | if (lastStr === 'H') { |
| | | const hourValueValue = prop.data.substring(2, prop.data.length - 1); |
| | | if (hourValueConst.includes(hourValueValue)) { |
| | | hourValue.value = hourValueValue; |
| | | } else { |
| | | hourValue.value = 'èªå®ä¹'; |
| | | customHourValue.value = Number(hourValueValue); |
| | | } |
| | | } |
| | | const dayAndWeekAndMonthValue = prop.data.substring(1, prop.data.length - 1); |
| | | if (lastStr === 'D') { |
| | | if (dayAndWeekAndMonthValueConst.includes(dayAndWeekAndMonthValue)) { |
| | | dayValue.value = dayAndWeekAndMonthValue; |
| | | } else { |
| | | dayValue.value = 'èªå®ä¹'; |
| | | customDayValue.value = Number(dayAndWeekAndMonthValue); |
| | | } |
| | | } |
| | | if (lastStr === 'W') { |
| | | if (dayAndWeekAndMonthValueConst.includes(dayAndWeekAndMonthValue)) { |
| | | weekValue.value = dayAndWeekAndMonthValue; |
| | | } else { |
| | | weekValue.value = 'èªå®ä¹'; |
| | | customWeekValue.value = Number(dayAndWeekAndMonthValue); |
| | | } |
| | | } |
| | | if (lastStr === 'M') { |
| | | if (dayAndWeekAndMonthValueConst.includes(dayAndWeekAndMonthValue)) { |
| | | monthValue.value = dayAndWeekAndMonthValue; |
| | | } else { |
| | | monthValue.value = 'èªå®ä¹'; |
| | | customMonthValue.value = Number(dayAndWeekAndMonthValue); |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const confirm = () => { |
| | | emit('update:modelValue', formValue.value); |
| | | emit('confirmCallBack', formValue.value); |
| | | closeDialog(); |
| | | }; |
| | | |
| | | const customHourValueChange = (customHourValue) => { |
| | | formValue.value = `PT${customHourValue}H`; |
| | | |
| | | dayValue.value = ''; |
| | | weekValue.value = ''; |
| | | monthValue.value = ''; |
| | | customDayValue.value = 1; |
| | | customWeekValue.value = 1; |
| | | customMonthValue.value = 1; |
| | | }; |
| | | const customDayValueChange = (customDayValue) => { |
| | | formValue.value = `P${customDayValue}D`; |
| | | hourValue.value = ''; |
| | | weekValue.value = ''; |
| | | monthValue.value = ''; |
| | | |
| | | customHourValue.value = 1; |
| | | customWeekValue.value = 1; |
| | | customMonthValue.value = 1; |
| | | }; |
| | | |
| | | const customWeekValueChange = (customWeekValue) => { |
| | | formValue.value = `P${customWeekValue}W`; |
| | | hourValue.value = ''; |
| | | dayValue.value = ''; |
| | | monthValue.value = ''; |
| | | |
| | | customHourValue.value = 1; |
| | | customDayValue.value = 1; |
| | | customMonthValue.value = 1; |
| | | }; |
| | | |
| | | const customMonthValueChange = (customMonthValue) => { |
| | | formValue.value = `P${customMonthValue}M`; |
| | | hourValue.value = ''; |
| | | dayValue.value = ''; |
| | | weekValue.value = ''; |
| | | |
| | | customHourValue.value = 1; |
| | | customDayValue.value = 1; |
| | | customWeekValue.value = 1; |
| | | }; |
| | | |
| | | const hourChange = (hourValue) => { |
| | | if (hourValue === 'èªå®ä¹') { |
| | | formValue.value = `PT${customHourValue.value}H`; |
| | | } else { |
| | | formValue.value = `PT${hourValue}H`; |
| | | } |
| | | |
| | | dayValue.value = ''; |
| | | weekValue.value = ''; |
| | | monthValue.value = ''; |
| | | customDayValue.value = 1; |
| | | customWeekValue.value = 1; |
| | | customMonthValue.value = 1; |
| | | }; |
| | | const dayChange = (dayValue) => { |
| | | if (dayValue === 'èªå®ä¹') { |
| | | formValue.value = `P${customDayValue.value}D`; |
| | | } else { |
| | | formValue.value = `P${dayValue}D`; |
| | | } |
| | | |
| | | hourValue.value = ''; |
| | | weekValue.value = ''; |
| | | monthValue.value = ''; |
| | | |
| | | customHourValue.value = 1; |
| | | customWeekValue.value = 1; |
| | | customMonthValue.value = 1; |
| | | }; |
| | | const weekChange = (weekValue) => { |
| | | if (weekValue === 'èªå®ä¹') { |
| | | formValue.value = `P${customWeekValue.value}W`; |
| | | } else { |
| | | formValue.value = `P${weekValue}W`; |
| | | } |
| | | |
| | | hourValue.value = ''; |
| | | dayValue.value = ''; |
| | | monthValue.value = ''; |
| | | |
| | | customHourValue.value = 1; |
| | | customDayValue.value = 1; |
| | | customMonthValue.value = 1; |
| | | }; |
| | | const monthChange = (monthValue) => { |
| | | if (monthValue === 'èªå®ä¹') { |
| | | formValue.value = `P${customMonthValue.value}M`; |
| | | } else { |
| | | formValue.value = `P${monthValue}M`; |
| | | } |
| | | |
| | | hourValue.value = ''; |
| | | dayValue.value = ''; |
| | | weekValue.value = ''; |
| | | |
| | | customHourValue.value = 1; |
| | | customDayValue.value = 1; |
| | | customWeekValue.value = 1; |
| | | }; |
| | | |
| | | watch( |
| | | () => visible.value, |
| | | () => { |
| | | if (visible.value) { |
| | | initValue(); |
| | | } |
| | | } |
| | | ); |
| | | |
| | | defineExpose({ |
| | | openDialog, |
| | | closeDialog |
| | | }); |
| | | </script> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <vxe-toolbar> |
| | | <template #buttons> |
| | | <el-button type="primary" link size="small" @click="insertEvent">æ°å¢</el-button> |
| | | <el-button type="primary" link size="small" @click="removeSelectRowEvent">å é¤</el-button> |
| | | </template> |
| | | </vxe-toolbar> |
| | | <vxe-table |
| | | ref="tableRef" |
| | | size="mini" |
| | | height="100px" |
| | | border |
| | | show-overflow |
| | | keep-source |
| | | :data="tableData" |
| | | :menu-config="menuConfig" |
| | | @cell-dblclick="cellDBLClickEvent" |
| | | @menu-click="contextMenuClickEvent" |
| | | > |
| | | <vxe-column type="checkbox" width="40"></vxe-column> |
| | | <vxe-column type="seq" width="40"></vxe-column> |
| | | <vxe-column field="event" title="äºä»¶" min-width="100px"> |
| | | <template #default="slotParams"> |
| | | <span>{{ eventSelect.find((e) => e.value === slotParams.row.event)?.label }}</span> |
| | | </template> |
| | | </vxe-column> |
| | | <vxe-column field="type" title="ç±»å" min-width="100px"> |
| | | <template #default="slotParams"> |
| | | <span>{{ typeSelect.find((e) => e.value === slotParams.row.type)?.label }}</span> |
| | | </template> |
| | | </vxe-column> |
| | | <vxe-column field="className" title="Java ç±»å" min-width="100px"> </vxe-column> |
| | | </vxe-table> |
| | | |
| | | <el-dialog |
| | | v-model="formDialog.visible.value" |
| | | :title="formDialog.title.value" |
| | | width="600px" |
| | | :close-on-click-modal="false" |
| | | :close-on-press-escape="false" |
| | | :show-close="false" |
| | | append-to-body |
| | | > |
| | | <el-form ref="formRef" :model="formData" :rules="tableRules" label-width="90px"> |
| | | <el-form-item label="äºä»¶" prop="event"> |
| | | <el-select v-model="formData.event"> |
| | | <el-option v-for="item in eventSelect" :key="item.id" :value="item.value" :label="item.label"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="ç±»å" prop="type"> |
| | | <template #label> |
| | | <span> |
| | | ç±»å |
| | | <el-tooltip placement="top"> |
| | | <el-icon><QuestionFilled /></el-icon> |
| | | <template #content> |
| | | ç±»ï¼ç¤ºä¾ com.company.MyCustomListenerï¼èªå®ä¹ç±»å¿
é¡»å®ç° org.flowable.engine.delegate.TaskListener æ¥å£<br /> |
| | | 表达å¼ï¼ç¤ºä¾ ${myObject.callMethod(task, task.eventName)}<br /> |
| | | å§æè¡¨è¾¾å¼ï¼ç¤ºä¾ ${myListenerSpringBean} ï¼è¯¥ springBean éè¦å®ç° org.flowable.engine.delegate.TaskListener æ¥å£ |
| | | </template> |
| | | </el-tooltip> |
| | | </span> |
| | | </template> |
| | | <el-select v-model="formData.type"> |
| | | <el-option v-for="item in typeSelect" :key="item.id" :value="item.value" :label="item.label"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="Java ç±»å" prop="className"> |
| | | <el-input v-model="formData.className" type="text"></el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | <el-tabs type="border-card"> |
| | | <el-tab-pane label="åæ°"> |
| | | <ListenerParam ref="listenerParamRef" :table-data="formData.params" /> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="formDialog.closeDialog">å æ¶</el-button> |
| | | <el-button type="primary" @click="submitEvent">ç¡® å®</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import ListenerParam from './ListenerParam.vue'; |
| | | import { VxeTableEvents, VxeTableInstance, VxeTablePropTypes } from 'vxe-table'; |
| | | import { ExecutionListenerVO } from 'bpmnDesign'; |
| | | import { Moddle, Modeler, ModdleElement } from 'bpmn'; |
| | | |
| | | import usePanel from '@/components/BpmnDesign/hooks/usePanel'; |
| | | import useDialog from '@/hooks/useDialog'; |
| | | import useModelerStore from '@/store/modules/modeler'; |
| | | |
| | | const emit = defineEmits(['close']); |
| | | interface PropType { |
| | | element: ModdleElement; |
| | | } |
| | | const props = withDefaults(defineProps<PropType>(), {}); |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | const selectRow = ref<ExecutionListenerVO | null>(); |
| | | const formDialog = useDialog({ |
| | | title: selectRow.value ? 'ç¼è¾&ä¿å' : 'æ°å¢&ä¿å' |
| | | }); |
| | | |
| | | const { showConfig, elementType, updateProperties } = usePanel({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const { getModdle } = useModelerStore(); |
| | | const moddle = getModdle(); |
| | | |
| | | const listenerParamRef = ref<InstanceType<typeof ListenerParam>>(); |
| | | const tableRef = ref<VxeTableInstance<ExecutionListenerVO>>(); |
| | | const formRef = ref<ElFormInstance>(); |
| | | |
| | | const initData: ExecutionListenerVO = { |
| | | event: '', |
| | | type: '', |
| | | className: '', |
| | | params: [] |
| | | }; |
| | | const formData = ref<ExecutionListenerVO>({ ...initData }); |
| | | const tableData = ref<ExecutionListenerVO[]>([]); |
| | | const tableRules = ref<ElFormRules>({ |
| | | event: [{ required: true, message: 'è¯·éæ©', trigger: 'blur' }], |
| | | type: [{ required: true, message: 'è¯·éæ©', trigger: 'blur' }], |
| | | className: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }] |
| | | }); |
| | | |
| | | const submitEvent = async () => { |
| | | const error = await listenerParamRef.value.validate(); |
| | | await formRef.value.validate((validate) => { |
| | | if (validate && !error) { |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | formData.value.params = listenerParamRef.value.getTableData(); |
| | | if (selectRow.value) { |
| | | Object.assign(selectRow.value, formData.value); |
| | | } else { |
| | | $table.insertAt({ ...formData.value }, -1); |
| | | } |
| | | updateElement(); |
| | | formDialog.closeDialog(); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const removeSelectRowEvent = async () => { |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | const selectCount = $table.getCheckboxRecords().length; |
| | | if (selectCount === 0) { |
| | | proxy?.$modal.msgWarning('è¯·éæ©è¡'); |
| | | } else { |
| | | await $table.removeCheckboxRow(); |
| | | updateElement(); |
| | | } |
| | | } |
| | | }; |
| | | const insertEvent = async () => { |
| | | Object.assign(formData.value, initData); |
| | | selectRow.value = null; |
| | | formDialog.openDialog(); |
| | | }; |
| | | |
| | | const editEvent = (row: ExecutionListenerVO) => { |
| | | Object.assign(formData.value, row); |
| | | selectRow.value = row; |
| | | formDialog.openDialog(); |
| | | }; |
| | | |
| | | const removeEvent = async (row: ExecutionListenerVO) => { |
| | | await proxy?.$modal.confirm('æ¨ç¡®å®è¦å é¤è¯¥æ°æ®?'); |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | await $table.remove(row); |
| | | updateElement(); |
| | | } |
| | | }; |
| | | const updateElement = () => { |
| | | const $table = tableRef.value; |
| | | const data = $table.getTableData().fullData; |
| | | if (data.length) { |
| | | let extensionElements = props.element.businessObject.get('extensionElements'); |
| | | if (!extensionElements) { |
| | | extensionElements = moddle.create('bpmn:ExtensionElements'); |
| | | } |
| | | // æ¸
餿§å¼ |
| | | extensionElements.values = extensionElements.values?.filter((item) => item.$type !== 'flowable:ExecutionListener') ?? []; |
| | | data.forEach((item) => { |
| | | const executionListener = moddle.create('flowable:ExecutionListener'); |
| | | executionListener['event'] = item.event; |
| | | executionListener[item.type] = item.className; |
| | | if (item.params && item.params.length) { |
| | | item.params.forEach((field) => { |
| | | const fieldElement = moddle.create('flowable:Field'); |
| | | fieldElement['name'] = field.name; |
| | | fieldElement[field.type] = field.value; |
| | | executionListener.get('fields').push(fieldElement); |
| | | }); |
| | | } |
| | | extensionElements.get('values').push(executionListener); |
| | | }); |
| | | updateProperties({ extensionElements: extensionElements }); |
| | | } else { |
| | | const extensionElements = props.element.businessObject[`extensionElements`]; |
| | | if (extensionElements) { |
| | | extensionElements.values = extensionElements.values?.filter((item) => item.$type !== 'flowable:ExecutionListener') ?? []; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const cellDBLClickEvent: VxeTableEvents.CellDblclick<ExecutionListenerVO> = ({ row }) => { |
| | | editEvent(row); |
| | | }; |
| | | |
| | | const menuConfig = reactive<VxeTablePropTypes.MenuConfig<ExecutionListenerVO>>({ |
| | | body: { |
| | | options: [ |
| | | [ |
| | | { code: 'edit', name: 'ç¼è¾', prefixIcon: 'vxe-icon-edit', disabled: false }, |
| | | { code: 'remove', name: 'å é¤', prefixIcon: 'vxe-icon-delete', disabled: false } |
| | | ] |
| | | ] |
| | | }, |
| | | visibleMethod({ options, column }) { |
| | | const isDisabled = !column; |
| | | options.forEach((list) => { |
| | | list.forEach((item) => { |
| | | item.disabled = isDisabled; |
| | | }); |
| | | }); |
| | | return true; |
| | | } |
| | | }); |
| | | const contextMenuClickEvent: VxeTableEvents.MenuClick<ExecutionListenerVO> = ({ menu, row, column }) => { |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | switch (menu.code) { |
| | | case 'edit': |
| | | editEvent(row); |
| | | break; |
| | | case 'remove': |
| | | removeEvent(row); |
| | | break; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const initTableData = () => { |
| | | tableData.value = |
| | | props.element.businessObject.extensionElements?.values |
| | | .filter((item) => item.$type === 'flowable:ExecutionListener') |
| | | .map((item) => { |
| | | let type; |
| | | if ('class' in item) type = 'class'; |
| | | if ('expression' in item) type = 'expression'; |
| | | if ('delegateExpression' in item) type = 'delegateExpression'; |
| | | return { |
| | | event: item.event, |
| | | type: type, |
| | | className: item[type], |
| | | params: |
| | | item.fields?.map((field) => { |
| | | let fieldType; |
| | | if ('stringValue' in field) fieldType = 'stringValue'; |
| | | if ('expression' in field) fieldType = 'expression'; |
| | | return { |
| | | name: field.name, |
| | | type: fieldType, |
| | | value: field[fieldType] |
| | | }; |
| | | }) ?? [] |
| | | }; |
| | | }) ?? []; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | initTableData(); |
| | | }); |
| | | |
| | | const typeSelect = [ |
| | | { id: '742fdeb7-23b4-416b-ac66-cd4ec8b901b7', label: 'ç±»', value: 'class' }, |
| | | { id: '660c9c46-8fae-4bae-91a0-0335420019dc', label: '表达å¼', value: 'expression' }, |
| | | { id: '4b8135ab-6bc3-4a0f-80be-22f58bc6c5fd', label: 'å§æè¡¨è¾¾å¼', value: 'delegateExpression' } |
| | | ]; |
| | | const eventSelect = [ |
| | | { id: 'e6e0a51a-2d5d-4dc4-b847-b5c14f43a6ab', label: 'start', value: 'start' }, |
| | | { id: '6da97c1e-15fc-4445-8943-75d09f49778e', label: 'end', value: 'end' }, |
| | | { id: '6a2cbcec-e026-4f11-bef7-fff0b5c871e2', label: 'take', value: 'take' } |
| | | ]; |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .el-badge { |
| | | :deep(.el-badge__content) { |
| | | top: 10px; |
| | | } |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <vxe-toolbar> |
| | | <template #buttons> |
| | | <el-button icon="Plus" @click="insertRow">æ°å¢</el-button> |
| | | </template> |
| | | </vxe-toolbar> |
| | | <vxe-table |
| | | ref="tableRef" |
| | | :height="height" |
| | | border |
| | | show-overflow |
| | | keep-source |
| | | :data="tableData" |
| | | :edit-rules="tableRules" |
| | | :edit-config="{ trigger: 'click', mode: 'row', showStatus: true }" |
| | | > |
| | | <vxe-column type="seq" width="40"></vxe-column> |
| | | <vxe-column field="type" title="ç±»å" :edit-render="{}"> |
| | | <template #default="slotParams"> |
| | | <span>{{ typeSelect.find((e) => e.value === slotParams.row.type)?.label }}</span> |
| | | </template> |
| | | <template #edit="slotParams"> |
| | | <vxe-select v-model="slotParams.row.type"> |
| | | <vxe-option v-for="item in typeSelect" :key="item.id" :value="item.value" :label="item.label"></vxe-option> |
| | | </vxe-select> |
| | | </template> |
| | | </vxe-column> |
| | | <vxe-column field="name" title="åç§°" :edit-render="{}"> |
| | | <template #edit="slotParams"> |
| | | <vxe-input v-model="slotParams.row.name" type="text"></vxe-input> |
| | | </template> |
| | | </vxe-column> |
| | | <vxe-column field="value" title="å¼" :edit-render="{}"> |
| | | <template #edit="slotParams"> |
| | | <vxe-input v-model="slotParams.row.value" type="text"></vxe-input> |
| | | </template> |
| | | </vxe-column> |
| | | <vxe-column title="æä½" width="100" show-overflow align="center"> |
| | | <template #default="slotParams"> |
| | | <el-tooltip content="å é¤" placement="top"> |
| | | <el-button link type="danger" icon="Delete" @click="removeRow(slotParams.row)"></el-button> |
| | | </el-tooltip> |
| | | </template> |
| | | </vxe-column> |
| | | </vxe-table> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { VXETable, VxeTableInstance, VxeTablePropTypes } from 'vxe-table'; |
| | | import { ParamVO } from 'bpmnDesign'; |
| | | import useDialog from '@/hooks/useDialog'; |
| | | |
| | | interface PropType { |
| | | height?: string; |
| | | tableData?: ParamVO[]; |
| | | } |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | const props = withDefaults(defineProps<PropType>(), { |
| | | height: '200px', |
| | | tableData: () => [] |
| | | }); |
| | | |
| | | const tableRules = ref<VxeTablePropTypes.EditRules>({ |
| | | type: [{ required: true, message: 'è¯·éæ©', trigger: 'blur' }], |
| | | name: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }], |
| | | value: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }] |
| | | }); |
| | | |
| | | const { title, visible, openDialog, closeDialog } = useDialog({ |
| | | title: 'çå¬å¨åæ°' |
| | | }); |
| | | const typeSelect = [ |
| | | { id: '742fdeb7-23b4-416b-ac66-cd4ec8b901b7', label: 'å符串', value: 'stringValue' }, |
| | | { id: '660c9c46-8fae-4bae-91a0-0335420019dc', label: '表达å¼', value: 'expression' } |
| | | ]; |
| | | |
| | | const tableRef = ref<VxeTableInstance<ParamVO>>(); |
| | | |
| | | const getTableData = () => { |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | return $table.getTableData().fullData; |
| | | } |
| | | return []; |
| | | }; |
| | | |
| | | const insertRow = async () => { |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | const { row: newRow } = await $table.insertAt({}, -1); |
| | | // æå
¥ä¸æ¡æ°æ®å¹¶è§¦åæ ¡éª |
| | | await $table.validate(newRow); |
| | | } |
| | | }; |
| | | |
| | | const removeRow = async (row: ParamVO) => { |
| | | await proxy?.$modal.confirm('æ¨ç¡®å®è¦å é¤è¯¥æ°æ®?'); |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | await $table.remove(row); |
| | | } |
| | | }; |
| | | |
| | | const validate = async () => { |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | return await $table.validate(true); |
| | | } |
| | | }; |
| | | |
| | | defineExpose({ |
| | | closeDialog, |
| | | openDialog, |
| | | validate, |
| | | getTableData |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"></style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <vxe-toolbar> |
| | | <template #buttons> |
| | | <el-button type="primary" link size="small" @click="insertEvent">æ°å¢</el-button> |
| | | <el-button type="primary" link size="small" @click="removeSelectRowEvent">å é¤</el-button> |
| | | </template> |
| | | </vxe-toolbar> |
| | | <vxe-table |
| | | ref="tableRef" |
| | | size="mini" |
| | | height="100px" |
| | | border |
| | | show-overflow |
| | | keep-source |
| | | :data="tableData" |
| | | :menu-config="menuConfig" |
| | | @cell-dblclick="cellDBLClickEvent" |
| | | @menu-click="contextMenuClickEvent" |
| | | > |
| | | <vxe-column type="checkbox" width="40"></vxe-column> |
| | | <vxe-column type="seq" width="40"></vxe-column> |
| | | <vxe-column field="event" title="äºä»¶" min-width="100px"> |
| | | <template #default="slotParams"> |
| | | <span>{{ eventSelect.find((e) => e.value === slotParams.row.event)?.label }}</span> |
| | | </template> |
| | | </vxe-column> |
| | | <vxe-column field="type" title="ç±»å" min-width="100px"> |
| | | <template #default="slotParams"> |
| | | <span>{{ typeSelect.find((e) => e.value === slotParams.row.type)?.label }}</span> |
| | | </template> |
| | | </vxe-column> |
| | | <vxe-column field="className" title="Java ç±»å" min-width="100px"> </vxe-column> |
| | | </vxe-table> |
| | | |
| | | <el-dialog |
| | | v-model="formDialog.visible.value" |
| | | :title="formDialog.title.value" |
| | | width="600px" |
| | | :close-on-click-modal="false" |
| | | :close-on-press-escape="false" |
| | | :show-close="false" |
| | | append-to-body |
| | | > |
| | | <el-form ref="formRef" :model="formData" :rules="tableRules" label-width="90px"> |
| | | <el-form-item label="äºä»¶" prop="event"> |
| | | <template #label> |
| | | <span> |
| | | äºä»¶ |
| | | <el-tooltip placement="top"> |
| | | <el-icon><QuestionFilled /></el-icon> |
| | | <template #content> |
| | | createï¼å建ï¼ï¼å½ä»»å¡å·²ç»å建ï¼å¹¶ä¸ææä»»å¡åæ°é½å·²ç»è®¾ç½®æ¶è§¦åã<br /> |
| | | assignmentï¼ææ´¾ï¼ï¼å½ä»»å¡å·²ç»ææ´¾ç»æäººæ¶è§¦åã请注æï¼å½æµç¨æ§è¡å°è¾¾ç¨æ·ä»»å¡æ¶ï¼å¨è§¦åcreateäºä»¶ä¹åï¼ä¼é¦å
触åassignmentäºä»¶ã<br /> |
| | | completeï¼å®æï¼ï¼å½ä»»å¡å·²ç»å®æï¼ä»è¿è¡æ¶æ°æ®ä¸å é¤å触åã<br /> |
| | | deleteï¼å é¤ï¼ï¼å¨ä»»å¡å³å°è¢«å é¤å触åã请注æä»»å¡ç±completeTaskæ£å¸¸å®ææ¶ä¹ä¼è§¦åã |
| | | </template> |
| | | </el-tooltip> |
| | | </span> |
| | | </template> |
| | | <el-select v-model="formData.event"> |
| | | <el-option v-for="item in eventSelect" :key="item.id" :value="item.value" :label="item.label"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="ç±»å" prop="type"> |
| | | <el-select v-model="formData.type"> |
| | | <el-option v-for="item in typeSelect" :key="item.id" :value="item.value" :label="item.label"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="Java ç±»å" prop="className"> |
| | | <el-input v-model="formData.className" type="text"></el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | <el-tabs type="border-card"> |
| | | <el-tab-pane label="åæ°"> |
| | | <ListenerParam ref="listenerParamRef" :table-data="formData.params" /> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="formDialog.closeDialog">å æ¶</el-button> |
| | | <el-button type="primary" @click="submitEvent">ç¡® å®</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import ListenerParam from './ListenerParam.vue'; |
| | | import { VxeTableEvents, VxeTableInstance, VxeTablePropTypes } from 'vxe-table'; |
| | | import { TaskListenerVO } from 'bpmnDesign'; |
| | | import { ModdleElement } from 'bpmn'; |
| | | |
| | | import usePanel from '@/components/BpmnDesign/hooks/usePanel'; |
| | | import useDialog from '@/hooks/useDialog'; |
| | | import useModelerStore from '@/store/modules/modeler'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | interface PropType { |
| | | element: ModdleElement; |
| | | } |
| | | const props = withDefaults(defineProps<PropType>(), {}); |
| | | |
| | | const selectRow = ref<TaskListenerVO | null>(); |
| | | const formDialog = useDialog({ |
| | | title: selectRow.value ? 'ç¼è¾&ä¿å' : 'æ°å¢&ä¿å' |
| | | }); |
| | | const { showConfig, elementType, updateProperties } = usePanel({ |
| | | element: toRaw(props.element) |
| | | }); |
| | | const { getModdle } = useModelerStore(); |
| | | const moddle = getModdle(); |
| | | |
| | | const listenerParamRef = ref<InstanceType<typeof ListenerParam>>(); |
| | | const tableRef = ref<VxeTableInstance<TaskListenerVO>>(); |
| | | const formRef = ref<ElFormInstance>(); |
| | | |
| | | const initData: TaskListenerVO = { |
| | | event: '', |
| | | type: '', |
| | | className: '', |
| | | name: '', |
| | | params: [] |
| | | }; |
| | | const formData = ref<TaskListenerVO>({ ...initData }); |
| | | const currentIndex = ref(0); |
| | | const tableData = ref<TaskListenerVO[]>([]); |
| | | const tableRules = ref<VxeTablePropTypes.EditRules>({ |
| | | event: [{ required: true, message: 'è¯·éæ©', trigger: 'blur' }], |
| | | type: [{ required: true, message: 'è¯·éæ©', trigger: 'blur' }], |
| | | name: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }], |
| | | className: [{ required: true, message: '请è¾å
¥', trigger: 'blur' }] |
| | | }); |
| | | |
| | | const submitEvent = async () => { |
| | | const error = await listenerParamRef.value.validate(); |
| | | await formRef.value.validate((validate) => { |
| | | if (validate && !error) { |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | formData.value.params = listenerParamRef.value.getTableData(); |
| | | if (selectRow.value) { |
| | | Object.assign(selectRow.value, formData.value); |
| | | } else { |
| | | $table.insertAt({ ...formData.value }, -1); |
| | | } |
| | | updateElement(); |
| | | formDialog.closeDialog(); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const insertEvent = async () => { |
| | | Object.assign(formData.value, initData); |
| | | selectRow.value = null; |
| | | formDialog.openDialog(); |
| | | }; |
| | | |
| | | const editEvent = (row: TaskListenerVO) => { |
| | | Object.assign(formData.value, row); |
| | | selectRow.value = row; |
| | | formDialog.openDialog(); |
| | | }; |
| | | const removeEvent = async (row: TaskListenerVO) => { |
| | | await proxy?.$modal.confirm('æ¨ç¡®å®è¦å é¤è¯¥æ°æ®?'); |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | await $table.remove(row); |
| | | updateElement(); |
| | | } |
| | | }; |
| | | |
| | | const removeSelectRowEvent = async () => { |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | const selectCount = $table.getCheckboxRecords().length; |
| | | if (selectCount === 0) { |
| | | proxy?.$modal.msgWarning('è¯·éæ©è¡'); |
| | | } else { |
| | | await $table.removeCheckboxRow(); |
| | | updateElement(); |
| | | } |
| | | } |
| | | }; |
| | | const updateElement = () => { |
| | | const $table = tableRef.value; |
| | | const data = $table.getTableData().fullData; |
| | | if (data.length) { |
| | | let extensionElements = props.element.businessObject.get('extensionElements'); |
| | | if (!extensionElements) { |
| | | extensionElements = moddle.create('bpmn:ExtensionElements'); |
| | | } |
| | | // æ¸
餿§å¼ |
| | | extensionElements.values = extensionElements.values?.filter((item) => item.$type !== 'flowable:TaskListener') ?? []; |
| | | data.forEach((item) => { |
| | | const taskListener = moddle.create('flowable:TaskListener'); |
| | | taskListener['event'] = item.event; |
| | | taskListener[item.type] = item.className; |
| | | if (item.params && item.params.length) { |
| | | item.params.forEach((field) => { |
| | | const fieldElement = moddle.create('flowable:Field'); |
| | | fieldElement['name'] = field.name; |
| | | fieldElement[field.type] = field.value; |
| | | taskListener.get('fields').push(fieldElement); |
| | | }); |
| | | } |
| | | extensionElements.get('values').push(taskListener); |
| | | }); |
| | | updateProperties({ extensionElements: extensionElements }); |
| | | } else { |
| | | const extensionElements = props.element.businessObject[`extensionElements`]; |
| | | if (extensionElements) { |
| | | extensionElements.values = extensionElements.values?.filter((item) => item.$type !== 'flowable:TaskListener') ?? []; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const cellDBLClickEvent: VxeTableEvents.CellDblclick<TaskListenerVO> = ({ row }) => { |
| | | editEvent(row); |
| | | }; |
| | | |
| | | const menuConfig = reactive<VxeTablePropTypes.MenuConfig<TaskListenerVO>>({ |
| | | body: { |
| | | options: [ |
| | | [ |
| | | { code: 'edit', name: 'ç¼è¾', prefixIcon: 'vxe-icon-edit', disabled: false }, |
| | | { code: 'remove', name: 'å é¤', prefixIcon: 'vxe-icon-delete', disabled: false } |
| | | ] |
| | | ] |
| | | }, |
| | | visibleMethod({ options, column }) { |
| | | const isDisabled = !column; |
| | | options.forEach((list) => { |
| | | list.forEach((item) => { |
| | | item.disabled = isDisabled; |
| | | }); |
| | | }); |
| | | return true; |
| | | } |
| | | }); |
| | | const contextMenuClickEvent: VxeTableEvents.MenuClick<TaskListenerVO> = ({ menu, row, column }) => { |
| | | const $table = tableRef.value; |
| | | if ($table) { |
| | | switch (menu.code) { |
| | | case 'edit': |
| | | editEvent(row); |
| | | break; |
| | | case 'remove': |
| | | removeEvent(row); |
| | | break; |
| | | } |
| | | } |
| | | }; |
| | | const initTableData = () => { |
| | | tableData.value = |
| | | props.element.businessObject.extensionElements?.values |
| | | .filter((item) => item.$type === 'flowable:TaskListener') |
| | | .map((item) => { |
| | | let type; |
| | | if ('class' in item) type = 'class'; |
| | | if ('expression' in item) type = 'expression'; |
| | | if ('delegateExpression' in item) type = 'delegateExpression'; |
| | | return { |
| | | event: item.event, |
| | | type: type, |
| | | className: item[type], |
| | | params: |
| | | item.fields?.map((field) => { |
| | | let fieldType; |
| | | if ('stringValue' in field) fieldType = 'stringValue'; |
| | | if ('expression' in field) fieldType = 'expression'; |
| | | return { |
| | | name: field.name, |
| | | type: fieldType, |
| | | value: field[fieldType] |
| | | }; |
| | | }) ?? [] |
| | | }; |
| | | }) ?? []; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | initTableData(); |
| | | }); |
| | | |
| | | const typeSelect = [ |
| | | { id: '742fdeb7-23b4-416b-ac66-cd4ec8b901b7', label: 'ç±»', value: 'class' }, |
| | | { id: '660c9c46-8fae-4bae-91a0-0335420019dc', label: '表达å¼', value: 'expression' }, |
| | | { id: '4b8135ab-6bc3-4a0f-80be-22f58bc6c5fd', label: 'å§æè¡¨è¾¾å¼', value: 'delegateExpression' } |
| | | ]; |
| | | const eventSelect = [ |
| | | { id: 'e6e0a51a-2d5d-4dc4-b847-b5c14f43a6ab', label: 'å建', value: 'create' }, |
| | | { id: '6da97c1e-15fc-4445-8943-75d09f49778e', label: 'ææ´¾', value: 'assignment' }, |
| | | { id: '6a2cbcec-e026-4f11-bef7-fff0b5c871e2', label: '宿', value: 'complete' }, |
| | | { id: '68801972-85f1-482f-bd86-1fad015c26ed', label: 'å é¤', value: 'delete' } |
| | | ]; |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .el-badge { |
| | | :deep(.el-badge__content) { |
| | | top: 10px; |
| | | } |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-dialog v-model="visible" draggable title="审æ¹è®°å½" :width="props.width" :height="props.height" append-to-body |
| | | :close-on-click-modal="false"> |
| | | <div v-loading="loading"> |
| | | <div style="width: 100%;height: 300px;overflow: auto;position: relative;"> |
| | | <div v-for="(graphic, index) in graphicInfoVos" :key="index" :style="{ |
| | | position: 'absolute', |
| | | left: `${graphic.x}px`, |
| | | top: `${graphic.y}px`, |
| | | width: `${graphic.width}px`, |
| | | height: `${graphic.height}px`, |
| | | cursor: 'pointer', |
| | | zIndex: 99 |
| | | }" @mouseover="handleMouseOver(graphic)" @mouseleave="handleMouseLeave()"></div> |
| | | <!-- å¼¹åºç div å
ç´ --> |
| | | <div v-show="popupVisible" class="triangle" :style="{ |
| | | position: 'absolute', |
| | | left: `${graphicX}px`, |
| | | top: `${graphicY}px`, |
| | | backgroundColor: '#fff', |
| | | padding: '10px', |
| | | zIndex: 100 |
| | | }"> |
| | | <p>审æ¹äººå: {{ nodeInfo.nickName }}</p> |
| | | <p>èç¹ç¶æï¼{{ nodeInfo.status }}</p> |
| | | <p>å¼å§æ¶é´ï¼{{ nodeInfo.startTime }}</p> |
| | | <p>ç»ææ¶é´ï¼{{ nodeInfo.endTime }}</p> |
| | | <p>审æ¹èæ¶ï¼{{ nodeInfo.runDuration }}</p> |
| | | </div> |
| | | <el-image :src="src" /> |
| | | </div> |
| | | <div> |
| | | <el-table :data="historyList" style="width: 100%" border fit max-height="570"> |
| | | <el-table-column label="æµç¨å®¡æ¹åå²è®°å½" align="center"> |
| | | <el-table-column type="index" label="åºå·" align="center" width="50"></el-table-column> |
| | | <el-table-column prop="name" label="ä»»å¡åç§°" sortable align="center"></el-table-column> |
| | | <el-table-column prop="nickName" label="åç人" sortable align="center"></el-table-column> |
| | | <el-table-column label="ç¶æ" sortable align="center"> |
| | | <template #default="scope"> |
| | | <el-tag type="success">{{ scope.row.statusName }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="comment" label="å®¡æ¹æè§" sortable align="center"></el-table-column> |
| | | <el-table-column prop="attachmentList" label="éä»¶" sortable align="center"> |
| | | <template #default="scope"> |
| | | <el-popover placement="right" v-if="scope.row.attachmentList && scope.row.attachmentList.length > 0" :width="310" trigger="click"> |
| | | <template #reference> |
| | | <el-button style="margin-right: 16px">éä»¶</el-button> |
| | | </template> |
| | | <el-table border :data="scope.row.attachmentList"> |
| | | <el-table-column prop="name" width="202" :show-overflow-tooltip="true" label="éä»¶åç§°"></el-table-column> |
| | | <el-table-column prop="name" width="80" align="center" :show-overflow-tooltip="true" label="æä½"> |
| | | <template #default="tool"> |
| | | <el-button type="text" @click="handleDownload(tool.row.contentId)">ä¸è½½</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | </el-popover> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="startTime" label="å¼å§æ¶é´" sortable align="center"></el-table-column> |
| | | <el-table-column prop="endTime" label="ç»ææ¶é´" sortable align="center"></el-table-column> |
| | | <el-table-column prop="runDuration" label="è¿è¡æ¶é¿" sortable align="center"></el-table-column> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | </el-dialog> |
| | | </template> |
| | | <script lang="ts" setup> |
| | | import { getHistoryProcessImage, getHistoryRecord } from '@/api/workflow/processInstance'; |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | import { ref } from 'vue'; |
| | | const props = defineProps({ |
| | | width: { |
| | | type: String, |
| | | default: '70%' |
| | | }, |
| | | height: { |
| | | type: String, |
| | | default: '100%' |
| | | } |
| | | }); |
| | | const loading = ref(false); |
| | | const src = ref(''); |
| | | const visible = ref(false); |
| | | const historyList = ref<Array<any>>([]); |
| | | const deleteReason = ref<string>(''); |
| | | const graphicInfoVos = ref<Array<any>>([]); |
| | | const nodeListInfo = ref<Array<any>>([]); |
| | | const popupVisible = ref(false); |
| | | const nodeInfo = ref<any>({}); |
| | | const graphicX = ref<number | string>(0); |
| | | const graphicY = ref<number | string>(0); |
| | | //åå§åæ¥è¯¢å®¡æ¹è®°å½ |
| | | const init = async (processInstanceId: string) => { |
| | | visible.value = true; |
| | | loading.value = true; |
| | | historyList.value = []; |
| | | graphicInfoVos.value = []; |
| | | getHistoryProcessImage(processInstanceId).then((res) => { |
| | | src.value = 'data:image/png;base64,' + res.data |
| | | }); |
| | | getHistoryRecord(processInstanceId).then((response) => { |
| | | historyList.value = response.data.historyRecordList; |
| | | graphicInfoVos.value = response.data.graphicInfoVos; |
| | | nodeListInfo.value = response.data.nodeListInfo; |
| | | deleteReason.value = response.data.deleteReason; |
| | | loading.value = false; |
| | | }); |
| | | }; |
| | | //æ¬æµ®äºä»¶ |
| | | const handleMouseOver = async (graphic: any) => { |
| | | graphicX.value = graphic.x + graphic.width + 10; |
| | | graphicY.value = graphic.y - graphic.height + -10; |
| | | nodeInfo.value = {}; |
| | | if (nodeListInfo.value && nodeListInfo.value.length > 0) { |
| | | let info = nodeListInfo.value.find((e: any) => e.taskDefinitionKey == graphic.nodeId); |
| | | if (info) { |
| | | nodeInfo.value = { |
| | | nickName: info.nickName, |
| | | status: info.status, |
| | | startTime: info.startTime, |
| | | endTime: info.endTime, |
| | | runDuration: info.runDuration |
| | | }; |
| | | popupVisible.value = true; |
| | | } |
| | | } |
| | | }; |
| | | //å
³é |
| | | const handleMouseLeave = async () => { |
| | | popupVisible.value = false; |
| | | }; |
| | | |
| | | /** ä¸è½½æé®æä½ */ |
| | | const handleDownload = (ossId: string) => { |
| | | proxy?.$download.oss(ossId); |
| | | }; |
| | | /** |
| | | * 坹夿´é²åç»ä»¶æ¹æ³ |
| | | */ |
| | | defineExpose({ |
| | | init |
| | | }); |
| | | </script> |
| | | <style scoped> |
| | | .triangle { |
| | | box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); |
| | | border-radius: 6px; |
| | | } |
| | | |
| | | .triangle::after { |
| | | content: ' '; |
| | | position: absolute; |
| | | top: 8em; |
| | | right: 215px; |
| | | border: 15px solid; |
| | | border-color: transparent #fff transparent transparent; |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-dialog v-model="visible" draggable :title="title" :width="width" :height="height" append-to-body |
| | | :close-on-click-modal="false"> |
| | | <div class="p-2" v-if="multiInstance === 'add'"> |
| | | <el-row :gutter="20"> |
| | | <!-- é¨é¨æ --> |
| | | <el-col :lg="4" :xs="24" style=""> |
| | | <el-card shadow="hover"> |
| | | <el-input v-model="deptName" placeholder="请è¾å
¥é¨é¨åç§°" prefix-icon="Search" clearable /> |
| | | <el-tree class="mt-2" ref="deptTreeRef" node-key="id" :data="deptOptions" |
| | | :props="{ label: 'label', children: 'children' }" :expand-on-click-node="false" |
| | | :filter-node-method="filterNode" highlight-current default-expand-all |
| | | @node-click="handleNodeClick"></el-tree> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :lg="20" :xs="24"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" |
| | | :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div class="search" v-show="showSearch"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px"> |
| | | <el-form-item label="ç¨æ·åç§°" prop="userName"> |
| | | <el-input v-model="queryParams.userName" placeholder="请è¾å
¥ç¨æ·åç§°" clearable style="width: 240px" |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="ææºå·ç " prop="phonenumber"> |
| | | <el-input v-model="queryParams.phonenumber" placeholder="请è¾å
¥ææºå·ç " clearable style="width: 240px" |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleQuery" icon="Search">æç´¢</el-button> |
| | | <el-button @click="resetQuery" icon="Refresh">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </transition> |
| | | |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <el-row :gutter="10"> |
| | | <right-toolbar v-model:showSearch="showSearch" @queryTable="handleQuery" :search="true"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table v-loading="loading" :data="userList" ref="multipleTableRef" row-key="userId" |
| | | @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="50" align="center" /> |
| | | <el-table-column label="ç¨æ·ç¼å·" align="center" key="userId" prop="userId" /> |
| | | <el-table-column label="ç¨æ·åç§°" align="center" key="userName" prop="userName" :show-overflow-tooltip="true" /> |
| | | <el-table-column label="ç¨æ·æµç§°" align="center" key="nickName" prop="nickName" :show-overflow-tooltip="true" /> |
| | | <el-table-column label="ææºå·ç " align="center" key="phonenumber" prop="phonenumber" width="120" /> |
| | | <el-table-column label="å建æ¶é´" align="center" prop="createTime" width="160"> |
| | | <template #default="scope"> |
| | | <span>{{ scope.row.createTime }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" @pagination="handleQuery" /> |
| | | </el-card> |
| | | <el-card shadow="hover"> |
| | | <el-tag v-for="(user, index) in chooseUserList" :key="user.userId" style="margin:2px" closable |
| | | @close="handleCloseTag(user, index)">{{ user.userName }} |
| | | </el-tag> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | <div class="p-2" v-if="multiInstance === 'delete'"> |
| | | <el-table v-loading="loading" :data="taskList" @selection-change="handleTaskSelection"> |
| | | <el-table-column type="selection" width="55" /> |
| | | <el-table-column prop="name" label="ä»»å¡åç§°" /> |
| | | <el-table-column prop="assigneeName" label="åç人" /> |
| | | </el-table> |
| | | </div> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitFileForm">ç¡® å®</el-button> |
| | | <el-button @click="visible = false">å æ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup name="User" lang="ts"> |
| | | import { deptTreeSelect } from '@/api/system/user'; |
| | | import { getWorkflowAddMultiListByPage, getWorkflowDeleteMultiInstanceList, getUserListByIds } from '@/api/workflow/workflowUser'; |
| | | import { addMultiInstanceExecution, deleteMultiInstanceExecution } from '@/api/workflow/task'; |
| | | import { UserVO } from '@/api/system/user/types'; |
| | | import { DeptVO } from '@/api/system/dept/types'; |
| | | import { ComponentInternalInstance } from 'vue'; |
| | | import { ElTree, ElTable } from 'element-plus'; |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | const props = defineProps({ |
| | | // 宽 |
| | | width: { |
| | | type: String, |
| | | default: '70%' |
| | | }, |
| | | // é« |
| | | height: { |
| | | type: String, |
| | | default: '100%' |
| | | }, |
| | | // æ é¢ |
| | | title: { |
| | | type: String, |
| | | default: 'å ç¾äººå' |
| | | }, |
| | | //æ¯å¦å¤é |
| | | multiple: { |
| | | type: Boolean, |
| | | default: true |
| | | }, |
| | | //åæ¾ç¨æ·id |
| | | userIdList: { |
| | | type: Array, |
| | | default: [] |
| | | } |
| | | }); |
| | | const deptTreeRef = ref(ElTree); |
| | | const multipleTableRef = ref(ElTable); |
| | | |
| | | const userList = ref<UserVO[]>(); |
| | | const taskList = ref<Array<any>[]>(); |
| | | const loading = ref(true); |
| | | const showSearch = ref(true); |
| | | const selectionTask = ref<Array<any>[]>(); |
| | | const visible = ref(false); |
| | | const total = ref(0); |
| | | const deptName = ref(''); |
| | | const deptOptions = ref<DeptVO[]>([]); |
| | | const chooseUserList = ref(ref<UserVO[]>()); |
| | | const userIds = ref<Array<number | string>>([]); |
| | | //å ç¾æè
åç¾ |
| | | const multiInstance = ref(''); |
| | | const queryParams = ref<Record<string, any>>({ |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | userName: '', |
| | | nickName: '', |
| | | taskId: '' |
| | | }); |
| | | /** æ¥è¯¢ç¨æ·å表 */ |
| | | const getAddMultiInstanceList = async (taskId: string, userIdList: Array<number | string>) => { |
| | | deptOptions.value = []; |
| | | getTreeSelect(); |
| | | multiInstance.value = 'add'; |
| | | userIds.value = userIdList; |
| | | visible.value = true; |
| | | queryParams.value.taskId = taskId; |
| | | loading.value = true; |
| | | const res = await getWorkflowAddMultiListByPage(queryParams.value); |
| | | loading.value = false; |
| | | userList.value = res.rows; |
| | | total.value = res.total; |
| | | if (userList.value && userIds.value.length > 0) { |
| | | const data = await getUserListByIds(userIds.value); |
| | | if (data.data && data.data.length > 0) { |
| | | chooseUserList.value = data.data; |
| | | data.data.forEach((user: UserVO) => { |
| | | multipleTableRef.value!.toggleRowSelection( |
| | | userList.value.find((item) => { |
| | | return item.userId == user.userId; |
| | | }), |
| | | true |
| | | ); |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const getList = async () => { |
| | | loading.value = true; |
| | | const res = await getWorkflowAddMultiListByPage(queryParams.value); |
| | | loading.value = false; |
| | | userList.value = res.rows; |
| | | total.value = res.total; |
| | | if (userList.value && userIds.value.length > 0) { |
| | | const data = await getUserListByIds(userIds.value); |
| | | if (data.data && data.data.length > 0) { |
| | | chooseUserList.value = data.data; |
| | | data.data.forEach((user: UserVO) => { |
| | | multipleTableRef.value!.toggleRowSelection( |
| | | userList.value.find((item) => { |
| | | return item.userId == user.userId; |
| | | }), |
| | | true |
| | | ); |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const getDeleteMultiInstanceList = async (taskId: string) => { |
| | | deptOptions.value = []; |
| | | loading.value = true; |
| | | queryParams.value.taskId = taskId; |
| | | multiInstance.value = 'delete'; |
| | | visible.value = true; |
| | | const res = await getWorkflowDeleteMultiInstanceList(taskId); |
| | | taskList.value = res.data; |
| | | loading.value = false; |
| | | }; |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | getAddMultiInstanceList(queryParams.value.taskId, userIds.value); |
| | | }; |
| | | |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | queryParams.value.deptId = undefined; |
| | | queryParams.value.userName = undefined; |
| | | queryParams.value.nickName = undefined; |
| | | deptTreeRef.value.setCurrentKey(null); |
| | | handleQuery(); |
| | | }; |
| | | |
| | | /** éæ©æ¡æ° */ |
| | | const handleSelectionChange = (selection: UserVO[]) => { |
| | | if (props.multiple) { |
| | | chooseUserList.value = selection.filter((element, index, self) => { |
| | | return self.findIndex((x) => x.userId === element.userId) === index; |
| | | }); |
| | | selection.forEach((u) => { |
| | | if (chooseUserList.value && !chooseUserList.value.includes(u)) { |
| | | multipleTableRef.value!.toggleRowSelection(u, undefined); |
| | | } |
| | | }); |
| | | userIds.value = chooseUserList.value.map((item) => { |
| | | return item.userId; |
| | | }); |
| | | } else { |
| | | chooseUserList.value = selection; |
| | | if (selection.length > 1) { |
| | | let delRow = selection.shift(); |
| | | multipleTableRef.value!.toggleRowSelection(delRow, undefined); |
| | | } |
| | | if (selection.length === 0) { |
| | | chooseUserList.value = []; |
| | | } |
| | | } |
| | | }; |
| | | /** éæ©æ¡æ° */ |
| | | const handleTaskSelection = (selection: any) => { |
| | | selectionTask.value = selection; |
| | | }; |
| | | |
| | | /** æ¥è¯¢é¨é¨ä¸ææ ç»æ */ |
| | | const getTreeSelect = async () => { |
| | | const res = await deptTreeSelect(); |
| | | deptOptions.value = res.data; |
| | | }; |
| | | |
| | | /** éè¿æ¡ä»¶è¿æ»¤èç¹ */ |
| | | const filterNode = (value: string, data: any) => { |
| | | if (!value) return true; |
| | | return data.label.indexOf(value) !== -1; |
| | | }; |
| | | /** æ ¹æ®åç§°çéé¨é¨æ */ |
| | | watchEffect( |
| | | () => { |
| | | if (visible.value && deptOptions.value && deptOptions.value.length > 0) { |
| | | deptTreeRef.value.filter(deptName.value); |
| | | } |
| | | }, |
| | | { |
| | | flush: 'post' // watchEffectä¼å¨DOMæè½½æè
æ´æ°ä¹åå°±ä¼è§¦åï¼æ¤å±æ§æ§å¶å¨DOMå
ç´ æ´æ°åè¿è¡ |
| | | } |
| | | ); |
| | | /** èç¹åå»äºä»¶ */ |
| | | const handleNodeClick = (data: DeptVO) => { |
| | | queryParams.value.deptId = data.id; |
| | | getList(); |
| | | }; |
| | | //å é¤tag |
| | | const handleCloseTag = (user: UserVO, index: any) => { |
| | | if (multipleTableRef.value.selection && multipleTableRef.value.selection.length > 0) { |
| | | multipleTableRef.value.selection.forEach((u: UserVO, i: Number) => { |
| | | if (user.userId === u.userId) { |
| | | multipleTableRef.value.selection.splice(i, 1); |
| | | } |
| | | }); |
| | | } |
| | | if (chooseUserList.value && chooseUserList.value.length > 0) { |
| | | chooseUserList.value.splice(index, 1); |
| | | } |
| | | multipleTableRef.value.toggleRowSelection(user, undefined); |
| | | |
| | | if (userIds.value && userIds.value.length > 0) { |
| | | userIds.value.forEach((userId, i) => { |
| | | if (userId === user.userId) { |
| | | userIds.value.splice(i, 1); |
| | | } |
| | | }); |
| | | } |
| | | }; |
| | | const submitFileForm = async () => { |
| | | if (multiInstance.value === 'add') { |
| | | if (chooseUserList.value && chooseUserList.value.length > 0) { |
| | | loading.value = true; |
| | | let userIds = chooseUserList.value.map((item) => { |
| | | return item.userId; |
| | | }); |
| | | let nickNames = chooseUserList.value.map((item) => { |
| | | return item.nickName; |
| | | }); |
| | | let params = { |
| | | taskId: queryParams.value.taskId, |
| | | assignees: userIds, |
| | | assigneeNames: nickNames |
| | | }; |
| | | await addMultiInstanceExecution(params); |
| | | emits('submitCallback'); |
| | | loading.value = false; |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | visible.value = false; |
| | | } |
| | | } else { |
| | | if (selectionTask.value && selectionTask.value.length > 0) { |
| | | loading.value = true; |
| | | let taskIds = selectionTask.value.map((item: any) => { |
| | | return item.id; |
| | | }); |
| | | let executionIds = selectionTask.value.map((item: any) => { |
| | | return item.executionId; |
| | | }); |
| | | let assigneeIds = selectionTask.value.map((item: any) => { |
| | | return item.assignee; |
| | | }); |
| | | let assigneeNames = selectionTask.value.map((item: any) => { |
| | | return item.assigneeName; |
| | | }); |
| | | let params = { |
| | | taskId: queryParams.value.taskId, |
| | | taskIds: taskIds, |
| | | executionIds: executionIds, |
| | | assigneeIds: assigneeIds, |
| | | assigneeNames: assigneeNames |
| | | }; |
| | | await deleteMultiInstanceExecution(params); |
| | | emits('submitCallback'); |
| | | loading.value = false; |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | visible.value = false; |
| | | } |
| | | } |
| | | }; |
| | | //äºä»¶ |
| | | const emits = defineEmits(['submitCallback']); |
| | | |
| | | /** |
| | | * 坹夿´é²åç»ä»¶æ¹æ³ |
| | | */ |
| | | defineExpose({ |
| | | getAddMultiInstanceList, |
| | | getDeleteMultiInstanceList |
| | | }); |
| | | </script> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-dialog v-model="dialog.visible" :title="dialog.title" width="50%" draggable :before-close="cancel" :close-on-click-modal="false"> |
| | | <el-form v-loading="loading" :model="form" label-width="120px"> |
| | | <el-form-item label="æ¶æ¯æé"> |
| | | <el-checkbox-group v-model="form.messageType"> |
| | | <el-checkbox label="1" name="type" disabled>ç«å
ä¿¡</el-checkbox> |
| | | <el-checkbox label="2" name="type">é®ä»¶</el-checkbox> |
| | | <el-checkbox label="3" name="type">çä¿¡</el-checkbox> |
| | | </el-checkbox-group> |
| | | </el-form-item> |
| | | <el-form-item label="éä»¶"> |
| | | <fileUpload v-model="form.fileId" :fileType="['doc', 'xls', 'ppt', 'txt', 'pdf', 'xlsx', 'docx', 'zip']" :fileSize="'20'"/> |
| | | </el-form-item> |
| | | <el-form-item label="æé"> |
| | | <el-button type="primary" @click="openUserSelectCopy" icon="Plus" circle /> |
| | | <el-tag v-for="user in selectCopyUserList" :key="user.userId" closable style="margin: 2px" @close="handleCopyCloseTag(user)"> |
| | | {{ user.userName }} |
| | | </el-tag> |
| | | </el-form-item> |
| | | <el-form-item label="å®¡æ¹æè§" v-if="businessStatus === 'waiting'"> |
| | | <el-input v-model="form.message" type="textarea" resize="none" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button v-loading="buttonLoading" @click="cancel">åæ¶</el-button> |
| | | <el-button v-loading="buttonLoading" type="primary" @click="handleCompleteTask"> æäº¤ </el-button> |
| | | <el-button v-if="businessStatus === 'waiting'" v-loading="buttonLoading" type="danger" @click="handleBackProcess"> éå </el-button> |
| | | </span> |
| | | </template> |
| | | <UserSelect ref="userSelectCopyRef" :data="selectCopyUserIds" @confirm-call-back="userSelectCopyCallBack"></UserSelect> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import { ref } from 'vue'; |
| | | import { ComponentInternalInstance } from 'vue'; |
| | | import { ElForm } from 'element-plus'; |
| | | import { completeTask, backProcess, getBusinessStatus } from '@/api/workflow/task'; |
| | | import UserSelect from '@/components/UserSelect'; |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | import { UserVO } from '@/api/system/user/types'; |
| | | const userSelectCopyRef = ref<InstanceType<typeof UserSelect>>(); |
| | | |
| | | const props = defineProps({ |
| | | taskVariables: { |
| | | type: Object as () => Record<string, any>, |
| | | default: {} |
| | | } |
| | | }); |
| | | //é®ç½©å± |
| | | const loading = ref(true); |
| | | //æé® |
| | | const buttonLoading = ref(true); |
| | | //æµç¨ç¶æ |
| | | const businessStatus = ref<string>(''); |
| | | //ä»»å¡id |
| | | const taskId = ref<string>(''); |
| | | //æé人 |
| | | const selectCopyUserList = ref<UserVO[]>([]); |
| | | //æé人id |
| | | const selectCopyUserIds = ref<string>(''); |
| | | |
| | | |
| | | const dialog = reactive<DialogOption>({ |
| | | visible: false, |
| | | title: 'æç¤º' |
| | | }); |
| | | |
| | | const form = ref<Record<string, any>>({ |
| | | taskId: undefined, |
| | | message: undefined, |
| | | variables: {}, |
| | | messageType: ['1'], |
| | | wfCopyList: [] |
| | | }); |
| | | //æå¼å¼¹çª |
| | | const openDialog = (id?: string) => { |
| | | selectCopyUserIds.value = '' |
| | | selectCopyUserList.value = [] |
| | | form.value.fileId = undefined |
| | | taskId.value = id; |
| | | form.value.message = undefined; |
| | | dialog.visible = true; |
| | | loading.value = true; |
| | | buttonLoading.value = true; |
| | | nextTick(() => { |
| | | getBusinessStatus(taskId.value).then((response) => { |
| | | businessStatus.value = response.data; |
| | | loading.value = false; |
| | | buttonLoading.value = false; |
| | | }); |
| | | }); |
| | | }; |
| | | |
| | | onMounted(() => {}); |
| | | const emits = defineEmits(['submitCallback', 'cancelCallback']); |
| | | |
| | | /** åçæµç¨ */ |
| | | const handleCompleteTask = async () => { |
| | | form.value.taskId = taskId.value; |
| | | form.value.taskVariables = props.taskVariables; |
| | | if(selectCopyUserList && selectCopyUserList.value.length > 0){ |
| | | let wfCopyList = [] |
| | | selectCopyUserList.value.forEach( e=> { |
| | | let copyUser = { |
| | | userId: e.userId, |
| | | userName: e.nickName |
| | | } |
| | | wfCopyList.push(copyUser) |
| | | }) |
| | | form.value.wfCopyList = wfCopyList |
| | | } |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤æäº¤ï¼'); |
| | | loading.value = true; |
| | | buttonLoading.value = true; |
| | | await completeTask(form.value).finally(() => (loading.value = false)); |
| | | dialog.visible = false; |
| | | emits('submitCallback'); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | }; |
| | | |
| | | /** é©³åæµç¨ */ |
| | | const handleBackProcess = async () => { |
| | | form.value.taskId = taskId.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤é©³åå°ç³è¯·äººï¼'); |
| | | loading.value = true; |
| | | buttonLoading.value = true; |
| | | await backProcess(form.value).finally(() => (loading.value = false)); |
| | | dialog.visible = false; |
| | | emits('submitCallback'); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | }; |
| | | //åæ¶ |
| | | const cancel = async () => { |
| | | dialog.visible = false; |
| | | buttonLoading.value = false; |
| | | emits('cancelCallback'); |
| | | }; |
| | | //æå¼æé人å |
| | | const openUserSelectCopy = () => { |
| | | userSelectCopyRef.value.open(); |
| | | }; |
| | | //确认æé人å |
| | | const userSelectCopyCallBack = (data: UserVO[]) => { |
| | | if(data && data.length > 0){ |
| | | selectCopyUserList.value = data |
| | | selectCopyUserIds.value = selectCopyUserList.value.map((item) => item.userId).join(','); |
| | | } |
| | | } |
| | | //å 餿é人å |
| | | const handleCopyCloseTag = (user: UserVO) => { |
| | | const userId = user.userId; |
| | | // 使ç¨splitå é¤ç¨æ· |
| | | const index = selectCopyUserList.value.findIndex((item) => item.userId === userId); |
| | | selectCopyUserList.value.splice(index, 1); |
| | | selectCopyUserIds.value = selectCopyUserList.value.map((item) => item.userId).join(','); |
| | | }; |
| | | /** |
| | | * 坹夿´é²åç»ä»¶æ¹æ³ |
| | | */ |
| | | defineExpose({ |
| | | openDialog |
| | | }); |
| | | </script> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-dialog v-model="visible" draggable :title="title" :width="width" :height="height" append-to-body :close-on-click-modal="false"> |
| | | <div class="p-2"> |
| | | <el-row :gutter="20"> |
| | | <!-- é¨é¨æ --> |
| | | <el-col :lg="4" :xs="24" style=""> |
| | | <el-card shadow="hover"> |
| | | <el-input v-model="deptName" placeholder="请è¾å
¥é¨é¨åç§°" prefix-icon="Search" clearable /> |
| | | <el-tree |
| | | ref="deptTreeRef" |
| | | class="mt-2" |
| | | node-key="id" |
| | | :data="deptOptions" |
| | | :props="{ label: 'label', children: 'children' }" |
| | | :expand-on-click-node="false" |
| | | :filter-node-method="filterNode" |
| | | highlight-current |
| | | default-expand-all |
| | | @node-click="handleNodeClick" |
| | | ></el-tree> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :lg="20" :xs="24"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div v-show="showSearch" class="search"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px"> |
| | | <el-form-item label="ç¨æ·åç§°" prop="userName"> |
| | | <el-input v-model="queryParams.userName" placeholder="请è¾å
¥ç¨æ·åç§°" clearable style="width: 240px" @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç¨æ·æµç§°" prop="nickName"> |
| | | <el-input v-model="queryParams.nickName" placeholder="请è¾å
¥ç¨æ·æµç§°" clearable style="width: 240px" @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">æç´¢</el-button> |
| | | <el-button icon="Refresh" @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </transition> |
| | | |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <el-row :gutter="10"> |
| | | <right-toolbar v-model:showSearch="showSearch" :search="true" @query-table="getUserList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table ref="multipleTableRef" v-loading="loading" :data="userList" row-key="userId" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="50" align="center" :reserve-selection="true" /> |
| | | <el-table-column key="userId" label="ç¨æ·ç¼å·" align="center" prop="userId" /> |
| | | <el-table-column key="userName" label="ç¨æ·åç§°" align="center" prop="userName" :show-overflow-tooltip="true" /> |
| | | <el-table-column key="nickName" label="ç¨æ·æµç§°" align="center" prop="nickName" :show-overflow-tooltip="true" /> |
| | | <el-table-column key="phonenumber" label="ææºå·ç " align="center" prop="phonenumber" width="120" /> |
| | | <el-table-column label="å建æ¶é´" align="center" prop="createTime" width="160"> |
| | | <template #default="scope"> |
| | | <span>{{ scope.row.createTime }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination |
| | | v-show="total > 0" |
| | | v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" |
| | | :total="total" |
| | | @pagination="getUserList" |
| | | /> |
| | | </el-card> |
| | | <el-card shadow="hover"> |
| | | <el-tag v-for="(user, index) in chooseUserList" :key="user.userId" style="margin: 2px" closable @close="handleCloseTag(user, index)" |
| | | >{{ user.userName }} |
| | | </el-tag> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitFileForm">ç¡® å®</el-button> |
| | | <el-button @click="visible = false">å æ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup name="User" lang="ts"> |
| | | import { deptTreeSelect } from '@/api/system/user'; |
| | | import { getUserListByPage, getUserListByIds } from '@/api/workflow/workflowUser'; |
| | | import { UserVO } from '@/api/system/user/types'; |
| | | import { DeptVO } from '@/api/system/dept/types'; |
| | | import { ComponentInternalInstance } from 'vue'; |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | const props = defineProps({ |
| | | // 宽 |
| | | width: { |
| | | type: String, |
| | | default: '70%' |
| | | }, |
| | | // é« |
| | | height: { |
| | | type: String, |
| | | default: '100%' |
| | | }, |
| | | // æ é¢ |
| | | title: { |
| | | type: String, |
| | | default: 'ç¨æ·' |
| | | }, |
| | | //æ¯å¦å¤é |
| | | multiple: { |
| | | type: Boolean, |
| | | default: true |
| | | }, |
| | | //åæ¾ç¨æ·id |
| | | userIdList: { |
| | | type: Array, |
| | | default: () => [] |
| | | } |
| | | }); |
| | | const deptTreeRef = ref<ElTreeInstance>(); |
| | | const multipleTableRef = ref<ElTableInstance>(); |
| | | |
| | | const userList = ref<UserVO[]>(); |
| | | const loading = ref(true); |
| | | const showSearch = ref(true); |
| | | const visible = ref(false); |
| | | const total = ref(0); |
| | | const deptName = ref(''); |
| | | const deptOptions = ref<DeptVO[]>([]); |
| | | const chooseUserList = ref(ref<UserVO[]>()); |
| | | const userIds = ref<Array<number | string>>([]); |
| | | //æ¥è¯¢åæ° |
| | | const queryParams = ref<Record<string, any>>({ |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | userName: undefined, |
| | | nickName: undefined, |
| | | deptId: undefined |
| | | }); |
| | | /** æ¥è¯¢ç¨æ·å表 */ |
| | | const getUserList = async (userIdList: Array<number | string>) => { |
| | | deptOptions.value = []; |
| | | getTreeSelect(); |
| | | userIds.value = userIdList; |
| | | visible.value = true; |
| | | loading.value = true; |
| | | const res = await getUserListByPage(queryParams.value); |
| | | loading.value = false; |
| | | userList.value = res.rows; |
| | | total.value = res.total; |
| | | if (userList.value && userIds.value.length > 0) { |
| | | const data = await getUserListByIds(userIds.value); |
| | | if (data.data && data.data.length > 0) { |
| | | chooseUserList.value = data.data; |
| | | data.data.forEach((user: UserVO) => { |
| | | multipleTableRef.value!.toggleRowSelection( |
| | | userList.value.find((item) => { |
| | | return item.userId == user.userId; |
| | | }), |
| | | true |
| | | ); |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const getList = async () => { |
| | | loading.value = true; |
| | | const res = await getUserListByPage(queryParams.value); |
| | | loading.value = false; |
| | | userList.value = res.rows; |
| | | total.value = res.total; |
| | | |
| | | if (userList.value && userIds.value.length > 0) { |
| | | const data = await getUserListByIds(userIds.value); |
| | | if (data.data && data.data.length > 0) { |
| | | chooseUserList.value = data.data; |
| | | data.data.forEach((user: UserVO) => { |
| | | multipleTableRef.value!.toggleRowSelection( |
| | | userList.value.find((item) => { |
| | | return item.userId == user.userId; |
| | | }), |
| | | true |
| | | ); |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | getUserList(userIds.value); |
| | | }; |
| | | |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | queryParams.value.deptId = undefined; |
| | | queryParams.value.userName = undefined; |
| | | queryParams.value.nickName = undefined; |
| | | deptTreeRef.value.setCurrentKey(null); |
| | | handleQuery(); |
| | | }; |
| | | |
| | | /** éæ©æ¡æ° */ |
| | | const handleSelectionChange = (selection: UserVO[]) => { |
| | | console.log(selection); |
| | | if (props.multiple) { |
| | | chooseUserList.value = selection.filter((element, index, self) => { |
| | | return self.findIndex((x) => x.userId === element.userId) === index; |
| | | }); |
| | | selection.forEach((u) => { |
| | | if (chooseUserList.value && !chooseUserList.value.includes(u)) { |
| | | multipleTableRef.value!.toggleRowSelection(u, undefined); |
| | | } |
| | | }); |
| | | userIds.value = chooseUserList.value.map((item) => { |
| | | return item.userId; |
| | | }); |
| | | } else { |
| | | chooseUserList.value = selection; |
| | | if (selection.length > 1) { |
| | | let delRow = selection.shift(); |
| | | multipleTableRef.value!.toggleRowSelection(delRow, undefined); |
| | | } |
| | | if (selection.length === 0) { |
| | | chooseUserList.value = []; |
| | | } |
| | | } |
| | | }; |
| | | /** æ¥è¯¢é¨é¨ä¸ææ ç»æ */ |
| | | const getTreeSelect = async () => { |
| | | const res = await deptTreeSelect(); |
| | | deptOptions.value = res.data; |
| | | }; |
| | | |
| | | /** éè¿æ¡ä»¶è¿æ»¤èç¹ */ |
| | | const filterNode = (value: string, data: any) => { |
| | | if (!value) return true; |
| | | return data.label.indexOf(value) !== -1; |
| | | }; |
| | | /** æ ¹æ®åç§°çéé¨é¨æ */ |
| | | watchEffect( |
| | | () => { |
| | | if (visible.value && deptOptions.value && deptOptions.value.length > 0) { |
| | | deptTreeRef.value.filter(deptName.value); |
| | | } |
| | | }, |
| | | { |
| | | flush: 'post' // watchEffectä¼å¨DOMæè½½æè
æ´æ°ä¹åå°±ä¼è§¦åï¼æ¤å±æ§æ§å¶å¨DOMå
ç´ æ´æ°åè¿è¡ |
| | | } |
| | | ); |
| | | /** èç¹åå»äºä»¶ */ |
| | | const handleNodeClick = (data: DeptVO) => { |
| | | queryParams.value.deptId = data.id; |
| | | getList(); |
| | | }; |
| | | //å é¤tag |
| | | const handleCloseTag = (user: UserVO, index: any) => { |
| | | if (multipleTableRef.value.selection && multipleTableRef.value.selection.length > 0) { |
| | | multipleTableRef.value.selection.forEach((u: UserVO, i: number) => { |
| | | if (user.userId === u.userId) { |
| | | multipleTableRef.value.selection.splice(i, 1); |
| | | } |
| | | }); |
| | | } |
| | | if (chooseUserList.value && chooseUserList.value.length > 0) { |
| | | chooseUserList.value.splice(index, 1); |
| | | } |
| | | multipleTableRef.value.toggleRowSelection(user, undefined); |
| | | |
| | | if (userIds.value && userIds.value.length > 0) { |
| | | userIds.value.forEach((userId, i) => { |
| | | if (userId === user.userId) { |
| | | userIds.value.splice(i, 1); |
| | | } |
| | | }); |
| | | } |
| | | }; |
| | | const submitFileForm = async () => { |
| | | loading.value = true; |
| | | emits('submitCallback', chooseUserList); |
| | | }; |
| | | const close = async () => { |
| | | visible.value = false; |
| | | loading.value = false; |
| | | emits('close'); |
| | | }; |
| | | //äºä»¶ |
| | | const emits = defineEmits(['submitCallback', 'close']); |
| | | |
| | | /** |
| | | * 坹夿´é²åç»ä»¶æ¹æ³ |
| | | */ |
| | | defineExpose({ |
| | | getUserList, |
| | | close |
| | | }); |
| | | </script> |
| | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
| | | </script> |
| | |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped></style> |
| | | <style lang="scss" scoped></style> |
| | |
| | | * v-copyText å¤å¶ææ¬å
容 |
| | | * Copyright (c) 2022 ruoyi |
| | | */ |
| | | import { DirectiveBinding } from 'vue'; |
| | | |
| | | export default { |
| | | beforeMount(el: any, { value, arg }: any) { |
| | | beforeMount(el: any, { value, arg }: DirectiveBinding) { |
| | | if (arg === 'callback') { |
| | | el.$copyCallback = value; |
| | | } else { |
¶Ô±ÈÐÂÎļþ |
| | |
| | | export enum AllocationTypeEnum { |
| | | USER = 'user', |
| | | CANDIDATE = 'candidate', |
| | | YOURSELF = 'yourself', |
| | | SPECIFY = 'specify' |
| | | } |
| | | |
| | | export enum SpecifyDescEnum { |
| | | SPECIFY_MULTIPLE = 'specifyMultiple', |
| | | SPECIFY_SINGLE = 'specifySingle' |
| | | } |
| | | |
| | | export enum MultiInstanceTypeEnum { |
| | | SERIAL = 'serial', |
| | | PARALLEL = 'parallel', |
| | | NONE = 'none' |
| | | } |
| | |
| | | openDialog, |
| | | closeDialog |
| | | }; |
| | | }; |
| | | }; |
| | |
| | | // 注åæä»¶ |
| | | import plugins from './plugins/index'; // plugins |
| | | |
| | | // é«äº®ç»ä»¶ |
| | | // import 'highlight.js/styles/a11y-light.css'; |
| | | import 'highlight.js/styles/atom-one-dark.css'; |
| | | import 'highlight.js/lib/common'; |
| | | import HighLight from '@highlightjs/vue-plugin'; |
| | | |
| | | // svg徿 |
| | | import 'virtual:svg-icons-register'; |
| | | import ElementIcons from '@/plugins/svgicon'; |
| | |
| | | |
| | | const app = createApp(App); |
| | | |
| | | app.use(HighLight); |
| | | app.use(ElementIcons); |
| | | app.use(router); |
| | | app.use(store); |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { Modeler, Modeling, Canvas, ElementRegistry, Moddle, BpmnFactory } from 'bpmn'; |
| | | |
| | | type ModelerStore = { |
| | | modeler: Modeler | undefined; |
| | | moddle: Moddle | undefined; |
| | | modeling: Modeling | undefined; |
| | | canvas: Canvas | undefined; |
| | | elementRegistry: ElementRegistry | undefined; |
| | | bpmnFactory: BpmnFactory | undefined; |
| | | // æµç¨å®ä¹æ ¹èç¹ä¿¡æ¯ |
| | | procDefId: string | undefined; |
| | | procDefName: string | undefined; |
| | | }; |
| | | |
| | | const defaultState: ModelerStore = { |
| | | modeler: undefined, |
| | | moddle: undefined, |
| | | modeling: undefined, |
| | | canvas: undefined, |
| | | elementRegistry: undefined, |
| | | bpmnFactory: undefined, |
| | | procDefId: undefined, |
| | | procDefName: undefined |
| | | }; |
| | | export const useModelerStore = defineStore('modeler', () => { |
| | | let modeler = defaultState.modeler; |
| | | let moddle = defaultState.moddle; |
| | | let modeling = defaultState.modeling; |
| | | let canvas = defaultState.canvas; |
| | | let elementRegistry = defaultState.elementRegistry; |
| | | let bpmnFactory = defaultState.bpmnFactory; |
| | | const procDefId = ref(defaultState.procDefId); |
| | | const procDefName = ref(defaultState.procDefName); |
| | | |
| | | const getModeler = () => modeler; |
| | | const getModdle = () => moddle; |
| | | const getModeling = (): Modeling | undefined => modeling; |
| | | const getCanvas = (): Canvas | undefined => canvas; |
| | | const getElRegistry = (): ElementRegistry | undefined => elementRegistry; |
| | | const getBpmnFactory = (): BpmnFactory | undefined => bpmnFactory; |
| | | const getProcDefId = (): string | undefined => procDefId.value; |
| | | const getProcDefName = (): string | undefined => procDefName.value; |
| | | |
| | | // è®¾ç½®æ ¹èç¹ |
| | | const setModeler = (modelers: Modeler | undefined) => { |
| | | if (modelers) { |
| | | modeler = modelers; |
| | | modeling = modelers.get<Modeling>('modeling'); |
| | | moddle = modelers.get<Moddle>('moddle'); |
| | | canvas = modelers.get<Canvas>('canvas'); |
| | | bpmnFactory = modelers.get<BpmnFactory>('bpmnFactory'); |
| | | elementRegistry = modelers.get<ElementRegistry>('elementRegistry'); |
| | | } else { |
| | | modeling = moddle = canvas = elementRegistry = bpmnFactory = undefined; |
| | | } |
| | | }; |
| | | // 设置æµç¨å®ä¹æ ¹èç¹ä¿¡æ¯ |
| | | const setProcDef = (modeler: Modeler | undefined) => { |
| | | procDefId.value = modeler.get<Canvas>('canvas').getRootElement().businessObject.get('id'); |
| | | procDefName.value = modeler.get<Canvas>('canvas').getRootElement().businessObject.get('name'); |
| | | }; |
| | | |
| | | return { |
| | | getModeler, |
| | | getModdle, |
| | | getModeling, |
| | | getCanvas, |
| | | getElRegistry, |
| | | getBpmnFactory, |
| | | getProcDefId, |
| | | getProcDefName, |
| | | setModeler, |
| | | setProcDef |
| | | }; |
| | | }); |
| | | export default useModelerStore; |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { MessageApiInjection } from 'naive-ui/lib/message/src/MessageProvider'; |
| | | |
| | | declare global { |
| | | interface Window { |
| | | bpmnInstances: any; |
| | | __messageBox: MessageApiInjection; |
| | | URL: any; |
| | | } |
| | | } |
| | | |
| | | declare interface Window { |
| | | bpmnInstances: any; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | declare module 'bpmn' { |
| | | import type modeler from 'bpmn-js/lib/Modeler'; |
| | | import type modeling from 'bpmn-js/lib/features/modeling/Modeling'; |
| | | import type canvas from 'diagram-js/lib/core/Canvas'; |
| | | import type elementRegistry from 'diagram-js/lib/core/ElementRegistry'; |
| | | import type bpmnFactory from 'bpmn-js/lib/features/modeling/BpmnFactory'; |
| | | |
| | | export type Modeler = modeler; |
| | | export type Modeling = modeling; |
| | | export type Canvas = canvas; |
| | | export type ElementRegistry = elementRegistry; |
| | | export type Moddle = import('moddle').Moddle; |
| | | export type ModdleElement = import('moddle').ModdleElement; |
| | | export type BpmnFactory = bpmnFactory; |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | declare module 'moddle' { |
| | | import type { Element as element } from 'bpmn-js/lib/model/Types'; |
| | | |
| | | export type Element = { |
| | | get<T>(name: string): T; |
| | | |
| | | set(name: string, value: any): void; |
| | | } & element; |
| | | |
| | | export interface ModdleElement extends Element { |
| | | $model: Moddle; |
| | | readonly $type: string; |
| | | $attrs: object | {}; |
| | | $parent: any; |
| | | businessObject: ModdleElement; |
| | | type: string; |
| | | |
| | | [field: string]: any; |
| | | |
| | | hasType(element: ModdleElement, type?: string): boolean; |
| | | } |
| | | |
| | | export interface Package { |
| | | name: string; |
| | | prefix: string; |
| | | } |
| | | |
| | | export interface Moddle { |
| | | typeCache: Record<string, ModdleElement>; |
| | | |
| | | getPackage: typeof Registry.prototype.getPackage; |
| | | |
| | | getPackages: typeof Registry.prototype.getPackages; |
| | | |
| | | create(type: string, attrs?: any): ModdleElement; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | declare module 'bpmnDesign' { |
| | | import { AllocationTypeEnum, SpecifyDescEnum, MultiInstanceTypeEnum } from '@/enums/bpmn/IndexEnums'; |
| | | |
| | | export interface ParamVO { |
| | | type: string; |
| | | name: string; |
| | | value: string; |
| | | } |
| | | |
| | | export interface TaskListenerVO { |
| | | event: string; |
| | | type: string; |
| | | name: string; |
| | | className: string; |
| | | params: ParamVO[]; |
| | | } |
| | | |
| | | export interface ExecutionListenerVO { |
| | | event: string; |
| | | type: string; |
| | | className: string; |
| | | params: ParamVO[]; |
| | | } |
| | | |
| | | interface BasePanel { |
| | | id: string; |
| | | name: string; |
| | | } |
| | | export interface ProcessPanel extends BasePanel {} |
| | | |
| | | export interface TaskPanel extends BasePanel { |
| | | allocationType: AllocationTypeEnum; |
| | | specifyDesc: SpecifyDescEnum; |
| | | multiInstanceType: MultiInstanceTypeEnum; |
| | | async?: boolean; |
| | | priority?: number; |
| | | skipExpression?: string; |
| | | isForCompensation?: boolean; |
| | | triggerServiceTask?: boolean; |
| | | autoStoreVariables?: boolean; |
| | | ruleVariablesInput?: string; |
| | | excludeTaskListener?: boolean; |
| | | exclude?: boolean; |
| | | class?: string; |
| | | dueDate?: string; |
| | | fixedAssignee?: string; |
| | | |
| | | candidateUsers?: string; |
| | | assignee?: string; |
| | | candidateGroups?: string; |
| | | collection?: string; |
| | | elementVariable?: string; |
| | | completionCondition?: string; |
| | | isSequential?: boolean; |
| | | |
| | | loopCharacteristics?: { |
| | | collection: string; |
| | | elementVariable: string; |
| | | isSequential: boolean; |
| | | completionCondition: { |
| | | body: string; |
| | | }; |
| | | }; |
| | | } |
| | | |
| | | export interface StartEndPanel extends BasePanel {} |
| | | export interface GatewayPanel extends BasePanel {} |
| | | export interface SequenceFlowPanel extends BasePanel { |
| | | conditionExpression: { |
| | | body: string; |
| | | }; |
| | | conditionExpressionValue: string; |
| | | skipExpression: string; |
| | | } |
| | | } |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div v-show="showSearch" class="search"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px"> |
| | | <el-form-item label="åç±»åç§°" prop="categoryName"> |
| | | <el-input v-model="queryParams.categoryName" placeholder="请è¾å
¥åç±»åç§°" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="åç±»ç¼ç " prop="categoryCode"> |
| | | <el-input v-model="queryParams.categoryCode" placeholder="请è¾å
¥åç±»ç¼ç " clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">æç´¢</el-button> |
| | | <el-button icon="Refresh" @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </transition> |
| | | |
| | | <el-card shadow="never"> |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button v-hasPermi="['workflow:category:add']" type="primary" plain icon="Plus" @click="handleAdd()">æ°å¢</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">å±å¼/æå </el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | <el-table |
| | | ref="categoryTableRef" |
| | | v-loading="loading" |
| | | :data="categoryList" |
| | | row-key="id" |
| | | :default-expand-all="isExpandAll" |
| | | :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" |
| | | > |
| | | <el-table-column label="åç±»åç§°" prop="categoryName" /> |
| | | <el-table-column label="åç±»ç¼ç " align="center" prop="categoryCode" /> |
| | | <el-table-column label="æåº" align="center" prop="sortNum" /> |
| | | <el-table-column label="æä½" align="center" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-tooltip content="ä¿®æ¹" placement="top"> |
| | | <el-button v-hasPermi="['workflow:category:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" /> |
| | | </el-tooltip> |
| | | <el-tooltip content="æ°å¢" placement="top"> |
| | | <el-button v-hasPermi="['workflow:category:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" /> |
| | | </el-tooltip> |
| | | <el-tooltip content="å é¤" placement="top"> |
| | | <el-button v-hasPermi="['workflow:category:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)" /> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-card> |
| | | <!-- æ·»å æä¿®æ¹æµç¨åç±»å¯¹è¯æ¡ --> |
| | | <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body> |
| | | <el-form ref="categoryFormRef" v-loading="loading" :model="form" :rules="rules" label-width="80px"> |
| | | <el-form-item label="ç¶çº§åç±»" prop="parentId"> |
| | | <el-tree-select |
| | | v-model="form.parentId" |
| | | :data="categoryOptions" |
| | | :props="{ value: 'id', label: 'categoryName', children: 'children' }" |
| | | value-key="id" |
| | | placeholder="è¯·éæ©ç¶çº§id" |
| | | check-strictly |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="åç±»åç§°" prop="categoryName"> |
| | | <el-input v-model="form.categoryName" placeholder="请è¾å
¥åç±»åç§°" /> |
| | | </el-form-item> |
| | | <el-form-item label="åç±»ç¼ç " prop="categoryCode"> |
| | | <el-input v-model="form.categoryCode" placeholder="请è¾å
¥åç±»ç¼ç " /> |
| | | </el-form-item> |
| | | <el-form-item label="æåº" prop="sortNum"> |
| | | <el-input-number v-model="form.sortNum" placeholder="请è¾å
¥æåº" controls-position="right" :min="0" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button :loading="buttonLoading" type="primary" @click="submitForm">ç¡® å®</el-button> |
| | | <el-button @click="cancel">å æ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup name="Category" lang="ts"> |
| | | import { listCategory, getCategory, delCategory, addCategory, updateCategory } from '@/api/workflow/category'; |
| | | import { CategoryVO, CategoryQuery, CategoryForm } from '@/api/workflow/category/types'; |
| | | |
| | | type CategoryOption = { |
| | | id: number; |
| | | categoryName: string; |
| | | children?: CategoryOption[]; |
| | | }; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | const categoryList = ref<CategoryVO[]>([]); |
| | | const categoryOptions = ref<CategoryOption[]>([]); |
| | | const buttonLoading = ref(false); |
| | | const showSearch = ref(true); |
| | | const isExpandAll = ref(true); |
| | | const loading = ref(false); |
| | | |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | | const categoryFormRef = ref<ElFormInstance>(); |
| | | const categoryTableRef = ref<ElTableInstance>(); |
| | | |
| | | const dialog = reactive<DialogOption>({ |
| | | visible: false, |
| | | title: '' |
| | | }); |
| | | |
| | | const initFormData: CategoryForm = { |
| | | id: undefined, |
| | | categoryName: undefined, |
| | | categoryCode: undefined, |
| | | parentId: undefined, |
| | | sortNum: 0 |
| | | }; |
| | | |
| | | const data = reactive<PageData<CategoryForm, CategoryQuery>>({ |
| | | form: { ...initFormData }, |
| | | queryParams: { |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | categoryName: undefined, |
| | | categoryCode: undefined |
| | | }, |
| | | rules: { |
| | | id: [{ required: true, message: '主é®ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | categoryName: [{ required: true, message: 'åç±»åç§°ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | categoryCode: [{ required: true, message: 'åç±»ç¼ç ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | parentId: [{ required: true, message: 'ç¶çº§idä¸è½ä¸ºç©º', trigger: 'blur' }] |
| | | } |
| | | }); |
| | | |
| | | const { queryParams, form, rules } = toRefs(data); |
| | | |
| | | /** æ¥è¯¢æµç¨åç±»å表 */ |
| | | const getList = async () => { |
| | | loading.value = true; |
| | | const res = await listCategory(queryParams.value); |
| | | const data = proxy?.handleTree<CategoryVO>(res.data, 'id', 'parentId'); |
| | | if (data) { |
| | | categoryList.value = data; |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | |
| | | /** æ¥è¯¢æµç¨åç±»ä¸ææ ç»æ */ |
| | | const getTreeselect = async () => { |
| | | const res = await listCategory(); |
| | | categoryOptions.value = []; |
| | | const data: CategoryOption = { id: 0, categoryName: '顶级èç¹', children: [] }; |
| | | data.children = proxy?.handleTree<CategoryOption>(res.data, 'id', 'parentId'); |
| | | categoryOptions.value.push(data); |
| | | }; |
| | | |
| | | // åæ¶æé® |
| | | const cancel = () => { |
| | | reset(); |
| | | dialog.visible = false; |
| | | }; |
| | | |
| | | // 表åéç½® |
| | | const reset = () => { |
| | | form.value = { ...initFormData }; |
| | | categoryFormRef.value?.resetFields(); |
| | | }; |
| | | |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | getList(); |
| | | }; |
| | | |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | handleQuery(); |
| | | }; |
| | | |
| | | /** æ°å¢æé®æä½ */ |
| | | const handleAdd = (row?: CategoryVO) => { |
| | | dialog.visible = true; |
| | | dialog.title = 'æ·»å æµç¨åç±»'; |
| | | nextTick(() => { |
| | | reset(); |
| | | getTreeselect(); |
| | | if (row != null && row.id) { |
| | | form.value.parentId = row.id; |
| | | } else { |
| | | form.value.parentId = 0; |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | /** å±å¼/æå æä½ */ |
| | | const handleToggleExpandAll = () => { |
| | | isExpandAll.value = !isExpandAll.value; |
| | | toggleExpandAll(categoryList.value, isExpandAll.value); |
| | | }; |
| | | |
| | | /** å±å¼/æå æä½ */ |
| | | const toggleExpandAll = (data: CategoryVO[], status: boolean) => { |
| | | data.forEach((item) => { |
| | | categoryTableRef.value?.toggleRowExpansion(item, status); |
| | | if (item.children && item.children.length > 0) toggleExpandAll(item.children, status); |
| | | }); |
| | | }; |
| | | |
| | | /** ä¿®æ¹æé®æä½ */ |
| | | const handleUpdate = (row: CategoryVO) => { |
| | | loading.value = true; |
| | | dialog.visible = true; |
| | | dialog.title = 'ä¿®æ¹æµç¨åç±»'; |
| | | nextTick(async () => { |
| | | reset(); |
| | | await getTreeselect(); |
| | | if (row != null) { |
| | | form.value.parentId = row.id; |
| | | } |
| | | const res = await getCategory(row.id); |
| | | loading.value = false; |
| | | Object.assign(form.value, res.data); |
| | | }); |
| | | }; |
| | | |
| | | /** æäº¤æé® */ |
| | | const submitForm = () => { |
| | | categoryFormRef.value.validate(async (valid: boolean) => { |
| | | if (valid) { |
| | | buttonLoading.value = true; |
| | | if (form.value.id) { |
| | | await updateCategory(form.value).finally(() => (buttonLoading.value = false)); |
| | | } else { |
| | | await addCategory(form.value).finally(() => (buttonLoading.value = false)); |
| | | } |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | dialog.visible = false; |
| | | await getList(); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row: CategoryVO) => { |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å 餿µç¨åç±»ç¼å·ä¸º"' + row.id + '"çæ°æ®é¡¹ï¼'); |
| | | loading.value = true; |
| | | await delCategory(row.id).finally(() => (loading.value = false)); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div v-show="showSearch" class="search"> |
| | | <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px"> |
| | | <el-form-item label="请å天æ°" prop="startLeaveDays"> |
| | | <el-input v-model="queryParams.startLeaveDays" placeholder="请è¾å
¥è¯·å天æ°" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item prop="endLeaveDays"> è³ </el-form-item> |
| | | <el-form-item prop="endLeaveDays"> |
| | | <el-input v-model="queryParams.endLeaveDays" placeholder="请è¾å
¥è¯·å天æ°" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">æç´¢</el-button> |
| | | <el-button icon="Refresh" @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </transition> |
| | | |
| | | <el-card shadow="never"> |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button v-hasPermi="['demo:leave:add']" type="primary" plain icon="Plus" @click="handleAdd">æ°å¢</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button v-hasPermi="['demo:leave:export']" type="warning" plain icon="Download" @click="handleExport">导åº</el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table v-loading="loading" :data="leaveList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column v-if="false" label="主é®" align="center" prop="id" /> |
| | | <el-table-column label="请åç±»å" align="center"> |
| | | <template #default="scope"> |
| | | <el-tag>{{ options.find((e) => e.value === scope.row.leaveType)?.label }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å¼å§æ¶é´" align="center" prop="startDate"> |
| | | <template #default="scope"> |
| | | <span>{{ parseTime(scope.row.startDate, '{y}-{m}-{d}') }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ç»ææ¶é´" align="center" prop="endDate"> |
| | | <template #default="scope"> |
| | | <span>{{ parseTime(scope.row.endDate, '{y}-{m}-{d}') }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="请å天æ°" align="center" prop="leaveDays" /> |
| | | <el-table-column label="请ååå " align="center" prop="remark" /> |
| | | <el-table-column align="center" prop="businessStatusName" label="æµç¨ç¶æ" min-width="70"> |
| | | <template #default="scope"> |
| | | <el-tag type="success">{{ scope.row.processInstanceVo.businessStatusName }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" align="center" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-tooltip |
| | | v-if=" |
| | | scope.row.processInstanceVo.businessStatus === 'draft' || |
| | | scope.row.processInstanceVo.businessStatus === 'cancel' || |
| | | scope.row.processInstanceVo.businessStatus === 'back' |
| | | " |
| | | content="ä¿®æ¹" |
| | | placement="top" |
| | | > |
| | | <el-button v-hasPermi="['demo:leave:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | <el-tooltip |
| | | v-if=" |
| | | scope.row.processInstanceVo.businessStatus === 'draft' || |
| | | scope.row.processInstanceVo.businessStatus === 'cancel' || |
| | | scope.row.processInstanceVo.businessStatus === 'back' |
| | | " |
| | | content="å é¤" |
| | | placement="top" |
| | | > |
| | | <el-button v-hasPermi="['demo:leave:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button> |
| | | </el-tooltip> |
| | | <el-tooltip v-if="scope.row.processInstanceVo.businessStatus === 'waiting'" content="æ¤é" placement="top"> |
| | | <el-button link type="primary" icon="Notification" @click="handleCancelProcessApply(scope.row.processInstanceVo.id)"></el-button> |
| | | </el-tooltip> |
| | | <el-tooltip v-if="scope.row.processInstanceVo.businessStatus === 'waiting'" content="审æ¹è®°å½" placement="top"> |
| | | <el-button link type="primary" icon="Document" @click="handleApprovalRecord(scope.row.processInstanceVo.id)"></el-button> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" /> |
| | | </el-card> |
| | | <!-- æ·»å æä¿®æ¹è¯·åå¯¹è¯æ¡ --> |
| | | <el-dialog v-model="dialog.visible" :title="dialog.title" width="800px" append-to-body> |
| | | <el-form ref="leaveFormRef" v-loading="loading" :model="form" :rules="rules" label-width="80px"> |
| | | <el-form-item label="请åç±»å" prop="leaveType"> |
| | | <el-select v-model="form.leaveType" placeholder="è¯·éæ©è¯·åç±»å" style="width: 100%"> |
| | | <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="è¯·åæ¶é´"> |
| | | <el-date-picker |
| | | v-model="leaveTime" |
| | | type="daterange" |
| | | range-separator="To" |
| | | start-placeholder="å¼å§æ¶é´" |
| | | end-placeholder="ç»ææ¶é´" |
| | | @change="changeLeaveTime()" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="请å天æ°" prop="leaveDays"> |
| | | <el-input v-model="form.leaveDays" disabled type="number" placeholder="请è¾å
¥è¯·å天æ°" /> |
| | | </el-form-item> |
| | | <el-form-item label="请ååå " prop="remark"> |
| | | <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请è¾å
¥è¯·ååå " /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button :loading="buttonLoading" type="info" @click="submitForm('draft')">æ å</el-button> |
| | | <el-button :loading="buttonLoading" type="primary" @click="submitForm('submit')">æ 交</el-button> |
| | | <el-button @click="cancel">å æ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- æäº¤ç»ä»¶ --> |
| | | <submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" /> |
| | | <!-- 审æ¹è®°å½ --> |
| | | <approvalRecord ref="approvalRecordRef" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup name="Leave" lang="ts"> |
| | | import { addLeave, delLeave, getLeave, listLeave, updateLeave } from '@/api/workflow/leave'; |
| | | import { cancelProcessApply } from '@/api/workflow/processInstance'; |
| | | import { LeaveForm, LeaveQuery, LeaveVO } from '@/api/workflow/leave/types'; |
| | | import { startWorkFlow } from '@/api/workflow/task'; |
| | | import SubmitVerify from '@/components/Process/submitVerify.vue'; |
| | | import ApprovalRecord from '@/components/Process/approvalRecord.vue'; |
| | | import { AxiosResponse } from 'axios'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | const leaveList = ref<LeaveVO[]>([]); |
| | | const buttonLoading = ref(false); |
| | | const loading = ref(true); |
| | | const showSearch = ref(true); |
| | | const ids = ref<Array<string | number>>([]); |
| | | const single = ref(true); |
| | | const multiple = ref(true); |
| | | const total = ref(0); |
| | | const leaveTime = ref<Array<string>>([]); |
| | | const options = [ |
| | | { |
| | | value: '1', |
| | | label: 'äºå' |
| | | }, |
| | | { |
| | | value: '2', |
| | | label: 'è°ä¼' |
| | | }, |
| | | { |
| | | value: '3', |
| | | label: 'ç
å' |
| | | }, |
| | | { |
| | | value: '4', |
| | | label: 'å©å' |
| | | } |
| | | ]; |
| | | //æäº¤ç»ä»¶ |
| | | const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>(); |
| | | //审æ¹è®°å½ç»ä»¶ |
| | | const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>(); |
| | | |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | | const leaveFormRef = ref<ElFormInstance>(); |
| | | |
| | | const submitFormData = ref<Record<string, any>>({ |
| | | businessKey: '', |
| | | processKey: '', |
| | | variables: {} |
| | | }); |
| | | const taskVariables = ref<Record<string, any>>({}); |
| | | |
| | | const dialog = reactive<DialogOption>({ |
| | | visible: false, |
| | | title: '' |
| | | }); |
| | | |
| | | const initFormData: LeaveForm = { |
| | | id: undefined, |
| | | leaveType: undefined, |
| | | startDate: undefined, |
| | | endDate: undefined, |
| | | leaveDays: undefined, |
| | | remark: undefined |
| | | }; |
| | | const data = reactive<PageData<LeaveForm, LeaveQuery>>({ |
| | | form: { ...initFormData }, |
| | | queryParams: { |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | startLeaveDays: undefined, |
| | | endLeaveDays: undefined |
| | | }, |
| | | rules: { |
| | | id: [{ required: true, message: '主é®ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | leaveType: [{ required: true, message: '请åç±»åä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | leaveTime: [{ required: true, message: 'è¯·åæ¶é´ä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | leaveDays: [{ required: true, message: '请å天æ°ä¸è½ä¸ºç©º', trigger: 'blur' }] |
| | | } |
| | | }); |
| | | |
| | | const { queryParams, form, rules } = toRefs(data); |
| | | |
| | | /** æ¥è¯¢è¯·åå表 */ |
| | | const getList = async () => { |
| | | loading.value = true; |
| | | const res = await listLeave(queryParams.value); |
| | | leaveList.value = res.rows; |
| | | total.value = res.total; |
| | | loading.value = false; |
| | | }; |
| | | |
| | | /** åæ¶æé® */ |
| | | const cancel = () => { |
| | | reset(); |
| | | dialog.visible = false; |
| | | }; |
| | | |
| | | /** 表åéç½® */ |
| | | const reset = () => { |
| | | form.value = { ...initFormData }; |
| | | leaveTime.value = []; |
| | | leaveFormRef.value?.resetFields(); |
| | | }; |
| | | |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | handleQuery(); |
| | | }; |
| | | |
| | | /** å¤éæ¡é䏿°æ® */ |
| | | const handleSelectionChange = (selection: LeaveVO[]) => { |
| | | ids.value = selection.map((item) => item.id); |
| | | single.value = selection.length != 1; |
| | | multiple.value = !selection.length; |
| | | }; |
| | | |
| | | /** æ°å¢æé®æä½ */ |
| | | const handleAdd = () => { |
| | | dialog.visible = true; |
| | | dialog.title = 'æ·»å 请åç³è¯·'; |
| | | nextTick(() => { |
| | | reset(); |
| | | }); |
| | | }; |
| | | |
| | | const changeLeaveTime = () => { |
| | | const startDate = new Date(leaveTime.value[0]).getTime(); |
| | | const endDate = new Date(leaveTime.value[1]).getTime(); |
| | | const diffInMilliseconds = endDate - startDate; |
| | | form.value.leaveDays = Math.floor(diffInMilliseconds / (1000 * 60 * 60 * 24)); |
| | | }; |
| | | /** ä¿®æ¹æé®æä½ */ |
| | | const handleUpdate = (row?: LeaveVO) => { |
| | | buttonLoading.value = false; |
| | | dialog.visible = true; |
| | | dialog.title = 'ä¿®æ¹è¯·åç³è¯·'; |
| | | nextTick(async () => { |
| | | reset(); |
| | | const _id = row?.id || ids.value[0]; |
| | | const res = await getLeave(_id); |
| | | Object.assign(form.value, res.data); |
| | | leaveTime.value = []; |
| | | leaveTime.value.push(form.value.startDate); |
| | | leaveTime.value.push(form.value.endDate); |
| | | }); |
| | | }; |
| | | |
| | | /** æäº¤æé® */ |
| | | const submitForm = (status: string) => { |
| | | if (leaveTime.value.length === 0) { |
| | | proxy?.$modal.msgError('è¯·åæ¶é´ä¸è½ä¸ºç©º'); |
| | | return; |
| | | } |
| | | leaveFormRef.value?.validate(async (valid: boolean) => { |
| | | form.value.startDate = leaveTime.value[0]; |
| | | form.value.endDate = leaveTime.value[1]; |
| | | if (valid) { |
| | | buttonLoading.value = true; |
| | | let res: AxiosResponse<LeaveVO>; |
| | | if (form.value.id) { |
| | | res = await updateLeave(form.value); |
| | | } else { |
| | | res = await addLeave(form.value); |
| | | } |
| | | form.value = res.data; |
| | | if (status === 'draft') { |
| | | buttonLoading.value = false; |
| | | proxy?.$modal.msgSuccess('æåæå'); |
| | | dialog.visible = false; |
| | | await getList(); |
| | | } else { |
| | | await handleStartWorkFlow(res.data); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row?: LeaveVO) => { |
| | | const _ids = row?.id || ids.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å é¤è¯·åç¼å·ä¸º"' + _ids + '"çæ°æ®é¡¹ï¼').finally(() => (loading.value = false)); |
| | | await delLeave(_ids); |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | await getList(); |
| | | }; |
| | | |
| | | /** å¯¼åºæé®æä½ */ |
| | | const handleExport = () => { |
| | | proxy?.download( |
| | | 'demo/leave/export', |
| | | { |
| | | ...queryParams.value |
| | | }, |
| | | `leave_${new Date().getTime()}.xlsx` |
| | | ); |
| | | }; |
| | | |
| | | //æäº¤ç³è¯· |
| | | const handleStartWorkFlow = async (data: LeaveVO) => { |
| | | submitFormData.value.processKey = 'leave7'; |
| | | submitFormData.value.businessKey = data.id; |
| | | //æµç¨åé |
| | | taskVariables.value = { |
| | | entity: data, |
| | | leaveDays: data.leaveDays, |
| | | userList: [1, 2], |
| | | userList2: [1, 2] |
| | | }; |
| | | submitFormData.value.variables = taskVariables.value; |
| | | const resp = await startWorkFlow(submitFormData.value); |
| | | if (submitVerifyRef.value) { |
| | | buttonLoading.value = false; |
| | | submitVerifyRef.value.openDialog(resp.data.taskId); |
| | | } |
| | | }; |
| | | //审æ¹è®°å½ |
| | | const handleApprovalRecord = (id: string) => { |
| | | if (approvalRecordRef.value) { |
| | | approvalRecordRef.value.init(id); |
| | | } |
| | | }; |
| | | //æäº¤åè° |
| | | const submitCallback = async () => { |
| | | dialog.visible = false; |
| | | handleQuery(); |
| | | }; |
| | | /** æ¤éæé®æä½ */ |
| | | const handleCancelProcessApply = async (id: string) => { |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤æ¤éå½ååæ®ï¼'); |
| | | loading.value = true; |
| | | await cancelProcessApply(id).finally(() => (loading.value = false)); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess('æ¤éæå'); |
| | | }; |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="design"> |
| | | <el-dialog v-model="visible" width="100%" fullscreen :title="title"> |
| | | <div class="modeler"> |
| | | <bpmn-design ref="bpmnDesignRef" @save-call-back="saveCallBack"></bpmn-design> |
| | | </div> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup name="Design"> |
| | | import { getInfo, editModelXml } from '@/api/workflow/model'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | import { ModelForm } from '@/api/workflow/model/types'; |
| | | import BpmnDesign from '@/components/BpmnDesign'; |
| | | import useDialog from '@/hooks/useDialog'; |
| | | const bpmnDesignRef = ref<InstanceType<typeof BpmnDesign>>(); |
| | | const modelForm = ref<ModelForm>(); |
| | | const emit = defineEmits(['closeCallBack']); |
| | | const { visible, title } = useDialog({ |
| | | title: 'ç¼è¾æµç¨' |
| | | }); |
| | | const modelId = ref(''); |
| | | const open = async (id) => { |
| | | visible.value = true; |
| | | modelId.value = id; |
| | | const { data } = await getInfo(id); |
| | | modelForm.value = data; |
| | | bpmnDesignRef.value.initDiagram(modelForm.value.xml); |
| | | }; |
| | | //ä¿å模å |
| | | const saveCallBack = async (data) => { |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤ä¿åï¼'); |
| | | modelForm.value.id = modelId.value; |
| | | modelForm.value.xml = data.xml; |
| | | modelForm.value.svg = data.svg; |
| | | modelForm.value.key = data.key; |
| | | modelForm.value.name = data.name; |
| | | editModelXml(modelForm.value).then((res) => { |
| | | if (res.code === 200) { |
| | | visible.value = false; |
| | | proxy?.$modal.msgSuccess('ä¿åæå'); |
| | | emit('closeCallBack', data); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | /** |
| | | * 坹夿´é²åç»ä»¶æ¹æ³ |
| | | */ |
| | | defineExpose({ |
| | | open |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .design { |
| | | :deep(.el-dialog .el-dialog__body) { |
| | | max-height: 100% !important; |
| | | min-height: calc(100vh - 50px); |
| | | } |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <el-row :gutter="20"> |
| | | <!-- æµç¨åç±»æ --> |
| | | <el-col :lg="4" :xs="24" style=""> |
| | | <el-card shadow="hover"> |
| | | <el-input v-model="categoryName" placeholder="请è¾å
¥æµç¨åç±»å" prefix-icon="Search" clearable /> |
| | | <el-tree |
| | | ref="categoryTreeRef" |
| | | class="mt-2" |
| | | node-key="id" |
| | | :data="categoryOptions" |
| | | :props="{ label: 'categoryName', children: 'children' }" |
| | | :expand-on-click-node="false" |
| | | :filter-node-method="filterNode" |
| | | highlight-current |
| | | default-expand-all |
| | | @node-click="handleNodeClick" |
| | | ></el-tree> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :lg="20" :xs="24"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true" label-width="80px"> |
| | | <el-form-item label="模ååç§°" prop="name"> |
| | | <el-input v-model="queryParams.name" placeholder="请è¾å
¥æ¨¡ååç§°" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="模åKEY" prop="key"> |
| | | <el-input v-model="queryParams.key" placeholder="请è¾å
¥æ¨¡åKEY" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">æç´¢</el-button> |
| | | <el-button icon="Refresh" @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </el-card> |
| | | </div> |
| | | </transition> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button type="primary" plain icon="Plus" @click="handleAdd">æ°å¢</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="success" plain icon="Edit" :disabled="multiple" @click="handleUpdate()">ä¿®æ¹</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">å é¤</el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table v-loading="loading" :data="modelList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column fixed align="center" type="index" label="åºå·" width="50"></el-table-column> |
| | | <el-table-column fixed align="center" prop="name" label="模ååç§°"></el-table-column> |
| | | <el-table-column align="center" prop="key" label="模åKEY"></el-table-column> |
| | | <el-table-column align="center" prop="version" label="çæ¬å·" width="90"> |
| | | <template #default="scope"> v{{ scope.row.version }}.0</template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="metaInfo" label="夿³¨è¯´æ" min-width="130"></el-table-column> |
| | | <el-table-column align="center" prop="createTime" label="å建æ¶é´" width="160"></el-table-column> |
| | | <el-table-column align="center" prop="lastUpdateTime" label="æ´æ°æ¶é´" width="160"></el-table-column> |
| | | <el-table-column fixed="right" label="æä½" align="center" width="180" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button link type="primary" size="small" icon="Pointer" @click="clickDesign(scope.row.id)">设计æµç¨</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button link type="primary" size="small" icon="Download" @click="clickExportZip(scope.row)">导åº</el-button> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button link type="primary" size="small" icon="ScaleToOriginal" @click="clickDeploy(scope.row.id, scope.row.key)"> |
| | | æµç¨é¨ç½² |
| | | </el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button link type="primary" size="small" icon="Delete" @click="handleDelete(scope.row)">å é¤</el-button> |
| | | </el-col> |
| | | </el-row> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <pagination |
| | | v-show="total > 0" |
| | | v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" |
| | | :total="total" |
| | | @pagination="getList" |
| | | /> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | <!-- 设计æµç¨å¼å§ --> |
| | | <Design ref="designRef" @close-call-back="handleQuery"></Design> |
| | | <!-- 设计æµç¨ç»æ --> |
| | | <!-- æ·»å æ¨¡åå¯¹è¯æ¡ --> |
| | | <el-dialog v-model="dialog.visible" :title="dialog.title" width="650px" append-to-body :close-on-click-modal="false"> |
| | | <el-form ref="formRef" :model="form" :rules="rules" label-width="100px"> |
| | | <el-form-item label="模ååç§°ï¼" prop="name"> |
| | | <el-input v-model="form.name" :disabled="ids && ids.length > 0" maxlength="20" show-word-limit /> |
| | | </el-form-item> |
| | | <el-form-item label="模åKEYï¼" prop="key"> |
| | | <el-input v-model="form.key" :disabled="ids && ids.length > 0" maxlength="20" show-word-limit /> |
| | | </el-form-item> |
| | | <el-form-item label="æµç¨åç±»" prop="categoryCode"> |
| | | <el-tree-select |
| | | v-model="form.categoryCode" |
| | | :data="categoryOptions" |
| | | :props="{ value: 'categoryCode', label: 'categoryName', children: 'children' }" |
| | | value-key="categoryCode" |
| | | placeholder="è¯·éæ©æµç¨åç±»" |
| | | check-strictly |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="夿³¨ï¼" prop="description"> |
| | | <el-input v-model="form.description" type="textarea" maxlength="200" show-word-limit></el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button type="primary" @click="submitForm">ç¡® å®</el-button> |
| | | <el-button @click="cancel">å æ¶</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup name="Model"> |
| | | import Design from './design.vue'; |
| | | import { listModel, addModel, delModel, modelDeploy, getInfo, update } from '@/api/workflow/model'; |
| | | import { ModelQuery, ModelForm, ModelVO } from '@/api/workflow/model/types'; |
| | | import { listCategory } from '@/api/workflow/category'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | const formRef = ref<ElFormInstance>(); |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | | const categoryTreeRef = ref<ElTreeInstance>(); |
| | | const designRef = ref<InstanceType<typeof Design>>(); |
| | | |
| | | type CategoryOption = { |
| | | categoryCode: string; |
| | | categoryName: string; |
| | | children?: CategoryOption[]; |
| | | }; |
| | | |
| | | const buttonLoading = ref(false); |
| | | const loading = ref(true); |
| | | const ids = ref<string[]>([]); |
| | | const single = ref(true); |
| | | const multiple = ref(true); |
| | | const showSearch = ref(true); |
| | | const total = ref(0); |
| | | const modelList = ref<ModelVO[]>([]); |
| | | const categoryOptions = ref<CategoryOption[]>([]); |
| | | const categoryName = ref(''); |
| | | const modelId = ref<string>(''); |
| | | |
| | | const dialog = reactive<DialogOption>({ |
| | | visible: false, |
| | | title: '' |
| | | }); |
| | | |
| | | const initFormData: ModelForm = { |
| | | id: '', |
| | | name: '', |
| | | key: '', |
| | | categoryCode: '', |
| | | xml: '', |
| | | svg: '', |
| | | description: '' |
| | | }; |
| | | const data = reactive<PageData<ModelForm, ModelQuery>>({ |
| | | form: { ...initFormData }, |
| | | queryParams: { |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | name: '', |
| | | key: '', |
| | | categoryCode: '' |
| | | }, |
| | | rules: { |
| | | name: [{ required: true, message: '模åä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | key: [{ required: true, message: '模åKEYä¸è½ä¸ºç©º', trigger: 'blur' }], |
| | | categoryCode: [{ required: true, message: 'æµç¨åç±»ä¸è½ä¸ºç©º', trigger: 'blur' }] |
| | | } |
| | | }); |
| | | const { queryParams, form, rules } = toRefs(data); |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | getTreeselect(); |
| | | }); |
| | | |
| | | /** èç¹åå»äºä»¶ */ |
| | | const handleNodeClick = (data: ModelForm) => { |
| | | queryParams.value.categoryCode = data.categoryCode; |
| | | if (data.categoryCode === 'ALL') { |
| | | queryParams.value.categoryCode = ''; |
| | | } |
| | | handleQuery(); |
| | | }; |
| | | /** éè¿æ¡ä»¶è¿æ»¤èç¹ */ |
| | | const filterNode = (value: string, data: any) => { |
| | | if (!value) return true; |
| | | return data.categoryName.indexOf(value) !== -1; |
| | | }; |
| | | /** æ ¹æ®åç§°çéé¨é¨æ */ |
| | | watchEffect( |
| | | () => { |
| | | categoryTreeRef.value?.filter(categoryName.value); |
| | | }, |
| | | { |
| | | flush: 'post' // watchEffectä¼å¨DOMæè½½æè
æ´æ°ä¹åå°±ä¼è§¦åï¼æ¤å±æ§æ§å¶å¨DOMå
ç´ æ´æ°åè¿è¡ |
| | | } |
| | | ); |
| | | |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | getList(); |
| | | }; |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | queryParams.value.categoryCode = ''; |
| | | queryParams.value.pageNum = 1; |
| | | queryParams.value.pageSize = 10; |
| | | handleQuery(); |
| | | }; |
| | | // å¤éæ¡é䏿°æ® |
| | | const handleSelectionChange = (selection: ModelVO[]) => { |
| | | ids.value = selection.map((item: ModelVO) => item.id); |
| | | single.value = selection.length !== 1; |
| | | multiple.value = !selection.length; |
| | | }; |
| | | //å页 |
| | | const getList = async () => { |
| | | loading.value = true; |
| | | const resp = await listModel(queryParams.value); |
| | | modelList.value = resp.rows; |
| | | total.value = resp.total; |
| | | loading.value = false; |
| | | }; |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row?: ModelVO) => { |
| | | const id = row?.id || ids.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å 餿¨¡åid为ã' + id + 'ãçæ°æ®é¡¹ï¼'); |
| | | loading.value = true; |
| | | await delModel(id).finally(() => (loading.value = false)); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | }; |
| | | // æµç¨é¨ç½² |
| | | const clickDeploy = async (id: string, key: string) => { |
| | | await proxy?.$modal.confirm('æ¯å¦é¨ç½²æ¨¡åkey为ã' + key + 'ãæµç¨ï¼'); |
| | | loading.value = true; |
| | | await modelDeploy(id).finally(() => (loading.value = false)); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess('é¨ç½²æå'); |
| | | }; |
| | | const handleAdd = () => { |
| | | ids.value = []; |
| | | getTreeselect(); |
| | | form.value = { ...initFormData }; |
| | | dialog.visible = true; |
| | | dialog.title = 'æ°å¢æ¨¡å'; |
| | | }; |
| | | const handleUpdate = () => { |
| | | dialog.title = 'ä¿®æ¹æ¨¡å'; |
| | | nextTick(async () => { |
| | | await getTreeselect(); |
| | | const _id = ids.value[0]; |
| | | const res = await getInfo(_id); |
| | | Object.assign(form.value, res.data); |
| | | dialog.visible = true; |
| | | }); |
| | | }; |
| | | |
| | | /** æäº¤æé® */ |
| | | const submitForm = () => { |
| | | formRef.value.validate(async (valid: boolean) => { |
| | | if (valid) { |
| | | buttonLoading.value = true; |
| | | if (ids.value && ids.value.length > 0) { |
| | | form.value.id = ids.value[0]; |
| | | await update(form.value); |
| | | proxy?.$modal.msgSuccess('æ°å¢æå'); |
| | | } else { |
| | | initXml(form.value.key, form.value.name); |
| | | form.value.xml = xml.value; |
| | | await addModel(form.value); |
| | | proxy?.$modal.msgSuccess('æ°å¢æå'); |
| | | } |
| | | dialog.visible = false; |
| | | await getList(); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | /** åæ¶æé® */ |
| | | const cancel = () => { |
| | | reset(); |
| | | dialog.visible = false; |
| | | }; |
| | | |
| | | /** 表åéç½® */ |
| | | const reset = () => { |
| | | form.value = { ...initFormData }; |
| | | formRef.value.resetFields(); |
| | | }; |
| | | |
| | | // æå¼è®¾è®¡æµç¨ |
| | | const clickDesign = async (id: string) => { |
| | | await designRef.value.open(id); |
| | | }; |
| | | // å¯¼åºæµç¨æ¨¡å |
| | | const clickExportZip = (data: any) => { |
| | | proxy?.$download.zip('/workflow/model/export/zip/' + data.id, data.name + '-' + data.key); |
| | | }; |
| | | /** æ¥è¯¢æµç¨åç±»ä¸ææ ç»æ */ |
| | | const getTreeselect = async () => { |
| | | const res = await listCategory(); |
| | | categoryOptions.value = []; |
| | | const data: CategoryOption = { categoryCode: 'ALL', categoryName: '顶级èç¹', children: [] }; |
| | | data.children = proxy?.handleTree<CategoryOption>(res.data, 'id', 'parentId'); |
| | | categoryOptions.value.push(data); |
| | | }; |
| | | |
| | | const xml = ref<string>(''); |
| | | |
| | | const initXml = async (key: string, name: string) => { |
| | | xml.value = `<?xml version="1.0" encoding="UTF-8"?> |
| | | <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:bioc="http://bpmn.io/schema/bpmn/biocolor/1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.org/bpmn" targetNamespace="http://www.flowable.org/processdef"> |
| | | <process id="${key}" name="${name}"> |
| | | <startEvent id="startNode1" name="å¼å§" /> |
| | | </process> |
| | | <bpmndi:BPMNDiagram id="BPMNDiagram_flow"> |
| | | <bpmndi:BPMNPlane id="BPMNPlane_flow" bpmnElement="T-2d89e7a3-ba79-4abd-9f64-ea59621c258c"> |
| | | <bpmndi:BPMNShape id="BPMNShape_startNode1" bpmnElement="startNode1" bioc:stroke=""> |
| | | <omgdc:Bounds x="240" y="200" width="30" height="30" /> |
| | | <bpmndi:BPMNLabel> |
| | | <omgdc:Bounds x="242" y="237" width="23" height="14" /> |
| | | </bpmndi:BPMNLabel> |
| | | </bpmndi:BPMNShape> |
| | | </bpmndi:BPMNPlane> |
| | | </bpmndi:BPMNDiagram> |
| | | </definitions>`; |
| | | return xml; |
| | | }; |
| | | </script> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-dialog v-model="data.visible" title="é¢è§" width="70%" append-to-body> |
| | | <div v-if="data.type === 'png'" style="align: center"> |
| | | <el-image v-if="data.type === 'png'" :src="data.url[0]"> |
| | | <div>æµç¨å¾å è½½ä¸ <i class="el-icon-loading"></i></div> |
| | | </el-image> |
| | | </div> |
| | | <div v-if="data.type === 'xml'" class="xml-data"> |
| | | <div v-for="(xml, index) in data.url" :key="index"> |
| | | <pre class="font">{{ xml }}</pre> |
| | | </div> |
| | | </div> |
| | | <template #footer> |
| | | <span v-if="data.type === 'xml'" class="dialog-footer"> </span> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | const data = reactive({ |
| | | visible: false, |
| | | url: new Array<string>(), |
| | | type: '' |
| | | }); |
| | | //æå¼ |
| | | const openDialog = (url: string[], type: string) => { |
| | | data.visible = true; |
| | | data.url = url; |
| | | data.type = type; |
| | | }; |
| | | /** |
| | | * 坹夿´é²åç»ä»¶æ¹æ³ |
| | | */ |
| | | defineExpose({ |
| | | openDialog |
| | | }); |
| | | </script> |
| | | <style> |
| | | .xml-data { |
| | | background-color: #2b2b2b; |
| | | border-radius: 5px; |
| | | color: #c6c6c6; |
| | | word-break: break-all; |
| | | overflow-y: scroll; |
| | | overflow-x: hidden; |
| | | box-sizing: border-box; |
| | | padding: 8px 0px; |
| | | height: 500px; |
| | | width: inherit; |
| | | line-height: 1px; |
| | | overflow: auto; |
| | | } |
| | | .font { |
| | | font-family: 'å¹¼å'; |
| | | font-weight: 500; |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <el-row :gutter="20"> |
| | | <!-- æµç¨åç±»æ --> |
| | | <el-col :lg="4" :xs="24" style=""> |
| | | <el-card shadow="hover"> |
| | | <el-input v-model="categoryName" placeholder="请è¾å
¥æµç¨åç±»å" prefix-icon="Search" clearable /> |
| | | <el-tree |
| | | ref="categoryTreeRef" |
| | | class="mt-2" |
| | | node-key="id" |
| | | :data="categoryOptions" |
| | | :props="{ label: 'categoryName', children: 'children' }" |
| | | :expand-on-click-node="false" |
| | | :filter-node-method="filterNode" |
| | | highlight-current |
| | | default-expand-all |
| | | @node-click="handleNodeClick" |
| | | ></el-tree> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :lg="20" :xs="24"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true" label-width="120px"> |
| | | <el-form-item label="æµç¨å®ä¹åç§°" prop="name"> |
| | | <el-input v-model="queryParams.name" placeholder="请è¾å
¥æµç¨å®ä¹åç§°" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="æµç¨å®ä¹KEY" prop="key"> |
| | | <el-input v-model="queryParams.key" placeholder="请è¾å
¥æµç¨å®ä¹KEY" clearable @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">æç´¢</el-button> |
| | | <el-button icon="Refresh" @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </el-card> |
| | | </div> |
| | | </transition> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-button type="primary" icon="UploadFilled" @click="uploadDialog.visible = true">é¨ç½²æµç¨æä»¶</el-button> |
| | | </el-card> |
| | | </div> |
| | | </transition> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table v-loading="loading" :data="processDefinitionList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column fixed align="center" type="index" label="åºå·" width="50"></el-table-column> |
| | | <el-table-column fixed align="center" prop="name" label="æµç¨å®ä¹åç§°"></el-table-column> |
| | | <el-table-column align="center" prop="key" label="æ è¯Key"></el-table-column> |
| | | <el-table-column align="center" prop="version" label="çæ¬å·" width="90"> |
| | | <template #default="scope"> v{{ scope.row.version }}.0</template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="resourceName" label="æµç¨XML" min-width="80" :show-overflow-tooltip="true"> |
| | | <template #default="scope"> |
| | | <el-link type="primary" @click="clickPreviewXML(scope.row.id)">{{ scope.row.resourceName }}</el-link> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="diagramResourceName" label="æµç¨å¾ç" min-width="80" :show-overflow-tooltip="true"> |
| | | <template #default="scope"> |
| | | <el-link type="primary" @click="clickPreviewImg(scope.row.id)">{{ scope.row.diagramResourceName }}</el-link> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="suspensionState" label="ç¶æ" min-width="70"> |
| | | <template #default="scope"> |
| | | <el-tag v-if="scope.row.suspensionState == 1" type="success">æ¿æ´»</el-tag> |
| | | <el-tag v-else type="danger">æèµ·</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="deploymentTime" label="é¨ç½²æ¶é´" :show-overflow-tooltip="true"></el-table-column> |
| | | <el-table-column fixed="right" label="æä½" align="center" width="200" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button |
| | | link |
| | | type="primary" |
| | | size="small" |
| | | :icon="scope.row.suspensionState === 1 ? 'Lock' : 'Unlock'" |
| | | @click="handleProcessDefState(scope.row)" |
| | | > |
| | | {{ scope.row.suspensionState === 1 ? 'æèµ·æµç¨' : 'æ¿æ´»æµç¨' }} |
| | | </el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button link type="primary" size="small" icon="Delete" @click="handleDelete(scope.row)">å é¤</el-button> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button link type="primary" size="small" icon="Sort" @click="handleConvertToModel(scope.row)"> è½¬æ¢æ¨¡å </el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button link type="primary" size="small" icon="Document" @click="getProcessDefinitionHitoryList(scope.row.id, scope.row.key)"> |
| | | åå²çæ¬ |
| | | </el-button> |
| | | </el-col> |
| | | </el-row> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <pagination |
| | | v-show="total > 0" |
| | | v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" |
| | | :total="total" |
| | | @pagination="getList" |
| | | /> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | <!-- é¢è§å¾çæxml --> |
| | | <process-preview ref="previewRef" /> |
| | | |
| | | <!-- é¨ç½²æä»¶ --> |
| | | <el-dialog v-if="uploadDialog.visible" v-model="uploadDialog.visible" :title="uploadDialog.title" width="30%"> |
| | | <div v-loading="uploadDialogLoading"> |
| | | <el-upload class="upload-demo" drag accept="application/zip,application/xml,.bpmn" :http-request="handerDeployProcessFile"> |
| | | <el-icon class="UploadFilled"><upload-filled /></el-icon> |
| | | <div class="el-upload__text"><em>ç¹å»ä¸ä¼ ï¼éæ©BPMNæµç¨æä»¶</em></div> |
| | | <div class="el-upload__text">ä»
æ¯æ .zipã.bpmn20.xmlãbpmn æ ¼å¼æä»¶</div> |
| | | <div class="el-upload__text">PS:å¦è¥é¨ç½²è¯·é¨ç½²ä»æ¬é¡¹ç®æ¨¡å管ç导åºçæ°æ®</div> |
| | | </el-upload> |
| | | </div> |
| | | </el-dialog> |
| | | |
| | | <!-- åå²çæ¬ --> |
| | | <el-dialog v-if="processDefinitionDialog.visible" v-model="processDefinitionDialog.visible" :title="processDefinitionDialog.title" width="70%"> |
| | | <el-table v-loading="loading" :data="processDefinitionHistoryList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column fixed align="center" type="index" label="åºå·" width="50"></el-table-column> |
| | | <el-table-column fixed align="center" prop="name" label="æµç¨å®ä¹åç§°"></el-table-column> |
| | | <el-table-column align="center" prop="key" label="æ è¯Key"></el-table-column> |
| | | <el-table-column align="center" prop="version" label="çæ¬å·" width="90"> |
| | | <template #default="scope"> v{{ scope.row.version }}.0</template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="resourceName" label="æµç¨XML" min-width="80" :show-overflow-tooltip="true"> |
| | | <template #default="scope"> |
| | | <el-link type="primary" @click="clickPreviewXML(scope.row.id)">{{ scope.row.resourceName }}</el-link> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="diagramResourceName" label="æµç¨å¾ç" min-width="80" :show-overflow-tooltip="true"> |
| | | <template #default="scope"> |
| | | <el-link type="primary" @click="clickPreviewImg(scope.row.id)">{{ scope.row.diagramResourceName }}</el-link> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="suspensionState" label="ç¶æ" min-width="70"> |
| | | <template #default="scope"> |
| | | <el-tag v-if="scope.row.suspensionState == 1" type="success">æ¿æ´»</el-tag> |
| | | <el-tag v-else type="danger">æèµ·</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="deploymentTime" label="é¨ç½²æ¶é´" :show-overflow-tooltip="true"></el-table-column> |
| | | <el-table-column fixed="right" label="æä½" align="center" width="200" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button |
| | | link |
| | | type="primary" |
| | | size="small" |
| | | :icon="scope.row.suspensionState === 1 ? 'Lock' : 'Unlock'" |
| | | @click="handleProcessDefState(scope.row)" |
| | | > |
| | | {{ scope.row.suspensionState === 1 ? 'æèµ·æµç¨' : 'æ¿æ´»æµç¨' }} |
| | | </el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button link type="primary" icon="Delete" size="small" @click="handleDelete(scope.row)">å é¤</el-button> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button link type="primary" icon="Sort" size="small" @click="handleConvertToModel(scope.row)"> è½¬æ¢æ¨¡å </el-button> |
| | | </el-col> |
| | | </el-row> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup name="processDefinition"> |
| | | import { |
| | | listProcessDefinition, |
| | | processDefinitionImage, |
| | | processDefinitionXml, |
| | | deleteProcessDefinition, |
| | | updateProcessDefState, |
| | | convertToModel, |
| | | deployProcessFile, |
| | | getProcessDefinitionListByKey |
| | | } from '@/api/workflow/processDefinition'; |
| | | import ProcessPreview from './components/processPreview.vue'; |
| | | import { listCategory } from '@/api/workflow/category'; |
| | | import { CategoryVO } from '@/api/workflow/category/types'; |
| | | import { ProcessDefinitionQuery, ProcessDefinitionVO } from '@/api/workflow/processDefinition/types'; |
| | | import { UploadRequestOptions } from 'element-plus'; |
| | | |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | |
| | | const previewRef = ref<InstanceType<typeof ProcessPreview>>(); |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | | const categoryTreeRef = ref<ElTreeInstance>(); |
| | | |
| | | type CategoryOption = { |
| | | categoryCode: string; |
| | | categoryName: string; |
| | | children?: CategoryOption[]; |
| | | }; |
| | | |
| | | const loading = ref(true); |
| | | const ids = ref<Array<string | number>>([]); |
| | | const single = ref(true); |
| | | const multiple = ref(true); |
| | | const showSearch = ref(true); |
| | | const total = ref(0); |
| | | const uploadDialogLoading = ref(false); |
| | | const processDefinitionList = ref<ProcessDefinitionVO[]>([]); |
| | | const processDefinitionHistoryList = ref<ProcessDefinitionVO[]>([]); |
| | | const url = ref<string[]>([]); |
| | | const categoryOptions = ref<CategoryOption[]>([]); |
| | | const categoryName = ref(''); |
| | | |
| | | const uploadDialog = reactive<DialogOption>({ |
| | | visible: false, |
| | | title: 'é¨ç½²æµç¨æä»¶' |
| | | }); |
| | | |
| | | const processDefinitionDialog = reactive<DialogOption>({ |
| | | visible: false, |
| | | title: 'åå²çæ¬' |
| | | }); |
| | | |
| | | // æ¥è¯¢åæ° |
| | | const queryParams = ref<ProcessDefinitionQuery>({ |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | name: undefined, |
| | | key: undefined, |
| | | categoryCode: undefined |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | getTreeselect(); |
| | | }); |
| | | |
| | | /** èç¹åå»äºä»¶ */ |
| | | const handleNodeClick = (data: CategoryVO) => { |
| | | queryParams.value.categoryCode = data.categoryCode; |
| | | if (data.categoryCode === 'ALL') { |
| | | queryParams.value.categoryCode = ''; |
| | | } |
| | | handleQuery(); |
| | | }; |
| | | /** éè¿æ¡ä»¶è¿æ»¤èç¹ */ |
| | | const filterNode = (value: string, data: any) => { |
| | | if (!value) return true; |
| | | return data.categoryName.indexOf(value) !== -1; |
| | | }; |
| | | /** æ ¹æ®åç§°çéé¨é¨æ */ |
| | | watchEffect( |
| | | () => { |
| | | categoryTreeRef.value.filter(categoryName.value); |
| | | }, |
| | | { |
| | | flush: 'post' // watchEffectä¼å¨DOMæè½½æè
æ´æ°ä¹åå°±ä¼è§¦åï¼æ¤å±æ§æ§å¶å¨DOMå
ç´ æ´æ°åè¿è¡ |
| | | } |
| | | ); |
| | | |
| | | /** æ¥è¯¢æµç¨åç±»ä¸ææ ç»æ */ |
| | | const getTreeselect = async () => { |
| | | const res = await listCategory(); |
| | | categoryOptions.value = []; |
| | | const data: CategoryOption = { categoryCode: 'ALL', categoryName: '顶级èç¹', children: [] }; |
| | | data.children = proxy?.handleTree<CategoryOption>(res.data, 'id', 'parentId'); |
| | | categoryOptions.value.push(data); |
| | | }; |
| | | |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | queryParams.value.pageNum = 1; |
| | | getList(); |
| | | }; |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | queryParams.value.categoryCode = ''; |
| | | queryParams.value.pageNum = 1; |
| | | queryParams.value.pageSize = 10; |
| | | handleQuery(); |
| | | }; |
| | | // å¤éæ¡é䏿°æ® |
| | | const handleSelectionChange = (selection: any) => { |
| | | ids.value = selection.map((item: any) => item.id); |
| | | single.value = selection.length !== 1; |
| | | multiple.value = !selection.length; |
| | | }; |
| | | //å页 |
| | | const getList = async () => { |
| | | loading.value = true; |
| | | const resp = await listProcessDefinition(queryParams.value); |
| | | processDefinitionList.value = resp.rows; |
| | | total.value = resp.total; |
| | | loading.value = false; |
| | | }; |
| | | //è·åå岿µç¨å®ä¹ |
| | | const getProcessDefinitionHitoryList = async (id: string, key: string) => { |
| | | processDefinitionDialog.visible = true; |
| | | loading.value = true; |
| | | const resp = await getProcessDefinitionListByKey(key); |
| | | if (resp.data && resp.data.length > 0) { |
| | | processDefinitionHistoryList.value = resp.data.filter((item: any) => item.id !== id); |
| | | } |
| | | loading.value = false; |
| | | }; |
| | | |
| | | //é¢è§å¾ç |
| | | const clickPreviewImg = async (id: string) => { |
| | | loading.value = true; |
| | | const resp = await processDefinitionImage(id); |
| | | if (previewRef.value) { |
| | | url.value = []; |
| | | url.value.push('data:image/png;base64,' + resp.data); |
| | | loading.value = false; |
| | | previewRef.value.openDialog(url.value, 'png'); |
| | | } |
| | | }; |
| | | //é¢è§xml |
| | | const clickPreviewXML = async (id: string) => { |
| | | loading.value = true; |
| | | const resp = await processDefinitionXml(id); |
| | | if (previewRef.value) { |
| | | url.value = []; |
| | | url.value = resp.data.xml; |
| | | loading.value = false; |
| | | previewRef.value.openDialog(url.value, 'xml'); |
| | | } |
| | | }; |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row: ProcessDefinitionVO) => { |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å 餿µç¨å®ä¹key为ã' + row.key + 'ãçæ°æ®é¡¹ï¼'); |
| | | loading.value = true; |
| | | await deleteProcessDefinition(row.deploymentId, row.id).finally(() => (loading.value = false)); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | }; |
| | | /** æèµ·/æ¿æ´» */ |
| | | const handleProcessDefState = async (row: ProcessDefinitionVO) => { |
| | | let msg: string; |
| | | if (row.suspensionState === 1) { |
| | | msg = `æååï¼æ¤æµç¨ä¸çææä»»å¡é½ä¸å
许å¾åæµè½¬ï¼æ¨ç¡®å®æèµ·ã${row.name || row.key}ãåï¼`; |
| | | } else { |
| | | msg = `å¯å¨åï¼æ¤æµç¨ä¸çææä»»å¡é½å
许å¾åæµè½¬ï¼æ¨ç¡®å®æ¿æ´»ã${row.name || row.key}ãåï¼`; |
| | | } |
| | | await proxy?.$modal.confirm(msg); |
| | | loading.value = true; |
| | | await updateProcessDefState(row.id).finally(() => (loading.value = false)); |
| | | await getList(); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | }; |
| | | /** æµç¨å®ä¹è½¬æ¢ä¸ºæ¨¡å */ |
| | | const handleConvertToModel = async (row: ProcessDefinitionVO) => { |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤è½¬æ¢æµç¨å®ä¹key为ã' + row.key + 'ãçæ°æ®é¡¹ï¼'); |
| | | await convertToModel(row.id).finally(() => (loading.value = false)); |
| | | getList(); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | }; |
| | | |
| | | //é¨ç½²æä»¶ |
| | | const handerDeployProcessFile = (data: UploadRequestOptions): XMLHttpRequest => { |
| | | let formData = new FormData(); |
| | | if (queryParams.value.categoryCode === 'ALL') { |
| | | proxy?.$modal.msgError('顶级èç¹ä¸å¯ä½ä¸ºåç±»ï¼'); |
| | | return; |
| | | } |
| | | if (!queryParams.value.categoryCode) { |
| | | proxy?.$modal.msgError('è¯·éæ©å·¦ä¾§è¦ä¸ä¼ çåç±»ï¼'); |
| | | return; |
| | | } |
| | | uploadDialogLoading.value = true |
| | | formData.append('file', data.file); |
| | | formData.append('categoryCode', queryParams.value.categoryCode); |
| | | deployProcessFile(formData).then(() => { |
| | | uploadDialog.visible = false; |
| | | proxy?.$modal.msgSuccess('é¨ç½²æå'); |
| | | uploadDialogLoading.value = false |
| | | handleQuery(); |
| | | }); |
| | | }; |
| | | </script> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <el-row :gutter="20"> |
| | | <!-- æµç¨åç±»æ --> |
| | | <el-col :lg="4" :xs="24" style=""> |
| | | <el-card shadow="hover"> |
| | | <el-input v-model="categoryName" placeholder="请è¾å
¥æµç¨åç±»å" prefix-icon="Search" clearable /> |
| | | <el-tree |
| | | ref="categoryTreeRef" |
| | | class="mt-2" |
| | | node-key="id" |
| | | :data="categoryOptions" |
| | | :props="{ label: 'categoryName', children: 'children' }" |
| | | :expand-on-click-node="false" |
| | | :filter-node-method="filterNode" |
| | | highlight-current |
| | | default-expand-all |
| | | @node-click="handleNodeClick" |
| | | ></el-tree> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :lg="20" :xs="24"> |
| | | <div class="mb-[10px]"> |
| | | <el-card shadow="hover" class="text-center"> |
| | | <el-radio-group v-model="tab" @change="changeTab(tab)"> |
| | | <el-radio-button label="running">è¿è¡ä¸</el-radio-button> |
| | | <el-radio-button label="finish">已宿</el-radio-button> |
| | | </el-radio-group> |
| | | </el-card> |
| | | </div> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true" label-width="120px"> |
| | | <el-form-item label="æµç¨å®ä¹åç§°" prop="name"> |
| | | <el-input v-model="queryParams.name" placeholder="请è¾å
¥æµç¨å®ä¹åç§°" @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="æµç¨å®ä¹KEY" prop="key"> |
| | | <el-input v-model="queryParams.key" placeholder="请è¾å
¥æµç¨å®ä¹KEY" @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">æç´¢</el-button> |
| | | <el-button icon="Refresh" @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </el-card> |
| | | </div> |
| | | </transition> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete">å é¤</el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="handleQuery"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table v-loading="loading" :data="processInstanceList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column fixed align="center" type="index" label="åºå·" width="50"></el-table-column> |
| | | <el-table-column v-if="false" fixed align="center" prop="id" label="id"></el-table-column> |
| | | <el-table-column fixed align="center" prop="processDefinitionName" label="æµç¨å®ä¹åç§°"></el-table-column> |
| | | <el-table-column fixed align="center" prop="processDefinitionKey" label="æµç¨å®ä¹KEY"></el-table-column> |
| | | <el-table-column align="center" prop="processDefinitionVersion" label="çæ¬å·" width="90"> |
| | | <template #default="scope"> v{{ scope.row.processDefinitionVersion }}.0</template> |
| | | </el-table-column> |
| | | <el-table-column v-if="tab === 'running'" align="center" prop="isSuspended" label="ç¶æ" min-width="70"> |
| | | <template #default="scope"> |
| | | <el-tag v-if="!scope.row.isSuspended" type="success">æ¿æ´»</el-tag> |
| | | <el-tag v-else type="danger">æèµ·</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="businessStatusName" label="æµç¨ç¶æ" min-width="70"> |
| | | <template #default="scope"> |
| | | <el-tag type="success">{{ scope.row.businessStatusName }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="startTime" label="å¯å¨æ¶é´" width="160"></el-table-column> |
| | | <el-table-column v-if="tab === 'finish'" align="center" prop="endTime" label="ç»ææ¶é´" width="160"></el-table-column> |
| | | <el-table-column label="æä½" align="center" width="160" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button link type="primary" size="small" icon="Document" @click="handleApprovalRecord(scope.row)">审æ¹è®°å½</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button link type="primary" size="small" icon="Delete" @click="handleDelete(scope.row)">å é¤</el-button> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row v-if="tab === 'running'" :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button |
| | | link |
| | | type="primary" |
| | | size="small" |
| | | icon="Sort" |
| | | @click="getProcessDefinitionHitoryList(scope.row.processDefinitionId, scope.row.processDefinitionKey)" |
| | | >åæ¢çæ¬</el-button |
| | | > |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-popover :ref="`popoverRef${scope.$index}`" trigger="click" placement="left" :width="300"> |
| | | <el-input v-model="deleteReason" resize="none" :rows="3" type="textarea" placeholder="请è¾å
¥ä½åºåå " /> |
| | | <div style="text-align: right; margin: 5px 0px 0px 0px"> |
| | | <el-button size="small" text @click="cancelPopover(scope.$index)">åæ¶</el-button> |
| | | <el-button size="small" type="primary" @click="handleInvalid(scope.row)">确认</el-button> |
| | | </div> |
| | | <template #reference> |
| | | <el-button link type="primary" size="small" icon="CircleClose">ä½åº</el-button> |
| | | </template> |
| | | </el-popover> |
| | | </el-col> |
| | | </el-row> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <pagination |
| | | v-show="total > 0" |
| | | v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" |
| | | :total="total" |
| | | @pagination="handleQuery" |
| | | /> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | <el-dialog v-if="processDefinitionDialog.visible" v-model="processDefinitionDialog.visible" :title="processDefinitionDialog.title" width="70%"> |
| | | <el-table v-loading="loading" :data="processDefinitionHistoryList"> |
| | | <el-table-column fixed align="center" type="index" label="åºå·" width="50"></el-table-column> |
| | | <el-table-column fixed align="center" prop="name" label="æµç¨å®ä¹åç§°"></el-table-column> |
| | | <el-table-column align="center" prop="key" label="æ è¯Key"></el-table-column> |
| | | <el-table-column align="center" prop="version" label="çæ¬å·" width="90"> |
| | | <template #default="scope"> v{{ scope.row.version }}.0</template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="suspensionState" label="ç¶æ" min-width="70"> |
| | | <template #default="scope"> |
| | | <el-tag v-if="scope.row.suspensionState == 1" type="success">æ¿æ´»</el-tag> |
| | | <el-tag v-else type="danger">æèµ·</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="deploymentTime" label="é¨ç½²æ¶é´" :show-overflow-tooltip="true"></el-table-column> |
| | | <el-table-column fixed="right" label="æä½" align="center" width="200" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" icon="Sort" @click="handleChange(scope.row.id)">忢</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-dialog> |
| | | <!-- 审æ¹è®°å½ --> |
| | | <approvalRecord ref="approvalRecordRef" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import { |
| | | getProcessInstanceRunningByPage, |
| | | getProcessInstanceFinishByPage, |
| | | deleteRuntimeProcessAndHisInst, |
| | | deleteFinishProcessAndHisInst, |
| | | deleteRuntimeProcessInst |
| | | } from '@/api/workflow/processInstance'; |
| | | import { getProcessDefinitionListByKey, migrationProcessDefinition } from '@/api/workflow/processDefinition'; |
| | | import ApprovalRecord from '@/components/Process/approvalRecord.vue'; |
| | | import { listCategory } from '@/api/workflow/category'; |
| | | import { CategoryVO } from '@/api/workflow/category/types'; |
| | | import { ProcessInstanceQuery, ProcessInstanceVO } from '@/api/workflow/processInstance/types'; |
| | | //审æ¹è®°å½ç»ä»¶ |
| | | const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>(); |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | | const categoryTreeRef = ref<ElTreeInstance>(); |
| | | |
| | | // é®ç½©å± |
| | | const loading = ref(true); |
| | | // é䏿°ç» |
| | | const ids = ref<Array<any>>([]); |
| | | // éå个ç¦ç¨ |
| | | const single = ref(true); |
| | | // éå¤ä¸ªç¦ç¨ |
| | | const multiple = ref(true); |
| | | // æ¾ç¤ºæç´¢æ¡ä»¶ |
| | | const showSearch = ref(true); |
| | | // æ»æ¡æ° |
| | | const total = ref(0); |
| | | // æµç¨å®ä¹id |
| | | const processDefinitionId = ref<string>(''); |
| | | // 模åå®ä¹è¡¨æ ¼æ°æ® |
| | | const processInstanceList = ref<ProcessInstanceVO[]>([]); |
| | | const processDefinitionHistoryList = ref<Array<any>>([]); |
| | | const categoryOptions = ref<CategoryOption[]>([]); |
| | | const categoryName = ref(''); |
| | | |
| | | const processDefinitionDialog = reactive<DialogOption>({ |
| | | visible: false, |
| | | title: 'æµç¨å®ä¹' |
| | | }); |
| | | |
| | | type CategoryOption = { |
| | | categoryCode: string; |
| | | categoryName: string; |
| | | children?: CategoryOption[]; |
| | | }; |
| | | |
| | | const tab = ref('running'); |
| | | // ä½åºåå |
| | | const deleteReason = ref(''); |
| | | // æ¥è¯¢åæ° |
| | | const queryParams = ref<ProcessInstanceQuery>({ |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | name: undefined, |
| | | key: undefined, |
| | | categoryCode: undefined |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | getProcessInstanceRunningList(); |
| | | getTreeselect(); |
| | | }); |
| | | |
| | | /** èç¹åå»äºä»¶ */ |
| | | const handleNodeClick = (data: CategoryVO) => { |
| | | queryParams.value.categoryCode = data.categoryCode; |
| | | if (data.categoryCode === 'ALL') { |
| | | queryParams.value.categoryCode = ''; |
| | | } |
| | | handleQuery(); |
| | | }; |
| | | /** éè¿æ¡ä»¶è¿æ»¤èç¹ */ |
| | | const filterNode = (value: string, data: any) => { |
| | | if (!value) return true; |
| | | return data.categoryName.indexOf(value) !== -1; |
| | | }; |
| | | /** æ ¹æ®åç§°çéé¨é¨æ */ |
| | | watchEffect( |
| | | () => { |
| | | categoryTreeRef.value.filter(categoryName.value); |
| | | }, |
| | | { |
| | | flush: 'post' // watchEffectä¼å¨DOMæè½½æè
æ´æ°ä¹åå°±ä¼è§¦åï¼æ¤å±æ§æ§å¶å¨DOMå
ç´ æ´æ°åè¿è¡ |
| | | } |
| | | ); |
| | | |
| | | /** æ¥è¯¢æµç¨åç±»ä¸ææ ç»æ */ |
| | | const getTreeselect = async () => { |
| | | const res = await listCategory(); |
| | | categoryOptions.value = []; |
| | | const data: CategoryOption = { categoryCode: 'ALL', categoryName: '顶级èç¹', children: [] }; |
| | | data.children = proxy?.handleTree<CategoryOption>(res.data, 'id', 'parentId'); |
| | | categoryOptions.value.push(data); |
| | | }; |
| | | |
| | | //审æ¹è®°å½ |
| | | const handleApprovalRecord = (row: any) => { |
| | | if (approvalRecordRef.value) { |
| | | approvalRecordRef.value.init(row.id); |
| | | } |
| | | }; |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | if ('running' === tab.value) { |
| | | getProcessInstanceRunningList(); |
| | | } else { |
| | | getProcessInstanceFinishList(); |
| | | } |
| | | }; |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | queryParams.value.categoryCode = ''; |
| | | queryParams.value.pageNum = 1; |
| | | queryParams.value.pageSize = 10; |
| | | handleQuery(); |
| | | }; |
| | | // å¤éæ¡é䏿°æ® |
| | | const handleSelectionChange = (selection: ProcessInstanceVO[]) => { |
| | | ids.value = selection.map((item: any) => item.id); |
| | | single.value = selection.length !== 1; |
| | | multiple.value = !selection.length; |
| | | }; |
| | | //å页 |
| | | const getProcessInstanceRunningList = () => { |
| | | loading.value = true; |
| | | getProcessInstanceRunningByPage(queryParams.value).then((resp) => { |
| | | processInstanceList.value = resp.rows; |
| | | total.value = resp.total; |
| | | loading.value = false; |
| | | }); |
| | | }; |
| | | //å页 |
| | | const getProcessInstanceFinishList = () => { |
| | | loading.value = true; |
| | | getProcessInstanceFinishByPage(queryParams.value).then((resp) => { |
| | | processInstanceList.value = resp.rows; |
| | | total.value = resp.total; |
| | | loading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row: any) => { |
| | | const id = row.id || ids.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å é¤id为ã' + id + 'ãçæ°æ®é¡¹ï¼'); |
| | | loading.value = true; |
| | | if ('running' === tab.value) { |
| | | await deleteRuntimeProcessAndHisInst(id).finally(() => (loading.value = false)); |
| | | getProcessInstanceRunningList(); |
| | | } else { |
| | | await deleteFinishProcessAndHisInst(id).finally(() => (loading.value = false)); |
| | | getProcessInstanceFinishList(); |
| | | } |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | }; |
| | | const changeTab = async (data: string) => { |
| | | queryParams.value.pageNum = 1; |
| | | if ('running' === data) { |
| | | getProcessInstanceRunningList(); |
| | | } else { |
| | | getProcessInstanceFinishList(); |
| | | } |
| | | }; |
| | | /** ä½åºæé®æä½ */ |
| | | const handleInvalid = async (row: ProcessInstanceVO) => { |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤ä½åºä¸å¡id为ã' + row.businessKey + 'ãçæ°æ®é¡¹ï¼'); |
| | | loading.value = true; |
| | | if ('running' === tab.value) { |
| | | let param = { |
| | | processInstanceId: row.id, |
| | | deleteReason: deleteReason.value |
| | | }; |
| | | await deleteRuntimeProcessInst(param).finally(() => (loading.value = false)); |
| | | getProcessInstanceRunningList(); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | } |
| | | }; |
| | | const cancelPopover = async (index: any) => { |
| | | (proxy?.$refs[`popoverRef${index}`] as any).hide(); //å
³éå¼¹çª |
| | | }; |
| | | //è·åæµç¨å®ä¹ |
| | | const getProcessDefinitionHitoryList = (id: string, key: string) => { |
| | | processDefinitionDialog.visible = true; |
| | | processDefinitionId.value = id; |
| | | loading.value = true; |
| | | getProcessDefinitionListByKey(key).then((resp) => { |
| | | if (resp.data && resp.data.length > 0) { |
| | | processDefinitionHistoryList.value = resp.data.filter((item: any) => item.id !== id); |
| | | } |
| | | loading.value = false; |
| | | }); |
| | | }; |
| | | //忢æµç¨çæ¬ |
| | | const handleChange = async (id: string) => { |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤åæ¢ï¼'); |
| | | loading.value = true; |
| | | migrationProcessDefinition(processDefinitionId.value, id).then((resp) => { |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | getProcessInstanceRunningList(); |
| | | processDefinitionDialog.visible = false; |
| | | loading.value = false; |
| | | }); |
| | | }; |
| | | </script> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <div class="mb-[10px]"> |
| | | <el-card shadow="hover" class="text-center"> |
| | | <el-radio-group v-model="tab" @change="changeTab(tab)"> |
| | | <el-radio-button label="waiting">å¾
åä»»å¡</el-radio-button> |
| | | <el-radio-button label="finish">å·²åä»»å¡</el-radio-button> |
| | | </el-radio-group> |
| | | </el-card> |
| | | </div> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px"> |
| | | <el-form-item label="ä»»å¡åç§°" prop="name"> |
| | | <el-input v-model="queryParams.name" placeholder="请è¾å
¥ä»»å¡åç§°" @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="æµç¨å®ä¹åç§°" label-width="100" prop="processDefinitionName"> |
| | | <el-input v-model="queryParams.processDefinitionName" placeholder="请è¾å
¥æµç¨å®ä¹åç§°" @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="æµç¨å®ä¹KEY" label-width="100" prop="processDefinitionKey"> |
| | | <el-input v-model="queryParams.processDefinitionKey" placeholder="请è¾å
¥æµç¨å®ä¹KEY" @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">æç´¢</el-button> |
| | | <el-button icon="Refresh" @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </el-card> |
| | | </div> |
| | | </transition> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button type="primary" plain icon="Edit" @click="handleUpdate">ä¿®æ¹åç人</el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="handleQuery"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table v-loading="loading" :data="taskList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column fixed align="center" type="index" label="åºå·" width="50"></el-table-column> |
| | | <el-table-column fixed align="center" prop="processDefinitionName" label="æµç¨å®ä¹åç§°"></el-table-column> |
| | | <el-table-column fixed align="center" prop="processDefinitionKey" label="æµç¨å®ä¹KEY"></el-table-column> |
| | | <el-table-column fixed align="center" prop="name" label="ä»»å¡åç§°"></el-table-column> |
| | | <el-table-column fixed align="center" prop="assigneeName" label="åç人"> |
| | | <template v-if="tab === 'waiting'" #default="scope"> |
| | | <template v-if="scope.row.participantVo && scope.row.assignee === null"> |
| | | <el-tag v-for="(item, index) in scope.row.participantVo.candidateName" :key="index" type="success"> |
| | | {{ item }} |
| | | </el-tag> |
| | | </template> |
| | | <template v-else> |
| | | <el-tag type="success"> |
| | | {{ scope.row.assigneeName }} |
| | | </el-tag> |
| | | </template> |
| | | </template> |
| | | <template v-else-if="tab === 'finish'" #default="scope"> |
| | | <el-tag type="success"> |
| | | {{ scope.row.assigneeName }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="businessStatusName" label="æµç¨ç¶æ" min-width="70"> |
| | | <template #default="scope"> |
| | | <el-tag v-if="tab === 'waiting'" type="success">{{ scope.row.businessStatusName }}</el-tag> |
| | | <el-tag v-else type="success">已宿</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="createTime" label="å建æ¶é´" width="160"></el-table-column> |
| | | <el-table-column label="æä½" align="center" width="160" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button link type="primary" size="small" icon="Document" @click="handleApprovalRecord(scope.row)">审æ¹è®°å½</el-button> |
| | | </el-col> |
| | | <el-col v-if="scope.row.multiInstance" :span="1.5"> |
| | | <el-button link type="primary" size="small" icon="CirclePlus" @click="addMultiInstanceUser(scope.row)">å ç¾</el-button> |
| | | </el-col> |
| | | <el-col v-if="scope.row.multiInstance" :span="1.5"> |
| | | <el-button link type="primary" size="small" icon="Remove" @click="deleteMultiInstanceUser(scope.row)">åç¾</el-button> |
| | | </el-col> |
| | | </el-row> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <pagination |
| | | v-show="total > 0" |
| | | v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" |
| | | :total="total" |
| | | @pagination="handleQuery" |
| | | /> |
| | | </el-card> |
| | | <!-- 审æ¹è®°å½ --> |
| | | <approvalRecord ref="approvalRecordRef" /> |
| | | <!-- æäº¤ç»ä»¶ --> |
| | | <submitVerify ref="submitVerifyRef" :task-id="taskId" @submit-callback="handleQuery" /> |
| | | <!-- å ç¾ç»ä»¶ --> |
| | | <multiInstanceUser ref="multiInstanceUserRef" :title="title" @submit-callback="handleQuery" /> |
| | | <!-- å ç¾ç»ä»¶ --> |
| | | <SysUser ref="sysUserRef" :multiple="true" @submit-callback="submitCallback" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import { getAllTaskWaitByPage, getAllTaskFinishByPage, updateAssignee } from '@/api/workflow/task'; |
| | | import ApprovalRecord from '@/components/Process/approvalRecord.vue'; |
| | | import SubmitVerify from '@/components/Process/submitVerify.vue'; |
| | | import MultiInstanceUser from '@/components/Process/multiInstance-user.vue'; |
| | | import SysUser from '@/components/Process/sys-user.vue'; |
| | | import { TaskQuery, TaskVO } from '@/api/workflow/task/types'; |
| | | //æäº¤ç»ä»¶ |
| | | const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>(); |
| | | //审æ¹è®°å½ç»ä»¶ |
| | | const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>(); |
| | | //å ç¾ç»ä»¶ |
| | | const multiInstanceUserRef = ref<InstanceType<typeof MultiInstanceUser>>(); |
| | | //é人ç»ä»¶ |
| | | const sysUserRef = ref<InstanceType<typeof SysUser>>(); |
| | | |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | // é®ç½©å± |
| | | const loading = ref(true); |
| | | // é䏿°ç» |
| | | const ids = ref<Array<any>>([]); |
| | | // éå个ç¦ç¨ |
| | | const single = ref(true); |
| | | // éå¤ä¸ªç¦ç¨ |
| | | const multiple = ref(true); |
| | | // æ¾ç¤ºæç´¢æ¡ä»¶ |
| | | const showSearch = ref(true); |
| | | // æ»æ¡æ° |
| | | const total = ref(0); |
| | | // 模åå®ä¹è¡¨æ ¼æ°æ® |
| | | const taskList = ref([]); |
| | | // ä»»å¡id |
| | | const taskId = ref(''); |
| | | const title = ref(''); |
| | | // æ¥è¯¢åæ° |
| | | const queryParams = ref<TaskQuery>({ |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | name: undefined, |
| | | processDefinitionName: undefined, |
| | | processDefinitionKey: undefined |
| | | }); |
| | | const tab = ref('waiting'); |
| | | onMounted(() => { |
| | | getWaitingList(); |
| | | }); |
| | | //审æ¹è®°å½ |
| | | const handleApprovalRecord = (row: TaskVO) => { |
| | | if (approvalRecordRef.value) { |
| | | approvalRecordRef.value.init(row.processInstanceId); |
| | | } |
| | | }; |
| | | //å ç¾ |
| | | const addMultiInstanceUser = (row: TaskVO) => { |
| | | if (multiInstanceUserRef.value) { |
| | | title.value = 'å ç¾äººå'; |
| | | multiInstanceUserRef.value.getAddMultiInstanceList(row.id, []); |
| | | } |
| | | }; |
| | | //åç¾ |
| | | const deleteMultiInstanceUser = (row: TaskVO) => { |
| | | if (multiInstanceUserRef.value) { |
| | | title.value = 'åç¾äººå'; |
| | | multiInstanceUserRef.value.getDeleteMultiInstanceList(row.id); |
| | | } |
| | | }; |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | if ('waiting' === tab.value) { |
| | | getWaitingList(); |
| | | } else { |
| | | getFinishList(); |
| | | } |
| | | }; |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | queryParams.value.pageNum = 1; |
| | | queryParams.value.pageSize = 10; |
| | | handleQuery(); |
| | | }; |
| | | // å¤éæ¡é䏿°æ® |
| | | const handleSelectionChange = (selection: any) => { |
| | | ids.value = selection.map((item: any) => item.id); |
| | | single.value = selection.length !== 1; |
| | | multiple.value = !selection.length; |
| | | }; |
| | | const changeTab = async (data: string) => { |
| | | queryParams.value.pageNum = 1; |
| | | if ('waiting' === data) { |
| | | getWaitingList(); |
| | | } else { |
| | | getFinishList(); |
| | | } |
| | | }; |
| | | //å页 |
| | | const getWaitingList = () => { |
| | | loading.value = true; |
| | | getAllTaskWaitByPage(queryParams.value).then((resp) => { |
| | | taskList.value = resp.rows; |
| | | total.value = resp.total; |
| | | loading.value = false; |
| | | }); |
| | | }; |
| | | const getFinishList = () => { |
| | | loading.value = true; |
| | | getAllTaskFinishByPage(queryParams.value).then((resp) => { |
| | | taskList.value = resp.rows; |
| | | total.value = resp.total; |
| | | loading.value = false; |
| | | }); |
| | | }; |
| | | const handleUpdate = () => { |
| | | if (sysUserRef.value) { |
| | | sysUserRef.value.getUserList([]); |
| | | } |
| | | }; |
| | | //ä¿®æ¹åç人 |
| | | const submitCallback = (data) => { |
| | | if (data && data.value.length > 0) { |
| | | updateAssignee(ids.value, data.value[0].userId).then((resp) => { |
| | | sysUserRef.value.close(); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | handleQuery(); |
| | | }); |
| | | } |
| | | }; |
| | | </script> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <el-row :gutter="20"> |
| | | <!-- æµç¨åç±»æ --> |
| | | <el-col :lg="4" :xs="24" style=""> |
| | | <el-card shadow="hover"> |
| | | <el-input v-model="categoryName" placeholder="请è¾å
¥æµç¨åç±»å" prefix-icon="Search" clearable /> |
| | | <el-tree |
| | | ref="categoryTreeRef" |
| | | class="mt-2" |
| | | node-key="id" |
| | | :data="categoryOptions" |
| | | :props="{ label: 'categoryName', children: 'children' }" |
| | | :expand-on-click-node="false" |
| | | :filter-node-method="filterNode" |
| | | highlight-current |
| | | default-expand-all |
| | | @node-click="handleNodeClick" |
| | | ></el-tree> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :lg="20" :xs="24"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true" label-width="120px"> |
| | | <el-form-item label="æµç¨å®ä¹åç§°" prop="name"> |
| | | <el-input v-model="queryParams.name" placeholder="请è¾å
¥æµç¨å®ä¹åç§°" @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">æç´¢</el-button> |
| | | <el-button icon="Refresh" @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </el-card> |
| | | </div> |
| | | </transition> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="handleQuery"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table v-loading="loading" :data="processInstanceList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column fixed align="center" type="index" label="åºå·" width="50"></el-table-column> |
| | | <el-table-column v-if="false" fixed align="center" prop="id" label="id"></el-table-column> |
| | | <el-table-column fixed align="center" prop="processDefinitionName" label="æµç¨å®ä¹åç§°"></el-table-column> |
| | | <el-table-column fixed align="center" prop="processDefinitionKey" label="æµç¨å®ä¹KEY"></el-table-column> |
| | | <el-table-column align="center" prop="processDefinitionVersion" label="çæ¬å·" width="90"> |
| | | <template #default="scope"> v{{ scope.row.processDefinitionVersion }}.0</template> |
| | | </el-table-column> |
| | | <el-table-column v-if="tab === 'running'" align="center" prop="isSuspended" label="ç¶æ" min-width="70"> |
| | | <template #default="scope"> |
| | | <el-tag v-if="!scope.row.isSuspended" type="success">æ¿æ´»</el-tag> |
| | | <el-tag v-else type="danger">æèµ·</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="businessStatusName" label="æµç¨ç¶æ" min-width="70"> |
| | | <template #default="scope"> |
| | | <el-tag type="success">{{ scope.row.businessStatusName }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="startTime" label="å¯å¨æ¶é´" width="160"></el-table-column> |
| | | <el-table-column v-if="tab === 'finish'" align="center" prop="endTime" label="ç»ææ¶é´" width="160"></el-table-column> |
| | | <el-table-column label="æä½" align="center" width="160" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button link type="primary" size="small" icon="Document" @click="handleApprovalRecord(scope.row.id)">审æ¹è®°å½</el-button> |
| | | </el-col> |
| | | <el-col |
| | | v-if="scope.row.businessStatus === 'draft' || scope.row.businessStatus === 'cancel' || scope.row.businessStatus === 'back'" |
| | | :span="1.5" |
| | | > |
| | | <el-button link type="primary" size="small" icon="Delete" @click="handleDelete(scope.row)">å é¤</el-button> |
| | | </el-col> |
| | | <el-col v-if="scope.row.businessStatus === 'waiting'" :span="1.5"> |
| | | <el-button link type="primary" size="small" icon="Notification" @click="handleCancelProcessApply(scope.row.id)">æ¤é</el-button> |
| | | </el-col> |
| | | <el-col |
| | | v-if="scope.row.businessStatus === 'draft' || scope.row.businessStatus === 'cancel' || scope.row.businessStatus === 'back'" |
| | | :span="1.5" |
| | | > |
| | | <el-button link type="primary" size="small" icon="Edit" @click="submitVerifyOpen(scope.row.taskVoList[0].id)">æäº¤</el-button> |
| | | </el-col> |
| | | </el-row> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <pagination |
| | | v-show="total > 0" |
| | | v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" |
| | | :total="total" |
| | | @pagination="getList" |
| | | /> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | <!-- 审æ¹è®°å½ --> |
| | | <approvalRecord ref="approvalRecordRef" /> |
| | | <!-- æäº¤ç»ä»¶ --> |
| | | <submitVerify ref="submitVerifyRef" @submit-callback="getList" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import { getCurrentSubmitByPage, deleteRuntimeProcessAndHisInst, cancelProcessApply } from '@/api/workflow/processInstance'; |
| | | import ApprovalRecord from '@/components/Process/approvalRecord.vue'; |
| | | import SubmitVerify from '@/components/Process/submitVerify.vue'; |
| | | import { listCategory } from '@/api/workflow/category'; |
| | | import { CategoryVO } from '@/api/workflow/category/types'; |
| | | import { ProcessInstanceQuery, ProcessInstanceVO } from '@/api/workflow/processInstance/types'; |
| | | //æäº¤ç»ä»¶ |
| | | const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>(); |
| | | //审æ¹è®°å½ç»ä»¶ |
| | | const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>(); |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | | const categoryTreeRef = ref<ElTreeInstance>(); |
| | | |
| | | // é®ç½©å± |
| | | const loading = ref(true); |
| | | // é䏿°ç» |
| | | const ids = ref<Array<any>>([]); |
| | | // éå个ç¦ç¨ |
| | | const single = ref(true); |
| | | // éå¤ä¸ªç¦ç¨ |
| | | const multiple = ref(true); |
| | | // æ¾ç¤ºæç´¢æ¡ä»¶ |
| | | const showSearch = ref(true); |
| | | // æ»æ¡æ° |
| | | const total = ref(0); |
| | | // 模åå®ä¹è¡¨æ ¼æ°æ® |
| | | const processInstanceList = ref<ProcessInstanceVO[]>([]); |
| | | |
| | | const categoryOptions = ref<CategoryOption[]>([]); |
| | | const categoryName = ref(''); |
| | | |
| | | interface CategoryOption { |
| | | categoryCode: string; |
| | | categoryName: string; |
| | | children?: CategoryOption[]; |
| | | } |
| | | |
| | | const tab = ref('running'); |
| | | // æ¥è¯¢åæ° |
| | | const queryParams = ref<ProcessInstanceQuery>({ |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | name: undefined, |
| | | categoryCode: undefined |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | getTreeselect(); |
| | | }); |
| | | |
| | | /** èç¹åå»äºä»¶ */ |
| | | const handleNodeClick = (data: CategoryVO) => { |
| | | queryParams.value.categoryCode = data.categoryCode; |
| | | if (data.categoryCode === 'ALL') { |
| | | queryParams.value.categoryCode = ''; |
| | | } |
| | | handleQuery(); |
| | | }; |
| | | /** éè¿æ¡ä»¶è¿æ»¤èç¹ */ |
| | | const filterNode = (value: string, data: any) => { |
| | | if (!value) return true; |
| | | return data.categoryName.indexOf(value) !== -1; |
| | | }; |
| | | /** æ ¹æ®åç§°çéé¨é¨æ */ |
| | | watchEffect( |
| | | () => { |
| | | categoryTreeRef.value.filter(categoryName.value); |
| | | }, |
| | | { |
| | | flush: 'post' // watchEffectä¼å¨DOMæè½½æè
æ´æ°ä¹åå°±ä¼è§¦åï¼æ¤å±æ§æ§å¶å¨DOMå
ç´ æ´æ°åè¿è¡ |
| | | } |
| | | ); |
| | | |
| | | /** æ¥è¯¢æµç¨åç±»ä¸ææ ç»æ */ |
| | | const getTreeselect = async () => { |
| | | const res = await listCategory(); |
| | | categoryOptions.value = []; |
| | | const data: CategoryOption = { categoryCode: 'ALL', categoryName: '顶级èç¹', children: [] }; |
| | | data.children = proxy?.handleTree<CategoryOption>(res.data, 'id', 'parentId'); |
| | | categoryOptions.value.push(data); |
| | | }; |
| | | |
| | | //审æ¹è®°å½ |
| | | const handleApprovalRecord = (processInstanceId: string) => { |
| | | if (approvalRecordRef.value) { |
| | | approvalRecordRef.value.init(processInstanceId); |
| | | } |
| | | }; |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | getList(); |
| | | }; |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | queryParams.value.categoryCode = ''; |
| | | queryParams.value.pageNum = 1; |
| | | queryParams.value.pageSize = 10; |
| | | handleQuery(); |
| | | }; |
| | | // å¤éæ¡é䏿°æ® |
| | | const handleSelectionChange = (selection: ProcessInstanceVO[]) => { |
| | | ids.value = selection.map((item: any) => item.id); |
| | | single.value = selection.length !== 1; |
| | | multiple.value = !selection.length; |
| | | }; |
| | | //å页 |
| | | const getList = () => { |
| | | loading.value = true; |
| | | getCurrentSubmitByPage(queryParams.value).then((resp) => { |
| | | processInstanceList.value = resp.rows; |
| | | total.value = resp.total; |
| | | loading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | /** å é¤æé®æä½ */ |
| | | const handleDelete = async (row: ProcessInstanceVO) => { |
| | | const id = row.id || ids.value; |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤å é¤id为ã' + id + 'ãçæ°æ®é¡¹ï¼'); |
| | | loading.value = true; |
| | | if ('running' === tab.value) { |
| | | await deleteRuntimeProcessAndHisInst(id).finally(() => (loading.value = false)); |
| | | getList(); |
| | | } |
| | | proxy?.$modal.msgSuccess('å 餿å'); |
| | | }; |
| | | |
| | | /** æ¤éæé®æä½ */ |
| | | const handleCancelProcessApply = async (processInstanceId: string) => { |
| | | await proxy?.$modal.confirm('æ¯å¦ç¡®è®¤æ¤éå½ååæ®ï¼'); |
| | | loading.value = true; |
| | | if ('running' === tab.value) { |
| | | await cancelProcessApply(processInstanceId).finally(() => (loading.value = false)); |
| | | getList(); |
| | | } |
| | | proxy?.$modal.msgSuccess('æ¤éæå'); |
| | | }; |
| | | //æäº¤ |
| | | const submitVerifyOpen = async (id: string) => { |
| | | if (submitVerifyRef.value) { |
| | | submitVerifyRef.value.openDialog(id); |
| | | } |
| | | }; |
| | | </script> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px"> |
| | | <el-form-item label="ä»»å¡åç§°" prop="name"> |
| | | <el-input v-model="queryParams.name" placeholder="请è¾å
¥ä»»å¡åç§°" @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="æµç¨å®ä¹åç§°" label-width="100" prop="processDefinitionName"> |
| | | <el-input v-model="queryParams.processDefinitionName" placeholder="请è¾å
¥æµç¨å®ä¹åç§°" @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="æµç¨å®ä¹KEY" label-width="100" prop="processDefinitionKey"> |
| | | <el-input v-model="queryParams.processDefinitionKey" placeholder="请è¾å
¥æµç¨å®ä¹KEY" @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">æç´¢</el-button> |
| | | <el-button icon="Refresh" @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </el-card> |
| | | </div> |
| | | </transition> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="handleQuery"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table v-loading="loading" :data="taskList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column fixed align="center" type="index" label="åºå·" width="50"></el-table-column> |
| | | <el-table-column fixed align="center" prop="processDefinitionName" label="æµç¨å®ä¹åç§°"></el-table-column> |
| | | <el-table-column fixed align="center" prop="processDefinitionKey" label="æµç¨å®ä¹KEY"></el-table-column> |
| | | <el-table-column fixed align="center" prop="name" label="ä»»å¡åç§°"></el-table-column> |
| | | <el-table-column fixed align="center" prop="assigneeName" label="åç人"> |
| | | <template #default="scope"> |
| | | <template v-if="scope.row.participantVo && scope.row.assignee === null"> |
| | | <el-tag v-for="(item, index) in scope.row.participantVo.candidateName" :key="index" type="success"> |
| | | {{ item }} |
| | | </el-tag> |
| | | </template> |
| | | <template v-else> |
| | | <el-tag type="success"> |
| | | {{ scope.row.assigneeName }} |
| | | </el-tag> |
| | | </template> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="businessStatusName" label="æµç¨ç¶æ" min-width="70"> |
| | | <template #default="scope"> |
| | | <el-tag type="success">{{ scope.row.businessStatusName }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" align="center" width="160" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" icon="Document" @click="handleApprovalRecord(scope.row)">审æ¹è®°å½</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <pagination |
| | | v-show="total > 0" |
| | | v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" |
| | | :total="total" |
| | | @pagination="handleQuery" |
| | | /> |
| | | </el-card> |
| | | <!-- 审æ¹è®°å½ --> |
| | | <approvalRecord ref="approvalRecordRef" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import { getTaskCopyByPage} from '@/api/workflow/task'; |
| | | import ApprovalRecord from '@/components/Process/approvalRecord.vue'; |
| | | import { TaskQuery, TaskVO } from '@/api/workflow/task/types'; |
| | | //审æ¹è®°å½ç»ä»¶ |
| | | const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>(); |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | // é®ç½©å± |
| | | const loading = ref(true); |
| | | // é䏿°ç» |
| | | const ids = ref<Array<any>>([]); |
| | | // éå个ç¦ç¨ |
| | | const single = ref(true); |
| | | // éå¤ä¸ªç¦ç¨ |
| | | const multiple = ref(true); |
| | | // æ¾ç¤ºæç´¢æ¡ä»¶ |
| | | const showSearch = ref(true); |
| | | // æ»æ¡æ° |
| | | const total = ref(0); |
| | | // 模åå®ä¹è¡¨æ ¼æ°æ® |
| | | const taskList = ref([]); |
| | | // æ¥è¯¢åæ° |
| | | const queryParams = ref<TaskQuery>({ |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | name: undefined, |
| | | processDefinitionName: undefined, |
| | | processDefinitionKey: undefined |
| | | }); |
| | | onMounted(() => { |
| | | getTaskCopyList(); |
| | | }); |
| | | //审æ¹è®°å½ |
| | | const handleApprovalRecord = (row: TaskVO) => { |
| | | if (approvalRecordRef.value) { |
| | | approvalRecordRef.value.init(row.processInstanceId); |
| | | } |
| | | }; |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | getTaskCopyList(); |
| | | }; |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | queryParams.value.pageNum = 1; |
| | | queryParams.value.pageSize = 10; |
| | | handleQuery(); |
| | | }; |
| | | // å¤éæ¡é䏿°æ® |
| | | const handleSelectionChange = (selection: any) => { |
| | | ids.value = selection.map((item: any) => item.id); |
| | | single.value = selection.length !== 1; |
| | | multiple.value = !selection.length; |
| | | }; |
| | | //å页 |
| | | const getTaskCopyList = () => { |
| | | loading.value = true; |
| | | getTaskCopyByPage(queryParams.value).then((resp) => { |
| | | taskList.value = resp.rows; |
| | | total.value = resp.total; |
| | | loading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | </script> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px"> |
| | | <el-form-item label="ä»»å¡åç§°" prop="name"> |
| | | <el-input v-model="queryParams.name" placeholder="请è¾å
¥ä»»å¡åç§°" @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="æµç¨å®ä¹åç§°" label-width="100" prop="processDefinitionName"> |
| | | <el-input v-model="queryParams.processDefinitionName" placeholder="请è¾å
¥æµç¨å®ä¹åç§°" @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="æµç¨å®ä¹KEY" label-width="100" prop="processDefinitionKey"> |
| | | <el-input v-model="queryParams.processDefinitionKey" placeholder="请è¾å
¥æµç¨å®ä¹KEY" @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">æç´¢</el-button> |
| | | <el-button icon="Refresh" @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </el-card> |
| | | </div> |
| | | </transition> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="handleQuery"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table v-loading="loading" :data="taskList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column fixed align="center" type="index" label="åºå·" width="50"></el-table-column> |
| | | <el-table-column fixed align="center" prop="processDefinitionName" label="æµç¨å®ä¹åç§°"></el-table-column> |
| | | <el-table-column fixed align="center" prop="processDefinitionKey" label="æµç¨å®ä¹KEY"></el-table-column> |
| | | <el-table-column fixed align="center" prop="name" label="ä»»å¡åç§°"></el-table-column> |
| | | <el-table-column fixed align="center" prop="assigneeName" label="åç人"> |
| | | <template #default="scope"> |
| | | <el-tag type="success"> |
| | | {{ scope.row.assigneeName }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="createTime" label="å建æ¶é´" width="160"></el-table-column> |
| | | <el-table-column label="æä½" align="center" width="160" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" icon="Document" @click="handleApprovalRecord(scope.row)">审æ¹è®°å½</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <pagination |
| | | v-show="total > 0" |
| | | v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" |
| | | :total="total" |
| | | @pagination="handleQuery" |
| | | /> |
| | | </el-card> |
| | | <!-- 审æ¹è®°å½ --> |
| | | <approvalRecord ref="approvalRecordRef" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import { getTaskFinishByPage } from '@/api/workflow/task'; |
| | | import ApprovalRecord from '@/components/Process/approvalRecord.vue'; |
| | | import { TaskQuery, TaskVO } from '@/api/workflow/task/types'; |
| | | //审æ¹è®°å½ç»ä»¶ |
| | | const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>(); |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | // é®ç½©å± |
| | | const loading = ref(true); |
| | | // é䏿°ç» |
| | | const ids = ref<Array<any>>([]); |
| | | // éå个ç¦ç¨ |
| | | const single = ref(true); |
| | | // éå¤ä¸ªç¦ç¨ |
| | | const multiple = ref(true); |
| | | // æ¾ç¤ºæç´¢æ¡ä»¶ |
| | | const showSearch = ref(true); |
| | | // æ»æ¡æ° |
| | | const total = ref(0); |
| | | // 模åå®ä¹è¡¨æ ¼æ°æ® |
| | | const taskList = ref([]); |
| | | // æ¥è¯¢åæ° |
| | | const queryParams = ref<TaskQuery>({ |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | name: undefined, |
| | | processDefinitionName: undefined, |
| | | processDefinitionKey: undefined |
| | | }); |
| | | onMounted(() => { |
| | | getFinishList(); |
| | | }); |
| | | //审æ¹è®°å½ |
| | | const handleApprovalRecord = (row: TaskVO) => { |
| | | if (approvalRecordRef.value) { |
| | | approvalRecordRef.value.init(row.processInstanceId); |
| | | } |
| | | }; |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | getFinishList(); |
| | | }; |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | queryParams.value.pageNum = 1; |
| | | queryParams.value.pageSize = 10; |
| | | handleQuery(); |
| | | }; |
| | | // å¤éæ¡é䏿°æ® |
| | | const handleSelectionChange = (selection: any) => { |
| | | ids.value = selection.map((item: any) => item.id); |
| | | single.value = selection.length !== 1; |
| | | multiple.value = !selection.length; |
| | | }; |
| | | const getFinishList = () => { |
| | | loading.value = true; |
| | | getTaskFinishByPage(queryParams.value).then((resp) => { |
| | | taskList.value = resp.rows; |
| | | total.value = resp.total; |
| | | loading.value = false; |
| | | }); |
| | | }; |
| | | </script> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="p-2"> |
| | | <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> |
| | | <div v-show="showSearch" class="mb-[10px]"> |
| | | <el-card shadow="hover"> |
| | | <el-form v-show="showSearch" ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px"> |
| | | <el-form-item label="ä»»å¡åç§°" prop="name"> |
| | | <el-input v-model="queryParams.name" placeholder="请è¾å
¥ä»»å¡åç§°" @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="æµç¨å®ä¹åç§°" label-width="100" prop="processDefinitionName"> |
| | | <el-input v-model="queryParams.processDefinitionName" placeholder="请è¾å
¥æµç¨å®ä¹åç§°" @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="æµç¨å®ä¹KEY" label-width="100" prop="processDefinitionKey"> |
| | | <el-input v-model="queryParams.processDefinitionKey" placeholder="请è¾å
¥æµç¨å®ä¹KEY" @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">æç´¢</el-button> |
| | | <el-button icon="Refresh" @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </el-card> |
| | | </div> |
| | | </transition> |
| | | <el-card shadow="hover"> |
| | | <template #header> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <right-toolbar v-model:showSearch="showSearch" @query-table="handleQuery"></right-toolbar> |
| | | </el-row> |
| | | </template> |
| | | |
| | | <el-table v-loading="loading" :data="taskList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column fixed align="center" type="index" label="åºå·" width="50"></el-table-column> |
| | | <el-table-column fixed align="center" prop="processDefinitionName" label="æµç¨å®ä¹åç§°"></el-table-column> |
| | | <el-table-column fixed align="center" prop="processDefinitionKey" label="æµç¨å®ä¹KEY"></el-table-column> |
| | | <el-table-column fixed align="center" prop="name" label="ä»»å¡åç§°"></el-table-column> |
| | | <el-table-column fixed align="center" prop="assigneeName" label="åç人"> |
| | | <template #default="scope"> |
| | | <template v-if="scope.row.participantVo && scope.row.assignee === null"> |
| | | <el-tag v-for="(item, index) in scope.row.participantVo.candidateName" :key="index" type="success"> |
| | | {{ item }} |
| | | </el-tag> |
| | | </template> |
| | | <template v-else> |
| | | <el-tag type="success"> |
| | | {{ scope.row.assigneeName }} |
| | | </el-tag> |
| | | </template> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="businessStatusName" label="æµç¨ç¶æ" min-width="70"> |
| | | <template #default="scope"> |
| | | <el-tag type="success">{{ scope.row.businessStatusName }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" prop="createTime" label="å建æ¶é´" width="160"></el-table-column> |
| | | <el-table-column label="æä½" align="center" width="160" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button link type="primary" size="small" icon="Document" @click="handleApprovalRecord(scope.row)">审æ¹è®°å½</el-button> |
| | | </el-col> |
| | | <el-col v-if="scope.row.participantVo && (scope.row.participantVo.claim === null || scope.row.participantVo.claim === true)" :span="1.5"> |
| | | <el-button link type="primary" size="small" icon="Edit" @click="submitVerifyOpen(scope.row.id)">åç</el-button> |
| | | </el-col> |
| | | <el-col v-if="scope.row.participantVo && scope.row.participantVo.claim === true" :span="1.5"> |
| | | <el-button link type="primary" size="small" icon="Document" @click="handleReturnTask(scope.row.id)">å½è¿</el-button> |
| | | </el-col> |
| | | <el-col v-if="scope.row.participantVo && scope.row.participantVo.claim === false" :span="1.5"> |
| | | <el-button link type="primary" size="small" icon="Document" @click="handleClaimTask(scope.row.id)">认é¢</el-button> |
| | | </el-col> |
| | | </el-row> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <pagination |
| | | v-show="total > 0" |
| | | v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" |
| | | :total="total" |
| | | @pagination="handleQuery" |
| | | /> |
| | | </el-card> |
| | | <!-- 审æ¹è®°å½ --> |
| | | <approvalRecord ref="approvalRecordRef" /> |
| | | <!-- æäº¤ç»ä»¶ --> |
| | | <submitVerify ref="submitVerifyRef" @submit-callback="handleQuery" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import { getTaskWaitByPage, claim, returnTask } from '@/api/workflow/task'; |
| | | import ApprovalRecord from '@/components/Process/approvalRecord.vue'; |
| | | import SubmitVerify from '@/components/Process/submitVerify.vue'; |
| | | import { TaskQuery, TaskVO } from '@/api/workflow/task/types'; |
| | | //æäº¤ç»ä»¶ |
| | | const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>(); |
| | | //审æ¹è®°å½ç»ä»¶ |
| | | const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>(); |
| | | const queryFormRef = ref<ElFormInstance>(); |
| | | const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
| | | // é®ç½©å± |
| | | const loading = ref(true); |
| | | // é䏿°ç» |
| | | const ids = ref<Array<any>>([]); |
| | | // éå个ç¦ç¨ |
| | | const single = ref(true); |
| | | // éå¤ä¸ªç¦ç¨ |
| | | const multiple = ref(true); |
| | | // æ¾ç¤ºæç´¢æ¡ä»¶ |
| | | const showSearch = ref(true); |
| | | // æ»æ¡æ° |
| | | const total = ref(0); |
| | | // 模åå®ä¹è¡¨æ ¼æ°æ® |
| | | const taskList = ref([]); |
| | | // æ¥è¯¢åæ° |
| | | const queryParams = ref<TaskQuery>({ |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | name: undefined, |
| | | processDefinitionName: undefined, |
| | | processDefinitionKey: undefined |
| | | }); |
| | | onMounted(() => { |
| | | getWaitingList(); |
| | | }); |
| | | //审æ¹è®°å½ |
| | | const handleApprovalRecord = (row: TaskVO) => { |
| | | if (approvalRecordRef.value) { |
| | | approvalRecordRef.value.init(row.processInstanceId); |
| | | } |
| | | }; |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | getWaitingList(); |
| | | }; |
| | | /** éç½®æé®æä½ */ |
| | | const resetQuery = () => { |
| | | queryFormRef.value?.resetFields(); |
| | | queryParams.value.pageNum = 1; |
| | | queryParams.value.pageSize = 10; |
| | | handleQuery(); |
| | | }; |
| | | // å¤éæ¡é䏿°æ® |
| | | const handleSelectionChange = (selection: any) => { |
| | | ids.value = selection.map((item: any) => item.id); |
| | | single.value = selection.length !== 1; |
| | | multiple.value = !selection.length; |
| | | }; |
| | | //å页 |
| | | const getWaitingList = () => { |
| | | loading.value = true; |
| | | getTaskWaitByPage(queryParams.value).then((resp) => { |
| | | taskList.value = resp.rows; |
| | | total.value = resp.total; |
| | | loading.value = false; |
| | | }); |
| | | }; |
| | | //æäº¤ |
| | | const submitVerifyOpen = async (id: string) => { |
| | | if (submitVerifyRef.value) { |
| | | submitVerifyRef.value.openDialog(id); |
| | | } |
| | | }; |
| | | |
| | | /** 认é¢ä»»å¡ */ |
| | | const handleClaimTask = async (taskId: string) => { |
| | | loading.value = true; |
| | | await claim(taskId).finally(() => (loading.value = false)); |
| | | getWaitingList(); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | }; |
| | | |
| | | /** å½è¿ä»»å¡ */ |
| | | const handleReturnTask = async (taskId: string) => { |
| | | loading.value = true; |
| | | await returnTask(taskId).finally(() => (loading.value = false)); |
| | | getWaitingList(); |
| | | proxy?.$modal.msgSuccess('æä½æå'); |
| | | }; |
| | | </script> |
| | |
| | | 'echarts', |
| | | 'vue-i18n', |
| | | '@vueup/vue-quill', |
| | | 'bpmn-js/lib/Modeler.js', |
| | | 'bpmn-js-properties-panel', |
| | | 'min-dash', |
| | | 'bpmn-js/lib/features/palette/PaletteProvider', |
| | | 'bpmn-js/lib/features/context-pad/ContextPadProvider', |
| | | 'diagram-js/lib/draw/BaseRenderer', |
| | | 'tiny-svg', |
| | | |
| | | 'element-plus/es/components/collapse-item/style/css', |
| | | 'element-plus/es/components/collapse/style/css', |
| | | 'element-plus/es/components/space/style/css', |
| | | 'element-plus/es/components/container/style/css', |
| | | 'element-plus/es/components/aside/style/css', |
| | | 'element-plus/es/components/main/style/css', |
| | | 'element-plus/es/components/header/style/css', |
| | | 'element-plus/es/components/button-group/style/css', |
| | | 'element-plus/es/components/radio-button/style/css', |
| | | 'element-plus/es/components/checkbox-group/style/css', |
| | | 'element-plus/es/components/form/style/css', |
| | | 'element-plus/es/components/form-item/style/css', |
| | | 'element-plus/es/components/button/style/css', |