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