88 changed files with 14 additions and 11563 deletions
@ -1,12 +0,0 @@ |
|||||
@echo off |
|
||||
echo. |
|
||||
echo [信息] 打包Web工程,生成dist文件。 |
|
||||
echo. |
|
||||
|
|
||||
%~d0 |
|
||||
cd %~dp0 |
|
||||
|
|
||||
cd .. |
|
||||
yarn build:prod |
|
||||
|
|
||||
pause |
|
||||
@ -1,12 +0,0 @@ |
|||||
@echo off |
|
||||
echo. |
|
||||
echo [信息] 安装Web工程,生成node_modules文件。 |
|
||||
echo. |
|
||||
|
|
||||
%~d0 |
|
||||
cd %~dp0 |
|
||||
|
|
||||
cd .. |
|
||||
yarn --registry=https://registry.npmmirror.com |
|
||||
|
|
||||
pause |
|
||||
@ -1,12 +0,0 @@ |
|||||
@echo off |
|
||||
echo. |
|
||||
echo [信息] 使用 Vite 命令运行 Web 工程。 |
|
||||
echo. |
|
||||
|
|
||||
%~d0 |
|
||||
cd %~dp0 |
|
||||
|
|
||||
cd .. |
|
||||
yarn dev |
|
||||
|
|
||||
pause |
|
||||
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 34 KiB |
@ -1,62 +0,0 @@ |
|||||
import request from '@/utils/request'; |
|
||||
import { AxiosPromise } from 'axios'; |
|
||||
import { DemoVO, DemoForm, DemoQuery } from '@/api/demo/demo/types'; |
|
||||
|
|
||||
/** |
|
||||
* 查询测试单列表 |
|
||||
* @param query |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
export const listDemo = (query?: DemoQuery): AxiosPromise<DemoVO[]> => { |
|
||||
return request({ |
|
||||
url: '/demo/demo/list', |
|
||||
method: 'get', |
|
||||
params: query |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 查询测试单详细 |
|
||||
* @param id |
|
||||
*/ |
|
||||
export const getDemo = (id: string | number): AxiosPromise<DemoVO> => { |
|
||||
return request({ |
|
||||
url: '/demo/demo/' + id, |
|
||||
method: 'get' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 新增测试单 |
|
||||
* @param data |
|
||||
*/ |
|
||||
export const addDemo = (data: DemoForm) => { |
|
||||
return request({ |
|
||||
url: '/demo/demo', |
|
||||
method: 'post', |
|
||||
data: data |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 修改测试单 |
|
||||
* @param data |
|
||||
*/ |
|
||||
export const updateDemo = (data: DemoForm) => { |
|
||||
return request({ |
|
||||
url: '/demo/demo', |
|
||||
method: 'put', |
|
||||
data: data |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 删除测试单 |
|
||||
* @param id |
|
||||
*/ |
|
||||
export const delDemo = (id: string | number | Array<string | number>) => { |
|
||||
return request({ |
|
||||
url: '/demo/demo/' + id, |
|
||||
method: 'delete' |
|
||||
}); |
|
||||
}; |
|
||||
@ -1,90 +0,0 @@ |
|||||
export interface DemoVO { |
|
||||
/** |
|
||||
* 主键 |
|
||||
*/ |
|
||||
id: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 部门id |
|
||||
*/ |
|
||||
deptId: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 用户id |
|
||||
*/ |
|
||||
userId: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 排序号 |
|
||||
*/ |
|
||||
orderNum: number; |
|
||||
|
|
||||
/** |
|
||||
* key键 |
|
||||
*/ |
|
||||
testKey: string; |
|
||||
|
|
||||
/** |
|
||||
* 值 |
|
||||
*/ |
|
||||
value: string; |
|
||||
} |
|
||||
|
|
||||
export interface DemoForm extends BaseEntity { |
|
||||
/** |
|
||||
* 主键 |
|
||||
*/ |
|
||||
id?: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 部门id |
|
||||
*/ |
|
||||
deptId?: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 用户id |
|
||||
*/ |
|
||||
userId?: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 排序号 |
|
||||
*/ |
|
||||
orderNum?: number; |
|
||||
|
|
||||
/** |
|
||||
* key键 |
|
||||
*/ |
|
||||
testKey?: string; |
|
||||
|
|
||||
/** |
|
||||
* 值 |
|
||||
*/ |
|
||||
value?: string; |
|
||||
} |
|
||||
|
|
||||
export interface DemoQuery extends PageQuery { |
|
||||
/** |
|
||||
* 部门id |
|
||||
*/ |
|
||||
deptId?: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 用户id |
|
||||
*/ |
|
||||
userId?: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 排序号 |
|
||||
*/ |
|
||||
orderNum?: number; |
|
||||
|
|
||||
/** |
|
||||
* key键 |
|
||||
*/ |
|
||||
testKey?: string; |
|
||||
|
|
||||
/** |
|
||||
* 值 |
|
||||
*/ |
|
||||
value?: string; |
|
||||
} |
|
||||
@ -1,62 +0,0 @@ |
|||||
import request from '@/utils/request'; |
|
||||
import { AxiosPromise } from 'axios'; |
|
||||
import { TreeVO, TreeForm, TreeQuery } from '@/api/demo/tree/types'; |
|
||||
|
|
||||
/** |
|
||||
* 查询测试树列表 |
|
||||
* @param query |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
export const listTree = (query?: TreeQuery): AxiosPromise<TreeVO[]> => { |
|
||||
return request({ |
|
||||
url: '/demo/tree/list', |
|
||||
method: 'get', |
|
||||
params: query |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 查询测试树详细 |
|
||||
* @param id |
|
||||
*/ |
|
||||
export const getTree = (id: string | number): AxiosPromise<TreeVO> => { |
|
||||
return request({ |
|
||||
url: '/demo/tree/' + id, |
|
||||
method: 'get' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 新增测试树 |
|
||||
* @param data |
|
||||
*/ |
|
||||
export const addTree = (data: TreeForm) => { |
|
||||
return request({ |
|
||||
url: '/demo/tree', |
|
||||
method: 'post', |
|
||||
data: data |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 修改测试树 |
|
||||
* @param data |
|
||||
*/ |
|
||||
export const updateTree = (data: TreeForm) => { |
|
||||
return request({ |
|
||||
url: '/demo/tree', |
|
||||
method: 'put', |
|
||||
data: data |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 删除测试树 |
|
||||
* @param id |
|
||||
*/ |
|
||||
export const delTree = (id: string | number | Array<string | number>) => { |
|
||||
return request({ |
|
||||
url: '/demo/tree/' + id, |
|
||||
method: 'delete' |
|
||||
}); |
|
||||
}; |
|
||||
@ -1,80 +0,0 @@ |
|||||
export interface TreeVO { |
|
||||
/** |
|
||||
* 主键 |
|
||||
*/ |
|
||||
id: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 父id |
|
||||
*/ |
|
||||
parentId: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 部门id |
|
||||
*/ |
|
||||
deptId: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 用户id |
|
||||
*/ |
|
||||
userId: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 值 |
|
||||
*/ |
|
||||
treeName: string; |
|
||||
|
|
||||
/** |
|
||||
* 子对象 |
|
||||
*/ |
|
||||
children: TreeVO[]; |
|
||||
} |
|
||||
|
|
||||
export interface TreeForm extends BaseEntity { |
|
||||
/** |
|
||||
* 主键 |
|
||||
*/ |
|
||||
id?: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 父id |
|
||||
*/ |
|
||||
parentId?: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 部门id |
|
||||
*/ |
|
||||
deptId?: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 用户id |
|
||||
*/ |
|
||||
userId?: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 值 |
|
||||
*/ |
|
||||
treeName?: string; |
|
||||
} |
|
||||
|
|
||||
export interface TreeQuery { |
|
||||
/** |
|
||||
* 父id |
|
||||
*/ |
|
||||
parentId?: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 部门id |
|
||||
*/ |
|
||||
deptId?: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 用户id |
|
||||
*/ |
|
||||
userId?: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 值 |
|
||||
*/ |
|
||||
treeName?: string; |
|
||||
} |
|
||||
@ -1,63 +0,0 @@ |
|||||
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' |
|
||||
}); |
|
||||
}; |
|
||||
@ -1,67 +0,0 @@ |
|||||
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; |
|
||||
} |
|
||||
@ -1,49 +0,0 @@ |
|||||
import request from '@/utils/request'; |
|
||||
import { AxiosPromise } from 'axios'; |
|
||||
import { DefinitionConfigVO, DefinitionConfigForm } from '@/api/workflow/definitionConfig/types'; |
|
||||
|
|
||||
/** |
|
||||
* 查询表单配置详细 |
|
||||
* @param definitionId |
|
||||
*/ |
|
||||
export const getByDefId = (definitionId: string | number): AxiosPromise<DefinitionConfigVO> => { |
|
||||
return request({ |
|
||||
url: '/workflow/definitionConfig/getByDefId/' + definitionId, |
|
||||
method: 'get' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 新增表单配置 |
|
||||
* @param data |
|
||||
*/ |
|
||||
export const saveOrUpdate = (data: DefinitionConfigForm) => { |
|
||||
return request({ |
|
||||
url: '/workflow/definitionConfig/saveOrUpdate', |
|
||||
method: 'post', |
|
||||
data: data |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 删除表单配置 |
|
||||
* @param id |
|
||||
*/ |
|
||||
export const deldefinitionConfig = (id: string | number | Array<string | number>) => { |
|
||||
return request({ |
|
||||
url: '/workflow/definitionConfig/' + id, |
|
||||
method: 'delete' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 查询流程定义配置排除当前查询的流程定义 |
|
||||
* @param tableName |
|
||||
* @param definitionId |
|
||||
*/ |
|
||||
export const getByTableNameNotDefId = (tableName: string, definitionId: string | number) => { |
|
||||
return request({ |
|
||||
url: `/workflow/definitionConfig/getByTableNameNotDefId/${tableName}/${definitionId}`, |
|
||||
method: 'get' |
|
||||
}); |
|
||||
}; |
|
||||
@ -1,102 +0,0 @@ |
|||||
import { FormManageVO } from '@/api/workflow/formManage/types'; |
|
||||
|
|
||||
export interface DefinitionConfigVO { |
|
||||
/** |
|
||||
* 主键 |
|
||||
*/ |
|
||||
id: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 表名 |
|
||||
*/ |
|
||||
tableName?: string; |
|
||||
|
|
||||
/** |
|
||||
* 流程定义ID |
|
||||
*/ |
|
||||
definitionId: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 流程KEY |
|
||||
*/ |
|
||||
processKey: string; |
|
||||
|
|
||||
/** |
|
||||
* 流程版本 |
|
||||
*/ |
|
||||
version?: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 备注 |
|
||||
*/ |
|
||||
remark: string; |
|
||||
|
|
||||
/** |
|
||||
* 表单管理 |
|
||||
*/ |
|
||||
wfFormManageVo: FormManageVO; |
|
||||
} |
|
||||
|
|
||||
export interface DefinitionConfigForm extends BaseEntity { |
|
||||
/** |
|
||||
* 主键 |
|
||||
*/ |
|
||||
id?: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 表名 |
|
||||
*/ |
|
||||
tableName?: string; |
|
||||
|
|
||||
/** |
|
||||
* 流程定义ID |
|
||||
*/ |
|
||||
definitionId?: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 流程KEY |
|
||||
*/ |
|
||||
processKey?: string; |
|
||||
|
|
||||
/** |
|
||||
* 流程版本 |
|
||||
*/ |
|
||||
version?: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 备注 |
|
||||
*/ |
|
||||
remark?: string; |
|
||||
|
|
||||
/** |
|
||||
* 表单管理 |
|
||||
*/ |
|
||||
wfFormManageVo?: FormManageVO; |
|
||||
} |
|
||||
|
|
||||
export interface DefinitionConfigQuery extends PageQuery { |
|
||||
/** |
|
||||
* 表名 |
|
||||
*/ |
|
||||
tableName?: string; |
|
||||
|
|
||||
/** |
|
||||
* 流程定义ID |
|
||||
*/ |
|
||||
definitionId?: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 流程KEY |
|
||||
*/ |
|
||||
processKey?: string; |
|
||||
|
|
||||
/** |
|
||||
* 流程版本 |
|
||||
*/ |
|
||||
version?: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 表单管理 |
|
||||
*/ |
|
||||
wfFormManageVo: FormManageVO; |
|
||||
} |
|
||||
@ -1,76 +0,0 @@ |
|||||
import request from '@/utils/request'; |
|
||||
import { AxiosPromise } from 'axios'; |
|
||||
import { FormManageVO, FormManageForm, FormManageQuery } from '@/api/workflow/formManage/types'; |
|
||||
|
|
||||
/** |
|
||||
* 查询表单管理列表 |
|
||||
* @param query |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
|
|
||||
export const listFormManage = (query?: FormManageQuery): AxiosPromise<FormManageVO[]> => { |
|
||||
return request({ |
|
||||
url: '/workflow/formManage/list', |
|
||||
method: 'get', |
|
||||
params: query |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 查询表单管理列表 |
|
||||
* @param query |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
|
|
||||
export const selectListFormManage = (): AxiosPromise<FormManageVO[]> => { |
|
||||
return request({ |
|
||||
url: '/workflow/formManage/list/selectList', |
|
||||
method: 'get' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 查询表单管理详细 |
|
||||
* @param id |
|
||||
*/ |
|
||||
export const getFormManage = (id: string | number): AxiosPromise<FormManageVO> => { |
|
||||
return request({ |
|
||||
url: '/workflow/formManage/' + id, |
|
||||
method: 'get' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 新增表单管理 |
|
||||
* @param data |
|
||||
*/ |
|
||||
export const addFormManage = (data: FormManageForm) => { |
|
||||
return request({ |
|
||||
url: '/workflow/formManage', |
|
||||
method: 'post', |
|
||||
data: data |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 修改表单管理 |
|
||||
* @param data |
|
||||
*/ |
|
||||
export const updateFormManage = (data: FormManageForm) => { |
|
||||
return request({ |
|
||||
url: '/workflow/formManage', |
|
||||
method: 'put', |
|
||||
data: data |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 删除表单管理 |
|
||||
* @param id |
|
||||
*/ |
|
||||
export const delFormManage = (id: string | number | Array<string | number>) => { |
|
||||
return request({ |
|
||||
url: '/workflow/formManage/' + id, |
|
||||
method: 'delete' |
|
||||
}); |
|
||||
}; |
|
||||
@ -1,69 +0,0 @@ |
|||||
export interface FormManageVO { |
|
||||
/** |
|
||||
* 主键 |
|
||||
*/ |
|
||||
id: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 表单名称 |
|
||||
*/ |
|
||||
formName: string; |
|
||||
|
|
||||
/** |
|
||||
* 表单类型 |
|
||||
*/ |
|
||||
formType: string; |
|
||||
/** |
|
||||
* 表单类型名称 |
|
||||
*/ |
|
||||
formTypeName: string; |
|
||||
|
|
||||
/** |
|
||||
* 路由地址/表单ID |
|
||||
*/ |
|
||||
router: string; |
|
||||
|
|
||||
/** |
|
||||
* 备注 |
|
||||
*/ |
|
||||
remark: string; |
|
||||
} |
|
||||
|
|
||||
export interface FormManageForm extends BaseEntity { |
|
||||
/** |
|
||||
* 主键 |
|
||||
*/ |
|
||||
id?: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 表单名称 |
|
||||
*/ |
|
||||
formName?: string; |
|
||||
|
|
||||
/** |
|
||||
* 表单类型 |
|
||||
*/ |
|
||||
formType?: string; |
|
||||
|
|
||||
/** |
|
||||
* 路由地址/表单ID |
|
||||
*/ |
|
||||
router?: string; |
|
||||
|
|
||||
/** |
|
||||
* 备注 |
|
||||
*/ |
|
||||
remark?: string; |
|
||||
} |
|
||||
|
|
||||
export interface FormManageQuery extends PageQuery { |
|
||||
/** |
|
||||
* 表单名称 |
|
||||
*/ |
|
||||
formName?: string; |
|
||||
|
|
||||
/** |
|
||||
* 表单类型 |
|
||||
*/ |
|
||||
formType?: string; |
|
||||
} |
|
||||
@ -1,63 +0,0 @@ |
|||||
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: '/workflow/leave/list', |
|
||||
method: 'get', |
|
||||
params: query |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 查询请假详细 |
|
||||
* @param id |
|
||||
*/ |
|
||||
export const getLeave = (id: string | number): AxiosPromise<LeaveVO> => { |
|
||||
return request({ |
|
||||
url: '/workflow/leave/' + id, |
|
||||
method: 'get' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 新增请假 |
|
||||
* @param data |
|
||||
*/ |
|
||||
export const addLeave = (data: LeaveForm): AxiosPromise<LeaveVO> => { |
|
||||
return request({ |
|
||||
url: '/workflow/leave', |
|
||||
method: 'post', |
|
||||
data: data |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 修改请假 |
|
||||
* @param data |
|
||||
*/ |
|
||||
export const updateLeave = (data: LeaveForm): AxiosPromise<LeaveVO> => { |
|
||||
return request({ |
|
||||
url: '/workflow/leave', |
|
||||
method: 'put', |
|
||||
data: data |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 删除请假 |
|
||||
* @param id |
|
||||
*/ |
|
||||
export const delLeave = (id: string | number | Array<string | number>) => { |
|
||||
return request({ |
|
||||
url: '/workflow/leave/' + id, |
|
||||
method: 'delete' |
|
||||
}); |
|
||||
}; |
|
||||
@ -1,24 +0,0 @@ |
|||||
export interface LeaveVO { |
|
||||
id: string | number; |
|
||||
leaveType: string; |
|
||||
startDate: string; |
|
||||
endDate: string; |
|
||||
leaveDays: number; |
|
||||
remark: string; |
|
||||
status?: string; |
|
||||
} |
|
||||
|
|
||||
export interface LeaveForm extends BaseEntity { |
|
||||
id?: string | number; |
|
||||
leaveType?: string; |
|
||||
startDate?: string; |
|
||||
endDate?: string; |
|
||||
leaveDays?: number; |
|
||||
remark?: string; |
|
||||
status?: string; |
|
||||
} |
|
||||
|
|
||||
export interface LeaveQuery extends PageQuery { |
|
||||
startLeaveDays?: number; |
|
||||
endLeaveDays?: number; |
|
||||
} |
|
||||
@ -1,104 +0,0 @@ |
|||||
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' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 复制模型 |
|
||||
* @param data |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
export const copyModel = (data: ModelForm): AxiosPromise<void> => { |
|
||||
return request({ |
|
||||
url: '/workflow/model/copyModel', |
|
||||
method: 'post', |
|
||||
data: data |
|
||||
}); |
|
||||
}; |
|
||||
@ -1,66 +0,0 @@ |
|||||
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; |
|
||||
} |
|
||||
@ -1,38 +0,0 @@ |
|||||
import { FormManageVO } from '@/api/workflow/formManage/types'; |
|
||||
|
|
||||
export interface NodeConfigVO { |
|
||||
/** |
|
||||
* 主键 |
|
||||
*/ |
|
||||
id: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 表单id |
|
||||
*/ |
|
||||
formId: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 表单类型 |
|
||||
*/ |
|
||||
formType: string; |
|
||||
|
|
||||
/** |
|
||||
* 节点名称 |
|
||||
*/ |
|
||||
nodeName: string; |
|
||||
|
|
||||
/** |
|
||||
* 节点id |
|
||||
*/ |
|
||||
nodeId: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 流程定义id |
|
||||
*/ |
|
||||
definitionId: string | number; |
|
||||
|
|
||||
/** |
|
||||
* 表单管理 |
|
||||
*/ |
|
||||
wfFormManageVo: FormManageVO; |
|
||||
} |
|
||||
@ -1,114 +0,0 @@ |
|||||
import request from '@/utils/request'; |
|
||||
import { ProcessDefinitionQuery, ProcessDefinitionVO, definitionXmlVO } from '@/api/workflow/processDefinition/types'; |
|
||||
import { AxiosPromise } from 'axios'; |
|
||||
|
|
||||
/** |
|
||||
* 获取流程定义列表 |
|
||||
* @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 getListByKey = (key: string) => { |
|
||||
return request({ |
|
||||
url: `/workflow/processDefinition/getListByKey/${key}`, |
|
||||
method: 'get' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 通过流程定义id获取流程图 |
|
||||
*/ |
|
||||
export const definitionImage = (processDefinitionId: string): AxiosPromise<any> => { |
|
||||
return request({ |
|
||||
url: `/workflow/processDefinition/definitionImage/${processDefinitionId}` + '?t' + Math.random(), |
|
||||
method: 'get' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 通过流程定义id获取xml |
|
||||
* @param processDefinitionId 流程定义id |
|
||||
* @returns |
|
||||
*/ |
|
||||
export const definitionXml = (processDefinitionId: string): AxiosPromise<definitionXmlVO> => { |
|
||||
return request({ |
|
||||
url: `/workflow/processDefinition/definitionXml/${processDefinitionId}`, |
|
||||
method: 'get' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 删除流程定义 |
|
||||
* @param deploymentId 部署id |
|
||||
* @param processDefinitionId 流程定义id |
|
||||
* @returns |
|
||||
*/ |
|
||||
export const deleteProcessDefinition = (deploymentId: string | string[], processDefinitionId: string | string[]) => { |
|
||||
return request({ |
|
||||
url: `/workflow/processDefinition/${deploymentId}/${processDefinitionId}`, |
|
||||
method: 'delete' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 挂起/激活 |
|
||||
* @param processDefinitionId 流程定义id |
|
||||
* @returns |
|
||||
*/ |
|
||||
export const updateDefinitionState = (processDefinitionId: string) => { |
|
||||
return request({ |
|
||||
url: `/workflow/processDefinition/updateDefinitionState/${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, |
|
||||
headers: { |
|
||||
repeatSubmit: false |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 迁移流程 |
|
||||
* @param currentProcessDefinitionId |
|
||||
* @param fromProcessDefinitionId |
|
||||
* @returns |
|
||||
*/ |
|
||||
export const migrationDefinition = (currentProcessDefinitionId: string, fromProcessDefinitionId: string) => { |
|
||||
return request({ |
|
||||
url: `/workflow/processDefinition/migrationDefinition/${currentProcessDefinitionId}/${fromProcessDefinitionId}`, |
|
||||
method: 'put' |
|
||||
}); |
|
||||
}; |
|
||||
@ -1,24 +0,0 @@ |
|||||
import { DefinitionConfigVO } from '@/api/workflow/definitionConfig/types'; |
|
||||
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; |
|
||||
wfDefinitionConfigVo: DefinitionConfigVO; |
|
||||
} |
|
||||
|
|
||||
export interface definitionXmlVO { |
|
||||
xml: string[]; |
|
||||
xmlStr: string; |
|
||||
} |
|
||||
@ -1,136 +0,0 @@ |
|||||
import request from '@/utils/request'; |
|
||||
import { ProcessInstanceQuery, ProcessInstanceVO } from '@/api/workflow/processInstance/types'; |
|
||||
import { AxiosPromise } from 'axios'; |
|
||||
|
|
||||
/** |
|
||||
* 查询运行中实例列表 |
|
||||
* @param query |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
export const getPageByRunning = (query: ProcessInstanceQuery): AxiosPromise<ProcessInstanceVO[]> => { |
|
||||
return request({ |
|
||||
url: '/workflow/processInstance/getPageByRunning', |
|
||||
method: 'get', |
|
||||
params: query |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 查询已完成实例列表 |
|
||||
* @param query |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
export const getPageByFinish = (query: ProcessInstanceQuery): AxiosPromise<ProcessInstanceVO[]> => { |
|
||||
return request({ |
|
||||
url: '/workflow/processInstance/getPageByFinish', |
|
||||
method: 'get', |
|
||||
params: query |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 通过业务id获取历史流程图 |
|
||||
*/ |
|
||||
export const getHistoryImage = (businessKey: string) => { |
|
||||
return request({ |
|
||||
url: `/workflow/processInstance/getHistoryImage/${businessKey}` + '?t' + Math.random(), |
|
||||
method: 'get' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 通过业务id获取历史流程图运行中,历史等节点 |
|
||||
*/ |
|
||||
export const getHistoryList = (businessKey: string): AxiosPromise<Record<string, any>> => { |
|
||||
return request({ |
|
||||
url: `/workflow/processInstance/getHistoryList/${businessKey}` + '?t' + Math.random(), |
|
||||
method: 'get' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 获取审批记录 |
|
||||
* @param businessKey 业务id |
|
||||
* @returns |
|
||||
*/ |
|
||||
export const getHistoryRecord = (businessKey: string | number) => { |
|
||||
return request({ |
|
||||
url: `/workflow/processInstance/getHistoryRecord/${businessKey}`, |
|
||||
method: 'get' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 作废 |
|
||||
* @param data 参数 |
|
||||
* @returns |
|
||||
*/ |
|
||||
export const deleteRunInstance = (data: object) => { |
|
||||
return request({ |
|
||||
url: `/workflow/processInstance/deleteRunInstance`, |
|
||||
method: 'post', |
|
||||
data: data |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 运行中的实例 删除程实例,删除历史记录,删除业务与流程关联信息 |
|
||||
* @param businessKey 业务id |
|
||||
* @returns |
|
||||
*/ |
|
||||
export const deleteRunAndHisInstance = (businessKey: string | string[]) => { |
|
||||
return request({ |
|
||||
url: `/workflow/processInstance/deleteRunAndHisInstance/${businessKey}`, |
|
||||
method: 'delete' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 已完成的实例 删除程实例,删除历史记录,删除业务与流程关联信息 |
|
||||
* @param businessKey 业务id |
|
||||
* @returns |
|
||||
*/ |
|
||||
export const deleteFinishAndHisInstance = (businessKey: string | string[]) => { |
|
||||
return request({ |
|
||||
url: `/workflow/processInstance/deleteFinishAndHisInstance/${businessKey}`, |
|
||||
method: 'delete' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 分页查询当前登录人单据 |
|
||||
* @param query |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
export const getPageByCurrent = (query: ProcessInstanceQuery): AxiosPromise<ProcessInstanceVO[]> => { |
|
||||
return request({ |
|
||||
url: '/workflow/processInstance/getPageByCurrent', |
|
||||
method: 'get', |
|
||||
params: query |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 撤销流程 |
|
||||
* @param businessKey 业务id |
|
||||
* @returns |
|
||||
*/ |
|
||||
export const cancelProcessApply = (businessKey: string) => { |
|
||||
return request({ |
|
||||
url: `/workflow/processInstance/cancelProcessApply/${businessKey}`, |
|
||||
method: 'post' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
export default { |
|
||||
getPageByRunning, |
|
||||
getPageByFinish, |
|
||||
getHistoryImage, |
|
||||
getHistoryList, |
|
||||
getHistoryRecord, |
|
||||
deleteRunInstance, |
|
||||
deleteRunAndHisInstance, |
|
||||
deleteFinishAndHisInstance, |
|
||||
getPageByCurrent, |
|
||||
cancelProcessApply |
|
||||
}; |
|
||||
@ -1,27 +0,0 @@ |
|||||
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[]; |
|
||||
} |
|
||||
@ -1,264 +0,0 @@ |
|||||
import request from '@/utils/request'; |
|
||||
import { AxiosPromise } from 'axios'; |
|
||||
import { TaskQuery, TaskVO } from '@/api/workflow/task/types'; |
|
||||
|
|
||||
/** |
|
||||
* 查询待办列表 |
|
||||
* @param query |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
export const getPageByTaskWait = (query: TaskQuery): AxiosPromise<TaskVO[]> => { |
|
||||
return request({ |
|
||||
url: '/workflow/task/getPageByTaskWait', |
|
||||
method: 'get', |
|
||||
params: query |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 查询已办列表 |
|
||||
* @param query |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
export const getPageByTaskFinish = (query: TaskQuery): AxiosPromise<TaskVO[]> => { |
|
||||
return request({ |
|
||||
url: '/workflow/task/getPageByTaskFinish', |
|
||||
method: 'get', |
|
||||
params: query |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 查询当前用户的抄送列表 |
|
||||
* @param query |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
export const getPageByTaskCopy = (query: TaskQuery): AxiosPromise<TaskVO[]> => { |
|
||||
return request({ |
|
||||
url: '/workflow/task/getPageByTaskCopy', |
|
||||
method: 'get', |
|
||||
params: query |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 当前租户所有待办任务 |
|
||||
* @param query |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
export const getPageByAllTaskWait = (query: TaskQuery): AxiosPromise<TaskVO[]> => { |
|
||||
return request({ |
|
||||
url: '/workflow/task/getPageByAllTaskWait', |
|
||||
method: 'get', |
|
||||
params: query |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 当前租户所有已办任务 |
|
||||
* @param query |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
export const getPageByAllTaskFinish = (query: TaskQuery): AxiosPromise<TaskVO[]> => { |
|
||||
return request({ |
|
||||
url: '/workflow/task/getPageByAllTaskFinish', |
|
||||
method: 'get', |
|
||||
params: query |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 启动流程 |
|
||||
* @param data |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
export const startWorkFlow = (data: object): any => { |
|
||||
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): any => { |
|
||||
return request({ |
|
||||
url: '/workflow/task/claim/' + taskId, |
|
||||
method: 'post' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 归还任务 |
|
||||
* @param taskId |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
export const returnTask = (taskId: string): any => { |
|
||||
return request({ |
|
||||
url: '/workflow/task/returnTask/' + taskId, |
|
||||
method: 'post' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 任务驳回 |
|
||||
* @param data |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
export const backProcess = (data: any): any => { |
|
||||
return request({ |
|
||||
url: '/workflow/task/backProcess', |
|
||||
method: 'post', |
|
||||
data: data |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 获取当前任务 |
|
||||
* @param taskId |
|
||||
* @returns |
|
||||
*/ |
|
||||
export const getTaskById = (taskId: string) => { |
|
||||
return request({ |
|
||||
url: '/workflow/task/getTaskById/' + taskId, |
|
||||
method: 'get' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 加签 |
|
||||
* @param data |
|
||||
* @returns |
|
||||
*/ |
|
||||
export const addMultiInstanceExecution = (data: any) => { |
|
||||
return request({ |
|
||||
url: '/workflow/task/addMultiInstanceExecution', |
|
||||
method: 'post', |
|
||||
data: data |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 减签 |
|
||||
* @param data |
|
||||
* @returns |
|
||||
*/ |
|
||||
export const deleteMultiInstanceExecution = (data: any) => { |
|
||||
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' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 转办任务 |
|
||||
* @returns |
|
||||
*/ |
|
||||
export const transferTask = (data: any) => { |
|
||||
return request({ |
|
||||
url: `/workflow/task/transferTask`, |
|
||||
method: 'post', |
|
||||
data: data |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 终止任务 |
|
||||
* @returns |
|
||||
*/ |
|
||||
export const terminationTask = (data: any) => { |
|
||||
return request({ |
|
||||
url: `/workflow/task/terminationTask`, |
|
||||
method: 'post', |
|
||||
data: data |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 查询流程变量 |
|
||||
* @returns |
|
||||
*/ |
|
||||
export const getInstanceVariable = (taskId: string) => { |
|
||||
return request({ |
|
||||
url: `/workflow/task/getInstanceVariable/${taskId}`, |
|
||||
method: 'get' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 获取可驳回得任务节点 |
|
||||
* @returns |
|
||||
*/ |
|
||||
export const getTaskNodeList = (processInstanceId: string) => { |
|
||||
return request({ |
|
||||
url: `/workflow/task/getTaskNodeList/${processInstanceId}`, |
|
||||
method: 'get' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 委托任务 |
|
||||
* @returns |
|
||||
*/ |
|
||||
export const delegateTask = (data: any) => { |
|
||||
return request({ |
|
||||
url: `/workflow/task/delegateTask`, |
|
||||
method: 'post', |
|
||||
data: data |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 查询工作流任务用户选择加签人员 |
|
||||
* @param taskId |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
export const getTaskUserIdsByAddMultiInstance = (taskId: string) => { |
|
||||
return request({ |
|
||||
url: '/workflow/task/getTaskUserIdsByAddMultiInstance/' + taskId, |
|
||||
method: 'get' |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 查询工作流选择减签人员 |
|
||||
* @param taskId |
|
||||
* @returns {*} |
|
||||
*/ |
|
||||
export const getListByDeleteMultiInstance = (taskId: string) => { |
|
||||
return request({ |
|
||||
url: '/workflow/task/getListByDeleteMultiInstance/' + taskId, |
|
||||
method: 'get' |
|
||||
}); |
|
||||
}; |
|
||||
@ -1,49 +0,0 @@ |
|||||
import { NodeConfigVO } from '@/api/workflow/nodeConfig/types'; |
|
||||
import { DefinitionConfigVO } from '@/api/workflow/definitionConfig/types'; |
|
||||
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; |
|
||||
businessKey?: string; |
|
||||
wfNodeConfigVo?: NodeConfigVO; |
|
||||
wfDefinitionConfigVo?: DefinitionConfigVO; |
|
||||
} |
|
||||
|
|
||||
export interface VariableVo { |
|
||||
key: string; |
|
||||
value: string; |
|
||||
} |
|
||||
@ -1,29 +0,0 @@ |
|||||
import { RouterJumpVo } from '@/api/workflow/workflowCommon/types'; |
|
||||
|
|
||||
export default { |
|
||||
routerJump(routerJumpVo: RouterJumpVo, proxy) { |
|
||||
if (routerJumpVo.wfNodeConfigVo && routerJumpVo.wfNodeConfigVo.formType === 'static' && routerJumpVo.wfNodeConfigVo.wfFormManageVo) { |
|
||||
proxy.$tab.closePage(proxy.$route); |
|
||||
proxy.$router.push({ |
|
||||
path: `${routerJumpVo.wfNodeConfigVo.wfFormManageVo.router}`, |
|
||||
query: { |
|
||||
id: routerJumpVo.businessKey, |
|
||||
type: routerJumpVo.type, |
|
||||
taskId: routerJumpVo.taskId |
|
||||
} |
|
||||
}); |
|
||||
} else if (routerJumpVo.wfNodeConfigVo && routerJumpVo.wfNodeConfigVo.formType === 'dynamic' && routerJumpVo.wfNodeConfigVo.wfFormManageVo) { |
|
||||
proxy.$tab.closePage(proxy.$route); |
|
||||
proxy.$router.push({ |
|
||||
path: `${routerJumpVo.wfNodeConfigVo.wfFormManageVo.router}`, |
|
||||
query: { |
|
||||
id: routerJumpVo.businessKey, |
|
||||
type: routerJumpVo.type, |
|
||||
taskId: routerJumpVo.taskId |
|
||||
} |
|
||||
}); |
|
||||
} else { |
|
||||
proxy?.$modal.msgError('请到模型配置菜单!'); |
|
||||
} |
|
||||
} |
|
||||
}; |
|
||||
@ -1,16 +0,0 @@ |
|||||
import { NodeConfigVO } from '@/api/workflow/nodeConfig/types'; |
|
||||
import { DefinitionConfigVO } from '@/api/workflow/definitionConfig/types'; |
|
||||
|
|
||||
export interface RouterJumpVo { |
|
||||
wfNodeConfigVo: NodeConfigVO; |
|
||||
wfDefinitionConfigVo: DefinitionConfigVO; |
|
||||
businessKey: string; |
|
||||
taskId: string; |
|
||||
type: string; |
|
||||
} |
|
||||
|
|
||||
export interface StartProcessBo { |
|
||||
businessKey: string | number; |
|
||||
tableName: string; |
|
||||
variables: any; |
|
||||
} |
|
||||
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 34 KiB |
@ -1,23 +0,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>`;
|
|
||||
@ -1,126 +0,0 @@ |
|||||
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': '事件网关', |
|
||||
'bpmn:Participant': '池/参与者', |
|
||||
'bpmn:SubProcess': '子流程', |
|
||||
'bpmn:DataObjectReference': '数据对象引用', |
|
||||
'bpmn:DataStoreReference': '数据存储引用', |
|
||||
'bpmn:Group': '组' |
|
||||
}; |
|
||||
|
|
||||
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)': '清空池/参与者 (删除内容)', |
|
||||
'Empty pool/participant': '清空池/参与者', |
|
||||
'Expanded pool/participant': '展开池/参与者', |
|
||||
'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': '追加中间信号捕获事件', |
|
||||
'flow elements must be children of pools/participants': '流程元素必须是池/参与者的子元素' |
|
||||
}; |
|
||||
File diff suppressed because it is too large
@ -1,138 +0,0 @@ |
|||||
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-expect-error 忽略异常
|
|
||||
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; |
|
||||
@ -1,109 +0,0 @@ |
|||||
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); |
|
||||
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; |
|
||||
@ -1,56 +0,0 @@ |
|||||
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']; |
|
||||
@ -1,15 +0,0 @@ |
|||||
import zh from '../../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; |
|
||||
@ -1,17 +0,0 @@ |
|||||
// 翻译模块
|
|
||||
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; |
|
||||
@ -1,50 +0,0 @@ |
|||||
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 |
|
||||
} |
|
||||
}; |
|
||||
@ -1,284 +0,0 @@ |
|||||
.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; |
|
||||
} |
|
||||
} |
|
||||
.bpmn-icon-data-object { |
|
||||
display: 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-data-store { |
|
||||
display: none; |
|
||||
&: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-group { |
|
||||
display: none; |
|
||||
&:hover { |
|
||||
&:after { |
|
||||
content: '创建分组'; |
|
||||
position: absolute; |
|
||||
left: 100px; |
|
||||
width: 100px; |
|
||||
font-size: 15px; |
|
||||
font-weight: bold; |
|
||||
color: #3a84de; |
|
||||
border-radius: 2px; |
|
||||
border: 1px solid #cccccc; |
|
||||
background-color: #fafafa; |
|
||||
opacity: 0.8; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,145 +0,0 @@ |
|||||
import showConfig from '../assets/showConfig'; |
|
||||
import type { ModdleElement } from 'bpmn'; |
|
||||
import useModelerStore from '@/store/modules/modeler'; |
|
||||
import { MultiInstanceTypeEnum } from '@/enums/bpmn/IndexEnums'; |
|
||||
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 }); |
|
||||
} |
|
||||
}; |
|
||||
const formKeyChange = (newVal: string) => { |
|
||||
updateProperties({ formKey: newVal }); |
|
||||
}; |
|
||||
const constant = { |
|
||||
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 } |
|
||||
] |
|
||||
}; |
|
||||
|
|
||||
return { |
|
||||
elementType, |
|
||||
constant, |
|
||||
showConfig: config, |
|
||||
|
|
||||
updateProperties, |
|
||||
updateProperty, |
|
||||
updateModdleProperties, |
|
||||
|
|
||||
createModdleElement, |
|
||||
idChange, |
|
||||
nameChange, |
|
||||
formKeyChange, |
|
||||
getExtensionElements, |
|
||||
getPropertiesElements |
|
||||
}; |
|
||||
}; |
|
||||
@ -1,34 +0,0 @@ |
|||||
import type { 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 |
|
||||
}; |
|
||||
}; |
|
||||
@ -1,496 +0,0 @@ |
|||||
<template> |
|
||||
<div class="containers-bpmn"> |
|
||||
<!-- dark模式下 连接线的箭头样式 --> |
|
||||
<svg width="0" height="0" style="position: absolute"> |
|
||||
<defs> |
|
||||
<marker id="markerArrow-dark-mode" viewBox="0 0 20 20" refX="11" refY="10" markerWidth="10" markerHeight="10" orient="auto"> |
|
||||
<path d="M 1 5 L 11 10 L 1 15 Z" class="arrow-dark" /> |
|
||||
</marker> |
|
||||
</defs> |
|
||||
</svg> |
|
||||
<div v-loading="loading" class="app-containers-bpmn"> |
|
||||
<el-container class="h-full"> |
|
||||
<el-container style="align-items: stretch"> |
|
||||
<el-header> |
|
||||
<div class="process-toolbar"> |
|
||||
<el-space wrap :size="10"> |
|
||||
<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> |
|
||||
<el-space wrap :size="10" style="float: right; padding-right: 10px"> |
|
||||
<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-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 type { Canvas, Modeler } from 'bpmn'; |
|
||||
import PropertyPanel from './panel/index.vue'; |
|
||||
import BpmnModeler from 'bpmn-js/lib/Modeler.js'; |
|
||||
import defaultXML from './assets/defaultXML'; |
|
||||
import flowableModdle from './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 loading = ref(false); |
|
||||
|
|
||||
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-bpmn .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, |
|
||||
loading: loading |
|
||||
}; |
|
||||
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"> |
|
||||
/** 夜间模式 线条的颜色 */ |
|
||||
$stroke-color-dark: white; |
|
||||
$bpmn-font-size: 12px; |
|
||||
/** 日间模式 字体颜色 */ |
|
||||
$bpmn-font-color-dark: white; |
|
||||
/** 夜间模式 字体颜色 */ |
|
||||
$bpmn-font-color-light: #222; |
|
||||
|
|
||||
/* 背景网格 */ |
|
||||
@mixin djs-container { |
|
||||
background-image: linear-gradient(90deg, hsl(0deg 0% 78.4% / 15%) 10%, transparent 0), linear-gradient(hsl(0deg 0% 78.4% / 15%) 10%, transparent 0) !important; |
|
||||
background-size: 10px 10px !important; |
|
||||
} |
|
||||
|
|
||||
html[class='light'] { |
|
||||
/** 从左侧拖动时的背景图 */ |
|
||||
svg.new-parent { |
|
||||
@include djs-container; |
|
||||
} |
|
||||
|
|
||||
/** 双击编辑元素时样式保持一致 */ |
|
||||
div.djs-direct-editing-parent { |
|
||||
border-radius: 10px; |
|
||||
background-color: transparent !important; |
|
||||
color: $bpmn-font-color-light; |
|
||||
} |
|
||||
|
|
||||
g.djs-visual { |
|
||||
.djs-label { |
|
||||
fill: $bpmn-font-color-light !important; |
|
||||
font-size: $bpmn-font-size !important; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
html[class='dark'] { |
|
||||
/** dark模式下 连接线的箭头样式 */ |
|
||||
.arrow-dark { |
|
||||
stroke-width: 1px; |
|
||||
stroke-linecap: round; |
|
||||
stroke: $stroke-color-dark; |
|
||||
fill: $stroke-color-dark; |
|
||||
stroke-linejoin: round; |
|
||||
} |
|
||||
|
|
||||
/** 从左侧拖动时的背景图 */ |
|
||||
svg.new-parent { |
|
||||
background-color: black !important; |
|
||||
@include djs-container; |
|
||||
} |
|
||||
|
|
||||
/** 双击编辑元素时样式保持一致 */ |
|
||||
div.djs-direct-editing-parent { |
|
||||
border-radius: 10px; |
|
||||
background-color: transparent !important; |
|
||||
color: $bpmn-font-color-dark; |
|
||||
} |
|
||||
|
|
||||
/** 元素相关设置 */ |
|
||||
g.djs-visual { |
|
||||
/** 元素边框 需要去除文字(.djs-label) */ |
|
||||
& > *:first-child:not(.djs-label) { |
|
||||
stroke: $stroke-color-dark !important; |
|
||||
} |
|
||||
|
|
||||
/** 字体颜色 */ |
|
||||
.djs-label { |
|
||||
fill: $bpmn-font-color-dark !important; |
|
||||
font-size: $bpmn-font-size !important; |
|
||||
} |
|
||||
|
|
||||
/* 连接线样式 */ |
|
||||
path[data-corner-radius] { |
|
||||
stroke: $stroke-color-dark !important; |
|
||||
marker-end: url('#markerArrow-dark-mode') !important; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.containers-bpmn { |
|
||||
height: 100%; |
|
||||
.app-containers-bpmn { |
|
||||
width: 100%; |
|
||||
height: 100%; |
|
||||
.canvas { |
|
||||
width: 100%; |
|
||||
height: 100%; |
|
||||
@include djs-container; |
|
||||
} |
|
||||
.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: var(--bpmn-panel-bar-background-color); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
pre { |
|
||||
margin: 0; |
|
||||
height: 100%; |
|
||||
max-height: calc(80vh - 32px); |
|
||||
overflow-x: hidden; |
|
||||
overflow-y: auto; |
|
||||
.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 var(--bpmn-panel-border); |
|
||||
box-shadow: var(--bpmn-panel-box-shadow) 0 0 8px; |
|
||||
max-height: 100%; |
|
||||
width: 25%; |
|
||||
height: calc(100vh - 100px); |
|
||||
.el-collapse { |
|
||||
height: calc(100vh - 182px); |
|
||||
overflow: auto; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// 任务栏 透明度 |
|
||||
//:deep(.djs-palette) { |
|
||||
// opacity: 0.3; |
|
||||
// transition: all 1s; |
|
||||
//} |
|
||||
// |
|
||||
//:deep(.djs-palette:hover) { |
|
||||
// opacity: 1; |
|
||||
// transition: all 1s; |
|
||||
//} |
|
||||
</style> |
|
||||
@ -1,68 +0,0 @@ |
|||||
<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 '../hooks/useParseElement'; |
|
||||
import usePanel from '../hooks/usePanel'; |
|
||||
import type { Modeler, ModdleElement } from 'bpmn'; |
|
||||
import type { GatewayPanel } from 'bpmnDesign'; |
|
||||
import ExecutionListener from './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> |
|
||||
@ -1,68 +0,0 @@ |
|||||
<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> |
|
||||
</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 '../hooks/useParseElement'; |
|
||||
import usePanel from '../hooks/usePanel'; |
|
||||
import ExecutionListener from './property/ExecutionListener.vue'; |
|
||||
import type { ModdleElement } from 'bpmn'; |
|
||||
import type { ParticipantPanel } 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<ParticipantPanel>()); |
|
||||
const currentCollapseItem = ref(['1', '2']); |
|
||||
const formRules = ref<ElFormRules>({ |
|
||||
id: [{ required: true, message: '请输入', trigger: 'blur' }], |
|
||||
name: [{ required: true, message: '请输入', trigger: 'blur' }] |
|
||||
}); |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped></style> |
|
||||
@ -1,71 +0,0 @@ |
|||||
<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 '../hooks/useParseElement'; |
|
||||
import usePanel from '../hooks/usePanel'; |
|
||||
import type { Modeler, ModdleElement } from 'bpmn'; |
|
||||
import type { 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> |
|
||||
@ -1,95 +0,0 @@ |
|||||
<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 '../hooks/useParseElement'; |
|
||||
import useModelerStore from '@/store/modules/modeler'; |
|
||||
import usePanel from '../hooks/usePanel'; |
|
||||
import ExecutionListener from './property/ExecutionListener.vue'; |
|
||||
import type { Modeler, ModdleElement } from 'bpmn'; |
|
||||
import type { SequenceFlowPanel } from 'bpmnDesign'; |
|
||||
|
|
||||
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> |
|
||||
@ -1,67 +0,0 @@ |
|||||
<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> |
|
||||
</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 '../hooks/useParseElement'; |
|
||||
import usePanel from '../hooks/usePanel'; |
|
||||
import type { Modeler, ModdleElement } from 'bpmn'; |
|
||||
import type { 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 currentCollapseItem = ref(['1', '2']); |
|
||||
const formRules = ref<ElFormRules>({ |
|
||||
id: [{ required: true, message: '请输入', trigger: 'blur' }], |
|
||||
name: [{ required: true, message: '请输入', trigger: 'blur' }] |
|
||||
}); |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped></style> |
|
||||
@ -1,193 +0,0 @@ |
|||||
<template> |
|
||||
<div> |
|
||||
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="90px"> |
|
||||
<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> |
|
||||
</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-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 constant.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> |
|
||||
</el-form> |
|
||||
</div> |
|
||||
</template> |
|
||||
<script setup lang="ts"> |
|
||||
import ExecutionListener from './property/ExecutionListener.vue'; |
|
||||
import useParseElement from '../hooks/useParseElement'; |
|
||||
import usePanel from '../hooks/usePanel'; |
|
||||
import type { ModdleElement } from 'bpmn'; |
|
||||
import type { SubProcessPanel } from 'bpmnDesign'; |
|
||||
import { MultiInstanceTypeEnum } from '@/enums/bpmn/IndexEnums'; |
|
||||
|
|
||||
interface PropType { |
|
||||
element: ModdleElement; |
|
||||
} |
|
||||
const props = withDefaults(defineProps<PropType>(), {}); |
|
||||
const { nameChange, idChange, updateProperties, createModdleElement, constant } = usePanel({ |
|
||||
element: toRaw(props.element) |
|
||||
}); |
|
||||
const { parseData } = useParseElement({ |
|
||||
element: toRaw(props.element) |
|
||||
}); |
|
||||
|
|
||||
const formData = ref(parseData<SubProcessPanel>()); |
|
||||
const currentCollapseItem = ref(['1', '2', '3']); |
|
||||
|
|
||||
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 }); |
|
||||
}; |
|
||||
|
|
||||
onBeforeMount(() => { |
|
||||
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; |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
const formRules = ref<ElFormRules>({ |
|
||||
id: [{ required: true, message: '请输入', trigger: 'blur' }], |
|
||||
name: [{ required: true, message: '请输入', trigger: 'blur' }] |
|
||||
}); |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped></style> |
|
||||
@ -1,491 +0,0 @@ |
|||||
<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> |
|
||||
<el-form-item v-loading="formManageListLoading" prop="formKey" label="表单地址"> |
|
||||
<el-select v-model="formData.formKey" clearable filterable placeholder="请选择表单" style="width: 260px" @change="formKeyChange"> |
|
||||
<el-option |
|
||||
v-for="item in formManageList" |
|
||||
:key="item.id" |
|
||||
:label="item.formTypeName + ':' + item.formName" |
|
||||
:value="item.formType + ':' + item.id" |
|
||||
/> |
|
||||
</el-select> |
|
||||
</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"> |
|
||||
<el-tab-pane label="身份存储"> |
|
||||
<el-form-item label="分配人员"> |
|
||||
<el-input v-model="formData.assignee" @blur="blurAssignee(formData.assignee)"> |
|
||||
<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.assignee"> |
|
||||
<template #append> |
|
||||
<el-button icon="Search" type="primary" @click="openSingleUserSelect" /> |
|
||||
</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" :value="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 constant.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 '../hooks/useParseElement'; |
|
||||
import usePanel from '../hooks/usePanel'; |
|
||||
import UserSelect from '@/components/UserSelect'; |
|
||||
import RoleSelect from '@/components/RoleSelect'; |
|
||||
import ExecutionListener from './property/ExecutionListener.vue'; |
|
||||
import TaskListener from './property/TaskListener.vue'; |
|
||||
import DueDate from './property/DueDate.vue'; |
|
||||
import type { ModdleElement } from 'bpmn'; |
|
||||
import type { 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'; |
|
||||
import { selectListFormManage } from '@/api/workflow/formManage'; |
|
||||
import { FormManageVO } from '@/api/workflow/formManage/types'; |
|
||||
const formManageList = ref<FormManageVO[]>([]); |
|
||||
const formManageListLoading = ref(false); |
|
||||
interface PropType { |
|
||||
element: ModdleElement; |
|
||||
} |
|
||||
const props = withDefaults(defineProps<PropType>(), {}); |
|
||||
const { showConfig, nameChange, formKeyChange, idChange, updateProperties, getExtensionElements, createModdleElement, constant } = 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 openUserSelect = () => { |
|
||||
userSelectRef.value.open(); |
|
||||
}; |
|
||||
const openSingleUserSelect = () => { |
|
||||
if (formData.value.assignee?.includes('$')) { |
|
||||
formData.value.assignee = ''; |
|
||||
} |
|
||||
singleUserSelectRef.value.open(); |
|
||||
}; |
|
||||
const openRoleSelect = () => { |
|
||||
roleSelectRef.value.open(); |
|
||||
}; |
|
||||
const openDueDate = (e) => { |
|
||||
dueDateRef.value.openDialog(); |
|
||||
}; |
|
||||
const blurAssignee = (assignee) => { |
|
||||
updateProperties({ 'flowable:assignee': assignee ? assignee : undefined }); |
|
||||
}; |
|
||||
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 = ''; |
|
||||
// formData.value.fixedAssignee = ''; |
|
||||
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 listFormManage = async () => { |
|
||||
formManageListLoading.value = true; |
|
||||
const res = await selectListFormManage(); |
|
||||
formManageList.value = res.data; |
|
||||
formManageListLoading.value = false; |
|
||||
}; |
|
||||
onMounted(() => { |
|
||||
nextTick(() => { |
|
||||
listFormManage(); |
|
||||
}); |
|
||||
}); |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped></style> |
|
||||
@ -1,110 +0,0 @@ |
|||||
<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 ParticipantPanel from './ParticipantPanel.vue'; |
|
||||
import SubProcessPanel from './SubProcessPanel.vue'; |
|
||||
import type { 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; |
|
||||
if (type === 'bpmn:Participant') return ParticipantPanel; |
|
||||
if (type === 'bpmn:SubProcess') return SubProcessPanel; |
|
||||
//return proxy?.$modal.msgWarning('面板开发中....'); |
|
||||
return undefined; |
|
||||
}); |
|
||||
|
|
||||
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; |
|
||||
} |
|
||||
return ''; |
|
||||
}); |
|
||||
|
|
||||
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> |
|
||||
@ -1,252 +0,0 @@ |
|||||
<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" value="4" /> |
|
||||
<el-radio-button label="8" value="8" /> |
|
||||
<el-radio-button label="12" value="12" /> |
|
||||
<el-radio-button label="24" value="24" /> |
|
||||
<el-radio-button label="自定义" value="自定义" /> |
|
||||
<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" value="1" /> |
|
||||
<el-radio-button label="2" value="2" /> |
|
||||
<el-radio-button label="3" value="3" /> |
|
||||
<el-radio-button label="4" value="4" /> |
|
||||
<el-radio-button label="自定义" value="自定义" /> |
|
||||
<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" value="1" /> |
|
||||
<el-radio-button label="2" value="2" /> |
|
||||
<el-radio-button label="3" value="3" /> |
|
||||
<el-radio-button label="4" value="4" /> |
|
||||
<el-radio-button label="自定义" value="自定义" /> |
|
||||
<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" value="1" /> |
|
||||
<el-radio-button label="2" value="2" /> |
|
||||
<el-radio-button label="3" value="3" /> |
|
||||
<el-radio-button label="4" value="4" /> |
|
||||
<el-radio-button label="自定义" value="自定义" /> |
|
||||
<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> |
|
||||
@ -1,308 +0,0 @@ |
|||||
<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="100px"> |
|
||||
<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="typeSelect.filter((e) => e.value === formData.type)[0] ? typeSelect.filter((e) => e.value === formData.type)[0]?.label : '表达式'" |
|
||||
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 type { ExecutionListenerVO } from 'bpmnDesign'; |
|
||||
import type { Moddle, Modeler, ModdleElement } from 'bpmn'; |
|
||||
|
|
||||
import usePanel from '../../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: '开始', value: 'start' }, |
|
||||
{ id: '6da97c1e-15fc-4445-8943-75d09f49778e', label: '结束', value: 'end' }, |
|
||||
{ id: '6a2cbcec-e026-4f11-bef7-fff0b5c871e2', label: '启用', value: 'take' } |
|
||||
]; |
|
||||
</script> |
|
||||
|
|
||||
<style scoped lang="scss"> |
|
||||
.el-badge { |
|
||||
:deep(.el-badge__content) { |
|
||||
top: 10px; |
|
||||
} |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,121 +0,0 @@ |
|||||
<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 type { 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> |
|
||||
@ -1,310 +0,0 @@ |
|||||
<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="100px"> |
|
||||
<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="typeSelect.filter((e) => e.value === formData.type)[0] ? typeSelect.filter((e) => e.value === formData.type)[0]?.label : '表达式'" |
|
||||
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 type { TaskListenerVO } from 'bpmnDesign'; |
|
||||
import type { ModdleElement } from 'bpmn'; |
|
||||
|
|
||||
import usePanel from '../../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> |
|
||||
@ -1,71 +0,0 @@ |
|||||
<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 '@/bpmn/index.vue'; |
|
||||
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('是否确认保存?'); |
|
||||
data.loading.value = true; |
|
||||
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); |
|
||||
} |
|
||||
}); |
|
||||
data.loading.value = false; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 对外暴露子组件方法 |
|
||||
*/ |
|
||||
defineExpose({ |
|
||||
open |
|
||||
}); |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
.design { |
|
||||
:deep(.el-dialog .el-dialog__body) { |
|
||||
max-height: 100% !important; |
|
||||
min-height: calc(100vh - 80px); |
|
||||
padding: 10px 0 10px 0 !important; |
|
||||
} |
|
||||
:deep(.el-dialog__header) { |
|
||||
padding: 0 0 5px 0 !important; |
|
||||
} |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,411 +0,0 @@ |
|||||
<template> |
|
||||
<div v-loading="loading" class="bpmnDialogContainers"> |
|
||||
<el-header style="border-bottom: 1px solid rgb(218 218 218); height: auto"> |
|
||||
<div class="header-div"> |
|
||||
<div> |
|
||||
<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> |
|
||||
</div> |
|
||||
<div> |
|
||||
<div class="tips-label"> |
|
||||
<div class="un-complete">未完成</div> |
|
||||
<div class="in-progress">进行中</div> |
|
||||
<div class="complete">已完成</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</el-header> |
|
||||
<div class="flow-containers"> |
|
||||
<el-container class="bpmn-el-container" style="align-items: stretch"> |
|
||||
<el-main style="padding: 0"> |
|
||||
<div ref="canvas" class="canvas" /> |
|
||||
</el-main> |
|
||||
</el-container> |
|
||||
</div> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts" setup> |
|
||||
import BpmnViewer from 'bpmn-js/lib/Viewer'; |
|
||||
import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas'; |
|
||||
import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll'; |
|
||||
import { ModuleDeclaration } from 'didi'; |
|
||||
import type { Canvas, ModdleElement } from 'bpmn'; |
|
||||
import EventBus from 'diagram-js/lib/core/EventBus'; |
|
||||
import Overlays from 'diagram-js/lib/features/overlays/Overlays'; |
|
||||
import processApi from '@/api/workflow/processInstance/index'; |
|
||||
|
|
||||
const canvas = ref<HTMLElement>(); |
|
||||
const modeler = ref<BpmnViewer>(); |
|
||||
const taskList = ref([]); |
|
||||
const zoom = ref(1); |
|
||||
const xml = ref(''); |
|
||||
const loading = ref(false); |
|
||||
const bpmnVisible = ref(true); |
|
||||
const historyList = ref([]); |
|
||||
|
|
||||
const init = (businessKey) => { |
|
||||
loading.value = true; |
|
||||
bpmnVisible.value = true; |
|
||||
nextTick(async () => { |
|
||||
if (modeler.value) modeler.value.destroy(); |
|
||||
modeler.value = new BpmnViewer({ |
|
||||
container: canvas.value, |
|
||||
additionalModules: [ |
|
||||
{ |
|
||||
//禁止滚轮滚动 |
|
||||
zoomScroll: ['value', ''] |
|
||||
}, |
|
||||
ZoomScrollModule, |
|
||||
MoveCanvasModule |
|
||||
] as ModuleDeclaration[] |
|
||||
}); |
|
||||
const resp = await processApi.getHistoryList(businessKey); |
|
||||
xml.value = resp.data.xml; |
|
||||
taskList.value = resp.data.taskList; |
|
||||
historyList.value = resp.data.historyList; |
|
||||
await createDiagram(xml.value); |
|
||||
loading.value = false; |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
const initXml = (xmlStr: string) => { |
|
||||
loading.value = true; |
|
||||
bpmnVisible.value = true; |
|
||||
nextTick(async () => { |
|
||||
if (modeler.value) modeler.value.destroy(); |
|
||||
modeler.value = new BpmnViewer({ |
|
||||
container: canvas.value, |
|
||||
additionalModules: [ |
|
||||
{ |
|
||||
//禁止滚轮滚动 |
|
||||
zoomScroll: ['value', ''] |
|
||||
}, |
|
||||
ZoomScrollModule, |
|
||||
MoveCanvasModule |
|
||||
] as ModuleDeclaration[] |
|
||||
}); |
|
||||
xml.value = xmlStr; |
|
||||
await createDiagram(xml.value); |
|
||||
loading.value = false; |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
const createDiagram = async (data) => { |
|
||||
try { |
|
||||
await modeler.value.importXML(data); |
|
||||
fitViewport(); |
|
||||
fillColor(); |
|
||||
loading.value = false; |
|
||||
addEventBusListener(); |
|
||||
} catch (err) { |
|
||||
console.log(err); |
|
||||
} |
|
||||
}; |
|
||||
const addEventBusListener = () => { |
|
||||
const eventBus = modeler.value.get<EventBus>('eventBus'); |
|
||||
const overlays = modeler.value.get<Overlays>('overlays'); |
|
||||
eventBus.on<ModdleElement>('element.hover', (e) => { |
|
||||
let data = historyList.value.find((t) => t.taskDefinitionKey === e.element.id); |
|
||||
if (e.element.type === 'bpmn:UserTask' && data) { |
|
||||
setTimeout(() => { |
|
||||
genNodeDetailBox(e, overlays, data); |
|
||||
}, 10); |
|
||||
} |
|
||||
}); |
|
||||
eventBus.on('element.out', (e) => { |
|
||||
overlays.clear(); |
|
||||
}); |
|
||||
}; |
|
||||
const genNodeDetailBox = (e, overlays, data) => { |
|
||||
overlays.add(e.element.id, { |
|
||||
position: { top: e.element.height, left: 0 }, |
|
||||
html: `<div class="verlays"> |
|
||||
<p>审批人员: ${data.nickName || ''}<p/> |
|
||||
<p>节点状态:${data.status || ''}</p> |
|
||||
<p>开始时间:${data.startTime || ''}</p> |
|
||||
<p>结束时间:${data.endTime || ''}</p> |
|
||||
<p>审批耗时:${data.runDuration || ''}</p> |
|
||||
<p>流程版本:v${data.version || ''}</p> |
|
||||
</div>` |
|
||||
}); |
|
||||
}; |
|
||||
// 让图能自适应屏幕 |
|
||||
const fitViewport = () => { |
|
||||
zoom.value = modeler.value.get<Canvas>('canvas').zoom('fit-viewport'); |
|
||||
const bbox = document.querySelector<SVGGElement>('.flow-containers .viewport').getBBox(); |
|
||||
const currentViewBox = modeler.value.get('canvas').viewbox(); |
|
||||
const elementMid = { |
|
||||
x: bbox.x + bbox.width / 2 - 65, |
|
||||
y: bbox.y + bbox.height / 2 |
|
||||
}; |
|
||||
modeler.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; |
|
||||
}; |
|
||||
// 放大缩小 |
|
||||
const zoomViewport = (zoomIn = true) => { |
|
||||
zoom.value = modeler.value.get<Canvas>('canvas').zoom(); |
|
||||
zoom.value += zoomIn ? 0.1 : -0.1; |
|
||||
modeler.value.get<Canvas>('canvas').zoom(zoom.value); |
|
||||
}; |
|
||||
//上色 |
|
||||
const fillColor = () => { |
|
||||
const canvas = modeler.value.get<Canvas>('canvas'); |
|
||||
bpmnNodeList(modeler.value._definitions.rootElements[0].flowElements, canvas); |
|
||||
}; |
|
||||
//递归上色 |
|
||||
const bpmnNodeList = (flowElements, canvas) => { |
|
||||
flowElements.forEach((n) => { |
|
||||
if (n.$type === 'bpmn:UserTask') { |
|
||||
const completeTask = taskList.value.find((m) => m.key === n.id); |
|
||||
if (completeTask) { |
|
||||
canvas.addMarker(n.id, completeTask.completed ? 'highlight' : 'highlight-todo'); |
|
||||
n.outgoing?.forEach((nn) => { |
|
||||
const targetTask = taskList.value.find((m) => m.key === nn.targetRef.id); |
|
||||
if (targetTask) { |
|
||||
canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo'); |
|
||||
} else if (nn.targetRef.$type === 'bpmn:ExclusiveGateway') { |
|
||||
canvas.addMarker(nn.id, completeTask.completed ? 'highlight' : 'highlight-todo'); |
|
||||
canvas.addMarker(nn.targetRef.id, completeTask.completed ? 'highlight' : 'highlight-todo'); |
|
||||
nn.targetRef.outgoing.forEach((e) => { |
|
||||
gateway(e.id, e.targetRef.$type, e.targetRef.id, canvas, completeTask.completed); |
|
||||
}); |
|
||||
} else if (nn.targetRef.$type === 'bpmn:ParallelGateway') { |
|
||||
canvas.addMarker(nn.id, completeTask.completed ? 'highlight' : 'highlight-todo'); |
|
||||
canvas.addMarker(nn.targetRef.id, completeTask.completed ? 'highlight' : 'highlight-todo'); |
|
||||
nn.targetRef.outgoing.forEach((e) => { |
|
||||
gateway(e.id, e.targetRef.$type, e.targetRef.id, canvas, completeTask.completed); |
|
||||
}); |
|
||||
} else if (nn.targetRef.$type === 'bpmn:InclusiveGateway') { |
|
||||
canvas.addMarker(nn.id, completeTask.completed ? 'highlight' : 'highlight-todo'); |
|
||||
canvas.addMarker(nn.targetRef.id, completeTask.completed ? 'highlight' : 'highlight-todo'); |
|
||||
nn.targetRef.outgoing.forEach((e) => { |
|
||||
gateway(e.id, e.targetRef.$type, e.targetRef.id, canvas, completeTask.completed); |
|
||||
}); |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
} else if (n.$type === 'bpmn:ExclusiveGateway') { |
|
||||
n.outgoing.forEach((nn) => { |
|
||||
const targetTask = taskList.value.find((m) => m.key === nn.targetRef.id); |
|
||||
if (targetTask) { |
|
||||
canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo'); |
|
||||
} |
|
||||
}); |
|
||||
} else if (n.$type === 'bpmn:ParallelGateway') { |
|
||||
n.outgoing.forEach((nn) => { |
|
||||
const targetTask = taskList.value.find((m) => m.key === nn.targetRef.id); |
|
||||
if (targetTask) { |
|
||||
canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo'); |
|
||||
} |
|
||||
}); |
|
||||
} else if (n.$type === 'bpmn:InclusiveGateway') { |
|
||||
n.outgoing.forEach((nn) => { |
|
||||
const targetTask = taskList.value.find((m) => m.key === nn.targetRef.id); |
|
||||
if (targetTask) { |
|
||||
canvas.addMarker(nn.id, targetTask.completed ? 'highlight' : 'highlight-todo'); |
|
||||
} |
|
||||
}); |
|
||||
} else if (n.$type === 'bpmn:SubProcess') { |
|
||||
const completeTask = taskList.value.find((m) => m.key === n.id); |
|
||||
if (completeTask) { |
|
||||
canvas.addMarker(n.id, completeTask.completed ? 'highlight' : 'highlight-todo'); |
|
||||
} |
|
||||
bpmnNodeList(n.flowElements, canvas); |
|
||||
} else if (n.$type === 'bpmn:StartEvent') { |
|
||||
canvas.addMarker(n.id, 'startEvent'); |
|
||||
if (n.outgoing) { |
|
||||
n.outgoing.forEach((nn) => { |
|
||||
const completeTask = taskList.value.find((m) => m.key === nn.targetRef.id); |
|
||||
if (completeTask) { |
|
||||
canvas.addMarker(nn.id, 'highlight'); |
|
||||
canvas.addMarker(n.id, 'highlight'); |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
} else if (n.$type === 'bpmn:EndEvent') { |
|
||||
canvas.addMarker(n.id, 'endEvent'); |
|
||||
const completeTask = taskList.value.find((m) => m.key === n.id); |
|
||||
if (completeTask) { |
|
||||
canvas.addMarker(completeTask.key, 'highlight'); |
|
||||
canvas.addMarker(n.id, 'highlight'); |
|
||||
return; |
|
||||
} |
|
||||
} |
|
||||
}); |
|
||||
}; |
|
||||
const gateway = (id, targetRefType, targetRefId, canvas, completed) => { |
|
||||
if (targetRefType === 'bpmn:ExclusiveGateway') { |
|
||||
canvas.addMarker(id, completed ? 'highlight' : 'highlight-todo'); |
|
||||
canvas.addMarker(targetRefId, completed ? 'highlight' : 'highlight-todo'); |
|
||||
} |
|
||||
if (targetRefType === 'bpmn:ParallelGateway') { |
|
||||
canvas.addMarker(id, completed ? 'highlight' : 'highlight-todo'); |
|
||||
canvas.addMarker(targetRefId, completed ? 'highlight' : 'highlight-todo'); |
|
||||
} |
|
||||
if (targetRefType === 'bpmn:InclusiveGateway') { |
|
||||
canvas.addMarker(id, completed ? 'highlight' : 'highlight-todo'); |
|
||||
canvas.addMarker(targetRefId, completed ? 'highlight' : 'highlight-todo'); |
|
||||
} |
|
||||
}; |
|
||||
defineExpose({ |
|
||||
init, |
|
||||
initXml |
|
||||
}); |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
.canvas { |
|
||||
width: 100%; |
|
||||
height: 100%; |
|
||||
} |
|
||||
|
|
||||
.header-div { |
|
||||
display: flex; |
|
||||
padding: 10px 0; |
|
||||
justify-content: space-between; |
|
||||
|
|
||||
.tips-label { |
|
||||
display: flex; |
|
||||
div { |
|
||||
margin-right: 10px; |
|
||||
padding: 5px; |
|
||||
font-size: 12px; |
|
||||
} |
|
||||
.un-complete { |
|
||||
border: 1px solid #000; |
|
||||
} |
|
||||
.in-progress { |
|
||||
background-color: rgb(255, 237, 204); |
|
||||
border: 1px dashed orange; |
|
||||
} |
|
||||
.complete { |
|
||||
background-color: rgb(204, 230, 204); |
|
||||
border: 1px solid green; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.view-mode { |
|
||||
.el-header, |
|
||||
.el-aside, |
|
||||
.djs-palette, |
|
||||
.bjs-powered-by { |
|
||||
display: none; |
|
||||
} |
|
||||
.el-loading-mask { |
|
||||
background-color: initial; |
|
||||
} |
|
||||
.el-loading-spinner { |
|
||||
display: none; |
|
||||
} |
|
||||
} |
|
||||
.bpmn-el-container { |
|
||||
height: calc(100vh - 350px); |
|
||||
} |
|
||||
.flow-containers { |
|
||||
width: 100%; |
|
||||
height: 100%; |
|
||||
overflow-y: auto; |
|
||||
.canvas { |
|
||||
width: 100%; |
|
||||
height: 100%; |
|
||||
} |
|
||||
.load { |
|
||||
margin-right: 10px; |
|
||||
} |
|
||||
:deep(.el-form-item__label) { |
|
||||
font-size: 13px; |
|
||||
} |
|
||||
|
|
||||
:deep(.djs-palette) { |
|
||||
left: 0 !important; |
|
||||
top: 0; |
|
||||
border-top: none; |
|
||||
} |
|
||||
|
|
||||
:deep(.djs-container svg) { |
|
||||
min-height: 650px; |
|
||||
} |
|
||||
|
|
||||
:deep(.startEvent.djs-shape .djs-visual > :nth-child(1)) { |
|
||||
fill: #77df6d !important; |
|
||||
} |
|
||||
:deep(.endEvent.djs-shape .djs-visual > :nth-child(1)) { |
|
||||
fill: #ee7b77 !important; |
|
||||
} |
|
||||
:deep(.highlight.djs-shape .djs-visual > :nth-child(1)) { |
|
||||
fill: green !important; |
|
||||
stroke: green !important; |
|
||||
fill-opacity: 0.2 !important; |
|
||||
} |
|
||||
:deep(.highlight.djs-shape .djs-visual > :nth-child(2)) { |
|
||||
fill: green !important; |
|
||||
} |
|
||||
:deep(.highlight.djs-shape .djs-visual > path) { |
|
||||
fill: green !important; |
|
||||
fill-opacity: 0.2 !important; |
|
||||
stroke: green !important; |
|
||||
} |
|
||||
:deep(.highlight.djs-connection > .djs-visual > path) { |
|
||||
stroke: green !important; |
|
||||
} |
|
||||
|
|
||||
// 边框滚动动画 |
|
||||
@keyframes path-animation { |
|
||||
from { |
|
||||
stroke-dashoffset: 100%; |
|
||||
} |
|
||||
|
|
||||
to { |
|
||||
stroke-dashoffset: 0%; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
:deep(.highlight-todo.djs-connection > .djs-visual > path) { |
|
||||
animation: path-animation 60s; |
|
||||
animation-timing-function: linear; |
|
||||
animation-iteration-count: infinite; |
|
||||
stroke-dasharray: 4px !important; |
|
||||
stroke: orange !important; |
|
||||
fill-opacity: 0.2 !important; |
|
||||
marker-end: url('#sequenceflow-end-_E7DFDF-_E7DFDF-803g1kf6zwzmcig1y2ulm5egr'); |
|
||||
} |
|
||||
|
|
||||
:deep(.highlight-todo.djs-shape .djs-visual > :nth-child(1)) { |
|
||||
animation: path-animation 60s; |
|
||||
animation-timing-function: linear; |
|
||||
animation-iteration-count: infinite; |
|
||||
stroke-dasharray: 4px !important; |
|
||||
stroke: orange !important; |
|
||||
fill: orange !important; |
|
||||
fill-opacity: 0.2 !important; |
|
||||
} |
|
||||
} |
|
||||
:deep(.verlays) { |
|
||||
width: 250px; |
|
||||
background: rgb(102, 102, 102); |
|
||||
border-radius: 4px; |
|
||||
border: 1px solid #ebeef5; |
|
||||
color: #fff; |
|
||||
padding: 15px 10px; |
|
||||
p { |
|
||||
line-height: 28px; |
|
||||
margin: 0; |
|
||||
padding: 0; |
|
||||
} |
|
||||
cursor: pointer; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,13 +0,0 @@ |
|||||
<template> |
|
||||
<div> |
|
||||
<svg-icon icon-class="question" @click="goto" /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
const url = ref('https://plus-doc.dromara.org/'); |
|
||||
|
|
||||
function goto() { |
|
||||
window.open(url.value); |
|
||||
} |
|
||||
</script> |
|
||||
@ -1,13 +0,0 @@ |
|||||
<template> |
|
||||
<div> |
|
||||
<svg-icon icon-class="github" @click="goto" /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
const url = ref('https://gitee.com/dromara/RuoYi-Vue-Plus'); |
|
||||
|
|
||||
function goto() { |
|
||||
window.open(url.value); |
|
||||
} |
|
||||
</script> |
|
||||
@ -1,254 +0,0 @@ |
|||||
<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 ref="queryFormRef" :model="queryParams" :inline="true"> |
|
||||
<el-form-item label="部门id" prop="deptId"> |
|
||||
<el-input v-model="queryParams.deptId" placeholder="请输入部门id" clearable @keyup.enter="handleQuery" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="用户id" prop="userId"> |
|
||||
<el-input v-model="queryParams.userId" placeholder="请输入用户id" clearable @keyup.enter="handleQuery" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="排序号" prop="orderNum"> |
|
||||
<el-input v-model="queryParams.orderNum" placeholder="请输入排序号" clearable @keyup.enter="handleQuery" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="key键" prop="testKey"> |
|
||||
<el-input v-model="queryParams.testKey" placeholder="请输入key键" clearable @keyup.enter="handleQuery" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="值" prop="value"> |
|
||||
<el-input v-model="queryParams.value" 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> |
|
||||
</el-card> |
|
||||
</div> |
|
||||
</transition> |
|
||||
|
|
||||
<el-card shadow="hover"> |
|
||||
<template #header> |
|
||||
<el-row :gutter="10" class="mb8"> |
|
||||
<el-col :span="1.5"> |
|
||||
<el-button v-hasPermi="['demo:demo:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button> |
|
||||
</el-col> |
|
||||
<el-col :span="1.5"> |
|
||||
<el-button v-hasPermi="['demo:demo:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">修改</el-button> |
|
||||
</el-col> |
|
||||
<el-col :span="1.5"> |
|
||||
<el-button v-hasPermi="['demo:demo:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" |
|
||||
>删除</el-button |
|
||||
> |
|
||||
</el-col> |
|
||||
<el-col :span="1.5"> |
|
||||
<el-button v-hasPermi="['demo:demo: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="demoList" @selection-change="handleSelectionChange"> |
|
||||
<el-table-column type="selection" width="55" align="center" /> |
|
||||
<el-table-column v-if="true" label="主键" align="center" prop="id" /> |
|
||||
<el-table-column label="部门id" align="center" prop="deptId" /> |
|
||||
<el-table-column label="用户id" align="center" prop="userId" /> |
|
||||
<el-table-column label="排序号" align="center" prop="orderNum" /> |
|
||||
<el-table-column label="key键" align="center" prop="testKey" /> |
|
||||
<el-table-column label="值" align="center" prop="value" /> |
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> |
|
||||
<template #default="scope"> |
|
||||
<el-tooltip content="修改" placement="top"> |
|
||||
<el-button v-hasPermi="['demo:demo:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button> |
|
||||
</el-tooltip> |
|
||||
<el-tooltip content="删除" placement="top"> |
|
||||
<el-button v-hasPermi="['demo:demo:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></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="500px" append-to-body> |
|
||||
<el-form ref="demoFormRef" :model="form" :rules="rules" label-width="80px"> |
|
||||
<el-form-item label="部门id" prop="deptId"> |
|
||||
<el-input v-model="form.deptId" placeholder="请输入部门id" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="用户id" prop="userId"> |
|
||||
<el-input v-model="form.userId" placeholder="请输入用户id" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="排序号" prop="orderNum"> |
|
||||
<el-input v-model="form.orderNum" placeholder="请输入排序号" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="key键" prop="testKey"> |
|
||||
<el-input v-model="form.testKey" placeholder="请输入key键" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="值" prop="value"> |
|
||||
<el-input v-model="form.value" placeholder="请输入值" /> |
|
||||
</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="Demo" lang="ts"> |
|
||||
import { listDemo, getDemo, delDemo, addDemo, updateDemo } from '@/api/demo/demo'; |
|
||||
import { DemoVO, DemoQuery, DemoForm } from '@/api/demo/demo/types'; |
|
||||
|
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
|
||||
|
|
||||
const demoList = ref<DemoVO[]>([]); |
|
||||
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 queryFormRef = ref<ElFormInstance>(); |
|
||||
const demoFormRef = ref<ElFormInstance>(); |
|
||||
|
|
||||
const dialog = reactive<DialogOption>({ |
|
||||
visible: false, |
|
||||
title: '' |
|
||||
}); |
|
||||
|
|
||||
const initFormData: DemoForm = { |
|
||||
id: undefined, |
|
||||
deptId: undefined, |
|
||||
userId: undefined, |
|
||||
orderNum: undefined, |
|
||||
testKey: undefined, |
|
||||
value: undefined |
|
||||
}; |
|
||||
const data = reactive<PageData<DemoForm, DemoQuery>>({ |
|
||||
form: { ...initFormData }, |
|
||||
queryParams: { |
|
||||
pageNum: 1, |
|
||||
pageSize: 10, |
|
||||
deptId: undefined, |
|
||||
userId: undefined, |
|
||||
orderNum: undefined, |
|
||||
testKey: undefined, |
|
||||
value: undefined |
|
||||
}, |
|
||||
rules: { |
|
||||
id: [{ required: true, message: '主键不能为空', trigger: 'blur' }], |
|
||||
deptId: [{ required: true, message: '部门id不能为空', trigger: 'blur' }], |
|
||||
userId: [{ required: true, message: '用户id不能为空', trigger: 'blur' }], |
|
||||
orderNum: [{ required: true, message: '排序号不能为空', trigger: 'blur' }], |
|
||||
testKey: [{ required: true, message: 'key键不能为空', trigger: 'blur' }], |
|
||||
value: [{ required: true, message: '值不能为空', trigger: 'blur' }] |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
const { queryParams, form, rules } = toRefs(data); |
|
||||
|
|
||||
/** 查询测试单列表 */ |
|
||||
const getList = async () => { |
|
||||
loading.value = true; |
|
||||
const res = await listDemo(queryParams.value); |
|
||||
demoList.value = res.rows; |
|
||||
total.value = res.total; |
|
||||
loading.value = false; |
|
||||
}; |
|
||||
|
|
||||
/** 取消按钮 */ |
|
||||
const cancel = () => { |
|
||||
reset(); |
|
||||
dialog.visible = false; |
|
||||
}; |
|
||||
|
|
||||
/** 表单重置 */ |
|
||||
const reset = () => { |
|
||||
form.value = { ...initFormData }; |
|
||||
demoFormRef.value?.resetFields(); |
|
||||
}; |
|
||||
|
|
||||
/** 搜索按钮操作 */ |
|
||||
const handleQuery = () => { |
|
||||
queryParams.value.pageNum = 1; |
|
||||
getList(); |
|
||||
}; |
|
||||
|
|
||||
/** 重置按钮操作 */ |
|
||||
const resetQuery = () => { |
|
||||
queryFormRef.value?.resetFields(); |
|
||||
handleQuery(); |
|
||||
}; |
|
||||
|
|
||||
/** 多选框选中数据 */ |
|
||||
const handleSelectionChange = (selection: DemoVO[]) => { |
|
||||
ids.value = selection.map((item) => item.id); |
|
||||
single.value = selection.length != 1; |
|
||||
multiple.value = !selection.length; |
|
||||
}; |
|
||||
|
|
||||
/** 新增按钮操作 */ |
|
||||
const handleAdd = () => { |
|
||||
reset(); |
|
||||
dialog.visible = true; |
|
||||
dialog.title = '添加测试单'; |
|
||||
}; |
|
||||
|
|
||||
/** 修改按钮操作 */ |
|
||||
const handleUpdate = async (row?: DemoVO) => { |
|
||||
reset(); |
|
||||
const _id = row?.id || ids.value[0]; |
|
||||
const res = await getDemo(_id); |
|
||||
Object.assign(form.value, res.data); |
|
||||
dialog.visible = true; |
|
||||
dialog.title = '修改测试单'; |
|
||||
}; |
|
||||
|
|
||||
/** 提交按钮 */ |
|
||||
const submitForm = () => { |
|
||||
demoFormRef.value?.validate(async (valid: boolean) => { |
|
||||
if (valid) { |
|
||||
buttonLoading.value = true; |
|
||||
if (form.value.id) { |
|
||||
await updateDemo(form.value).finally(() => (buttonLoading.value = false)); |
|
||||
} else { |
|
||||
await addDemo(form.value).finally(() => (buttonLoading.value = false)); |
|
||||
} |
|
||||
proxy?.$modal.msgSuccess('修改成功'); |
|
||||
dialog.visible = false; |
|
||||
await getList(); |
|
||||
} |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** 删除按钮操作 */ |
|
||||
const handleDelete = async (row?: DemoVO) => { |
|
||||
const _ids = row?.id || ids.value; |
|
||||
await proxy?.$modal.confirm('是否确认删除测试单编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false)); |
|
||||
await delDemo(_ids); |
|
||||
proxy?.$modal.msgSuccess('删除成功'); |
|
||||
await getList(); |
|
||||
}; |
|
||||
|
|
||||
/** 导出按钮操作 */ |
|
||||
const handleExport = () => { |
|
||||
proxy?.download( |
|
||||
'demo/demo/export', |
|
||||
{ |
|
||||
...queryParams.value |
|
||||
}, |
|
||||
`demo_${new Date().getTime()}.xlsx` |
|
||||
); |
|
||||
}; |
|
||||
|
|
||||
onMounted(() => { |
|
||||
getList(); |
|
||||
}); |
|
||||
</script> |
|
||||
@ -1,258 +0,0 @@ |
|||||
<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 ref="queryFormRef" :model="queryParams" :inline="true"> |
|
||||
<el-form-item label="树节点名" prop="treeName"> |
|
||||
<el-input v-model="queryParams.treeName" 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> |
|
||||
</el-card> |
|
||||
</div> |
|
||||
</transition> |
|
||||
|
|
||||
<el-card shadow="hover"> |
|
||||
<template #header> |
|
||||
<el-row :gutter="10" class="mb8"> |
|
||||
<el-col :span="1.5"> |
|
||||
<el-button v-hasPermi="['demo:tree: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="treeTableRef" |
|
||||
v-loading="loading" |
|
||||
:data="treeList" |
|
||||
row-key="id" |
|
||||
:default-expand-all="isExpandAll" |
|
||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }" |
|
||||
> |
|
||||
<el-table-column label="父id" align="center" prop="parentId" /> |
|
||||
<el-table-column label="部门id" align="center" prop="deptId" /> |
|
||||
<el-table-column label="用户id" align="center" prop="userId" /> |
|
||||
<el-table-column label="树节点名" align="center" prop="treeName" /> |
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> |
|
||||
<template #default="scope"> |
|
||||
<el-tooltip content="修改" placement="top"> |
|
||||
<el-button v-hasPermi="['demo:tree:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" /> |
|
||||
</el-tooltip> |
|
||||
<el-tooltip content="新增" placement="top"> |
|
||||
<el-button v-hasPermi="['demo:tree:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" /> |
|
||||
</el-tooltip> |
|
||||
<el-tooltip content="删除" placement="top"> |
|
||||
<el-button v-hasPermi="['demo:tree: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="treeFormRef" :model="form" :rules="rules" label-width="80px"> |
|
||||
<el-form-item label="父id" prop="parentId"> |
|
||||
<el-tree-select |
|
||||
v-model="form.parentId" |
|
||||
:data="treeOptions" |
|
||||
:props="{ value: 'id', label: 'treeName', children: 'children' }" |
|
||||
value-key="id" |
|
||||
placeholder="请选择父id" |
|
||||
check-strictly |
|
||||
/> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="部门id" prop="deptId"> |
|
||||
<el-input v-model="form.deptId" placeholder="请输入部门id" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="用户id" prop="userId"> |
|
||||
<el-input v-model="form.userId" placeholder="请输入用户id" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="值" prop="treeName"> |
|
||||
<el-input v-model="form.treeName" placeholder="请输入值" /> |
|
||||
</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="Tree" lang="ts"> |
|
||||
import { listTree, getTree, delTree, addTree, updateTree } from '@/api/demo/tree'; |
|
||||
import { TreeVO, TreeQuery, TreeForm } from '@/api/demo/tree/types'; |
|
||||
|
|
||||
type TreeOption = { |
|
||||
id: number; |
|
||||
treeName: string; |
|
||||
children?: TreeOption[]; |
|
||||
}; |
|
||||
|
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
|
||||
|
|
||||
const treeList = ref<TreeVO[]>([]); |
|
||||
const treeOptions = ref<TreeOption[]>([]); |
|
||||
const buttonLoading = ref(false); |
|
||||
const showSearch = ref(true); |
|
||||
const isExpandAll = ref(true); |
|
||||
const loading = ref(false); |
|
||||
|
|
||||
const queryFormRef = ref<ElFormInstance>(); |
|
||||
const treeFormRef = ref<ElFormInstance>(); |
|
||||
const treeTableRef = ref<ElTableInstance>(); |
|
||||
|
|
||||
const dialog = reactive<DialogOption>({ |
|
||||
visible: false, |
|
||||
title: '' |
|
||||
}); |
|
||||
|
|
||||
const initFormData: TreeForm = { |
|
||||
id: undefined, |
|
||||
parentId: undefined, |
|
||||
deptId: undefined, |
|
||||
userId: undefined, |
|
||||
treeName: undefined |
|
||||
}; |
|
||||
|
|
||||
const data = reactive<PageData<TreeForm, TreeQuery>>({ |
|
||||
form: { ...initFormData }, |
|
||||
queryParams: { |
|
||||
parentId: undefined, |
|
||||
deptId: undefined, |
|
||||
userId: undefined, |
|
||||
treeName: undefined |
|
||||
}, |
|
||||
rules: { |
|
||||
id: [{ required: true, message: '主键不能为空', trigger: 'blur' }], |
|
||||
parentId: [{ required: true, message: '父id不能为空', trigger: 'blur' }], |
|
||||
deptId: [{ required: true, message: '部门id不能为空', trigger: 'blur' }], |
|
||||
userId: [{ required: true, message: '用户id不能为空', trigger: 'blur' }], |
|
||||
treeName: [{ required: true, message: '值不能为空', trigger: 'blur' }] |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
const { queryParams, form, rules } = toRefs(data); |
|
||||
|
|
||||
/** 查询测试树列表 */ |
|
||||
const getList = async () => { |
|
||||
loading.value = true; |
|
||||
const res = await listTree(queryParams.value); |
|
||||
const data = proxy?.handleTree<TreeVO>(res.data, 'id', 'parentId'); |
|
||||
if (data) { |
|
||||
treeList.value = data; |
|
||||
loading.value = false; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
/** 查询测试树下拉树结构 */ |
|
||||
const getTreeselect = async () => { |
|
||||
const res = await listTree(); |
|
||||
treeOptions.value = []; |
|
||||
const data: TreeOption = { id: 0, treeName: '顶级节点', children: [] }; |
|
||||
data.children = proxy?.handleTree<TreeOption>(res.data, 'id', 'parentId'); |
|
||||
treeOptions.value.push(data); |
|
||||
}; |
|
||||
|
|
||||
// 取消按钮 |
|
||||
const cancel = () => { |
|
||||
reset(); |
|
||||
dialog.visible = false; |
|
||||
}; |
|
||||
|
|
||||
// 表单重置 |
|
||||
const reset = () => { |
|
||||
form.value = { ...initFormData }; |
|
||||
treeFormRef.value?.resetFields(); |
|
||||
}; |
|
||||
|
|
||||
/** 搜索按钮操作 */ |
|
||||
const handleQuery = () => { |
|
||||
getList(); |
|
||||
}; |
|
||||
|
|
||||
/** 重置按钮操作 */ |
|
||||
const resetQuery = () => { |
|
||||
queryFormRef.value?.resetFields(); |
|
||||
handleQuery(); |
|
||||
}; |
|
||||
|
|
||||
/** 新增按钮操作 */ |
|
||||
const handleAdd = (row?: TreeVO) => { |
|
||||
reset(); |
|
||||
getTreeselect(); |
|
||||
if (row && row.id) { |
|
||||
form.value.parentId = row.id; |
|
||||
} else { |
|
||||
form.value.parentId = 0; |
|
||||
} |
|
||||
dialog.visible = true; |
|
||||
dialog.title = '添加测试树'; |
|
||||
}; |
|
||||
|
|
||||
/** 展开/折叠操作 */ |
|
||||
const handleToggleExpandAll = () => { |
|
||||
isExpandAll.value = !isExpandAll.value; |
|
||||
toggleExpandAll(treeList.value, isExpandAll.value); |
|
||||
}; |
|
||||
|
|
||||
/** 展开/折叠操作 */ |
|
||||
const toggleExpandAll = (data: TreeVO[], status: boolean) => { |
|
||||
data.forEach((item) => { |
|
||||
treeTableRef.value?.toggleRowExpansion(item, status); |
|
||||
if (item.children && item.children.length > 0) toggleExpandAll(item.children, status); |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** 修改按钮操作 */ |
|
||||
const handleUpdate = async (row: TreeVO) => { |
|
||||
reset(); |
|
||||
await getTreeselect(); |
|
||||
if (row) { |
|
||||
form.value.parentId = row.id; |
|
||||
} |
|
||||
const res = await getTree(row.id); |
|
||||
Object.assign(form.value, res.data); |
|
||||
dialog.visible = true; |
|
||||
dialog.title = '修改测试树'; |
|
||||
}; |
|
||||
|
|
||||
/** 提交按钮 */ |
|
||||
const submitForm = () => { |
|
||||
treeFormRef.value?.validate(async (valid: boolean) => { |
|
||||
if (valid) { |
|
||||
buttonLoading.value = true; |
|
||||
if (form.value.id) { |
|
||||
await updateTree(form.value).finally(() => (buttonLoading.value = false)); |
|
||||
} else { |
|
||||
await addTree(form.value).finally(() => (buttonLoading.value = false)); |
|
||||
} |
|
||||
proxy?.$modal.msgSuccess('操作成功'); |
|
||||
dialog.visible = false; |
|
||||
await getList(); |
|
||||
} |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** 删除按钮操作 */ |
|
||||
const handleDelete = async (row: TreeVO) => { |
|
||||
await proxy?.$modal.confirm('是否确认删除测试树编号为"' + row.id + '"的数据项?'); |
|
||||
loading.value = true; |
|
||||
await delTree(row.id).finally(() => (loading.value = false)); |
|
||||
await getList(); |
|
||||
proxy?.$modal.msgSuccess('删除成功'); |
|
||||
}; |
|
||||
|
|
||||
onMounted(() => { |
|
||||
getList(); |
|
||||
}); |
|
||||
</script> |
|
||||
@ -1,9 +0,0 @@ |
|||||
<template> |
|
||||
<div> |
|
||||
<i-frame v-model:src="url"></i-frame> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
const url = ref(import.meta.env.VITE_APP_MONITOR_ADMIN); |
|
||||
</script> |
|
||||
@ -1,9 +0,0 @@ |
|||||
<template> |
|
||||
<div> |
|
||||
<i-frame v-model:src="url"></i-frame> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
const url = ref(import.meta.env.VITE_APP_SNAILJOB_ADMIN); |
|
||||
</script> |
|
||||
@ -1,263 +0,0 @@ |
|||||
<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"> |
|
||||
<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> |
|
||||
@ -1,243 +0,0 @@ |
|||||
<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"> |
|
||||
<el-form-item label="表单名称" prop="formName"> |
|
||||
<el-input v-model="queryParams.formName" 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:formManage:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button> |
|
||||
</el-col> |
|
||||
<el-col :span="1.5"> |
|
||||
<el-button v-hasPermi="['workflow:formManage:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" |
|
||||
>修改</el-button |
|
||||
> |
|
||||
</el-col> |
|
||||
<el-col :span="1.5"> |
|
||||
<el-button v-hasPermi="['workflow:formManage:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" |
|
||||
>删除</el-button |
|
||||
> |
|
||||
</el-col> |
|
||||
<el-col :span="1.5"> |
|
||||
<el-button v-hasPermi="['workflow:formManage: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="formManageList" @selection-change="handleSelectionChange"> |
|
||||
<el-table-column type="selection" width="55" align="center" /> |
|
||||
<el-table-column label="表单名称" align="center" prop="formName" /> |
|
||||
<el-table-column label="表单类型" align="center"> |
|
||||
<template #default="scope"> |
|
||||
<dict-tag :options="wf_form_type" :value="scope.row.formType"></dict-tag> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column label="地址" align="center" prop="router" /> |
|
||||
<el-table-column label="备注" align="center" prop="remark" /> |
|
||||
<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:formManage:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button> |
|
||||
</el-tooltip> |
|
||||
<el-tooltip content="删除" placement="top"> |
|
||||
<el-button v-hasPermi="['workflow:formManage:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></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="500px" append-to-body> |
|
||||
<el-form ref="formManageFormRef" :model="form" :rules="rules" label-width="80px"> |
|
||||
<el-form-item label="表单名称" prop="formName"> |
|
||||
<el-input v-model="form.formName" placeholder="请输入表单名称" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="表单类型" prop="formType"> |
|
||||
<el-radio-group v-model="form.formType" @change="form.router = ''"> |
|
||||
<el-radio v-for="dict in wf_form_type" :key="dict.value" border :value="dict.value">{{ dict.label }}</el-radio> |
|
||||
</el-radio-group> |
|
||||
</el-form-item> |
|
||||
<el-form-item v-if="form.formType === 'static'" label="路由地址" prop="router"> |
|
||||
<el-input v-model="form.router" placeholder="请输入路由地址" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item v-else label="表单" prop="router"> |
|
||||
<el-input v-model="form.router" disabled placeholder="请选择表单"> |
|
||||
<template #append> |
|
||||
<el-button icon="Search" /> |
|
||||
</template> |
|
||||
</el-input> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="备注" prop="remark"> |
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" /> |
|
||||
</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="FormManage" lang="ts"> |
|
||||
import { listFormManage, getFormManage, delFormManage, addFormManage, updateFormManage } from '@/api/workflow/formManage'; |
|
||||
import { FormManageVO, FormManageQuery, FormManageForm } from '@/api/workflow/formManage/types'; |
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
|
||||
const { wf_form_type } = toRefs<any>(proxy?.useDict('wf_form_type')); |
|
||||
|
|
||||
const formManageList = ref<FormManageVO[]>([]); |
|
||||
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 queryFormRef = ref<ElFormInstance>(); |
|
||||
const formManageFormRef = ref<ElFormInstance>(); |
|
||||
|
|
||||
const dialog = reactive<DialogOption>({ |
|
||||
visible: false, |
|
||||
title: '' |
|
||||
}); |
|
||||
|
|
||||
const initFormData: FormManageForm = { |
|
||||
id: undefined, |
|
||||
formName: undefined, |
|
||||
formType: 'static', |
|
||||
remark: undefined |
|
||||
}; |
|
||||
const data = reactive<PageData<FormManageForm, FormManageQuery>>({ |
|
||||
form: { ...initFormData }, |
|
||||
queryParams: { |
|
||||
pageNum: 1, |
|
||||
pageSize: 10, |
|
||||
formName: undefined, |
|
||||
formType: undefined |
|
||||
}, |
|
||||
rules: { |
|
||||
id: [{ required: true, message: '主键不能为空', trigger: 'blur' }], |
|
||||
formName: [{ required: true, message: '表单名称不能为空', trigger: 'blur' }], |
|
||||
formType: [{ required: true, message: '表单类型不能为空', trigger: 'change' }], |
|
||||
router: [{ required: true, message: '不能为空', trigger: 'blur' }] |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
const { queryParams, form, rules } = toRefs(data); |
|
||||
|
|
||||
/** 查询表单管理列表 */ |
|
||||
const getList = async () => { |
|
||||
loading.value = true; |
|
||||
const res = await listFormManage(queryParams.value); |
|
||||
formManageList.value = res.rows; |
|
||||
total.value = res.total; |
|
||||
loading.value = false; |
|
||||
}; |
|
||||
|
|
||||
/** 取消按钮 */ |
|
||||
const cancel = () => { |
|
||||
reset(); |
|
||||
dialog.visible = false; |
|
||||
}; |
|
||||
|
|
||||
/** 表单重置 */ |
|
||||
const reset = () => { |
|
||||
form.value = { ...initFormData }; |
|
||||
formManageFormRef.value?.resetFields(); |
|
||||
}; |
|
||||
|
|
||||
/** 搜索按钮操作 */ |
|
||||
const handleQuery = () => { |
|
||||
queryParams.value.pageNum = 1; |
|
||||
getList(); |
|
||||
}; |
|
||||
|
|
||||
/** 重置按钮操作 */ |
|
||||
const resetQuery = () => { |
|
||||
queryFormRef.value?.resetFields(); |
|
||||
handleQuery(); |
|
||||
}; |
|
||||
|
|
||||
/** 多选框选中数据 */ |
|
||||
const handleSelectionChange = (selection: FormManageVO[]) => { |
|
||||
ids.value = selection.map((item) => item.id); |
|
||||
single.value = selection.length != 1; |
|
||||
multiple.value = !selection.length; |
|
||||
}; |
|
||||
|
|
||||
/** 新增按钮操作 */ |
|
||||
const handleAdd = () => { |
|
||||
reset(); |
|
||||
dialog.visible = true; |
|
||||
dialog.title = '添加表单管理'; |
|
||||
}; |
|
||||
|
|
||||
/** 修改按钮操作 */ |
|
||||
const handleUpdate = async (row?: FormManageVO) => { |
|
||||
reset(); |
|
||||
const _id = row?.id || ids.value[0]; |
|
||||
const res = await getFormManage(_id); |
|
||||
Object.assign(form.value, res.data); |
|
||||
dialog.visible = true; |
|
||||
dialog.title = '修改表单管理'; |
|
||||
}; |
|
||||
|
|
||||
/** 提交按钮 */ |
|
||||
const submitForm = () => { |
|
||||
formManageFormRef.value?.validate(async (valid: boolean) => { |
|
||||
if (valid) { |
|
||||
buttonLoading.value = true; |
|
||||
if (form.value.id) { |
|
||||
await updateFormManage(form.value).finally(() => (buttonLoading.value = false)); |
|
||||
} else { |
|
||||
await addFormManage(form.value).finally(() => (buttonLoading.value = false)); |
|
||||
} |
|
||||
proxy?.$modal.msgSuccess('操作成功'); |
|
||||
dialog.visible = false; |
|
||||
await getList(); |
|
||||
} |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** 删除按钮操作 */ |
|
||||
const handleDelete = async (row?: FormManageVO) => { |
|
||||
const _ids = row?.id || ids.value; |
|
||||
await proxy?.$modal.confirm('是否确认删除表单管理编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false)); |
|
||||
await delFormManage(_ids); |
|
||||
proxy?.$modal.msgSuccess('删除成功'); |
|
||||
await getList(); |
|
||||
}; |
|
||||
|
|
||||
/** 导出按钮操作 */ |
|
||||
const handleExport = () => { |
|
||||
proxy?.download( |
|
||||
'workflow/formManage/export', |
|
||||
{ |
|
||||
...queryParams.value |
|
||||
}, |
|
||||
`formManage_${new Date().getTime()}.xlsx` |
|
||||
); |
|
||||
}; |
|
||||
|
|
||||
onMounted(() => { |
|
||||
getList(); |
|
||||
}); |
|
||||
</script> |
|
||||
@ -1,242 +0,0 @@ |
|||||
<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"> |
|
||||
<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="['workflow:leave:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button> |
|
||||
</el-col> |
|
||||
<el-col :span="1.5"> |
|
||||
<el-button v-hasPermi="['workflow: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" label="流程状态" min-width="70"> |
|
||||
<template #default="scope"> |
|
||||
<dict-tag :options="wf_business_status" :value="scope.row.status"></dict-tag> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> |
|
||||
<template #default="scope"> |
|
||||
<el-button |
|
||||
v-if="scope.row.status === 'draft' || scope.row.status === 'cancel' || scope.row.status === 'back'" |
|
||||
v-hasPermi="['workflow:leave:edit']" |
|
||||
size="small" |
|
||||
link |
|
||||
type="primary" |
|
||||
icon="Edit" |
|
||||
@click="handleUpdate(scope.row)" |
|
||||
>修改</el-button |
|
||||
> |
|
||||
<el-button |
|
||||
v-if="scope.row.status === 'draft' || scope.row.status === 'cancel' || scope.row.status === 'back'" |
|
||||
v-hasPermi="['workflow:leave:remove']" |
|
||||
size="small" |
|
||||
link |
|
||||
type="primary" |
|
||||
icon="Delete" |
|
||||
@click="handleDelete(scope.row)" |
|
||||
>删除</el-button |
|
||||
> |
|
||||
<el-button link type="primary" size="small" icon="View" @click="handleView(scope.row)">查看</el-button> |
|
||||
<el-button |
|
||||
v-if="scope.row.status === 'waiting'" |
|
||||
link |
|
||||
size="small" |
|
||||
type="primary" |
|
||||
icon="Notification" |
|
||||
@click="handleCancelProcessApply(scope.row.id)" |
|
||||
>撤销</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="getList" /> |
|
||||
</el-card> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script setup name="Leave" lang="ts"> |
|
||||
import { delLeave, listLeave } from '@/api/workflow/leave'; |
|
||||
import { cancelProcessApply } from '@/api/workflow/processInstance'; |
|
||||
import { LeaveForm, LeaveQuery, LeaveVO } from '@/api/workflow/leave/types'; |
|
||||
|
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
|
||||
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status')); |
|
||||
const leaveList = ref<LeaveVO[]>([]); |
|
||||
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 options = [ |
|
||||
{ |
|
||||
value: '1', |
|
||||
label: '事假' |
|
||||
}, |
|
||||
{ |
|
||||
value: '2', |
|
||||
label: '调休' |
|
||||
}, |
|
||||
{ |
|
||||
value: '3', |
|
||||
label: '病假' |
|
||||
}, |
|
||||
{ |
|
||||
value: '4', |
|
||||
label: '婚假' |
|
||||
} |
|
||||
]; |
|
||||
|
|
||||
const queryFormRef = ref<ElFormInstance>(); |
|
||||
|
|
||||
const data = reactive<PageData<LeaveForm, LeaveQuery>>({ |
|
||||
form: {}, |
|
||||
queryParams: { |
|
||||
pageNum: 1, |
|
||||
pageSize: 10, |
|
||||
startLeaveDays: undefined, |
|
||||
endLeaveDays: undefined |
|
||||
}, |
|
||||
rules: {} |
|
||||
}); |
|
||||
|
|
||||
const { queryParams } = 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 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 = () => { |
|
||||
proxy.$tab.closePage(proxy.$route); |
|
||||
proxy.$router.push({ |
|
||||
path: `/workflow/leaveEdit/index`, |
|
||||
query: { |
|
||||
type: 'add' |
|
||||
} |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** 修改按钮操作 */ |
|
||||
const handleUpdate = (row?: LeaveVO) => { |
|
||||
proxy.$tab.closePage(proxy.$route); |
|
||||
proxy.$router.push({ |
|
||||
path: `/workflow/leaveEdit/index`, |
|
||||
query: { |
|
||||
id: row.id, |
|
||||
type: 'update' |
|
||||
} |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** 查看按钮操作 */ |
|
||||
const handleView = (row?: LeaveVO) => { |
|
||||
proxy.$tab.closePage(proxy.$route); |
|
||||
proxy.$router.push({ |
|
||||
path: `/workflow/leaveEdit/index`, |
|
||||
query: { |
|
||||
id: row.id, |
|
||||
type: 'view' |
|
||||
} |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** 删除按钮操作 */ |
|
||||
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( |
|
||||
'workflow/leave/export', |
|
||||
{ |
|
||||
...queryParams.value |
|
||||
}, |
|
||||
`leave_${new Date().getTime()}.xlsx` |
|
||||
); |
|
||||
}; |
|
||||
|
|
||||
/** 撤销按钮操作 */ |
|
||||
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> |
|
||||
@ -1,252 +0,0 @@ |
|||||
<template> |
|
||||
<div class="p-2"> |
|
||||
<el-card shadow="never"> |
|
||||
<div style="display: flex; justify-content: space-between"> |
|
||||
<div> |
|
||||
<el-button v-if="submitButtonShow" :loading="buttonLoading" type="info" @click="submitForm('draft')">暂存</el-button> |
|
||||
<el-button v-if="submitButtonShow" :loading="buttonLoading" type="primary" @click="submitForm('submit')">提 交</el-button> |
|
||||
<el-button v-if="approvalButtonShow" :loading="buttonLoading" type="primary" @click="approvalVerifyOpen">审批</el-button> |
|
||||
<el-button v-if="form && form.id && form.status !== 'draft'" type="primary" @click="handleApprovalRecord">流程进度</el-button> |
|
||||
</div> |
|
||||
<div> |
|
||||
<el-button style="float: right" @click="goBack()">返回</el-button> |
|
||||
</div> |
|
||||
</div> |
|
||||
</el-card> |
|
||||
<el-card shadow="never" style="height: 78vh; overflow-y: auto"> |
|
||||
<el-form ref="leaveFormRef" v-loading="loading" :disabled="routeParams.type === 'view'" :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" |
|
||||
value-format="YYYY-MM-DD HH:mm:ss" |
|
||||
type="daterange" |
|
||||
range-separator="To" |
|
||||
start-placeholder="开始时间" |
|
||||
end-placeholder="结束时间" |
|
||||
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]" |
|
||||
@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> |
|
||||
</el-card> |
|
||||
<!-- 提交组件 --> |
|
||||
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" /> |
|
||||
<!-- 审批记录 --> |
|
||||
<approvalRecord ref="approvalRecordRef" /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script setup name="Leave" lang="ts"> |
|
||||
import { addLeave, getLeave, updateLeave } from '@/api/workflow/leave'; |
|
||||
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'; |
|
||||
import { StartProcessBo } from '@/api/workflow/workflowCommon/types'; |
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
|
||||
|
|
||||
const buttonLoading = ref(false); |
|
||||
const loading = ref(true); |
|
||||
const leaveTime = ref<Array<string>>([]); |
|
||||
//路由参数 |
|
||||
const routeParams = ref<Record<string, any>>({}); |
|
||||
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 leaveFormRef = ref<ElFormInstance>(); |
|
||||
|
|
||||
const submitFormData = ref<StartProcessBo>({ |
|
||||
businessKey: '', |
|
||||
tableName: '', |
|
||||
variables: {} |
|
||||
}); |
|
||||
const taskVariables = ref<Record<string, any>>({}); |
|
||||
|
|
||||
const initFormData: LeaveForm = { |
|
||||
id: undefined, |
|
||||
leaveType: undefined, |
|
||||
startDate: undefined, |
|
||||
endDate: undefined, |
|
||||
leaveDays: undefined, |
|
||||
remark: undefined, |
|
||||
status: 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 { form, rules } = toRefs(data); |
|
||||
|
|
||||
/** 表单重置 */ |
|
||||
const reset = () => { |
|
||||
form.value = { ...initFormData }; |
|
||||
leaveTime.value = []; |
|
||||
leaveFormRef.value?.resetFields(); |
|
||||
}; |
|
||||
|
|
||||
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)) + 1; |
|
||||
}; |
|
||||
/** 获取详情 */ |
|
||||
const getInfo = () => { |
|
||||
loading.value = true; |
|
||||
buttonLoading.value = false; |
|
||||
nextTick(async () => { |
|
||||
const res = await getLeave(routeParams.value.id); |
|
||||
Object.assign(form.value, res.data); |
|
||||
leaveTime.value = []; |
|
||||
leaveTime.value.push(form.value.startDate); |
|
||||
leaveTime.value.push(form.value.endDate); |
|
||||
loading.value = false; |
|
||||
buttonLoading.value = false; |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** 提交按钮 */ |
|
||||
const submitForm = (status: string) => { |
|
||||
if (leaveTime.value.length === 0) { |
|
||||
proxy?.$modal.msgError('请假时间不能为空'); |
|
||||
return; |
|
||||
} |
|
||||
try { |
|
||||
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('暂存成功'); |
|
||||
proxy.$tab.closePage(proxy.$route); |
|
||||
proxy.$router.go(-1); |
|
||||
} else { |
|
||||
await handleStartWorkFlow(res.data); |
|
||||
} |
|
||||
} |
|
||||
}); |
|
||||
} finally { |
|
||||
buttonLoading.value = false; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
//提交申请 |
|
||||
const handleStartWorkFlow = async (data: LeaveVO) => { |
|
||||
try { |
|
||||
submitFormData.value.tableName = 'test_leave'; |
|
||||
submitFormData.value.businessKey = data.id; |
|
||||
//流程变量 |
|
||||
taskVariables.value = { |
|
||||
entity: data, |
|
||||
leaveDays: data.leaveDays, |
|
||||
userList: ["1", "3"], |
|
||||
userList2: ["1", "3"] |
|
||||
}; |
|
||||
submitFormData.value.variables = taskVariables.value; |
|
||||
const resp = await startWorkFlow(submitFormData.value); |
|
||||
if (submitVerifyRef.value) { |
|
||||
buttonLoading.value = false; |
|
||||
submitVerifyRef.value.openDialog(resp.data.taskId); |
|
||||
} |
|
||||
} finally { |
|
||||
buttonLoading.value = false; |
|
||||
} |
|
||||
}; |
|
||||
//审批记录 |
|
||||
const handleApprovalRecord = () => { |
|
||||
approvalRecordRef.value.init(form.value.id); |
|
||||
}; |
|
||||
//提交回调 |
|
||||
const submitCallback = async () => { |
|
||||
await proxy.$tab.closePage(proxy.$route); |
|
||||
proxy.$router.go(-1); |
|
||||
}; |
|
||||
|
|
||||
//返回 |
|
||||
const goBack = () => { |
|
||||
proxy.$tab.closePage(proxy.$route); |
|
||||
proxy.$router.go(-1); |
|
||||
}; |
|
||||
//审批 |
|
||||
const approvalVerifyOpen = async () => { |
|
||||
submitVerifyRef.value.openDialog(routeParams.value.taskId); |
|
||||
}; |
|
||||
//校验提交按钮是否显示 |
|
||||
const submitButtonShow = computed(() => { |
|
||||
return ( |
|
||||
routeParams.value.type === 'add' || |
|
||||
(routeParams.value.type === 'update' && |
|
||||
form.value.status && |
|
||||
(form.value.status === 'draft' || form.value.status === 'cancel' || form.value.status === 'back')) |
|
||||
); |
|
||||
}); |
|
||||
|
|
||||
//校验审批按钮是否显示 |
|
||||
const approvalButtonShow = computed(() => { |
|
||||
return routeParams.value.type === 'approval' && form.value.status && form.value.status === 'waiting'; |
|
||||
}); |
|
||||
|
|
||||
onMounted(() => { |
|
||||
nextTick(async () => { |
|
||||
routeParams.value = proxy.$route.query; |
|
||||
reset(); |
|
||||
loading.value = false; |
|
||||
if (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval') { |
|
||||
getInfo(); |
|
||||
} |
|
||||
}); |
|
||||
}); |
|
||||
</script> |
|
||||
@ -1,383 +0,0 @@ |
|||||
<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"> |
|
||||
<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="single" @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> |
|
||||
<el-col :span="1.5"> |
|
||||
<el-button type="primary" plain :disabled="multiple" icon="Download" @click="clickExportZip()">导出</el-button> |
|
||||
</el-col> |
|
||||
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
|
||||
</el-row> |
|
||||
</template> |
|
||||
|
|
||||
<el-table v-loading="loading" border :data="modelList" @selection-change="handleSelectionChange"> |
|
||||
<el-table-column type="selection" width="55" align="center" /> |
|
||||
<el-table-column fixed align="center" type="index" label="序号" width="80"></el-table-column> |
|
||||
<el-table-column align="center" :show-overflow-tooltip="true" prop="name" label="模型名称" width="200"></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" :show-overflow-tooltip="true" prop="createTime" label="创建时间" width="160"></el-table-column> |
|
||||
<el-table-column align="center" :show-overflow-tooltip="true" prop="lastUpdateTime" label="更新时间" width="160"></el-table-column> |
|
||||
<el-table-column fixed="right" label="操作" align="center" width="170" 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="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="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="CopyDocument" @click="handleCopy(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 && billType === 'update'" 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 && billType === 'update'" 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 '../../../components/BpmnDesign/index.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'; |
|
||||
import { copyModel } from '@/api/workflow/model'; |
|
||||
|
|
||||
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 billType = 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 = () => { |
|
||||
billType.value = 'add'; |
|
||||
ids.value = []; |
|
||||
getTreeselect(); |
|
||||
form.value = { ...initFormData }; |
|
||||
dialog.visible = true; |
|
||||
dialog.title = '新增模型'; |
|
||||
}; |
|
||||
//修改打开 |
|
||||
const handleUpdate = () => { |
|
||||
billType.value = 'update'; |
|
||||
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 handleCopy = (row?: ModelVO) => { |
|
||||
billType.value = 'copy'; |
|
||||
dialog.title = '复制模型'; |
|
||||
nextTick(async () => { |
|
||||
await getTreeselect(); |
|
||||
form.value = { ...initFormData }; |
|
||||
form.value.id = row.id; |
|
||||
dialog.visible = true; |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** 提交按钮 */ |
|
||||
const submitForm = () => { |
|
||||
formRef.value.validate(async (valid: boolean) => { |
|
||||
if (valid) { |
|
||||
buttonLoading.value = true; |
|
||||
if ('copy' === billType.value) { |
|
||||
await copyModel(form.value); |
|
||||
proxy?.$modal.msgSuccess('操作成功'); |
|
||||
} else if (ids.value && ids.value.length > 0 && 'update' === billType.value) { |
|
||||
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 = () => { |
|
||||
proxy?.$download.zip('/workflow/model/export/zip/' + ids.value, '模型'); |
|
||||
}; |
|
||||
/** 查询流程分类下拉树结构 */ |
|
||||
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> |
|
||||
@ -1,45 +0,0 @@ |
|||||
<template> |
|
||||
<el-dialog v-model="data.visible" title="预览" width="70%" append-to-body destroy-on-close> |
|
||||
<div v-if="data.type === 'bpmn' && data.xmlStr"> |
|
||||
<BpmnViewer ref="bpmnViewerRef"></BpmnViewer> |
|
||||
</div> |
|
||||
<div v-if="data.type === 'xml' && data.xmlStr"> |
|
||||
<highlightjs language="xml" :code="data.xmlStr" /> |
|
||||
</div> |
|
||||
<template #footer> |
|
||||
<span v-if="data.type === 'xml'" class="dialog-footer"> </span> |
|
||||
</template> |
|
||||
</el-dialog> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
import BpmnViewer from '@/components/BpmnView/index.vue'; |
|
||||
|
|
||||
const data = reactive({ |
|
||||
visible: false, |
|
||||
type: '', |
|
||||
xmlStr: '' |
|
||||
}); |
|
||||
|
|
||||
const bpmnViewerRef = ref<InstanceType<typeof BpmnViewer>>(); |
|
||||
type PreviewType = 'xml' | 'bpmn'; |
|
||||
//打开 |
|
||||
const openDialog = (xmlStr: string, type: PreviewType) => { |
|
||||
data.visible = true; |
|
||||
data.xmlStr = xmlStr; |
|
||||
data.type = type; |
|
||||
/** 流程图 */ |
|
||||
if (type === 'bpmn') { |
|
||||
/** 必须放在nextTick 否则第一次打开为空 */ |
|
||||
nextTick(() => { |
|
||||
bpmnViewerRef.value?.initXml(data.xmlStr); |
|
||||
}); |
|
||||
} |
|
||||
}; |
|
||||
/** |
|
||||
* 对外暴露子组件方法 |
|
||||
*/ |
|
||||
defineExpose({ |
|
||||
openDialog |
|
||||
}); |
|
||||
</script> |
|
||||
@ -1,517 +0,0 @@ |
|||||
<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> |
|
||||
<el-card shadow="hover"> |
|
||||
<template #header> |
|
||||
<el-row :gutter="10" class="mb8"> |
|
||||
<el-col :span="1.5"> |
|
||||
<el-button type="danger" icon="Delete" :disabled="multiple" @click="handleDelete()">删除</el-button> |
|
||||
</el-col> |
|
||||
<el-col :span="1.5"> |
|
||||
<el-button type="primary" icon="UploadFilled" @click="uploadDialog.visible = true">部署流程文件</el-button> |
|
||||
</el-col> |
|
||||
<right-toolbar v-model:showSearch="showSearch" @query-table="getList"></right-toolbar> |
|
||||
</el-row> |
|
||||
</template> |
|
||||
|
|
||||
<el-table v-loading="loading" border :data="processDefinitionList" @selection-change="handleSelectionChange"> |
|
||||
<el-table-column type="selection" width="55" align="center" /> |
|
||||
<el-table-column align="center" type="index" label="序号" width="60"></el-table-column> |
|
||||
<el-table-column align="center" prop="name" label="流程定义名称" :show-overflow-tooltip="true"></el-table-column> |
|
||||
<el-table-column align="center" prop="key" label="标识KEY" width="80"></el-table-column> |
|
||||
<el-table-column align="center" prop="version" label="版本号" width="80"> |
|
||||
<template #default="scope"> v{{ scope.row.version }}.0</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" prop="resourceName" label="流程XML" width="100" :show-overflow-tooltip="true"> |
|
||||
<template #default="scope"> |
|
||||
<el-link type="primary" @click="clickPreview(scope.row.id, 'xml')">{{ scope.row.resourceName }}</el-link> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" prop="diagramResourceName" label="流程图片" width="100" :show-overflow-tooltip="true"> |
|
||||
<template #default="scope"> |
|
||||
<el-link type="primary" @click="clickPreview(scope.row.id, 'bpmn')">{{ scope.row.diagramResourceName }}</el-link> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" prop="suspensionState" label="状态" width="80"> |
|
||||
<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="部署时间" width="120" :show-overflow-tooltip="true"></el-table-column> |
|
||||
<el-table-column align="center" label="表名/表单KEY" width="120" :show-overflow-tooltip="true"> |
|
||||
<template #default="scope"> |
|
||||
<span v-if="scope.row.wfDefinitionConfigVo"> |
|
||||
{{ scope.row.wfDefinitionConfigVo.tableName }} |
|
||||
</span> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column fixed="right" label="操作" align="center" width="220" 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="Document" @click="getProcessDefinitionHitoryList(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> |
|
||||
<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="Tickets" @click="handleDefinitionConfigOpen(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> |
|
||||
<!-- 预览图片或xml --> |
|
||||
<process-preview ref="previewRef" /> |
|
||||
|
|
||||
<!-- 部署文件 --> |
|
||||
<el-dialog v-if="uploadDialog.visible" v-model="uploadDialog.visible" :title="uploadDialog.title" width="30%"> |
|
||||
<div v-loading="uploadDialogLoading"> |
|
||||
<div class="mb5"> |
|
||||
<el-text class="mx-1" size="large"><span class="text-danger">*</span>请选择部署流程分类:</el-text> |
|
||||
<el-tree-select |
|
||||
v-model="selectCategory" |
|
||||
:data="categoryOptions" |
|
||||
:props="{ value: 'categoryCode', label: 'categoryName', children: 'children' }" |
|
||||
filterable |
|
||||
value-key="categoryCode" |
|
||||
:render-after-expand="false" |
|
||||
check-strictly |
|
||||
style="width: 240px" |
|
||||
/> |
|
||||
</div> |
|
||||
<el-upload |
|
||||
class="upload-demo" |
|
||||
drag |
|
||||
multiple |
|
||||
accept="application/zip,application/xml,.bpmn" |
|
||||
:before-upload="handlerBeforeUpload" |
|
||||
: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 align="center" type="index" label="序号" width="60"></el-table-column> |
|
||||
<el-table-column align="center" prop="name" label="流程定义名称" :show-overflow-tooltip="true" min-width="80"></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 type="text" size="small" icon="Tickets" @click="handleDefinitionConfigOpen(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-col :span="1.5"> |
|
||||
<el-button link type="primary" icon="Delete" size="small" @click="handleDelete(scope.row)">删除</el-button> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
</el-table> |
|
||||
</el-dialog> |
|
||||
|
|
||||
<!-- 表单配置 --> |
|
||||
<el-dialog |
|
||||
v-model="definitionConfigDialog.visible" |
|
||||
:title="definitionConfigDialog.title" |
|
||||
width="650px" |
|
||||
append-to-body |
|
||||
:close-on-click-modal="false" |
|
||||
> |
|
||||
<el-form :model="definitionConfigForm" label-width="auto"> |
|
||||
<el-form-item label="流程KEY"> |
|
||||
<el-input v-model="definitionConfigForm.processKey" disabled /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="表名" prop="formId"> |
|
||||
<el-input v-model="definitionConfigForm.tableName" placeholder="示例:test_leave" /> |
|
||||
</el-form-item> |
|
||||
<el-form-item label="备注"> |
|
||||
<el-input v-model="definitionConfigForm.remark" type="textarea" resize="none" /> |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
|
|
||||
<template #footer> |
|
||||
<div class="dialog-footer"> |
|
||||
<el-button @click="definitionConfigDialog.visible = false">取消</el-button> |
|
||||
<el-button type="primary" @click="handlerSaveForm">保存</el-button> |
|
||||
</div> |
|
||||
</template> |
|
||||
</el-dialog> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts" setup name="processDefinition"> |
|
||||
import { |
|
||||
listProcessDefinition, |
|
||||
definitionImage, |
|
||||
definitionXml, |
|
||||
deleteProcessDefinition, |
|
||||
updateDefinitionState, |
|
||||
convertToModel, |
|
||||
deployProcessFile, |
|
||||
getListByKey |
|
||||
} from '@/api/workflow/processDefinition'; |
|
||||
import { getByTableNameNotDefId, getByDefId, saveOrUpdate } from '@/api/workflow/definitionConfig'; |
|
||||
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 { DefinitionConfigForm } from '@/api/workflow/definitionConfig/types'; |
|
||||
import { UploadRequestOptions, ElMessage, ElMessageBox } from 'element-plus'; |
|
||||
|
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
|
||||
|
|
||||
const previewRef = ref<InstanceType<typeof ProcessPreview>>(); |
|
||||
const queryFormRef = ref<ElFormInstance>(); |
|
||||
const categoryTreeRef = ref<ElTreeInstance>(); |
|
||||
const definitionConfigForm = ref<DefinitionConfigForm>({}); |
|
||||
|
|
||||
type CategoryOption = { |
|
||||
categoryCode: string; |
|
||||
categoryName: string; |
|
||||
children?: CategoryOption[]; |
|
||||
}; |
|
||||
|
|
||||
const loading = ref(true); |
|
||||
const ids = ref<Array<any>>([]); |
|
||||
const deploymentIds = ref<Array<any>>([]); |
|
||||
const keys = ref<Array<any>>([]); |
|
||||
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 categoryOptions = ref<CategoryOption[]>([]); |
|
||||
const categoryName = ref(''); |
|
||||
/** 部署文件分类选择 */ |
|
||||
const selectCategory = ref(); |
|
||||
|
|
||||
const uploadDialog = reactive<DialogOption>({ |
|
||||
visible: false, |
|
||||
title: '部署流程文件' |
|
||||
}); |
|
||||
|
|
||||
const processDefinitionDialog = reactive<DialogOption>({ |
|
||||
visible: false, |
|
||||
title: '历史版本' |
|
||||
}); |
|
||||
|
|
||||
const definitionConfigDialog = 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); |
|
||||
deploymentIds.value = selection.map((item: any) => item.deploymentId); |
|
||||
keys.value = selection.map((item: any) => item.key); |
|
||||
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 getListByKey(key); |
|
||||
if (resp.data && resp.data.length > 0) { |
|
||||
processDefinitionHistoryList.value = resp.data.filter((item: any) => item.id !== id); |
|
||||
} |
|
||||
loading.value = false; |
|
||||
}; |
|
||||
|
|
||||
type PreviewType = 'xml' | 'bpmn'; |
|
||||
//预览 公共方法 |
|
||||
const clickPreview = async (id: string, type: PreviewType) => { |
|
||||
loading.value = true; |
|
||||
const resp = await definitionXml(id); |
|
||||
if (previewRef.value) { |
|
||||
const xmlStr = resp.data.xmlStr; |
|
||||
loading.value = false; |
|
||||
previewRef.value.openDialog(xmlStr, type); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
/** 删除按钮操作 */ |
|
||||
const handleDelete = async (row?: ProcessDefinitionVO) => { |
|
||||
const id = row?.id || ids.value; |
|
||||
const deployIds = row?.deploymentId || deploymentIds.value; |
|
||||
const defKeys = row?.key || keys.value; |
|
||||
await proxy?.$modal.confirm('是否确认删除流程定义KEY为【' + defKeys + '】的数据项?'); |
|
||||
loading.value = true; |
|
||||
await deleteProcessDefinition(deployIds, 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 updateDefinitionState(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 handlerBeforeUpload = () => { |
|
||||
if (selectCategory.value === 'ALL') { |
|
||||
proxy?.$modal.msgError('顶级节点不可作为分类!'); |
|
||||
return false; |
|
||||
} |
|
||||
if (!selectCategory.value) { |
|
||||
proxy?.$modal.msgError('请选择左侧要上传的分类!'); |
|
||||
return false; |
|
||||
} |
|
||||
}; |
|
||||
//部署文件 |
|
||||
const handerDeployProcessFile = (data: UploadRequestOptions): XMLHttpRequest => { |
|
||||
let formData = new FormData(); |
|
||||
uploadDialogLoading.value = true; |
|
||||
formData.append('file', data.file); |
|
||||
formData.append('categoryCode', selectCategory.value); |
|
||||
deployProcessFile(formData) |
|
||||
.then(() => { |
|
||||
uploadDialog.visible = false; |
|
||||
proxy?.$modal.msgSuccess('部署成功'); |
|
||||
handleQuery(); |
|
||||
}) |
|
||||
.finally(() => { |
|
||||
uploadDialogLoading.value = false; |
|
||||
}); |
|
||||
return; |
|
||||
}; |
|
||||
//打开流程定义配置 |
|
||||
const handleDefinitionConfigOpen = async (row: ProcessDefinitionVO) => { |
|
||||
definitionConfigDialog.visible = true; |
|
||||
definitionConfigForm.value.processKey = row.key; |
|
||||
definitionConfigForm.value.definitionId = row.id; |
|
||||
definitionConfigForm.value.version = row.version; |
|
||||
const resp = await getByDefId(row.id); |
|
||||
if (resp.data) { |
|
||||
definitionConfigForm.value = resp.data; |
|
||||
} else { |
|
||||
definitionConfigForm.value.tableName = undefined; |
|
||||
definitionConfigForm.value.remark = undefined; |
|
||||
} |
|
||||
}; |
|
||||
//保存表单 |
|
||||
const handlerSaveForm = async () => { |
|
||||
getByTableNameNotDefId(definitionConfigForm.value.tableName, definitionConfigForm.value.definitionId).then((res) => { |
|
||||
if (res.data && res.data.length > 0) { |
|
||||
ElMessageBox.confirm('表名已被【' + res.data[0].processKey + '】版本v' + res.data[0].version + '.0绑定确认后将会删除绑定的流程KEY!', '提示', { |
|
||||
confirmButtonText: '确认', |
|
||||
cancelButtonText: '取消', |
|
||||
type: 'warning' |
|
||||
}).then(() => { |
|
||||
saveOrUpdate(definitionConfigForm.value).then((resp) => { |
|
||||
if (resp.code === 200) { |
|
||||
proxy?.$modal.msgSuccess('操作成功'); |
|
||||
definitionConfigDialog.visible = false; |
|
||||
getList(); |
|
||||
} |
|
||||
}); |
|
||||
}); |
|
||||
} else { |
|
||||
saveOrUpdate(definitionConfigForm.value).then((resp) => { |
|
||||
if (resp.code === 200) { |
|
||||
proxy?.$modal.msgSuccess('操作成功'); |
|
||||
definitionConfigDialog.visible = false; |
|
||||
getList(); |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
}); |
|
||||
}; |
|
||||
</script> |
|
||||
@ -1,364 +0,0 @@ |
|||||
<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 value="running">运行中</el-radio-button> |
|
||||
<el-radio-button value="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" border :data="processInstanceList" @selection-change="handleSelectionChange"> |
|
||||
<el-table-column type="selection" width="55" align="center" /> |
|
||||
<el-table-column align="center" type="index" label="序号" width="60"></el-table-column> |
|
||||
<el-table-column :show-overflow-tooltip="true" align="center" label="流程定义名称"> |
|
||||
<template #default="scope"> |
|
||||
<span>{{ scope.row.processDefinitionName }}v{{ scope.row.processDefinitionVersion }}.0</span> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column 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" label="流程状态" min-width="70"> |
|
||||
<template #default="scope"> |
|
||||
<dict-tag :options="wf_business_status" :value="scope.row.businessStatus"></dict-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="130"> |
|
||||
<template #default="scope"> |
|
||||
<el-row v-if="tab === 'running'" :gutter="10" class="mb8"> |
|
||||
<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-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="View" @click="handleView(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> |
|
||||
</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="60"></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> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts" setup> |
|
||||
import { |
|
||||
getPageByRunning, |
|
||||
getPageByFinish, |
|
||||
deleteRunAndHisInstance, |
|
||||
deleteFinishAndHisInstance, |
|
||||
deleteRunInstance |
|
||||
} from '@/api/workflow/processInstance'; |
|
||||
import { getListByKey, migrationDefinition } from '@/api/workflow/processDefinition'; |
|
||||
import { listCategory } from '@/api/workflow/category'; |
|
||||
import { CategoryVO } from '@/api/workflow/category/types'; |
|
||||
import { ProcessInstanceQuery, ProcessInstanceVO } from '@/api/workflow/processInstance/types'; |
|
||||
import workflowCommon from '@/api/workflow/workflowCommon'; |
|
||||
import { RouterJumpVo } from '@/api/workflow/workflowCommon/types'; |
|
||||
//审批记录组件 |
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
|
||||
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status')); |
|
||||
const queryFormRef = ref<ElFormInstance>(); |
|
||||
const categoryTreeRef = ref<ElTreeInstance>(); |
|
||||
|
|
||||
// 遮罩层 |
|
||||
const loading = ref(true); |
|
||||
// 选中数组 |
|
||||
const ids = ref<Array<any>>([]); |
|
||||
// 选中业务id数组 |
|
||||
const businessKeys = 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 |
|
||||
}); |
|
||||
|
|
||||
/** 节点单击事件 */ |
|
||||
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 = () => { |
|
||||
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); |
|
||||
businessKeys.value = selection.map((item: any) => item.businessKey); |
|
||||
single.value = selection.length !== 1; |
|
||||
multiple.value = !selection.length; |
|
||||
}; |
|
||||
//分页 |
|
||||
const getProcessInstanceRunningList = () => { |
|
||||
loading.value = true; |
|
||||
getPageByRunning(queryParams.value).then((resp) => { |
|
||||
processInstanceList.value = resp.rows; |
|
||||
total.value = resp.total; |
|
||||
loading.value = false; |
|
||||
}); |
|
||||
}; |
|
||||
//分页 |
|
||||
const getProcessInstanceFinishList = () => { |
|
||||
loading.value = true; |
|
||||
getPageByFinish(queryParams.value).then((resp) => { |
|
||||
processInstanceList.value = resp.rows; |
|
||||
total.value = resp.total; |
|
||||
loading.value = false; |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** 删除按钮操作 */ |
|
||||
const handleDelete = async (row: any) => { |
|
||||
const businessKey = row.businessKey || businessKeys.value; |
|
||||
await proxy?.$modal.confirm('是否确认删除业务id为【' + businessKey + '】的数据项?'); |
|
||||
loading.value = true; |
|
||||
if ('running' === tab.value) { |
|
||||
await deleteRunAndHisInstance(businessKey).finally(() => (loading.value = false)); |
|
||||
getProcessInstanceRunningList(); |
|
||||
} else { |
|
||||
await deleteFinishAndHisInstance(businessKey).finally(() => (loading.value = false)); |
|
||||
getProcessInstanceFinishList(); |
|
||||
} |
|
||||
proxy?.$modal.msgSuccess('删除成功'); |
|
||||
}; |
|
||||
const changeTab = async (data: string) => { |
|
||||
processInstanceList.value = []; |
|
||||
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 = { |
|
||||
businessKey: row.businessKey, |
|
||||
deleteReason: deleteReason.value |
|
||||
}; |
|
||||
await deleteRunInstance(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; |
|
||||
getListByKey(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; |
|
||||
migrationDefinition(processDefinitionId.value, id).then((resp) => { |
|
||||
proxy?.$modal.msgSuccess('操作成功'); |
|
||||
getProcessInstanceRunningList(); |
|
||||
processDefinitionDialog.visible = false; |
|
||||
loading.value = false; |
|
||||
}); |
|
||||
}; |
|
||||
/** 查看按钮操作 */ |
|
||||
const handleView = (row) => { |
|
||||
const routerJumpVo = reactive<RouterJumpVo>({ |
|
||||
wfDefinitionConfigVo: row.wfDefinitionConfigVo, |
|
||||
wfNodeConfigVo: row.wfNodeConfigVo, |
|
||||
businessKey: row.businessKey, |
|
||||
taskId: row.id, |
|
||||
type: 'view' |
|
||||
}); |
|
||||
workflowCommon.routerJump(routerJumpVo, proxy); |
|
||||
}; |
|
||||
|
|
||||
onMounted(() => { |
|
||||
getProcessInstanceRunningList(); |
|
||||
getTreeselect(); |
|
||||
}); |
|
||||
</script> |
|
||||
@ -1,286 +0,0 @@ |
|||||
<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 value="waiting">待办任务</el-radio-button> |
|
||||
<el-radio-button value="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"> |
|
||||
<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" :disabled="multiple" @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" border :data="taskList" @selection-change="handleSelectionChange"> |
|
||||
<el-table-column type="selection" width="55" align="center" /> |
|
||||
<el-table-column align="center" type="index" label="序号" width="60"></el-table-column> |
|
||||
<el-table-column :show-overflow-tooltip="true" align="center" label="流程定义名称"> |
|
||||
<template #default="scope"> |
|
||||
<span>{{ scope.row.processDefinitionName }}v{{ scope.row.processDefinitionVersion }}.0</span> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" prop="processDefinitionKey" label="流程定义KEY"></el-table-column> |
|
||||
<el-table-column align="center" prop="name" label="任务名称"></el-table-column> |
|
||||
<el-table-column 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" label="流程状态" min-width="70"> |
|
||||
<template #default="scope"> |
|
||||
<dict-tag v-if="tab === 'waiting'" :options="wf_business_status" :value="scope.row.businessStatus"></dict-tag> |
|
||||
<el-tag v-else type="success">已完成</el-tag> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column v-if="tab === 'waiting'" align="center" prop="createTime" label="创建时间" width="160"></el-table-column> |
|
||||
<el-table-column v-if="tab === 'finish'" align="center" prop="startTime" label="创建时间" width="160"></el-table-column> |
|
||||
<el-table-column label="操作" align="center" :width="tab === 'finish' ? '80' : '151'"> |
|
||||
<template #default="scope"> |
|
||||
<el-row :gutter="10" class="mb8"> |
|
||||
<el-col :span="1.5"> |
|
||||
<el-button link type="primary" size="small" icon="View" @click="handleView(scope.row)">查看</el-button> |
|
||||
</el-col> |
|
||||
<el-col v-if="tab === 'waiting'" :span="1.5"> |
|
||||
<el-button link type="primary" size="small" icon="Document" @click="handleInstanceVariable(scope.row)">流程变量</el-button> |
|
||||
</el-col> |
|
||||
</el-row> |
|
||||
<el-row v-if="scope.row.multiInstance" :gutter="10" class="mb8"> |
|
||||
<el-col :span="1.5"> |
|
||||
<el-button link type="primary" size="small" icon="Remove" @click="deleteMultiInstanceUser(scope.row)">减签</el-button> |
|
||||
</el-col> |
|
||||
<el-col :span="1.5"> |
|
||||
<el-button link type="primary" size="small" icon="CirclePlus" @click="addMultiInstanceUser(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> |
|
||||
<!-- 加签组件 --> |
|
||||
<multiInstanceUser ref="multiInstanceUserRef" :title="title" @submit-callback="handleQuery" /> |
|
||||
<!-- 选人组件 --> |
|
||||
<UserSelect ref="userSelectRef" :multiple="false" @confirm-call-back="submitCallback"></UserSelect> |
|
||||
<!-- 流程变量开始 --> |
|
||||
<el-dialog v-model="variableVisible" draggable title="流程变量" width="60%" :close-on-click-modal="false"> |
|
||||
<el-card v-loading="variableLoading" class="box-card"> |
|
||||
<template #header> |
|
||||
<div class="clearfix"> |
|
||||
<span |
|
||||
>流程定义名称:<el-tag>{{ processDefinitionName }}</el-tag></span |
|
||||
> |
|
||||
</div> |
|
||||
</template> |
|
||||
<div v-for="(v, index) in variableList" :key="index"> |
|
||||
<el-form v-if="v.key !== '_FLOWABLE_SKIP_EXPRESSION_ENABLED'" :label-position="'right'" label-width="150px"> |
|
||||
<el-form-item :label="v.key + ':'"> |
|
||||
{{ v.value }} |
|
||||
</el-form-item> |
|
||||
</el-form> |
|
||||
</div> |
|
||||
</el-card> |
|
||||
</el-dialog> |
|
||||
<!-- 流程变量结束 --> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts" setup> |
|
||||
import { getPageByAllTaskWait, getPageByAllTaskFinish, updateAssignee, getInstanceVariable } from '@/api/workflow/task'; |
|
||||
import MultiInstanceUser from '@/components/Process/multiInstanceUser.vue'; |
|
||||
import UserSelect from '@/components/UserSelect'; |
|
||||
import { TaskQuery, TaskVO, VariableVo } from '@/api/workflow/task/types'; |
|
||||
import workflowCommon from '@/api/workflow/workflowCommon'; |
|
||||
import { RouterJumpVo } from '@/api/workflow/workflowCommon/types'; |
|
||||
//审批记录组件 |
|
||||
//加签组件 |
|
||||
const multiInstanceUserRef = ref<InstanceType<typeof MultiInstanceUser>>(); |
|
||||
//选人组件 |
|
||||
const userSelectRef = ref<InstanceType<typeof UserSelect>>(); |
|
||||
|
|
||||
const queryFormRef = ref<ElFormInstance>(); |
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
|
||||
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status')); |
|
||||
// 遮罩层 |
|
||||
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 title = ref(''); |
|
||||
// 流程变量是否显示 |
|
||||
const variableVisible = ref(false); |
|
||||
const variableLoading = ref(true); |
|
||||
// 流程变量 |
|
||||
const variableList = ref<VariableVo>({ |
|
||||
key: '', |
|
||||
value: '' |
|
||||
}); |
|
||||
//流程定义名称 |
|
||||
const processDefinitionName = ref(); |
|
||||
// 查询参数 |
|
||||
const queryParams = ref<TaskQuery>({ |
|
||||
pageNum: 1, |
|
||||
pageSize: 10, |
|
||||
name: undefined, |
|
||||
processDefinitionName: undefined, |
|
||||
processDefinitionKey: undefined |
|
||||
}); |
|
||||
const tab = ref('waiting'); |
|
||||
|
|
||||
//加签 |
|
||||
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) => { |
|
||||
taskList.value = []; |
|
||||
queryParams.value.pageNum = 1; |
|
||||
if ('waiting' === data) { |
|
||||
getWaitingList(); |
|
||||
} else { |
|
||||
getFinishList(); |
|
||||
} |
|
||||
}; |
|
||||
//分页 |
|
||||
const getWaitingList = () => { |
|
||||
loading.value = true; |
|
||||
getPageByAllTaskWait(queryParams.value).then((resp) => { |
|
||||
taskList.value = resp.rows; |
|
||||
total.value = resp.total; |
|
||||
loading.value = false; |
|
||||
}); |
|
||||
}; |
|
||||
const getFinishList = () => { |
|
||||
loading.value = true; |
|
||||
getPageByAllTaskFinish(queryParams.value).then((resp) => { |
|
||||
taskList.value = resp.rows; |
|
||||
total.value = resp.total; |
|
||||
loading.value = false; |
|
||||
}); |
|
||||
}; |
|
||||
//打开修改选人 |
|
||||
const handleUpdate = () => { |
|
||||
userSelectRef.value.open(); |
|
||||
}; |
|
||||
//修改办理人 |
|
||||
const submitCallback = async (data) => { |
|
||||
if (data && data.length > 0) { |
|
||||
await proxy?.$modal.confirm('是否确认提交?'); |
|
||||
loading.value = true; |
|
||||
await updateAssignee(ids.value, data[0].userId); |
|
||||
handleQuery(); |
|
||||
proxy?.$modal.msgSuccess('操作成功'); |
|
||||
} else { |
|
||||
proxy?.$modal.msgWarning('请选择用户!'); |
|
||||
} |
|
||||
}; |
|
||||
//查询流程变量 |
|
||||
const handleInstanceVariable = async (row: TaskVO) => { |
|
||||
variableLoading.value = true; |
|
||||
variableVisible.value = true; |
|
||||
processDefinitionName.value = row.processDefinitionName; |
|
||||
let data = await getInstanceVariable(row.id); |
|
||||
variableList.value = data.data; |
|
||||
variableLoading.value = false; |
|
||||
}; |
|
||||
/** 查看按钮操作 */ |
|
||||
const handleView = (row) => { |
|
||||
const routerJumpVo = reactive<RouterJumpVo>({ |
|
||||
wfDefinitionConfigVo: row.wfDefinitionConfigVo, |
|
||||
wfNodeConfigVo: row.wfNodeConfigVo, |
|
||||
businessKey: row.businessKey, |
|
||||
taskId: row.id, |
|
||||
type: 'view' |
|
||||
}); |
|
||||
workflowCommon.routerJump(routerJumpVo, proxy); |
|
||||
}; |
|
||||
onMounted(() => { |
|
||||
getWaitingList(); |
|
||||
}); |
|
||||
</script> |
|
||||
@ -1,255 +0,0 @@ |
|||||
<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" border :data="processInstanceList" @selection-change="handleSelectionChange"> |
|
||||
<el-table-column type="selection" width="55" align="center" /> |
|
||||
<el-table-column align="center" type="index" label="序号" width="60"></el-table-column> |
|
||||
<el-table-column v-if="false" align="center" prop="id" label="id"></el-table-column> |
|
||||
<el-table-column :show-overflow-tooltip="true" align="center" label="流程定义名称"> |
|
||||
<template #default="scope"> |
|
||||
<span>{{ scope.row.processDefinitionName }}v{{ scope.row.processDefinitionVersion }}.0</span> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column 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" label="流程状态" min-width="70"> |
|
||||
<template #default="scope"> |
|
||||
<dict-tag :options="wf_business_status" :value="scope.row.businessStatus"></dict-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" class-name="small-padding fixed-width"> |
|
||||
<template #default="scope"> |
|
||||
<el-tooltip |
|
||||
v-if="scope.row.businessStatus === 'draft' || scope.row.businessStatus === 'cancel' || scope.row.businessStatus === 'back'" |
|
||||
content="修改" |
|
||||
placement="top" |
|
||||
> |
|
||||
<el-button link type="primary" icon="Edit" @click="handleOpen(scope.row, 'update')"></el-button> |
|
||||
</el-tooltip> |
|
||||
<el-tooltip |
|
||||
v-if="scope.row.businessStatus === 'draft' || scope.row.businessStatus === 'cancel' || scope.row.businessStatus === 'back'" |
|
||||
content="删除" |
|
||||
placement="top" |
|
||||
> |
|
||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button> |
|
||||
</el-tooltip> |
|
||||
<el-tooltip placement="top" content="查看"> |
|
||||
<el-button link type="primary" icon="View" @click="handleOpen(scope.row, 'view')"></el-button> |
|
||||
</el-tooltip> |
|
||||
<el-tooltip v-if="scope.row.businessStatus === 'waiting'" content="撤销" placement="top"> |
|
||||
<el-button link type="primary" icon="Notification" @click="handleCancelProcessApply(scope.row.businessKey)"></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-col> |
|
||||
</el-row> |
|
||||
<!-- 提交组件 --> |
|
||||
<submitVerify ref="submitVerifyRef" @submit-callback="getList" /> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts" setup> |
|
||||
import { getPageByCurrent, deleteRunAndHisInstance, cancelProcessApply } from '@/api/workflow/processInstance'; |
|
||||
import { listCategory } from '@/api/workflow/category'; |
|
||||
import { CategoryVO } from '@/api/workflow/category/types'; |
|
||||
import { ProcessInstanceQuery, ProcessInstanceVO } from '@/api/workflow/processInstance/types'; |
|
||||
import workflowCommon from '@/api/workflow/workflowCommon'; |
|
||||
import { RouterJumpVo } from '@/api/workflow/workflowCommon/types'; |
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
|
||||
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status')); |
|
||||
const queryFormRef = ref<ElFormInstance>(); |
|
||||
const categoryTreeRef = ref<ElTreeInstance>(); |
|
||||
|
|
||||
// 遮罩层 |
|
||||
const loading = ref(true); |
|
||||
// 选中数组 |
|
||||
const businessKeys = 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 handleQuery = () => { |
|
||||
getList(); |
|
||||
}; |
|
||||
/** 重置按钮操作 */ |
|
||||
const resetQuery = () => { |
|
||||
queryFormRef.value?.resetFields(); |
|
||||
queryParams.value.categoryCode = ''; |
|
||||
queryParams.value.pageNum = 1; |
|
||||
queryParams.value.pageSize = 10; |
|
||||
handleQuery(); |
|
||||
}; |
|
||||
// 多选框选中数据 |
|
||||
const handleSelectionChange = (selection: ProcessInstanceVO[]) => { |
|
||||
businessKeys.value = selection.map((item: any) => item.businessKey); |
|
||||
single.value = selection.length !== 1; |
|
||||
multiple.value = !selection.length; |
|
||||
}; |
|
||||
//分页 |
|
||||
const getList = () => { |
|
||||
loading.value = true; |
|
||||
getPageByCurrent(queryParams.value).then((resp) => { |
|
||||
processInstanceList.value = resp.rows; |
|
||||
total.value = resp.total; |
|
||||
loading.value = false; |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** 删除按钮操作 */ |
|
||||
const handleDelete = async (row: ProcessInstanceVO) => { |
|
||||
const businessKey = row.businessKey || businessKeys.value; |
|
||||
await proxy?.$modal.confirm('是否确认删除业务id为【' + businessKey + '】的数据项?'); |
|
||||
loading.value = true; |
|
||||
if ('running' === tab.value) { |
|
||||
await deleteRunAndHisInstance(businessKey).finally(() => (loading.value = false)); |
|
||||
getList(); |
|
||||
} |
|
||||
proxy?.$modal.msgSuccess('删除成功'); |
|
||||
}; |
|
||||
|
|
||||
/** 撤销按钮操作 */ |
|
||||
const handleCancelProcessApply = async (businessKey: string) => { |
|
||||
await proxy?.$modal.confirm('是否确认撤销当前单据?'); |
|
||||
loading.value = true; |
|
||||
if ('running' === tab.value) { |
|
||||
await cancelProcessApply(businessKey).finally(() => (loading.value = false)); |
|
||||
getList(); |
|
||||
} |
|
||||
proxy?.$modal.msgSuccess('撤销成功'); |
|
||||
}; |
|
||||
|
|
||||
//办理 |
|
||||
const handleOpen = async (row, type) => { |
|
||||
const routerJumpVo = reactive<RouterJumpVo>({ |
|
||||
wfDefinitionConfigVo: row.wfDefinitionConfigVo, |
|
||||
wfNodeConfigVo: row.wfNodeConfigVo, |
|
||||
businessKey: row.businessKey, |
|
||||
taskId: row.id, |
|
||||
type: type |
|
||||
}); |
|
||||
workflowCommon.routerJump(routerJumpVo, proxy); |
|
||||
}; |
|
||||
</script> |
|
||||
@ -1,150 +0,0 @@ |
|||||
<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"> |
|
||||
<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" border :data="taskList" @selection-change="handleSelectionChange"> |
|
||||
<el-table-column type="selection" width="55" align="center" /> |
|
||||
<el-table-column align="center" type="index" label="序号" width="60"></el-table-column> |
|
||||
<el-table-column :show-overflow-tooltip="true" align="center" label="流程定义名称"> |
|
||||
<template #default="scope"> |
|
||||
<span>{{ scope.row.processDefinitionName }}v{{ scope.row.processDefinitionVersion }}.0</span> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" prop="processDefinitionKey" label="流程定义KEY"></el-table-column> |
|
||||
<el-table-column align="center" prop="name" label="任务名称"></el-table-column> |
|
||||
<el-table-column 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" label="流程状态" min-width="70"> |
|
||||
<template #default="scope"> |
|
||||
<dict-tag :options="wf_business_status" :value="scope.row.businessStatus"></dict-tag> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column label="操作" align="center" width="200"> |
|
||||
<template #default="scope"> |
|
||||
<el-button type="primary" size="small" icon="View" @click="handleView(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> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts" setup> |
|
||||
import { getPageByTaskCopy } from '@/api/workflow/task'; |
|
||||
import { TaskQuery } from '@/api/workflow/task/types'; |
|
||||
import workflowCommon from '@/api/workflow/workflowCommon'; |
|
||||
import { RouterJumpVo } from '@/api/workflow/workflowCommon/types'; |
|
||||
//审批记录组件 |
|
||||
const queryFormRef = ref<ElFormInstance>(); |
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
|
||||
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status')); |
|
||||
// 遮罩层 |
|
||||
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 |
|
||||
}); |
|
||||
/** 搜索按钮操作 */ |
|
||||
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; |
|
||||
getPageByTaskCopy(queryParams.value).then((resp) => { |
|
||||
taskList.value = resp.rows; |
|
||||
total.value = resp.total; |
|
||||
loading.value = false; |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
/** 查看按钮操作 */ |
|
||||
const handleView = (row) => { |
|
||||
const routerJumpVo = reactive<RouterJumpVo>({ |
|
||||
wfDefinitionConfigVo: row.wfDefinitionConfigVo, |
|
||||
wfNodeConfigVo: row.wfNodeConfigVo, |
|
||||
businessKey: row.businessKey, |
|
||||
taskId: row.id, |
|
||||
type: 'view' |
|
||||
}); |
|
||||
workflowCommon.routerJump(routerJumpVo, proxy); |
|
||||
}; |
|
||||
|
|
||||
onMounted(() => { |
|
||||
getTaskCopyList(); |
|
||||
}); |
|
||||
</script> |
|
||||
@ -1,136 +0,0 @@ |
|||||
<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"> |
|
||||
<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" border :data="taskList" @selection-change="handleSelectionChange"> |
|
||||
<el-table-column type="selection" width="55" align="center" /> |
|
||||
<el-table-column align="center" type="index" label="序号" width="60"></el-table-column> |
|
||||
<el-table-column :show-overflow-tooltip="true" align="center" label="流程定义名称"> |
|
||||
<template #default="scope"> |
|
||||
<span>{{ scope.row.processDefinitionName }}v{{ scope.row.processDefinitionVersion }}.0</span> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" prop="processDefinitionKey" label="流程定义KEY"></el-table-column> |
|
||||
<el-table-column align="center" prop="name" label="任务名称"></el-table-column> |
|
||||
<el-table-column 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="startTime" label="创建时间" width="160"></el-table-column> |
|
||||
<el-table-column label="操作" align="center" width="200"> |
|
||||
<template #default="scope"> |
|
||||
<el-button type="primary" size="small" icon="View" @click="handleView(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> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts" setup> |
|
||||
import { getPageByTaskFinish } from '@/api/workflow/task'; |
|
||||
import { TaskQuery, TaskVO } from '@/api/workflow/task/types'; |
|
||||
import workflowCommon from '@/api/workflow/workflowCommon'; |
|
||||
import { RouterJumpVo } from '@/api/workflow/workflowCommon/types'; |
|
||||
//审批记录组件 |
|
||||
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 |
|
||||
}); |
|
||||
/** 搜索按钮操作 */ |
|
||||
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; |
|
||||
getPageByTaskFinish(queryParams.value).then((resp) => { |
|
||||
taskList.value = resp.rows; |
|
||||
total.value = resp.total; |
|
||||
loading.value = false; |
|
||||
}); |
|
||||
}; |
|
||||
/** 查看按钮操作 */ |
|
||||
const handleView = (row: TaskVO) => { |
|
||||
const routerJumpVo = reactive<RouterJumpVo>({ |
|
||||
wfDefinitionConfigVo: row.wfDefinitionConfigVo, |
|
||||
wfNodeConfigVo: row.wfNodeConfigVo, |
|
||||
businessKey: row.businessKey, |
|
||||
taskId: row.id, |
|
||||
type: 'view' |
|
||||
}); |
|
||||
workflowCommon.routerJump(routerJumpVo, proxy); |
|
||||
}; |
|
||||
|
|
||||
onMounted(() => { |
|
||||
getFinishList(); |
|
||||
}); |
|
||||
</script> |
|
||||
@ -1,149 +0,0 @@ |
|||||
<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"> |
|
||||
<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" border :data="taskList" @selection-change="handleSelectionChange"> |
|
||||
<el-table-column type="selection" width="55" align="center" /> |
|
||||
<el-table-column align="center" type="index" label="序号" width="60"></el-table-column> |
|
||||
<el-table-column :show-overflow-tooltip="true" align="center" label="流程定义名称"> |
|
||||
<template #default="scope"> |
|
||||
<span>{{ scope.row.processDefinitionName }}v{{ scope.row.processDefinitionVersion }}.0</span> |
|
||||
</template> |
|
||||
</el-table-column> |
|
||||
<el-table-column align="center" prop="processDefinitionKey" label="流程定义KEY"></el-table-column> |
|
||||
<el-table-column align="center" prop="name" label="任务名称"></el-table-column> |
|
||||
<el-table-column 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" label="流程状态" min-width="70"> |
|
||||
<template #default="scope"> |
|
||||
<dict-tag :options="wf_business_status" :value="scope.row.businessStatus"></dict-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="200"> |
|
||||
<template #default="scope"> |
|
||||
<el-button type="primary" size="small" icon="Edit" @click="handleOpen(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> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts" setup> |
|
||||
import { getPageByTaskWait } from '@/api/workflow/task'; |
|
||||
import { TaskQuery, TaskVO } from '@/api/workflow/task/types'; |
|
||||
import workflowCommon from '@/api/workflow/workflowCommon'; |
|
||||
import { RouterJumpVo } from '@/api/workflow/workflowCommon/types'; |
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance; |
|
||||
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status')); |
|
||||
//提交组件 |
|
||||
const queryFormRef = ref<ElFormInstance>(); |
|
||||
// 遮罩层 |
|
||||
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 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; |
|
||||
getPageByTaskWait(queryParams.value).then((resp) => { |
|
||||
taskList.value = resp.rows; |
|
||||
total.value = resp.total; |
|
||||
loading.value = false; |
|
||||
}); |
|
||||
}; |
|
||||
//办理 |
|
||||
const handleOpen = async (row: TaskVO) => { |
|
||||
const routerJumpVo = reactive<RouterJumpVo>({ |
|
||||
wfDefinitionConfigVo: row.wfDefinitionConfigVo, |
|
||||
wfNodeConfigVo: row.wfNodeConfigVo, |
|
||||
businessKey: row.businessKey, |
|
||||
taskId: row.id, |
|
||||
type: 'approval' |
|
||||
}); |
|
||||
workflowCommon.routerJump(routerJumpVo, proxy); |
|
||||
}; |
|
||||
</script> |
|
||||
@ -1,18 +0,0 @@ |
|||||
# http://editorconfig.org |
|
||||
root = true |
|
||||
|
|
||||
# 空格替代Tab缩进在各种编辑工具下效果一致 |
|
||||
[*] |
|
||||
indent_style = space |
|
||||
indent_size = 4 |
|
||||
charset = utf-8 |
|
||||
end_of_line = lf |
|
||||
trim_trailing_whitespace = true |
|
||||
insert_final_newline = true |
|
||||
|
|
||||
[*.{json,yml,yaml}] |
|
||||
indent_size = 2 |
|
||||
|
|
||||
[*.md] |
|
||||
insert_final_newline = false |
|
||||
trim_trailing_whitespace = false |
|
||||
@ -1,48 +0,0 @@ |
|||||
###################################################################### |
|
||||
# Build Tools |
|
||||
|
|
||||
.gradle |
|
||||
/build/ |
|
||||
!gradle/wrapper/gradle-wrapper.jar |
|
||||
|
|
||||
target/ |
|
||||
!.mvn/wrapper/maven-wrapper.jar |
|
||||
|
|
||||
###################################################################### |
|
||||
# IDE |
|
||||
|
|
||||
### STS ### |
|
||||
.apt_generated |
|
||||
.classpath |
|
||||
.factorypath |
|
||||
.project |
|
||||
.settings |
|
||||
.springBeans |
|
||||
|
|
||||
### IntelliJ IDEA ### |
|
||||
.idea |
|
||||
*.iws |
|
||||
*.iml |
|
||||
*.ipr |
|
||||
|
|
||||
### JRebel ### |
|
||||
rebel.xml |
|
||||
|
|
||||
### NetBeans ### |
|
||||
nbproject/private/ |
|
||||
build/* |
|
||||
nbbuild/ |
|
||||
nbdist/ |
|
||||
.nb-gradle/ |
|
||||
|
|
||||
###################################################################### |
|
||||
# Others |
|
||||
*.log |
|
||||
*.xml.versionsBackup |
|
||||
*.swp |
|
||||
|
|
||||
!*/build/*.java |
|
||||
!*/build/*.html |
|
||||
!*/build/*.xml |
|
||||
|
|
||||
.flattened-pom.xml |
|
||||
@ -1,182 +0,0 @@ |
|||||
<img src="https://foruda.gitee.com/images/1679673773341074847/178e8451_1766278.png" width="50%" height="50%"> |
|
||||
<div style="height: 10px; clear: both;"></div> |
|
||||
|
|
||||
- - - |
|
||||
## 平台简介 |
|
||||
|
|
||||
[](https://gitee.com/dromara/RuoYi-Vue-Plus) |
|
||||
[](https://github.com/dromara/RuoYi-Vue-Plus) |
|
||||
[](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE) |
|
||||
[](https://www.jetbrains.com/?from=RuoYi-Vue-Plus) |
|
||||
<br> |
|
||||
[](https://gitee.com/dromara/RuoYi-Vue-Plus) |
|
||||
[]() |
|
||||
[]() |
|
||||
[]() |
|
||||
|
|
||||
> RuoYi-Vue-Plus 是重写 RuoYi-Vue 针对 `分布式集群与多租户` 场景全方位升级(不兼容原框架) |
|
||||
|
|
||||
> 项目代码、文档 均开源免费可商用 遵循开源协议在项目中保留开源协议文件即可<br> |
|
||||
活到老写到老 为兴趣而开源 为学习而开源 为让大家真正可以学到技术而开源 |
|
||||
|
|
||||
> 系统演示: [传送门](https://plus-doc.dromara.org/#/common/demo_system) |
|
||||
|
|
||||
> 前端项目地址: [plus-ui](https://gitee.com/JavaLionLi/plus-ui) |
|
||||
|
|
||||
> 文档地址: [plus-doc](https://plus-doc.dromara.org) |
|
||||
|
|
||||
## 赞助商 |
|
||||
|
|
||||
MaxKey 业界领先单点登录产品 - https://gitee.com/dromara/MaxKey <br> |
|
||||
CCFlow 驰聘低代码-流程-表单 - https://gitee.com/opencc/RuoYi-JFlow <br> |
|
||||
数舵科技 软件定制开发APP小程序等 - http://www.shuduokeji.com/ <br> |
|
||||
引迈信息 软件开发平台 - https://www.jnpfsoft.com/index.html?from=plus-doc <br> |
|
||||
[如何成为赞助商 加群联系作者详谈](https://plus-doc.dromara.org/#/common/add_group) |
|
||||
|
|
||||
# 本框架与RuoYi的功能差异 |
|
||||
|
|
||||
| 功能 | 本框架 | RuoYi | |
|
||||
|-------------|-------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------| |
|
||||
| 前端项目 | 采用 Vue3 + TS + ElementPlus 重写 | 基于Vue2/Vue3 + JS | |
|
||||
| 后端项目结构 | 采用插件化 + 扩展包形式 结构解耦 易于扩展 | 模块相互注入耦合严重难以扩展 | |
|
||||
| 后端代码风格 | 严格遵守Alibaba规范与项目统一配置的代码格式化 | 代码书写与常规结构不同阅读障碍大 | |
|
||||
| Web容器 | 采用 Undertow 基于 XNIO 的高性能容器 | 采用 Tomcat | |
|
||||
| 权限认证 | 采用 Sa-Token、Jwt 静态使用功能齐全 低耦合 高扩展 | Spring Security 配置繁琐扩展性极差 | |
|
||||
| 权限注解 | 采用 Sa-Token 支持注解 登录校验、角色校验、权限校验、二级认证校验、HttpBasic校验、忽略校验<br/>角色与权限校验支持多种条件 如 `AND` `OR` 或 `权限 OR 角色` 等复杂表达式 | 只支持是否存在匹配 | |
|
||||
| 三方鉴权 | 采用 JustAuth 第三方登录组件 支持微信、钉钉等数十种三方认证 | 无 | |
|
||||
| 关系数据库支持 | 原生支持 MySQL、Oracle、PostgreSQL、SQLServer<br/>可同时使用异构切换(支持其他 mybatis-plus 支持的所有数据库 只需要增加jdbc依赖即可使用 达梦金仓等均有成功案例) | 支持 Mysql、Oracle 不支持同时使用、不支持异构切换 | |
|
||||
| 缓存数据库 | 支持 Redis 5-7 支持大部分新功能特性 如 分布式限流、分布式队列 | Redis 简单 get set 支持 | |
|
||||
| Redis客户端 | 采用 Redisson Redis官方推荐 基于Netty的客户端工具<br/>支持Redis 90%以上的命令 底层优化规避很多不正确的用法 例如: keys被转换为scan<br/>支持单机、哨兵、单主集群、多主集群等模式 | Lettuce + RedisTemplate 支持模式少 工具使用繁琐<br/>连接池采用 common-pool Bug多经常性出问题 | |
|
||||
| 缓存注解 | 采用 Spring-Cache 注解 对其扩展了实现支持了更多功能<br/>例如 过期时间 最大空闲时间 组最大长度等 只需一个注解即可完成数据自动缓存 | 需手动编写Redis代码逻辑 | |
|
||||
| ORM框架 | 采用 Mybatis-Plus 基于对象几乎不用写SQL全java操作 功能强大插件众多<br/>例如多租户插件 分页插件 乐观锁插件等等 | 采用 Mybatis 基于XML需要手写SQL | |
|
||||
| SQL监控 | 采用 p6spy 可输出完整SQL与执行时间监控 | log输出 需手动拼接sql与参数无法快速查看调试问题 | |
|
||||
| 数据分页 | 采用 Mybatis-Plus 分页插件<br/>框架对其进行了扩展 对象化分页对象 支持多种方式传参 支持前端多排序 复杂排序 | 采用 PageHelper 仅支持单查询分页 参数只能从param传 只能单排序 功能扩展性差 体验不好 | |
|
||||
| 数据权限 | 采用 Mybatis-Plus 插件 自行分析拼接SQL 无感式过滤<br/>只需为Mapper设置好注解条件 支持多种自定义 不限于部门角色 | 采用 注解+aop 实现 基于部门角色 生成的sql兼容性差 不支持其他业务扩展<br/>生成sql后需手动拼接到具体业务sql上 对于多个Mapper查询不起作用 | |
|
||||
| 数据脱敏 | 采用 注解 + jackson 序列化期间脱敏 支持不同模块不同的脱敏条件<br/>支持多种策略 如身份证、手机号、地址、邮箱、银行卡等 可自行扩展 | 无 | |
|
||||
| 数据加解密 | 采用 注解 + mybatis 拦截器 对存取数据期间自动加解密<br/>支持多种策略 如BASE64、AES、RSA、SM2、SM4等 | 无 | |
|
||||
| 接口传输加密 | 采用 动态 AES + RSA 加密请求 body 每一次请求秘钥都不同大幅度降低可破解性 | 无 | |
|
||||
| 数据翻译 | 采用 注解 + jackson 序列化期间动态修改数据 数据进行翻译<br/>支持多种模式: `映射翻译` `直接翻译` `其他扩展条件翻译` 接口化两步即可完成自定义扩展 内置多种翻译实现 | 无 | |
|
||||
| 多数据源框架 | 采用 dynamic-datasource 支持市面大部分数据库<br/>通过yml配置即可动态管理异构不同种类的数据库 也可通过前端页面添加数据源<br/>支持spel表达式从请求头参数等条件切换数据源 | 基于 druid 手动编写代码配置数据源 配置繁琐 支持性差 | |
|
||||
| 多数据源事务 | 采用 dynamic-datasource 支持多数据源不同种类的数据库事务回滚 | 不支持 | |
|
||||
| 数据库连接池 | 采用 HikariCP Spring官方内置连接池 配置简单 以性能与稳定性闻名天下 | 采用 druid bug众多 社区维护差 活跃度低 配置众多繁琐性能一般 | |
|
||||
| 数据库主键 | 采用 雪花ID 基于时间戳的 有序增长 唯一ID 再也不用为分库分表 数据合并主键冲突重复而发愁 | 采用 数据库自增ID 支持数据量有限 不支持多数据源主键唯一 | |
|
||||
| WebSocket协议 | 基于 Spring 封装的 WebSocket 协议 扩展了Token鉴权与分布式会话同步 不再只是基于单机的废物 | 无 | |
|
||||
| SSE推送 | 采用 Spring SSE 实现 扩展了Token鉴权与分布式会话同步 | 无 | |
|
||||
| 序列化 | 采用 Jackson Spring官方内置序列化 靠谱!!! | 采用 fastjson bugjson 远近闻名 | |
|
||||
| 分布式幂等 | 参考美团GTIS防重系统简化实现(细节可看文档) | 手动编写注解基于aop实现 | |
|
||||
| 分布式锁 | 采用 Lock4j 底层基于 Redisson | 无 | |
|
||||
| 分布式任务调度 | 采用 SnailJob 天生支持分布式 统一的管理中心 支持多种数据库 支持分片重试DAG任务流等 | 采用 Quartz 基于数据库锁性能差 集群需要做很多配置与改造 | |
|
||||
| 文件存储 | 采用 Minio 分布式文件存储 天生支持多机、多硬盘、多分片、多副本存储<br/>支持权限管理 安全可靠 文件可加密存储 | 采用 本机文件存储 文件裸漏 易丢失泄漏 不支持集群有单点效应 | |
|
||||
| 云存储 | 采用 AWS S3 协议客户端 支持 七牛、阿里、腾讯 等一切支持S3协议的厂家 | 不支持 | |
|
||||
| 短信 | 采用 sms4j 短信融合包 支持数十种短信厂家 只需在yml配置好厂家密钥即可使用 可多厂家共用 | 不支持 | |
|
||||
| 邮件 | 采用 mail-api 通用协议支持大部分邮件厂商 | 不支持 | |
|
||||
| 接口文档 | 采用 SpringDoc、javadoc 无注解零入侵基于java注释<br/>只需把注释写好 无需再写一大堆的文档注解了 | 采用 Springfox 已停止维护 需要编写大量的注解来支持文档生成 | |
|
||||
| 校验框架 | 采用 Validation 支持注解与工具类校验 注解支持国际化 | 仅支持注解 且注解不支持国际化 | |
|
||||
| Excel框架 | 采用 Alibaba EasyExcel 基于插件化<br/>框架对其增加了很多功能 例如 自动合并相同内容 自动排列布局 字典翻译等 | 基于 POI 手写实现 功能有限 复杂 扩展性差 | |
|
||||
| 工作流支持 | 支持各种复杂审批 转办 委派 加减签 会签 或签 票签 等功能 | 无 | |
|
||||
| 工具类框架 | 采用 Hutool、Lombok 上百种工具覆盖90%的使用需求 基于注解自动生成 get set 等简化框架大量代码 | 手写工具稳定性差易出问题 工具数量有限 代码臃肿需自己手写 get set 等 | |
|
||||
| 监控框架 | 采用 SpringBoot-Admin 基于SpringBoot官方 actuator 探针机制<br/>实时监控服务状态 框架还为其扩展了在线日志查看监控 | 无 | |
|
||||
| 链路追踪 | 采用 Apache SkyWalking 还在为请求不知道去哪了 到哪出了问题而烦恼吗<br/>用了它即可实时查看请求经过的每一处每一个节点 | 无 | |
|
||||
| 代码生成器 | 只需设计好表结构 一键生成所有crud代码与页面<br/>降低80%的开发量 把精力都投入到业务设计上<br/>框架为其适配MP、SpringDoc规范化代码 同时支持动态多数据源代码生成 | 代码生成原生结构 只支持单数据源生成 | |
|
||||
| 部署方式 | 支持 Docker 编排 一键搭建所有环境 让开发人员从此不再为搭建环境而烦恼 | 原生jar部署 其他环境需手动下载安装 自行搭建 | |
|
||||
| 项目路径修改 | 提供详细的修改方案文档 并为其做了一些改动 非常简单即可修改成自己想要的 | 需要做很多改造 文档说明有限 | |
|
||||
| 国际化 | 基于请求头动态返回不同语种的文本内容 开发难度低 有对应的工具类 支持大部分注解内容国际化 | 只提供基础功能 其他需自行编写扩展 | |
|
||||
| 代码单例测试 | 提供单例测试 使用方式编写方法与maven多环境单测插件 | 只提供基础功能 其他需自行编写扩展 | |
|
||||
| Demo案例 | 提供框架功能的实际使用案例 单独一个模块提供了很多很全 | 无 | |
|
||||
|
|
||||
|
|
||||
## 本框架与RuoYi的业务差异 |
|
||||
|
|
||||
| 业务 | 功能说明 | 本框架 | RuoYi | |
|
||||
|--------|----------------------------------------------------------------------|-----|------------------| |
|
||||
| 租户管理 | 系统内租户的管理 如:租户套餐、过期时间、用户数量、企业信息等 | 支持 | 无 | |
|
||||
| 租户套餐管理 | 系统内租户所能使用的套餐管理 如:套餐内所包含的菜单等 | 支持 | 无 | |
|
||||
| 客户端管理 | 系统内对接的所有客户端管理 如: pc端、小程序端等<br>支持动态授权登录方式 如: 短信登录、密码登录等 支持动态控制token时效 | 支持 | 无 | |
|
||||
| 用户管理 | 用户的管理配置 如:新增用户、分配用户所属部门、角色、岗位等 | 支持 | 支持 | |
|
||||
| 部门管理 | 配置系统组织机构(公司、部门、小组) 树结构展现支持数据权限 | 支持 | 支持 | |
|
||||
| 岗位管理 | 配置系统用户所属担任职务 | 支持 | 支持 | |
|
||||
| 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等 | 支持 | 支持 | |
|
||||
| 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 | 支持 | 支持 | |
|
||||
| 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 | 支持 | 支持 | |
|
||||
| 参数管理 | 对系统动态配置常用参数 | 支持 | 支持 | |
|
||||
| 通知公告 | 系统通知公告信息发布维护 | 支持 | 支持 | |
|
||||
| 操作日志 | 系统正常操作日志记录和查询 系统异常信息日志记录和查询 | 支持 | 支持 | |
|
||||
| 登录日志 | 系统登录日志记录查询包含登录异常 | 支持 | 支持 | |
|
||||
| 文件管理 | 系统文件展示、上传、下载、删除等管理 | 支持 | 无 | |
|
||||
| 文件配置管理 | 系统文件上传、下载所需要的配置信息动态添加、修改、删除等管理 | 支持 | 无 | |
|
||||
| 在线用户管理 | 已登录系统的在线用户信息监控与强制踢出操作 | 支持 | 支持 | |
|
||||
| 定时任务 | 运行报表、任务管理(添加、修改、删除)、日志管理、执行器管理等 | 支持 | 仅支持任务与日志管理 | |
|
||||
| 代码生成 | 多数据源前后端代码的生成(java、html、xml、sql)支持CRUD下载 | 支持 | 仅支持单数据源 | |
|
||||
| 系统接口 | 根据业务代码自动生成相关的api接口文档 | 支持 | 支持 | |
|
||||
| 服务监控 | 监视集群系统CPU、内存、磁盘、堆栈、在线日志、Spring相关配置等 | 支持 | 仅支持单机CPU、内存、磁盘监控 | |
|
||||
| 缓存监控 | 对系统的缓存信息查询,命令统计等。 | 支持 | 支持 | |
|
||||
| 在线构建器 | 拖动表单元素生成相应的HTML代码。 | 支持 | 支持 | |
|
||||
| 使用案例 | 系统的一些功能案例 | 支持 | 不支持 | |
|
||||
|
|
||||
## 参考文档 |
|
||||
|
|
||||
使用框架前请仔细阅读文档重点注意事项 |
|
||||
<br> |
|
||||
>[初始化项目 必看](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/init) |
|
||||
>>[https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/init](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/init) |
|
||||
> |
|
||||
>[专栏与视频 入门必看](https://plus-doc.dromara.org/#/common/column) |
|
||||
>>[https://plus-doc.dromara.org/#/common/column](https://plus-doc.dromara.org/#/common/column) |
|
||||
> |
|
||||
>[部署项目 必看](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/deploy) |
|
||||
>>[https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/deploy](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/deploy) |
|
||||
> |
|
||||
>[如何加群](https://plus-doc.dromara.org/#/common/add_group) |
|
||||
>>[https://plus-doc.dromara.org/#/common/add_group](https://plus-doc.dromara.org/#/common/add_group) |
|
||||
> |
|
||||
>[参考文档 Wiki](https://plus-doc.dromara.org) |
|
||||
>>[https://plus-doc.dromara.org](https://plus-doc.dromara.org) |
|
||||
|
|
||||
## 软件架构图 |
|
||||
|
|
||||
 |
|
||||
|
|
||||
## 如何参与贡献 |
|
||||
|
|
||||
[参与贡献的方式 https://plus-doc.dromara.org/#/common/contribution](https://plus-doc.dromara.org/#/common/contribution) |
|
||||
|
|
||||
## 捐献作者 |
|
||||
作者为兼职做开源,平时还需要工作,如果帮到了您可以请作者吃个盒饭 |
|
||||
<img src="https://foruda.gitee.com/images/1678975784848381069/d8661ed9_1766278.png" width="300px" height="450px" /> |
|
||||
<img src="https://foruda.gitee.com/images/1678975801230205215/6f96229d_1766278.png" width="300px" height="450px" /> |
|
||||
|
|
||||
## 演示图例 |
|
||||
|
|
||||
| | | |
|
||||
|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| |
|
||||
|  |  | |
|
||||
|  |  | |
|
||||
|  |  | |
|
||||
|  |  | |
|
||||
|  |  | |
|
||||
|  |  | |
|
||||
|  |  | |
|
||||
|  |  | |
|
||||
|  |  | |
|
||||
|  |  | |
|
||||
|  |  | |
|
||||
|  |  | |
|
||||
|  |  | |
|
||||
|  |  | |
|
||||
|  |  | |
|
||||
|  |  | |
|
||||
|  |  | |
|
||||
|  |  | |
|
||||
|  |  | |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
@ -1,23 +0,0 @@ |
|||||
package org.dromara; |
|
||||
|
|
||||
import org.springframework.boot.SpringApplication; |
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
|
||||
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; |
|
||||
|
|
||||
/** |
|
||||
* 启动程序 |
|
||||
* |
|
||||
* @author Lion Li |
|
||||
*/ |
|
||||
|
|
||||
@SpringBootApplication |
|
||||
public class DromaraApplication { |
|
||||
|
|
||||
public static void main(String[] args) { |
|
||||
SpringApplication application = new SpringApplication(DromaraApplication.class); |
|
||||
application.setApplicationStartup(new BufferingApplicationStartup(2048)); |
|
||||
application.run(args); |
|
||||
System.out.println("盒子IM后台管理服务启动成功"); |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
@ -1,18 +0,0 @@ |
|||||
package org.dromara; |
|
||||
|
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder; |
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; |
|
||||
|
|
||||
/** |
|
||||
* web容器中进行部署 |
|
||||
* |
|
||||
* @author Lion Li |
|
||||
*/ |
|
||||
public class DromaraServletInitializer extends SpringBootServletInitializer { |
|
||||
|
|
||||
@Override |
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { |
|
||||
return application.sources(DromaraApplication.class); |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
Loading…
Reference in new issue