@ -11,7 +11,7 @@ VITE_APP_BASE_API = '/dev-api'
|
|||||||
VITE_APP_CONTEXT_PATH = '/'
|
VITE_APP_CONTEXT_PATH = '/'
|
||||||
|
|
||||||
# 监控地址
|
# 监控地址
|
||||||
VITE_APP_MONITOR_ADMIN = 'http://localhost:9090/admin/applications'
|
VITE_APP_MONITOR_ADMIN = 'http://localhost:9090/applications'
|
||||||
|
|
||||||
# SnailJob 控制台地址
|
# SnailJob 控制台地址
|
||||||
VITE_APP_SNAILJOB_ADMIN = 'http://localhost:8800/snail-job'
|
VITE_APP_SNAILJOB_ADMIN = 'http://localhost:8800/snail-job'
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
*.sh
|
|
||||||
node_modules
|
|
||||||
*.md
|
|
||||||
*.woff
|
|
||||||
*.ttf
|
|
||||||
.vscode
|
|
||||||
.idea
|
|
||||||
dist
|
|
||||||
/public
|
|
||||||
/docs
|
|
||||||
.husky
|
|
||||||
.local
|
|
||||||
/bin
|
|
||||||
.eslintrc.cjs
|
|
||||||
prettier.config.js
|
|
||||||
src/assets
|
|
||||||
tailwind.config.js
|
|
@ -1,51 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
env: {
|
|
||||||
browser: true,
|
|
||||||
node: true,
|
|
||||||
es6: true
|
|
||||||
},
|
|
||||||
parser: 'vue-eslint-parser',
|
|
||||||
extends: [
|
|
||||||
'plugin:vue/vue3-recommended',
|
|
||||||
'./.eslintrc-auto-import.json',
|
|
||||||
'plugin:@typescript-eslint/recommended',
|
|
||||||
'prettier',
|
|
||||||
'plugin:prettier/recommended'
|
|
||||||
],
|
|
||||||
parserOptions: {
|
|
||||||
ecmaVersion: '2020',
|
|
||||||
sourceType: 'module',
|
|
||||||
project: './tsconfig.*?.json',
|
|
||||||
parser: '@typescript-eslint/parser'
|
|
||||||
},
|
|
||||||
plugins: ['vue', '@typescript-eslint', 'import', 'promise', 'node', 'prettier'],
|
|
||||||
rules: {
|
|
||||||
'@typescript-eslint/no-empty-function': 'off',
|
|
||||||
'@typescript-eslint/no-explicit-any': 'off',
|
|
||||||
'@typescript-eslint/no-unused-vars': 'off',
|
|
||||||
'@typescript-eslint/no-this-alias': 'off',
|
|
||||||
|
|
||||||
// vue
|
|
||||||
'vue/multi-word-component-names': 'off',
|
|
||||||
'vue/valid-define-props': 'off',
|
|
||||||
'vue/no-v-model-argument': 'off',
|
|
||||||
'prefer-rest-params': 'off',
|
|
||||||
// prettier
|
|
||||||
'prettier/prettier': 'error',
|
|
||||||
'@typescript-eslint/ban-types': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
// 关闭空类型检查 {}
|
|
||||||
extendDefaults: true,
|
|
||||||
types: {
|
|
||||||
'{}': false,
|
|
||||||
Function: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
globals: {
|
|
||||||
DialogOption: 'readonly',
|
|
||||||
OptionType: 'readonly'
|
|
||||||
}
|
|
||||||
};
|
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
- 本仓库为前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [TS](https://www.typescriptlang.org/) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) 版本。
|
- 本仓库为前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [TS](https://www.typescriptlang.org/) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) 版本。
|
||||||
- 成员项目: 基于 vben(ant-design-vue) 的前端项目 [ruoyi-plus-vben](https://gitee.com/dapppp/ruoyi-plus-vben)
|
- 成员项目: 基于 vben(ant-design-vue) 的前端项目 [ruoyi-plus-vben](https://gitee.com/dapppp/ruoyi-plus-vben)
|
||||||
|
- 成员项目: 基于 vben5(ant-design-vue) 的前端项目 [ruoyi-plus-vben5](https://gitee.com/dapppp/ruoyi-plus-vben5)
|
||||||
- 配套后端代码仓库地址
|
- 配套后端代码仓库地址
|
||||||
- [RuoYi-Vue-Plus 5.X(注意版本号)](https://gitee.com/dromara/RuoYi-Vue-Plus)
|
- [RuoYi-Vue-Plus 5.X(注意版本号)](https://gitee.com/dromara/RuoYi-Vue-Plus)
|
||||||
- [RuoYi-Cloud-Plus 2.X(注意版本号)](https://gitee.com/dromara/RuoYi-Cloud-Plus)
|
- [RuoYi-Cloud-Plus 2.X(注意版本号)](https://gitee.com/dromara/RuoYi-Cloud-Plus)
|
||||||
|
86
eslint.config.js
Normal file
86
eslint.config.js
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import globals from 'globals';
|
||||||
|
import pluginJs from '@eslint/js';
|
||||||
|
import tseslint from 'typescript-eslint';
|
||||||
|
import pluginVue from 'eslint-plugin-vue';
|
||||||
|
import { readFile } from 'node:fs/promises';
|
||||||
|
import prettier from 'eslint-plugin-prettier';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://blog.csdn.net/sayUonly/article/details/123482912
|
||||||
|
* 自动导入的配置
|
||||||
|
*/
|
||||||
|
const autoImportFile = new URL('./.eslintrc-auto-import.json', import.meta.url);
|
||||||
|
const autoImportGlobals = JSON.parse(await readFile(autoImportFile, 'utf8'));
|
||||||
|
|
||||||
|
/** @type {import('eslint').Linter.Config[]} */
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 不需要.eslintignore文件 而是在这里配置
|
||||||
|
*/
|
||||||
|
ignores: [
|
||||||
|
'*.sh',
|
||||||
|
'node_modules',
|
||||||
|
'*.md',
|
||||||
|
'*.woff',
|
||||||
|
'*.ttf',
|
||||||
|
'.vscode',
|
||||||
|
'.idea',
|
||||||
|
'dist',
|
||||||
|
'/public',
|
||||||
|
'/docs',
|
||||||
|
'.husky',
|
||||||
|
'.local',
|
||||||
|
'/bin',
|
||||||
|
'.eslintrc.cjs',
|
||||||
|
'prettier.config.js',
|
||||||
|
'src/assets',
|
||||||
|
'tailwind.config.js'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ files: ['**/*.{js,mjs,cjs,ts,vue}'] },
|
||||||
|
{
|
||||||
|
languageOptions: {
|
||||||
|
globals: globals.browser
|
||||||
|
}
|
||||||
|
},
|
||||||
|
pluginJs.configs.recommended,
|
||||||
|
...tseslint.configs.recommended,
|
||||||
|
...pluginVue.configs['flat/essential'],
|
||||||
|
{
|
||||||
|
files: ['**/*.vue'],
|
||||||
|
languageOptions: {
|
||||||
|
parserOptions: {
|
||||||
|
parser: tseslint.parser
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
languageOptions: {
|
||||||
|
globals: {
|
||||||
|
// 自动导入的配置 undef
|
||||||
|
...autoImportGlobals.globals,
|
||||||
|
DialogOption: 'readonly',
|
||||||
|
LayoutSetting: 'readonly'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plugins: { prettier },
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/no-empty-function': 'off',
|
||||||
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
'@typescript-eslint/no-unused-vars': 'off',
|
||||||
|
'@typescript-eslint/no-this-alias': 'off',
|
||||||
|
|
||||||
|
// vue
|
||||||
|
'vue/multi-word-component-names': 'off',
|
||||||
|
'vue/valid-define-props': 'off',
|
||||||
|
'vue/no-v-model-argument': 'off',
|
||||||
|
'prefer-rest-params': 'off',
|
||||||
|
// prettier
|
||||||
|
'prettier/prettier': 'error',
|
||||||
|
// 允许使用空Object类型 {}
|
||||||
|
'@typescript-eslint/no-empty-object-type': 'off',
|
||||||
|
'@typescript-eslint/no-unused-expressions': 'off'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
58
package.json
58
package.json
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/tsconfig",
|
||||||
"name": "ruoyi-vue-plus",
|
"name": "ruoyi-vue-plus",
|
||||||
"version": "5.2.3",
|
"version": "5.3.0-BETA",
|
||||||
"description": "RuoYi-Vue-Plus多租户管理系统",
|
"description": "RuoYi-Vue-Plus多租户管理系统",
|
||||||
"author": "LionLi",
|
"author": "LionLi",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -10,7 +11,8 @@
|
|||||||
"build:prod": "vite build --mode production",
|
"build:prod": "vite build --mode production",
|
||||||
"build:dev": "vite build --mode development",
|
"build:dev": "vite build --mode development",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"lint:eslint": "eslint --fix --ext .ts,.js,.vue ./src ",
|
"lint:eslint": "eslint",
|
||||||
|
"lint:eslint:fix": "eslint --fix",
|
||||||
"prettier": "prettier --write ."
|
"prettier": "prettier --write ."
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
@ -21,71 +23,65 @@
|
|||||||
"@element-plus/icons-vue": "2.3.1",
|
"@element-plus/icons-vue": "2.3.1",
|
||||||
"@highlightjs/vue-plugin": "2.1.0",
|
"@highlightjs/vue-plugin": "2.1.0",
|
||||||
"@vueup/vue-quill": "1.2.0",
|
"@vueup/vue-quill": "1.2.0",
|
||||||
"@vueuse/core": "10.9.0",
|
"@vueuse/core": "11.3.0",
|
||||||
"animate.css": "4.1.1",
|
"animate.css": "4.1.1",
|
||||||
"await-to-js": "3.0.0",
|
"await-to-js": "3.0.0",
|
||||||
"axios": "1.6.8",
|
"axios": "1.7.8",
|
||||||
"bpmn-js": "16.4.0",
|
|
||||||
"crypto-js": "4.2.0",
|
"crypto-js": "4.2.0",
|
||||||
"diagram-js": "12.3.0",
|
"diagram-js": "12.3.0",
|
||||||
"didi": "9.0.2",
|
"didi": "9.0.2",
|
||||||
"echarts": "5.5.0",
|
"echarts": "5.5.0",
|
||||||
"element-plus": "2.7.8",
|
"element-plus": "2.8.8",
|
||||||
"file-saver": "2.0.5",
|
"file-saver": "2.0.5",
|
||||||
"fuse.js": "7.0.0",
|
"fuse.js": "7.0.0",
|
||||||
"highlight.js": "11.9.0",
|
"highlight.js": "11.9.0",
|
||||||
"image-conversion": "^2.1.1",
|
"image-conversion": "2.1.1",
|
||||||
"js-cookie": "3.0.5",
|
"js-cookie": "3.0.5",
|
||||||
"jsencrypt": "3.3.2",
|
"jsencrypt": "3.3.2",
|
||||||
"nprogress": "0.2.0",
|
"nprogress": "0.2.0",
|
||||||
"pinia": "2.1.7",
|
"pinia": "2.2.6",
|
||||||
"screenfull": "6.0.2",
|
"screenfull": "6.0.2",
|
||||||
"vue": "3.4.34",
|
"vue": "3.5.13",
|
||||||
"vue-cropper": "1.1.1",
|
"vue-cropper": "1.1.1",
|
||||||
"vue-i18n": "9.10.2",
|
"vue-i18n": "10.0.5",
|
||||||
"vue-router": "4.3.2",
|
"vue-json-pretty": "2.4.0",
|
||||||
"vue-types": "5.1.1",
|
"vue-router": "4.4.5",
|
||||||
|
"vue-types": "5.1.3",
|
||||||
"vxe-table": "4.5.22"
|
"vxe-table": "4.5.22"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@iconify/json": "2.2.201",
|
"@eslint/js": "9.15.0",
|
||||||
"@intlify/unplugin-vue-i18n": "3.0.1",
|
"@iconify/json": "2.2.276",
|
||||||
"@types/crypto-js": "4.2.2",
|
"@types/crypto-js": "4.2.2",
|
||||||
"@types/file-saver": "2.0.7",
|
"@types/file-saver": "2.0.7",
|
||||||
"@types/js-cookie": "3.0.6",
|
"@types/js-cookie": "3.0.6",
|
||||||
"@types/node": "18.18.2",
|
"@types/node": "18.18.2",
|
||||||
"@types/nprogress": "0.2.3",
|
"@types/nprogress": "0.2.3",
|
||||||
"@typescript-eslint/eslint-plugin": "7.3.1",
|
"@unocss/preset-attributify": "0.64.1",
|
||||||
"@typescript-eslint/parser": "7.3.1",
|
"@unocss/preset-icons": "0.64.1",
|
||||||
"@unocss/preset-attributify": "0.58.6",
|
"@unocss/preset-uno": "0.64.1",
|
||||||
"@unocss/preset-icons": "0.58.6",
|
|
||||||
"@unocss/preset-uno": "0.58.6",
|
|
||||||
"@vitejs/plugin-vue": "5.0.4",
|
"@vitejs/plugin-vue": "5.0.4",
|
||||||
"@vue/compiler-sfc": "3.4.23",
|
"@vue/compiler-sfc": "3.4.23",
|
||||||
"autoprefixer": "10.4.18",
|
"autoprefixer": "10.4.18",
|
||||||
"eslint": "8.57.0",
|
"eslint": "9.15.0",
|
||||||
"eslint-config-prettier": "9.1.0",
|
"eslint-plugin-prettier": "^5.2.1",
|
||||||
"eslint-define-config": "2.1.0",
|
"eslint-plugin-vue": "9.31.0",
|
||||||
"eslint-plugin-prettier": "5.1.3",
|
|
||||||
"eslint-plugin-promise": "6.1.1",
|
|
||||||
"eslint-plugin-node": "11.1.0",
|
|
||||||
"eslint-plugin-import": "2.29.1",
|
|
||||||
"eslint-plugin-vue": "9.23.0",
|
|
||||||
"fast-glob": "3.3.2",
|
"fast-glob": "3.3.2",
|
||||||
|
"globals": "15.12.0",
|
||||||
"postcss": "8.4.36",
|
"postcss": "8.4.36",
|
||||||
"prettier": "3.2.5",
|
"prettier": "3.2.5",
|
||||||
"sass": "1.72.0",
|
"sass": "1.72.0",
|
||||||
"typescript": "5.4.5",
|
"typescript": "5.7.2",
|
||||||
"unocss": "0.58.6",
|
"typescript-eslint": "8.16.0",
|
||||||
|
"unocss": "0.64.1",
|
||||||
"unplugin-auto-import": "0.17.5",
|
"unplugin-auto-import": "0.17.5",
|
||||||
"unplugin-icons": "0.18.5",
|
"unplugin-icons": "0.18.5",
|
||||||
"unplugin-vue-components": "0.26.0",
|
"unplugin-vue-components": "0.26.0",
|
||||||
"unplugin-vue-setup-extend-plus": "1.0.1",
|
"unplugin-vue-setup-extend-plus": "1.0.1",
|
||||||
"vite": "5.2.12",
|
"vite": "5.4.11",
|
||||||
"vite-plugin-compression": "0.5.1",
|
"vite-plugin-compression": "0.5.1",
|
||||||
"vite-plugin-svg-icons": "2.0.1",
|
"vite-plugin-svg-icons": "2.0.1",
|
||||||
"vitest": "1.5.0",
|
"vitest": "1.5.0",
|
||||||
"vue-eslint-parser": "9.4.2",
|
|
||||||
"vue-tsc": "2.0.13"
|
"vue-tsc": "2.0.13"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,10 +51,12 @@ export function register(data: any) {
|
|||||||
* 注销
|
* 注销
|
||||||
*/
|
*/
|
||||||
export function logout() {
|
export function logout() {
|
||||||
request({
|
if (import.meta.env.VITE_APP_SSE === 'true') {
|
||||||
url: '/resource/sse/close',
|
request({
|
||||||
method: 'get'
|
url: '/resource/sse/close',
|
||||||
});
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
return request({
|
return request({
|
||||||
url: '/auth/logout',
|
url: '/auth/logout',
|
||||||
method: 'post'
|
method: 'post'
|
||||||
@ -100,11 +102,11 @@ export function getInfo(): AxiosPromise<UserInfo> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取租户列表
|
// 获取租户列表
|
||||||
export function getTenantList(): AxiosPromise<TenantInfo> {
|
export function getTenantList(isToken: boolean): AxiosPromise<TenantInfo> {
|
||||||
return request({
|
return request({
|
||||||
url: '/auth/tenant/list',
|
url: '/auth/tenant/list',
|
||||||
headers: {
|
headers: {
|
||||||
isToken: false
|
isToken: isToken
|
||||||
},
|
},
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
|
@ -30,7 +30,7 @@ export function getOnline() {
|
|||||||
// 删除当前在线设备
|
// 删除当前在线设备
|
||||||
export function delOnline(tokenId: string) {
|
export function delOnline(tokenId: string) {
|
||||||
return request({
|
return request({
|
||||||
url: '/monitor/online/' + tokenId,
|
url: '/monitor/online/myself/' + tokenId,
|
||||||
method: 'post'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import { AxiosPromise } from 'axios';
|
import { AxiosPromise } from 'axios';
|
||||||
import { DeptForm, DeptQuery, DeptVO } from './types';
|
import {DeptForm, DeptQuery, DeptTreeVO, DeptVO} from './types';
|
||||||
|
|
||||||
// 查询部门列表
|
// 查询部门列表
|
||||||
export const listDept = (query?: DeptQuery) => {
|
export const listDept = (query?: DeptQuery) => {
|
||||||
@ -11,6 +11,17 @@ export const listDept = (query?: DeptQuery) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过deptIds查询部门
|
||||||
|
* @param deptIds
|
||||||
|
*/
|
||||||
|
export const optionSelect = (deptIds: (number | string)[]): AxiosPromise<DeptVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept/optionselect?deptIds=' + deptIds,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// 查询部门列表(排除节点)
|
// 查询部门列表(排除节点)
|
||||||
export const listDeptExcludeChild = (deptId: string | number): AxiosPromise<DeptVO[]> => {
|
export const listDeptExcludeChild = (deptId: string | number): AxiosPromise<DeptVO[]> => {
|
||||||
return request({
|
return request({
|
||||||
@ -28,7 +39,7 @@ export const getDept = (deptId: string | number): AxiosPromise<DeptVO> => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 查询部门下拉树结构
|
// 查询部门下拉树结构
|
||||||
export const treeselect = (): AxiosPromise<DeptVO[]> => {
|
export const treeselect = (): AxiosPromise<DeptTreeVO[]> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/system/dept/treeselect',
|
url: '/system/dept/treeselect',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
|
@ -28,6 +28,18 @@ export interface DeptVO extends BaseEntity {
|
|||||||
menuId: string | number;
|
menuId: string | number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门类型
|
||||||
|
*/
|
||||||
|
export interface DeptTreeVO extends BaseEntity {
|
||||||
|
id: number | string;
|
||||||
|
label: string;
|
||||||
|
parentId: number | string;
|
||||||
|
weight: number;
|
||||||
|
children: DeptTreeVO[];
|
||||||
|
disabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 部门表单类型
|
* 部门表单类型
|
||||||
*/
|
*/
|
||||||
|
@ -96,6 +96,6 @@ export function syncTenantPackage(tenantId: string | number, packageId: string |
|
|||||||
export function syncTenantDict() {
|
export function syncTenantDict() {
|
||||||
return request({
|
return request({
|
||||||
url: '/system/tenant/syncTenantDict',
|
url: '/system/tenant/syncTenantDict',
|
||||||
method: 'get',
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { DeptVO } from './../dept/types';
|
import {DeptTreeVO, DeptVO} from './../dept/types';
|
||||||
import { RoleVO } from '@/api/system/role/types';
|
import { RoleVO } from '@/api/system/role/types';
|
||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import { AxiosPromise } from 'axios';
|
import { AxiosPromise } from 'axios';
|
||||||
@ -202,7 +202,7 @@ export const listUserByDeptId = (deptId: string | number): AxiosPromise<UserVO[]
|
|||||||
/**
|
/**
|
||||||
* 查询部门下拉树结构
|
* 查询部门下拉树结构
|
||||||
*/
|
*/
|
||||||
export const deptTreeSelect = (): AxiosPromise<DeptVO[]> => {
|
export const deptTreeSelect = (): AxiosPromise<DeptTreeVO[]> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/system/user/deptTree',
|
url: '/system/user/deptTree',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import { AxiosPromise } from 'axios';
|
import { AxiosPromise } from 'axios';
|
||||||
import { CategoryVO, CategoryForm, CategoryQuery } from '@/api/workflow/category/types';
|
import { CategoryVO, CategoryForm, CategoryQuery, CategoryTreeVO } from '@/api/workflow/category/types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询流程分类列表
|
* 查询流程分类列表
|
||||||
@ -18,11 +18,11 @@ export const listCategory = (query?: CategoryQuery): AxiosPromise<CategoryVO[]>
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询流程分类详细
|
* 查询流程分类详细
|
||||||
* @param id
|
* @param categoryId
|
||||||
*/
|
*/
|
||||||
export const getCategory = (id: string | number): AxiosPromise<CategoryVO> => {
|
export const getCategory = (categoryId: string | number): AxiosPromise<CategoryVO> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/workflow/category/' + id,
|
url: '/workflow/category/' + categoryId,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -53,11 +53,24 @@ export const updateCategory = (data: CategoryForm) => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除流程分类
|
* 删除流程分类
|
||||||
* @param id
|
* @param categoryId
|
||||||
*/
|
*/
|
||||||
export const delCategory = (id: string | number | Array<string | number>) => {
|
export const delCategory = (categoryId: string | number | Array<string | number>) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/workflow/category/' + id,
|
url: '/workflow/category/' + categoryId,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程分类树列表
|
||||||
|
* @param query 流程实例id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const categoryTree = (query?: CategoryForm): AxiosPromise<CategoryTreeVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/category/categoryTree`,
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
|
export interface CategoryTreeVO {
|
||||||
|
id: number | string;
|
||||||
|
label: string;
|
||||||
|
parentId: number | string;
|
||||||
|
weight: number;
|
||||||
|
children: CategoryTreeVO[];
|
||||||
|
}
|
||||||
export interface CategoryVO {
|
export interface CategoryVO {
|
||||||
/**
|
|
||||||
* 主键
|
|
||||||
*/
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分类名称
|
* 流程分类ID
|
||||||
*/
|
*/
|
||||||
categoryName: string;
|
categoryId: string | number;
|
||||||
|
|
||||||
/**
|
|
||||||
* 分类编码
|
|
||||||
*/
|
|
||||||
categoryCode: string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 父级id
|
* 父级id
|
||||||
@ -20,48 +18,55 @@ export interface CategoryVO {
|
|||||||
parentId: string | number;
|
parentId: string | number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 排序
|
* 流程分类名称
|
||||||
*/
|
*/
|
||||||
sortNum: number;
|
categoryName: string;
|
||||||
|
|
||||||
children?: CategoryVO[];
|
/**
|
||||||
|
* 显示顺序
|
||||||
|
*/
|
||||||
|
orderNum: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
createTime: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子对象
|
||||||
|
*/
|
||||||
|
children: CategoryVO[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CategoryForm extends BaseEntity {
|
export interface CategoryForm extends BaseEntity {
|
||||||
/**
|
|
||||||
* 主键
|
|
||||||
*/
|
|
||||||
id?: string | number;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分类名称
|
* 流程分类ID
|
||||||
|
*/
|
||||||
|
categoryId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程分类名称
|
||||||
*/
|
*/
|
||||||
categoryName?: string;
|
categoryName?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分类编码
|
* 父流程分类id
|
||||||
*/
|
|
||||||
categoryCode?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 父级id
|
|
||||||
*/
|
*/
|
||||||
parentId?: string | number;
|
parentId?: string | number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 排序
|
* 显示顺序
|
||||||
*/
|
*/
|
||||||
sortNum?: number;
|
orderNum?: number;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CategoryQuery extends PageQuery {
|
export interface CategoryQuery {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分类名称
|
* 流程分类名称
|
||||||
*/
|
*/
|
||||||
categoryName?: string;
|
categoryName?: string;
|
||||||
|
|
||||||
/**
|
|
||||||
* 分类编码
|
|
||||||
*/
|
|
||||||
categoryCode?: string;
|
|
||||||
}
|
}
|
||||||
|
170
src/api/workflow/definition/index.ts
Normal file
170
src/api/workflow/definition/index.ts
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
import { FlowDefinitionQuery, definitionXmlVO, FlowDefinitionForm, FlowDefinitionVo } from '@/api/workflow/definition/types';
|
||||||
|
import { AxiosPromise } from 'axios';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程定义列表
|
||||||
|
* @param query 流程实例id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const listDefinition = (query: FlowDefinitionQuery): AxiosPromise<FlowDefinitionVo[]> => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/list`,
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询未发布的流程定义列表
|
||||||
|
* @param query 流程实例id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const unPublishList = (query: FlowDefinitionQuery): AxiosPromise<FlowDefinitionVo[]> => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/unPublishList`,
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过流程定义id获取xml
|
||||||
|
* @param definitionId 流程定义id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const definitionXml = (definitionId: string): AxiosPromise<definitionXmlVO> => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/definitionXml/${definitionId}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除流程定义
|
||||||
|
* @param id 流程定义id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const deleteDefinition = (id: string | string[]) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/${id}`,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 挂起/激活
|
||||||
|
* @param definitionId 流程定义id
|
||||||
|
* @param activityStatus 状态
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const active = (definitionId: string, activityStatus: boolean) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/active/${definitionId}`,
|
||||||
|
method: 'put',
|
||||||
|
params: {
|
||||||
|
active: activityStatus
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过zip或xml部署流程定义
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function importDef(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/definition/importDef',
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
headers: {
|
||||||
|
repeatSubmit: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发布流程定义
|
||||||
|
* @param id 流程定义id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const publish = (id: string) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/publish/${id}`,
|
||||||
|
method: 'put'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消发布流程定义
|
||||||
|
* @param id 流程定义id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const unPublish = (id: string) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/unPublish/${id}`,
|
||||||
|
method: 'put'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程定义xml字符串
|
||||||
|
* @param id 流程定义id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const xmlString = (id: string) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/xmlString/${id}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增
|
||||||
|
* @param data 参数
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const add = (data: FlowDefinitionForm) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition`,
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改
|
||||||
|
* @param data 参数
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const edit = (data: FlowDefinitionForm) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition`,
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询详情
|
||||||
|
* @param id 参数
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getInfo = (id: number | string) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/${id}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制流程定义
|
||||||
|
* @param id 流程定义id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const copy = (id: string) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/definition/copy/${id}`,
|
||||||
|
method: 'post'
|
||||||
|
});
|
||||||
|
};
|
31
src/api/workflow/definition/types.ts
Normal file
31
src/api/workflow/definition/types.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
export interface FlowDefinitionQuery extends PageQuery {
|
||||||
|
flowCode?: string;
|
||||||
|
flowName?: string;
|
||||||
|
category: string | number;
|
||||||
|
isPublish?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FlowDefinitionVo {
|
||||||
|
id: string;
|
||||||
|
flowName: string;
|
||||||
|
flowCode: string;
|
||||||
|
formPath: string;
|
||||||
|
version: string;
|
||||||
|
isPublish: number;
|
||||||
|
activityStatus: number;
|
||||||
|
createTime: Date;
|
||||||
|
updateTime: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FlowDefinitionForm {
|
||||||
|
id: string;
|
||||||
|
flowName: string;
|
||||||
|
flowCode: string;
|
||||||
|
category: string;
|
||||||
|
formPath: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface definitionXmlVO {
|
||||||
|
xml: string[];
|
||||||
|
xmlStr: 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;
|
|
||||||
}
|
|
101
src/api/workflow/instance/index.ts
Normal file
101
src/api/workflow/instance/index.ts
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
import { FlowInstanceQuery, FlowInstanceVO } from '@/api/workflow/instance/types';
|
||||||
|
import { AxiosPromise } from 'axios';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询运行中实例列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const pageByRunning = (query: FlowInstanceQuery): AxiosPromise<FlowInstanceVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/instance/pageByRunning',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询已完成实例列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const pageByFinish = (query: FlowInstanceQuery): AxiosPromise<FlowInstanceVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/instance/pageByFinish',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过业务id获取历史流程图
|
||||||
|
*/
|
||||||
|
export const flowImage = (businessId: string | number) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/instance/flowImage/${businessId}` + '?t' + Math.random(),
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询当前登录人单据
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
export const pageByCurrent = (query: FlowInstanceQuery): AxiosPromise<FlowInstanceVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/workflow/instance/pageByCurrent',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 撤销流程
|
||||||
|
* @param data 参数
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const cancelProcessApply = (data: any) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/instance/cancelProcessApply`,
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程变量
|
||||||
|
* @param instanceId 实例id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const instanceVariable = (instanceId: string | number) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/instance/instanceVariable/${instanceId}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
* @param instanceIds 流程实例id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const deleteByInstanceIds = (instanceIds: Array<string | number> | string | number) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/instance/deleteByInstanceIds/${instanceIds}`,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 作废流程
|
||||||
|
* @param data 参数
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const invalid = (data: any) => {
|
||||||
|
return request({
|
||||||
|
url: `/workflow/instance/invalid`,
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
26
src/api/workflow/instance/types.ts
Normal file
26
src/api/workflow/instance/types.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { FlowTaskVO } from '@/api/workflow/task/types';
|
||||||
|
|
||||||
|
export interface FlowInstanceQuery extends PageQuery {
|
||||||
|
category?: string | number;
|
||||||
|
nodeName?: string;
|
||||||
|
flowCode?: string;
|
||||||
|
flowName?: string;
|
||||||
|
createByIds?: string[] | number[];
|
||||||
|
businessId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FlowInstanceVO extends BaseEntity {
|
||||||
|
id: string | number;
|
||||||
|
definitionId: string;
|
||||||
|
flowName: string;
|
||||||
|
flowCode: string;
|
||||||
|
version: string;
|
||||||
|
businessId: string;
|
||||||
|
activityStatus: number;
|
||||||
|
tenantId: string;
|
||||||
|
createTime: string;
|
||||||
|
createBy: string;
|
||||||
|
flowStatus: string;
|
||||||
|
flowStatusName: string;
|
||||||
|
flowTaskList: FlowTaskVO[];
|
||||||
|
}
|
@ -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,15 +1,15 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import { AxiosPromise } from 'axios';
|
import { AxiosPromise } from 'axios';
|
||||||
import { TaskQuery, TaskVO } from '@/api/workflow/task/types';
|
import { TaskQuery, FlowTaskVO, TaskOperationBo } from '@/api/workflow/task/types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询待办列表
|
* 查询待办列表
|
||||||
* @param query
|
* @param query
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
export const getPageByTaskWait = (query: TaskQuery): AxiosPromise<TaskVO[]> => {
|
export const pageByTaskWait = (query: TaskQuery): AxiosPromise<FlowTaskVO[]> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/workflow/task/getPageByTaskWait',
|
url: '/workflow/task/pageByTaskWait',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
@ -20,9 +20,9 @@ export const getPageByTaskWait = (query: TaskQuery): AxiosPromise<TaskVO[]> => {
|
|||||||
* @param query
|
* @param query
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
export const getPageByTaskFinish = (query: TaskQuery): AxiosPromise<TaskVO[]> => {
|
export const pageByTaskFinish = (query: TaskQuery): AxiosPromise<FlowTaskVO[]> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/workflow/task/getPageByTaskFinish',
|
url: '/workflow/task/pageByTaskFinish',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
@ -33,9 +33,9 @@ export const getPageByTaskFinish = (query: TaskQuery): AxiosPromise<TaskVO[]> =>
|
|||||||
* @param query
|
* @param query
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
export const getPageByTaskCopy = (query: TaskQuery): AxiosPromise<TaskVO[]> => {
|
export const pageByTaskCopy = (query: TaskQuery): AxiosPromise<FlowTaskVO[]> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/workflow/task/getPageByTaskCopy',
|
url: '/workflow/task/pageByTaskCopy',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
@ -46,9 +46,9 @@ export const getPageByTaskCopy = (query: TaskQuery): AxiosPromise<TaskVO[]> => {
|
|||||||
* @param query
|
* @param query
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
export const getPageByAllTaskWait = (query: TaskQuery): AxiosPromise<TaskVO[]> => {
|
export const pageByAllTaskWait = (query: TaskQuery): AxiosPromise<FlowTaskVO[]> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/workflow/task/getPageByAllTaskWait',
|
url: '/workflow/task/pageByAllTaskWait',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
@ -59,9 +59,9 @@ export const getPageByAllTaskWait = (query: TaskQuery): AxiosPromise<TaskVO[]> =
|
|||||||
* @param query
|
* @param query
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
export const getPageByAllTaskFinish = (query: TaskQuery): AxiosPromise<TaskVO[]> => {
|
export const pageByAllTaskFinish = (query: TaskQuery): AxiosPromise<FlowTaskVO[]> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/workflow/task/getPageByAllTaskFinish',
|
url: '/workflow/task/pageByAllTaskFinish',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
@ -93,30 +93,6 @@ export const completeTask = (data: object) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 认领任务
|
|
||||||
* @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
|
* @param data
|
||||||
@ -135,61 +111,24 @@ export const backProcess = (data: any): any => {
|
|||||||
* @param taskId
|
* @param taskId
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const getTaskById = (taskId: string) => {
|
export const getTask = (taskId: string) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/workflow/task/getTaskById/' + taskId,
|
url: '/workflow/task/getTask/' + taskId,
|
||||||
method: 'get'
|
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 taskIdList
|
||||||
* @param userId
|
* @param userId
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const updateAssignee = (taskIds: Array<string>, userId: string) => {
|
export const updateAssignee = (taskIdList: Array<string>, userId: string) => {
|
||||||
return request({
|
return request({
|
||||||
url: `/workflow/task/updateAssignee/${taskIds}/${userId}`,
|
url: `/workflow/task/updateAssignee/${userId}`,
|
||||||
method: 'put'
|
method: 'put',
|
||||||
});
|
data: taskIdList
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转办任务
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const transferTask = (data: any) => {
|
|
||||||
return request({
|
|
||||||
url: `/workflow/task/transferTask`,
|
|
||||||
method: 'post',
|
|
||||||
data: data
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -205,60 +144,37 @@ export const terminationTask = (data: any) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询流程变量
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const getInstanceVariable = (taskId: string) => {
|
|
||||||
return request({
|
|
||||||
url: `/workflow/task/getInstanceVariable/${taskId}`,
|
|
||||||
method: 'get'
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取可驳回得任务节点
|
* 获取可驳回得任务节点
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const getTaskNodeList = (processInstanceId: string) => {
|
export const getBackTaskNode = (definitionId: string, nodeCode: string) => {
|
||||||
return request({
|
return request({
|
||||||
url: `/workflow/task/getTaskNodeList/${processInstanceId}`,
|
url: `/workflow/task/getBackTaskNode/${definitionId}/${nodeCode}`,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 委托任务
|
* 任务操作 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const delegateTask = (data: any) => {
|
export const taskOperation = (data: TaskOperationBo, operation: string) => {
|
||||||
return request({
|
return request({
|
||||||
url: `/workflow/task/delegateTask`,
|
url: `/workflow/task/taskOperation/${operation}`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询工作流任务用户选择加签人员
|
* 获取当前任务办理人
|
||||||
* @param taskId
|
* @param taskId 任务id
|
||||||
* @returns {*}
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const getTaskUserIdsByAddMultiInstance = (taskId: string) => {
|
export const currentTaskAllUser = (taskId: string | number) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/workflow/task/getTaskUserIdsByAddMultiInstance/' + taskId,
|
url: `/workflow/task/currentTaskAllUser/${taskId}`,
|
||||||
method: 'get'
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询工作流选择减签人员
|
|
||||||
* @param taskId
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
export const getListByDeleteMultiInstance = (taskId: string) => {
|
|
||||||
return request({
|
|
||||||
url: '/workflow/task/getListByDeleteMultiInstance/' + taskId,
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { NodeConfigVO } from '@/api/workflow/nodeConfig/types';
|
|
||||||
import { DefinitionConfigVO } from '@/api/workflow/definitionConfig/types';
|
|
||||||
export interface TaskQuery extends PageQuery {
|
export interface TaskQuery extends PageQuery {
|
||||||
name?: string;
|
nodeName?: string;
|
||||||
processDefinitionKey?: string;
|
flowCode?: string;
|
||||||
processDefinitionName?: string;
|
flowName?: string;
|
||||||
|
createByIds?: string[] | number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ParticipantVo {
|
export interface ParticipantVo {
|
||||||
@ -12,38 +11,38 @@ export interface ParticipantVo {
|
|||||||
candidateName: string[];
|
candidateName: string[];
|
||||||
claim: boolean;
|
claim: boolean;
|
||||||
}
|
}
|
||||||
|
export interface FlowTaskVO {
|
||||||
export interface TaskVO extends BaseEntity {
|
id: string | number;
|
||||||
id: string;
|
createTime?: Date;
|
||||||
name: string;
|
updateTime?: Date;
|
||||||
description?: string;
|
tenantId?: string;
|
||||||
priority: number;
|
definitionId?: string;
|
||||||
owner?: string;
|
instanceId: string;
|
||||||
assignee?: string | number;
|
flowName: string;
|
||||||
assigneeName?: string;
|
businessId: string;
|
||||||
processInstanceId: string;
|
nodeCode: string;
|
||||||
executionId: string;
|
nodeName: string;
|
||||||
taskDefinitionId?: any;
|
flowCode: string;
|
||||||
processDefinitionId: string;
|
flowStatus: string;
|
||||||
endTime?: string;
|
formCustom: string;
|
||||||
taskDefinitionKey: string;
|
formPath: string;
|
||||||
dueDate?: string;
|
nodeType: number;
|
||||||
category?: any;
|
nodeRatio: string | number;
|
||||||
parentTaskId?: any;
|
version?: string;
|
||||||
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 {
|
export interface VariableVo {
|
||||||
key: string;
|
key: string;
|
||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TaskOperationBo {
|
||||||
|
//委派/转办人的用户ID(必填,准对委派/转办人操作)
|
||||||
|
userId?: string;
|
||||||
|
//加签/减签人的用户ID列表(必填,针对加签/减签操作)
|
||||||
|
userIds?: string[];
|
||||||
|
//任务ID(必填)
|
||||||
|
taskId: string | number;
|
||||||
|
//意见或备注信息(可选)
|
||||||
|
message?: string;
|
||||||
|
}
|
||||||
|
@ -2,28 +2,14 @@ import { RouterJumpVo } from '@/api/workflow/workflowCommon/types';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
routerJump(routerJumpVo: RouterJumpVo, proxy) {
|
routerJump(routerJumpVo: RouterJumpVo, proxy) {
|
||||||
if (routerJumpVo.wfNodeConfigVo && routerJumpVo.wfNodeConfigVo.formType === 'static' && routerJumpVo.wfNodeConfigVo.wfFormManageVo) {
|
proxy.$tab.closePage(proxy.$route);
|
||||||
proxy.$tab.closePage(proxy.$route);
|
proxy.$router.push({
|
||||||
proxy.$router.push({
|
path: routerJumpVo.formPath,
|
||||||
path: `${routerJumpVo.wfNodeConfigVo.wfFormManageVo.router}`,
|
query: {
|
||||||
query: {
|
id: routerJumpVo.businessId,
|
||||||
id: routerJumpVo.businessKey,
|
type: routerJumpVo.type,
|
||||||
type: routerJumpVo.type,
|
taskId: routerJumpVo.taskId
|
||||||
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 +1,13 @@
|
|||||||
import { NodeConfigVO } from '@/api/workflow/nodeConfig/types';
|
|
||||||
import { DefinitionConfigVO } from '@/api/workflow/definitionConfig/types';
|
|
||||||
|
|
||||||
export interface RouterJumpVo {
|
export interface RouterJumpVo {
|
||||||
wfNodeConfigVo: NodeConfigVO;
|
businessId: string;
|
||||||
wfDefinitionConfigVo: DefinitionConfigVO;
|
taskId: string | number;
|
||||||
businessKey: string;
|
|
||||||
taskId: string;
|
|
||||||
type: string;
|
type: string;
|
||||||
|
formCustom: string;
|
||||||
|
formPath: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StartProcessBo {
|
export interface StartProcessBo {
|
||||||
businessKey: string | number;
|
businessId: string | number;
|
||||||
tableName: string;
|
flowCode: string;
|
||||||
variables: any;
|
variables: any;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
.el-collapse {
|
.el-collapse {
|
||||||
.collapse__title {
|
.collapse__title {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
@ -14,14 +14,14 @@
|
|||||||
--tableHeaderBg: #f8f8f9;
|
--tableHeaderBg: #f8f8f9;
|
||||||
--tableHeaderTextColor: #515a6e;
|
--tableHeaderTextColor: #515a6e;
|
||||||
|
|
||||||
// 工作流
|
|
||||||
--bpmn-panel-border: #eeeeee;
|
|
||||||
--bpmn-panel-box-shadow: #cccccc;
|
|
||||||
--bpmn-panel-bar-background-color: #f5f7fa;
|
|
||||||
|
|
||||||
// ele
|
// ele
|
||||||
--brder-color: #e8e8e8
|
--brder-color: #e8e8e8;
|
||||||
|
|
||||||
|
// 添加 tag 相关变量
|
||||||
|
--tags-view-active-bg: var(--el-color-primary);
|
||||||
|
--tags-view-active-border-color: var(--el-color-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
html.dark {
|
html.dark {
|
||||||
--menuBg: #1d1e1f;
|
--menuBg: #1d1e1f;
|
||||||
--menuColor: #bfcbd9;
|
--menuColor: #bfcbd9;
|
||||||
@ -41,26 +41,40 @@ html.dark {
|
|||||||
.el-tree-node__content {
|
.el-tree-node__content {
|
||||||
--el-color-primary-light-9: #262727;
|
--el-color-primary-light-9: #262727;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-button--primary {
|
||||||
|
--el-button-bg-color: var(--el-color-primary-dark-6);
|
||||||
|
--el-button-border-color: var(--el-color-primary-light-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-switch {
|
||||||
|
--el-switch-on-color: var(--el-color-primary-dark-6);
|
||||||
|
--el-switch-border-color: var(--el-color-primary-light-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tag--primary {
|
||||||
|
--el-tag-bg-color: var(--el-color-primary-dark-6);
|
||||||
|
--el-tag-border-color: var(--el-color-primary-light-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在深色模式下使用更深的颜色
|
||||||
|
--tags-view-active-bg: var(--el-color-primary-dark-6);
|
||||||
|
--tags-view-active-border-color: var(--el-color-primary-light-2);
|
||||||
// vxe-table 主题
|
// vxe-table 主题
|
||||||
--vxe-font-color: #98989E;
|
--vxe-font-color: #98989e;
|
||||||
--vxe-primary-color: #2C7ECF;
|
--vxe-primary-color: #2c7ecf;
|
||||||
--vxe-icon-background-color: #98989E;
|
--vxe-icon-background-color: #98989e;
|
||||||
--vxe-table-font-color: #98989E;
|
--vxe-table-font-color: #98989e;
|
||||||
--vxe-table-resizable-color: #95969a;
|
--vxe-table-resizable-color: #95969a;
|
||||||
--vxe-table-header-background-color: #28282A;
|
--vxe-table-header-background-color: #28282a;
|
||||||
--vxe-table-body-background-color: #151518;
|
--vxe-table-body-background-color: #151518;
|
||||||
--vxe-table-background-color: #4a5663;
|
--vxe-table-background-color: #4a5663;
|
||||||
--vxe-table-border-width: 1px;
|
--vxe-table-border-width: 1px;
|
||||||
--vxe-table-border-color: #37373A;
|
--vxe-table-border-color: #37373a;
|
||||||
--vxe-toolbar-background-color: #37373A;
|
--vxe-toolbar-background-color: #37373a;
|
||||||
|
|
||||||
// 工作流
|
|
||||||
--bpmn-panel-border: #37373A;
|
|
||||||
--bpmn-panel-box-shadow: #37373A;
|
|
||||||
--bpmn-panel-bar-background-color: #37373A;
|
|
||||||
|
|
||||||
// ele
|
// ele
|
||||||
--brder-color: #37373A
|
--brder-color: #37373a;
|
||||||
}
|
}
|
||||||
|
|
||||||
// base color
|
// base color
|
||||||
@ -118,4 +132,4 @@ $base-sidebar-width: 200px;
|
|||||||
dangerColor: $--color-danger;
|
dangerColor: $--color-danger;
|
||||||
infoColor: $--color-info;
|
infoColor: $--color-info;
|
||||||
warningColor: $--color-warning;
|
warningColor: $--color-warning;
|
||||||
}
|
}
|
@ -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
Load Diff
@ -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>
|
|
@ -11,21 +11,53 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { RouteLocationMatched } from 'vue-router';
|
import { RouteLocationMatched } from 'vue-router';
|
||||||
|
import usePermissionStore from '@/store/modules/permission';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const permissionStore = usePermissionStore();
|
||||||
const levelList = ref<RouteLocationMatched[]>([]);
|
const levelList = ref<RouteLocationMatched[]>([]);
|
||||||
|
|
||||||
const getBreadcrumb = () => {
|
const getBreadcrumb = () => {
|
||||||
// only show routes with meta.title
|
// only show routes with meta.title
|
||||||
let matched = route.matched.filter((item) => item.meta && item.meta.title);
|
let matched = [];
|
||||||
const first = matched[0];
|
const pathNum = findPathNum(route.path);
|
||||||
|
// multi-level menu
|
||||||
|
if (pathNum > 2) {
|
||||||
|
const reg = /\/\w+/gi;
|
||||||
|
const pathList = route.path.match(reg).map((item, index) => {
|
||||||
|
if (index !== 0) item = item.slice(1);
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
getMatched(pathList, permissionStore.defaultRoutes, matched);
|
||||||
|
} else {
|
||||||
|
matched = route.matched.filter((item) => item.meta && item.meta.title);
|
||||||
|
}
|
||||||
// 判断是否为首页
|
// 判断是否为首页
|
||||||
if (!isDashboard(first)) {
|
if (!isDashboard(matched[0])) {
|
||||||
matched = ([{ path: '/index', meta: { title: '首页' } }] as any).concat(matched);
|
matched = [{ path: '/index', meta: { title: '首页' } }].concat(matched);
|
||||||
}
|
}
|
||||||
levelList.value = matched.filter((item) => item.meta && item.meta.title && item.meta.breadcrumb !== false);
|
levelList.value = matched.filter((item) => item.meta && item.meta.title && item.meta.breadcrumb !== false);
|
||||||
};
|
};
|
||||||
|
const findPathNum = (str, char = '/') => {
|
||||||
|
let index = str.indexOf(char);
|
||||||
|
let num = 0;
|
||||||
|
while (index !== -1) {
|
||||||
|
num++;
|
||||||
|
index = str.indexOf(char, index + 1);
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
};
|
||||||
|
const getMatched = (pathList, routeList, matched) => {
|
||||||
|
let data = routeList.find((item) => item.path == pathList[0] || (item.name += '').toLowerCase() == pathList[0]);
|
||||||
|
if (data) {
|
||||||
|
matched.push(data);
|
||||||
|
if (data.children && pathList.length) {
|
||||||
|
pathList.shift();
|
||||||
|
getMatched(pathList, data.children, matched);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
const isDashboard = (route: RouteLocationMatched) => {
|
const isDashboard = (route: RouteLocationMatched) => {
|
||||||
const name = route && (route.name as string);
|
const name = route && (route.name as string);
|
||||||
if (!name) {
|
if (!name) {
|
||||||
|
@ -121,6 +121,11 @@ const handleBeforeUpload = (file: any) => {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 校检文件名是否包含特殊字符
|
||||||
|
if (file.name.includes(',')) {
|
||||||
|
proxy?.$modal.msgError('文件名不正确,不能包含英文逗号!');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// 校检文件大小
|
// 校检文件大小
|
||||||
if (props.fileSize) {
|
if (props.fileSize) {
|
||||||
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
||||||
|
@ -139,6 +139,10 @@ const handleBeforeUpload = (file: any) => {
|
|||||||
proxy?.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join('/')}图片格式文件!`);
|
proxy?.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join('/')}图片格式文件!`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (file.name.includes(',')) {
|
||||||
|
proxy?.$modal.msgError('文件名不正确,不能包含英文逗号!');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (props.fileSize) {
|
if (props.fileSize) {
|
||||||
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
||||||
if (!isLt) {
|
if (!isLt) {
|
||||||
|
@ -2,39 +2,63 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<el-dialog v-model="visible" draggable title="审批记录" :width="props.width" :height="props.height" :close-on-click-modal="false">
|
<el-dialog v-model="visible" draggable title="审批记录" :width="props.width" :height="props.height" :close-on-click-modal="false">
|
||||||
<el-tabs v-model="tabActiveName" class="demo-tabs">
|
<el-tabs v-model="tabActiveName" class="demo-tabs">
|
||||||
<el-tab-pane label="流程图" name="bpmn">
|
<el-tab-pane v-loading="loading" label="流程图" name="image" style="height: 68vh">
|
||||||
<BpmnView ref="bpmnViewRef"></BpmnView>
|
<div
|
||||||
|
ref="imageWrapperRef"
|
||||||
|
class="image-wrapper"
|
||||||
|
@wheel="handleMouseWheel"
|
||||||
|
@mousedown="handleMouseDown"
|
||||||
|
@mousemove="handleMouseMove"
|
||||||
|
@mouseup="handleMouseUp"
|
||||||
|
@mouseleave="handleMouseLeave"
|
||||||
|
@dblclick="resetTransform"
|
||||||
|
:style="transformStyle"
|
||||||
|
>
|
||||||
|
<el-card class="box-card">
|
||||||
|
<el-image :src="imgUrl" class="scalable-image" />
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane v-loading="loading" label="审批信息" name="info">
|
<el-tab-pane v-loading="loading" label="审批信息" name="info">
|
||||||
<div>
|
<div>
|
||||||
<el-table :data="historyList" style="width: 100%" border fit>
|
<el-table :data="historyList" style="width: 100%" border fit>
|
||||||
<el-table-column type="index" label="序号" align="center" width="60"></el-table-column>
|
<el-table-column type="index" label="序号" align="center" width="60"></el-table-column>
|
||||||
<el-table-column prop="name" label="任务名称" sortable align="center"></el-table-column>
|
<el-table-column prop="nodeName" label="任务名称" sortable align="center"></el-table-column>
|
||||||
<el-table-column prop="nickName" :show-overflow-tooltip="true" label="办理人" sortable align="center">
|
<el-table-column prop="approveName" :show-overflow-tooltip="true" label="办理人" sortable align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag type="success">{{ scope.row.nickName || '无' }}</el-tag>
|
<template v-if="scope.row.approveName">
|
||||||
|
<el-tag v-for="(item, index) in scope.row.approveName.split(',')" :key="index" type="success">{{ item }}</el-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else> <el-tag type="success">无</el-tag></template>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="状态" sortable align="center">
|
<el-table-column prop="flowStatus" label="状态" width="80" sortable align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag type="success">{{ scope.row.statusName }}</el-tag>
|
<dict-tag :options="wf_task_status" :value="scope.row.flowStatus"></dict-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="comment" label="审批意见" sortable align="center"></el-table-column>
|
<el-table-column prop="message" label="审批意见" :show-overflow-tooltip="true" sortable align="center"></el-table-column>
|
||||||
<el-table-column prop="startTime" label="开始时间" sortable align="center"></el-table-column>
|
<el-table-column prop="createTime" label="开始时间" width="160" :show-overflow-tooltip="true" sortable align="center"></el-table-column>
|
||||||
<el-table-column prop="endTime" label="结束时间" sortable align="center"></el-table-column>
|
<el-table-column prop="updateTime" label="结束时间" width="160" :show-overflow-tooltip="true" sortable align="center"></el-table-column>
|
||||||
<el-table-column prop="runDuration" label="运行时长" sortable align="center"></el-table-column>
|
<el-table-column
|
||||||
<el-table-column prop="attachmentList" label="附件" sortable align="center">
|
prop="runDuration"
|
||||||
|
label="运行时常"
|
||||||
|
width="140"
|
||||||
|
:show-overflow-tooltip="true"
|
||||||
|
sortable
|
||||||
|
align="center"
|
||||||
|
></el-table-column>
|
||||||
|
<el-table-column prop="attachmentList" width="120" label="附件" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-popover v-if="scope.row.attachmentList && scope.row.attachmentList.length > 0" placement="right" :width="310" trigger="click">
|
<el-popover v-if="scope.row.attachmentList && scope.row.attachmentList.length > 0" placement="right" :width="310" trigger="click">
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<el-button style="margin-right: 16px">附件</el-button>
|
<el-button type="primary" style="margin-right: 16px">附件</el-button>
|
||||||
</template>
|
</template>
|
||||||
<el-table border :data="scope.row.attachmentList">
|
<el-table border :data="scope.row.attachmentList">
|
||||||
<el-table-column prop="name" width="202" :show-overflow-tooltip="true" label="附件名称"></el-table-column>
|
<el-table-column prop="originalName" width="202" :show-overflow-tooltip="true" label="附件名称"></el-table-column>
|
||||||
<el-table-column prop="name" width="80" align="center" :show-overflow-tooltip="true" label="操作">
|
<el-table-column prop="name" width="80" align="center" :show-overflow-tooltip="true" label="操作">
|
||||||
<template #default="tool">
|
<template #default="tool">
|
||||||
<el-button type="text" @click="handleDownload(tool.row.contentId)">下载</el-button>
|
<el-button type="text" @click="handleDownload(tool.row.ossId)">下载</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@ -49,42 +73,160 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import BpmnView from '@/components/BpmnView/index.vue';
|
import { flowImage } from '@/api/workflow/instance';
|
||||||
import processApi from '@/api/workflow/processInstance';
|
|
||||||
import { propTypes } from '@/utils/propTypes';
|
import { propTypes } from '@/utils/propTypes';
|
||||||
|
import { listByIds } from '@/api/system/oss';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
const { wf_task_status } = toRefs<any>(proxy?.useDict('wf_task_status'));
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
width: propTypes.string.def('70%'),
|
width: propTypes.string.def('80%'),
|
||||||
height: propTypes.string.def('100%')
|
height: propTypes.string.def('100%')
|
||||||
});
|
});
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
const historyList = ref<Array<any>>([]);
|
const historyList = ref<Array<any>>([]);
|
||||||
const tabActiveName = ref('bpmn');
|
const tabActiveName = ref('image');
|
||||||
|
const imgUrl = ref('');
|
||||||
const bpmnViewRef = ref<BpmnView>();
|
|
||||||
|
|
||||||
//初始化查询审批记录
|
//初始化查询审批记录
|
||||||
const init = async (businessKey: string | number) => {
|
const init = async (businessId: string | number) => {
|
||||||
visible.value = true;
|
visible.value = true;
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
tabActiveName.value = 'bpmn';
|
tabActiveName.value = 'image';
|
||||||
historyList.value = [];
|
historyList.value = [];
|
||||||
processApi.getHistoryRecord(businessKey).then((resp) => {
|
flowImage(businessId).then((resp) => {
|
||||||
historyList.value = resp.data;
|
if (resp.data) {
|
||||||
loading.value = false;
|
historyList.value = resp.data.list;
|
||||||
});
|
imgUrl.value = 'data:image/gif;base64,' + resp.data.image;
|
||||||
await nextTick(() => {
|
if (historyList.value.length > 0) {
|
||||||
bpmnViewRef.value.init(businessKey);
|
historyList.value.forEach((item) => {
|
||||||
|
if (item.ext) {
|
||||||
|
getIds(item.ext).then((res) => {
|
||||||
|
item.attachmentList = res.data;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
item.attachmentList = [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
const getIds = async (ids: string | number) => {
|
||||||
|
const res = await listByIds(ids);
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
/** 下载按钮操作 */
|
/** 下载按钮操作 */
|
||||||
const handleDownload = (ossId: string) => {
|
const handleDownload = (ossId: string) => {
|
||||||
proxy?.$download.oss(ossId);
|
proxy?.$download.oss(ossId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const imageWrapperRef = ref<HTMLElement | null>(null);
|
||||||
|
const scale = ref(1); // 初始缩放比例
|
||||||
|
const maxScale = 3; // 最大缩放比例
|
||||||
|
const minScale = 0.5; // 最小缩放比例
|
||||||
|
|
||||||
|
let isDragging = false;
|
||||||
|
let startX = 0;
|
||||||
|
let startY = 0;
|
||||||
|
let currentTranslateX = 0;
|
||||||
|
let currentTranslateY = 0;
|
||||||
|
|
||||||
|
const handleMouseWheel = (event: WheelEvent) => {
|
||||||
|
event.preventDefault();
|
||||||
|
let newScale = scale.value - event.deltaY / 1000;
|
||||||
|
newScale = Math.max(minScale, Math.min(newScale, maxScale));
|
||||||
|
if (newScale !== scale.value) {
|
||||||
|
scale.value = newScale;
|
||||||
|
resetDragPosition(); // 重置拖拽位置,使图片居中
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseDown = (event: MouseEvent) => {
|
||||||
|
if (scale.value > 1) {
|
||||||
|
event.preventDefault(); // 阻止默认行为,防止拖拽
|
||||||
|
isDragging = true;
|
||||||
|
startX = event.clientX;
|
||||||
|
startY = event.clientY;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseMove = (event: MouseEvent) => {
|
||||||
|
if (!isDragging || !imageWrapperRef.value) return;
|
||||||
|
|
||||||
|
const deltaX = event.clientX - startX;
|
||||||
|
const deltaY = event.clientY - startY;
|
||||||
|
startX = event.clientX;
|
||||||
|
startY = event.clientY;
|
||||||
|
|
||||||
|
currentTranslateX += deltaX;
|
||||||
|
currentTranslateY += deltaY;
|
||||||
|
|
||||||
|
// 边界检测,防止图片被拖出容器
|
||||||
|
const bounds = getBounds();
|
||||||
|
if (currentTranslateX > bounds.maxTranslateX) {
|
||||||
|
currentTranslateX = bounds.maxTranslateX;
|
||||||
|
} else if (currentTranslateX < bounds.minTranslateX) {
|
||||||
|
currentTranslateX = bounds.minTranslateX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentTranslateY > bounds.maxTranslateY) {
|
||||||
|
currentTranslateY = bounds.maxTranslateY;
|
||||||
|
} else if (currentTranslateY < bounds.minTranslateY) {
|
||||||
|
currentTranslateY = bounds.minTranslateY;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyTransform();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseUp = () => {
|
||||||
|
isDragging = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseLeave = () => {
|
||||||
|
isDragging = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetTransform = () => {
|
||||||
|
scale.value = 1;
|
||||||
|
currentTranslateX = 0;
|
||||||
|
currentTranslateY = 0;
|
||||||
|
applyTransform();
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetDragPosition = () => {
|
||||||
|
currentTranslateX = 0;
|
||||||
|
currentTranslateY = 0;
|
||||||
|
applyTransform();
|
||||||
|
};
|
||||||
|
|
||||||
|
const applyTransform = () => {
|
||||||
|
if (imageWrapperRef.value) {
|
||||||
|
imageWrapperRef.value.style.transform = `translate(${currentTranslateX}px, ${currentTranslateY}px) scale(${scale.value})`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getBounds = () => {
|
||||||
|
if (!imageWrapperRef.value) return { minTranslateX: 0, maxTranslateX: 0, minTranslateY: 0, maxTranslateY: 0 };
|
||||||
|
|
||||||
|
const imgRect = imageWrapperRef.value.getBoundingClientRect();
|
||||||
|
const containerRect = imageWrapperRef.value.parentElement?.getBoundingClientRect() ?? imgRect;
|
||||||
|
|
||||||
|
const minTranslateX = (containerRect.width - imgRect.width * scale.value) / 2;
|
||||||
|
const maxTranslateX = -(containerRect.width - imgRect.width * scale.value) / 2;
|
||||||
|
const minTranslateY = (containerRect.height - imgRect.height * scale.value) / 2;
|
||||||
|
const maxTranslateY = -(containerRect.height - imgRect.height * scale.value) / 2;
|
||||||
|
|
||||||
|
return { minTranslateX, maxTranslateX, minTranslateY, maxTranslateY };
|
||||||
|
};
|
||||||
|
|
||||||
|
const transformStyle = computed(() => ({
|
||||||
|
transition: isDragging ? 'none' : 'transform 0.2s ease'
|
||||||
|
}));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对外暴露子组件方法
|
* 对外暴露子组件方法
|
||||||
*/
|
*/
|
||||||
@ -113,4 +255,26 @@ defineExpose({
|
|||||||
min-height: calc(100vh - 170px) !important;
|
min-height: calc(100vh - 170px) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.image-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
user-select: none; /* 禁用文本选择 */
|
||||||
|
cursor: grab; /* 设置初始鼠标指针为可拖动 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-wrapper:active {
|
||||||
|
cursor: grabbing; /* 当正在拖动时改变鼠标指针 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.scalable-image {
|
||||||
|
object-fit: contain;
|
||||||
|
width: 100%;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,378 +0,0 @@
|
|||||||
<template>
|
|
||||||
<el-dialog v-model="visible" draggable :title="title" :width="width" :height="height" append-to-body :close-on-click-modal="false">
|
|
||||||
<div v-if="multiInstance === 'add'" class="p-2">
|
|
||||||
<el-row :gutter="20">
|
|
||||||
<!-- 部门树 -->
|
|
||||||
<el-col :lg="4" :xs="24" style="">
|
|
||||||
<el-card shadow="hover">
|
|
||||||
<el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
|
|
||||||
<el-tree
|
|
||||||
ref="deptTreeRef"
|
|
||||||
class="mt-2"
|
|
||||||
node-key="id"
|
|
||||||
:data="deptOptions"
|
|
||||||
:props="{ label: 'label', children: 'children' }"
|
|
||||||
:expand-on-click-node="false"
|
|
||||||
:filter-node-method="filterNode"
|
|
||||||
highlight-current
|
|
||||||
default-expand-all
|
|
||||||
@node-click="handleNodeClick"
|
|
||||||
></el-tree>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
<el-col :lg="20" :xs="24">
|
|
||||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
|
||||||
<div v-show="showSearch" class="search">
|
|
||||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
|
||||||
<el-form-item label="用户名称" prop="userName">
|
|
||||||
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="手机号码" prop="phonenumber">
|
|
||||||
<el-input v-model="queryParams.phonenumber" 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="hover">
|
|
||||||
<template #header>
|
|
||||||
<el-row :gutter="10">
|
|
||||||
<right-toolbar v-model:showSearch="showSearch" :search="true" @query-table="handleQuery"></right-toolbar>
|
|
||||||
</el-row>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<el-table ref="multipleTableRef" v-loading="loading" :data="userList" row-key="userId" @selection-change="handleSelectionChange">
|
|
||||||
<el-table-column type="selection" width="50" align="center" />
|
|
||||||
<el-table-column key="userId" label="用户编号" align="center" prop="userId" />
|
|
||||||
<el-table-column key="userName" label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" />
|
|
||||||
<el-table-column key="nickName" label="用户昵称" align="center" prop="nickName" :show-overflow-tooltip="true" />
|
|
||||||
<el-table-column key="phonenumber" label="手机号码" align="center" prop="phonenumber" width="120" />
|
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" width="160">
|
|
||||||
<template #default="scope">
|
|
||||||
<span>{{ scope.row.createTime }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
|
|
||||||
<pagination
|
|
||||||
v-show="total > 0"
|
|
||||||
v-model:page="queryParams.pageNum"
|
|
||||||
v-model:limit="queryParams.pageSize"
|
|
||||||
:total="total"
|
|
||||||
@pagination="handleQuery"
|
|
||||||
/>
|
|
||||||
</el-card>
|
|
||||||
<el-card shadow="hover">
|
|
||||||
<el-tag v-for="(user, index) in chooseUserList" :key="user.userId" style="margin: 2px" closable @close="handleCloseTag(user, index)"
|
|
||||||
>{{ user.userName }}
|
|
||||||
</el-tag>
|
|
||||||
</el-card>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</div>
|
|
||||||
<div v-if="multiInstance === 'delete'" class="p-2">
|
|
||||||
<el-table v-loading="loading" :data="taskList" @selection-change="handleTaskSelection">
|
|
||||||
<el-table-column type="selection" width="55" />
|
|
||||||
<el-table-column prop="name" label="任务名称" />
|
|
||||||
<el-table-column prop="assigneeName" label="办理人" />
|
|
||||||
</el-table>
|
|
||||||
</div>
|
|
||||||
<template #footer>
|
|
||||||
<div class="dialog-footer">
|
|
||||||
<el-button type="primary" @click="submitFileForm">确 定</el-button>
|
|
||||||
<el-button @click="visible = false">取 消</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup name="User" lang="ts">
|
|
||||||
import { deptTreeSelect, listUser, optionSelect } from '@/api/system/user';
|
|
||||||
import {
|
|
||||||
addMultiInstanceExecution,
|
|
||||||
deleteMultiInstanceExecution,
|
|
||||||
getTaskUserIdsByAddMultiInstance,
|
|
||||||
getListByDeleteMultiInstance
|
|
||||||
} from '@/api/workflow/task';
|
|
||||||
import { UserVO } from '@/api/system/user/types';
|
|
||||||
import { DeptVO } from '@/api/system/dept/types';
|
|
||||||
import { ComponentInternalInstance } from 'vue';
|
|
||||||
import { ElTree, ElTable } from 'element-plus';
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
// 宽
|
|
||||||
width: {
|
|
||||||
type: String,
|
|
||||||
default: '70%'
|
|
||||||
},
|
|
||||||
// 高
|
|
||||||
height: {
|
|
||||||
type: String,
|
|
||||||
default: '100%'
|
|
||||||
},
|
|
||||||
// 标题
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
default: '加签人员'
|
|
||||||
},
|
|
||||||
//是否多选
|
|
||||||
multiple: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
//回显用户id
|
|
||||||
userIdList: {
|
|
||||||
type: Array,
|
|
||||||
default: () => []
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const deptTreeRef = ref(ElTree);
|
|
||||||
const multipleTableRef = ref(ElTable);
|
|
||||||
|
|
||||||
const userList = ref<UserVO[]>();
|
|
||||||
const taskList = ref<Array<any>[]>();
|
|
||||||
const loading = ref(true);
|
|
||||||
const showSearch = ref(true);
|
|
||||||
const selectionTask = ref<Array<any>[]>();
|
|
||||||
const visible = ref(false);
|
|
||||||
const total = ref(0);
|
|
||||||
const deptName = ref('');
|
|
||||||
const deptOptions = ref<DeptVO[]>([]);
|
|
||||||
const chooseUserList = ref(ref<UserVO[]>());
|
|
||||||
const userIds = ref<Array<number | string>>([]);
|
|
||||||
//加签或者减签
|
|
||||||
const multiInstance = ref('');
|
|
||||||
const queryParams = ref<Record<string, any>>({
|
|
||||||
pageNum: 1,
|
|
||||||
pageSize: 10,
|
|
||||||
userName: '',
|
|
||||||
nickName: '',
|
|
||||||
taskId: ''
|
|
||||||
});
|
|
||||||
/** 查询用户列表 */
|
|
||||||
const getAddMultiInstanceList = async (taskId: string, userIdList: Array<number | string>) => {
|
|
||||||
deptOptions.value = [];
|
|
||||||
getTreeSelect();
|
|
||||||
multiInstance.value = 'add';
|
|
||||||
userIds.value = userIdList;
|
|
||||||
visible.value = true;
|
|
||||||
queryParams.value.taskId = taskId;
|
|
||||||
loading.value = true;
|
|
||||||
const res1 = await getTaskUserIdsByAddMultiInstance(taskId);
|
|
||||||
queryParams.value.excludeUserIds = res1.data;
|
|
||||||
const res = await listUser(queryParams.value);
|
|
||||||
loading.value = false;
|
|
||||||
userList.value = res.rows;
|
|
||||||
total.value = res.total;
|
|
||||||
if (userList.value && userIds.value.length > 0) {
|
|
||||||
const data = await optionSelect(userIds.value);
|
|
||||||
if (data.data && data.data.length > 0) {
|
|
||||||
chooseUserList.value = data.data;
|
|
||||||
data.data.forEach((user: UserVO) => {
|
|
||||||
multipleTableRef.value!.toggleRowSelection(
|
|
||||||
userList.value.find((item) => {
|
|
||||||
return item.userId == user.userId;
|
|
||||||
}),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getList = async () => {
|
|
||||||
loading.value = true;
|
|
||||||
const res1 = await getTaskUserIdsByAddMultiInstance(queryParams.value.taskId);
|
|
||||||
queryParams.value.excludeUserIds = res1.data;
|
|
||||||
const res = await listUser(queryParams.value);
|
|
||||||
loading.value = false;
|
|
||||||
userList.value = res.rows;
|
|
||||||
total.value = res.total;
|
|
||||||
if (userList.value && userIds.value.length > 0) {
|
|
||||||
const data = await optionSelect(userIds.value);
|
|
||||||
if (data.data && data.data.length > 0) {
|
|
||||||
chooseUserList.value = data.data;
|
|
||||||
data.data.forEach((user: UserVO) => {
|
|
||||||
multipleTableRef.value!.toggleRowSelection(
|
|
||||||
userList.value.find((item) => {
|
|
||||||
return item.userId == user.userId;
|
|
||||||
}),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getDeleteMultiInstanceList = async (taskId: string) => {
|
|
||||||
deptOptions.value = [];
|
|
||||||
loading.value = true;
|
|
||||||
queryParams.value.taskId = taskId;
|
|
||||||
multiInstance.value = 'delete';
|
|
||||||
visible.value = true;
|
|
||||||
const res = await getListByDeleteMultiInstance(taskId);
|
|
||||||
taskList.value = res.data;
|
|
||||||
loading.value = false;
|
|
||||||
};
|
|
||||||
/** 搜索按钮操作 */
|
|
||||||
const handleQuery = () => {
|
|
||||||
queryParams.value.pageNum = 1;
|
|
||||||
getAddMultiInstanceList(queryParams.value.taskId, userIds.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 重置按钮操作 */
|
|
||||||
const resetQuery = () => {
|
|
||||||
queryParams.value.pageNum = 1;
|
|
||||||
queryParams.value.deptId = undefined;
|
|
||||||
queryParams.value.userName = undefined;
|
|
||||||
queryParams.value.nickName = undefined;
|
|
||||||
deptTreeRef.value.setCurrentKey(null);
|
|
||||||
handleQuery();
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 选择条数 */
|
|
||||||
const handleSelectionChange = (selection: UserVO[]) => {
|
|
||||||
if (props.multiple) {
|
|
||||||
chooseUserList.value = selection.filter((element, index, self) => {
|
|
||||||
return self.findIndex((x) => x.userId === element.userId) === index;
|
|
||||||
});
|
|
||||||
selection.forEach((u) => {
|
|
||||||
if (chooseUserList.value && !chooseUserList.value.includes(u)) {
|
|
||||||
multipleTableRef.value!.toggleRowSelection(u, undefined);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
userIds.value = chooseUserList.value.map((item) => {
|
|
||||||
return item.userId;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
chooseUserList.value = selection;
|
|
||||||
if (selection.length > 1) {
|
|
||||||
let delRow = selection.shift();
|
|
||||||
multipleTableRef.value!.toggleRowSelection(delRow, undefined);
|
|
||||||
}
|
|
||||||
if (selection.length === 0) {
|
|
||||||
chooseUserList.value = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
/** 选择条数 */
|
|
||||||
const handleTaskSelection = (selection: any) => {
|
|
||||||
selectionTask.value = selection;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 查询部门下拉树结构 */
|
|
||||||
const getTreeSelect = async () => {
|
|
||||||
const res = await deptTreeSelect();
|
|
||||||
deptOptions.value = res.data;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 通过条件过滤节点 */
|
|
||||||
const filterNode = (value: string, data: any) => {
|
|
||||||
if (!value) return true;
|
|
||||||
return data.label.indexOf(value) !== -1;
|
|
||||||
};
|
|
||||||
/** 根据名称筛选部门树 */
|
|
||||||
watchEffect(
|
|
||||||
() => {
|
|
||||||
if (visible.value && deptOptions.value && deptOptions.value.length > 0) {
|
|
||||||
deptTreeRef.value.filter(deptName.value);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发,此属性控制在DOM元素更新后运行
|
|
||||||
}
|
|
||||||
);
|
|
||||||
/** 节点单击事件 */
|
|
||||||
const handleNodeClick = (data: DeptVO) => {
|
|
||||||
queryParams.value.deptId = data.id;
|
|
||||||
getList();
|
|
||||||
};
|
|
||||||
//删除tag
|
|
||||||
const handleCloseTag = (user: UserVO, index: any) => {
|
|
||||||
if (multipleTableRef.value.selection && multipleTableRef.value.selection.length > 0) {
|
|
||||||
multipleTableRef.value.selection.forEach((u: UserVO, i: number) => {
|
|
||||||
if (user.userId === u.userId) {
|
|
||||||
multipleTableRef.value.selection.splice(i, 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (chooseUserList.value && chooseUserList.value.length > 0) {
|
|
||||||
chooseUserList.value.splice(index, 1);
|
|
||||||
}
|
|
||||||
multipleTableRef.value.toggleRowSelection(user, undefined);
|
|
||||||
|
|
||||||
if (userIds.value && userIds.value.length > 0) {
|
|
||||||
userIds.value.forEach((userId, i) => {
|
|
||||||
if (userId === user.userId) {
|
|
||||||
userIds.value.splice(i, 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const submitFileForm = async () => {
|
|
||||||
if (multiInstance.value === 'add') {
|
|
||||||
if (chooseUserList.value && chooseUserList.value.length > 0) {
|
|
||||||
loading.value = true;
|
|
||||||
let userIds = chooseUserList.value.map((item) => {
|
|
||||||
return item.userId;
|
|
||||||
});
|
|
||||||
let nickNames = chooseUserList.value.map((item) => {
|
|
||||||
return item.nickName;
|
|
||||||
});
|
|
||||||
let params = {
|
|
||||||
taskId: queryParams.value.taskId,
|
|
||||||
assignees: userIds,
|
|
||||||
assigneeNames: nickNames
|
|
||||||
};
|
|
||||||
await addMultiInstanceExecution(params);
|
|
||||||
emits('submitCallback');
|
|
||||||
loading.value = false;
|
|
||||||
proxy?.$modal.msgSuccess('操作成功');
|
|
||||||
visible.value = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (selectionTask.value && selectionTask.value.length > 0) {
|
|
||||||
loading.value = true;
|
|
||||||
let taskIds = selectionTask.value.map((item: any) => {
|
|
||||||
return item.id;
|
|
||||||
});
|
|
||||||
let executionIds = selectionTask.value.map((item: any) => {
|
|
||||||
return item.executionId;
|
|
||||||
});
|
|
||||||
let assigneeIds = selectionTask.value.map((item: any) => {
|
|
||||||
return item.assignee;
|
|
||||||
});
|
|
||||||
let assigneeNames = selectionTask.value.map((item: any) => {
|
|
||||||
return item.assigneeName;
|
|
||||||
});
|
|
||||||
let params = {
|
|
||||||
taskId: queryParams.value.taskId,
|
|
||||||
taskIds: taskIds,
|
|
||||||
executionIds: executionIds,
|
|
||||||
assigneeIds: assigneeIds,
|
|
||||||
assigneeNames: assigneeNames
|
|
||||||
};
|
|
||||||
await deleteMultiInstanceExecution(params);
|
|
||||||
emits('submitCallback');
|
|
||||||
loading.value = false;
|
|
||||||
proxy?.$modal.msgSuccess('操作成功');
|
|
||||||
visible.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
//事件
|
|
||||||
const emits = defineEmits(['submitCallback']);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对外暴露子组件方法
|
|
||||||
*/
|
|
||||||
defineExpose({
|
|
||||||
getAddMultiInstanceList,
|
|
||||||
getDeleteMultiInstanceList
|
|
||||||
});
|
|
||||||
</script>
|
|
207
src/components/Process/processMeddle.vue
Normal file
207
src/components/Process/processMeddle.vue
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog v-model="visible" draggable title="流程干预" :width="props.width" :height="props.height" :close-on-click-modal="false">
|
||||||
|
<el-descriptions v-loading="loading" class="margin-top" :title="`${task.flowName}(${task.flowCode})`" :column="2" border>
|
||||||
|
<el-descriptions-item label="任务名称">{{ task.nodeName }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="节点编码">{{ task.nodeCode }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="开始时间">{{ task.createTime }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="流程实例ID">{{ task.instanceId }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="版本号">{{ task.version }}.0</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="业务ID">{{ task.businessId }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button v-if="task.flowStatus === 'waiting'" :disabled="buttonDisabled" type="primary" @click="openTransferTask"> 转办 </el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="task.flowStatus === 'waiting' && Number(task.nodeRatio) > 0"
|
||||||
|
:disabled="buttonDisabled"
|
||||||
|
type="primary"
|
||||||
|
@click="openMultiInstanceUser"
|
||||||
|
>
|
||||||
|
加签
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="task.flowStatus === 'waiting' && Number(task.nodeRatio) > 0"
|
||||||
|
:disabled="buttonDisabled"
|
||||||
|
type="primary"
|
||||||
|
@click="handleTaskUser"
|
||||||
|
>
|
||||||
|
减签
|
||||||
|
</el-button>
|
||||||
|
<el-button v-if="task.flowStatus === 'waiting'" :disabled="buttonDisabled" type="danger" @click="handleTerminationTask"> 终止 </el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<!-- 转办 -->
|
||||||
|
<UserSelect ref="transferTaskRef" :multiple="false" @confirm-call-back="handleTransferTask"></UserSelect>
|
||||||
|
<!-- 加签组件 -->
|
||||||
|
<UserSelect ref="multiInstanceUserRef" :multiple="true" @confirm-call-back="addMultiInstanceUser"></UserSelect>
|
||||||
|
<el-dialog v-model="deleteSignatureVisible" draggable title="减签人员" width="700px" height="400px" append-to-body :close-on-click-modal="false"
|
||||||
|
><div>
|
||||||
|
<el-table :data="deleteUserList" border>
|
||||||
|
<el-table-column prop="nodeName" label="任务名称" />
|
||||||
|
<el-table-column prop="nickName" label="办理人" />
|
||||||
|
<el-table-column label="操作" align="center" width="160">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button type="danger" size="small" icon="Delete" @click="deleteMultiInstanceUser(scope.row)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { propTypes } from '@/utils/propTypes';
|
||||||
|
import { FlowTaskVO, TaskOperationBo } from '@/api/workflow/task/types';
|
||||||
|
import UserSelect from '@/components/UserSelect';
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
import { getTask, taskOperation, currentTaskAllUser, terminationTask } from '@/api/workflow/task';
|
||||||
|
const props = defineProps({
|
||||||
|
width: propTypes.string.def('50%'),
|
||||||
|
height: propTypes.string.def('100%')
|
||||||
|
});
|
||||||
|
const emits = defineEmits(['submitCallback']);
|
||||||
|
const transferTaskRef = ref<InstanceType<typeof UserSelect>>();
|
||||||
|
const multiInstanceUserRef = ref<InstanceType<typeof UserSelect>>();
|
||||||
|
//遮罩层
|
||||||
|
const loading = ref(true);
|
||||||
|
//按钮
|
||||||
|
const buttonDisabled = ref(true);
|
||||||
|
const visible = ref(false);
|
||||||
|
//减签弹窗
|
||||||
|
const deleteSignatureVisible = ref(false);
|
||||||
|
//可减签的人员
|
||||||
|
const deleteUserList = ref<any>([]);
|
||||||
|
//任务
|
||||||
|
const task = ref<FlowTaskVO>({
|
||||||
|
id: undefined,
|
||||||
|
createTime: undefined,
|
||||||
|
updateTime: undefined,
|
||||||
|
tenantId: undefined,
|
||||||
|
definitionId: undefined,
|
||||||
|
instanceId: undefined,
|
||||||
|
flowName: undefined,
|
||||||
|
businessId: undefined,
|
||||||
|
nodeCode: undefined,
|
||||||
|
nodeName: undefined,
|
||||||
|
flowCode: undefined,
|
||||||
|
flowStatus: undefined,
|
||||||
|
nodeType: undefined,
|
||||||
|
nodeRatio: undefined,
|
||||||
|
version: undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
const open = (taskId: string) => {
|
||||||
|
visible.value = true;
|
||||||
|
getTask(taskId).then((response) => {
|
||||||
|
loading.value = false;
|
||||||
|
buttonDisabled.value = false;
|
||||||
|
task.value = response.data;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
//打开转办
|
||||||
|
const openTransferTask = () => {
|
||||||
|
transferTaskRef.value.open();
|
||||||
|
};
|
||||||
|
//转办
|
||||||
|
const handleTransferTask = async (data) => {
|
||||||
|
if (data && data.length > 0) {
|
||||||
|
const taskOperationBo = reactive<TaskOperationBo>({
|
||||||
|
userId: data[0].userId,
|
||||||
|
taskId: task.value.id,
|
||||||
|
message: ''
|
||||||
|
});
|
||||||
|
await proxy?.$modal.confirm('是否确认提交?');
|
||||||
|
loading.value = true;
|
||||||
|
buttonDisabled.value = true;
|
||||||
|
await taskOperation(taskOperationBo, 'transferTask').finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
buttonDisabled.value = false;
|
||||||
|
});
|
||||||
|
visible.value = false;
|
||||||
|
emits('submitCallback');
|
||||||
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
|
} else {
|
||||||
|
proxy?.$modal.msgWarning('请选择用户!');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//加签
|
||||||
|
const openMultiInstanceUser = async () => {
|
||||||
|
multiInstanceUserRef.value.open();
|
||||||
|
};
|
||||||
|
//加签
|
||||||
|
const addMultiInstanceUser = async (data) => {
|
||||||
|
if (data && data.length > 0) {
|
||||||
|
const taskOperationBo = reactive<TaskOperationBo>({
|
||||||
|
userIds: data.map((e) => e.userId),
|
||||||
|
taskId: task.value.id,
|
||||||
|
message: ''
|
||||||
|
});
|
||||||
|
await proxy?.$modal.confirm('是否确认提交?');
|
||||||
|
loading.value = true;
|
||||||
|
buttonDisabled.value = true;
|
||||||
|
await taskOperation(taskOperationBo, 'addSignature').finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
buttonDisabled.value = false;
|
||||||
|
});
|
||||||
|
visible.value = false;
|
||||||
|
emits('submitCallback');
|
||||||
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
|
} else {
|
||||||
|
proxy?.$modal.msgWarning('请选择用户!');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//减签
|
||||||
|
const deleteMultiInstanceUser = async (row) => {
|
||||||
|
await proxy?.$modal.confirm('是否确认提交?');
|
||||||
|
loading.value = true;
|
||||||
|
buttonDisabled.value = true;
|
||||||
|
const taskOperationBo = reactive<TaskOperationBo>({
|
||||||
|
userIds: [row.userId],
|
||||||
|
taskId: task.value.id,
|
||||||
|
message: ''
|
||||||
|
});
|
||||||
|
await taskOperation(taskOperationBo, 'reductionSignature').finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
buttonDisabled.value = false;
|
||||||
|
});
|
||||||
|
visible.value = false;
|
||||||
|
emits('submitCallback');
|
||||||
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
|
};
|
||||||
|
//获取办理人
|
||||||
|
const handleTaskUser = async () => {
|
||||||
|
let data = await currentTaskAllUser(task.value.id);
|
||||||
|
deleteUserList.value = data.data;
|
||||||
|
if (deleteUserList.value && deleteUserList.value.length > 0) {
|
||||||
|
deleteUserList.value.forEach((e) => {
|
||||||
|
e.nodeName = task.value.nodeName;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
deleteSignatureVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
//终止任务
|
||||||
|
const handleTerminationTask = async () => {
|
||||||
|
let params = {
|
||||||
|
taskId: task.value.id,
|
||||||
|
comment: ''
|
||||||
|
};
|
||||||
|
await proxy?.$modal.confirm('是否确认终止?');
|
||||||
|
loading.value = true;
|
||||||
|
buttonDisabled.value = true;
|
||||||
|
await terminationTask(params).finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
buttonDisabled.value = false;
|
||||||
|
});
|
||||||
|
visible.value = false;
|
||||||
|
emits('submitCallback');
|
||||||
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 对外暴露子组件方法
|
||||||
|
*/
|
||||||
|
defineExpose({
|
||||||
|
open
|
||||||
|
});
|
||||||
|
</script>
|
@ -3,47 +3,47 @@
|
|||||||
<el-form v-loading="loading" :model="form" label-width="120px">
|
<el-form v-loading="loading" :model="form" label-width="120px">
|
||||||
<el-form-item label="消息提醒">
|
<el-form-item label="消息提醒">
|
||||||
<el-checkbox-group v-model="form.messageType">
|
<el-checkbox-group v-model="form.messageType">
|
||||||
<el-checkbox label="1" name="type" disabled>站内信</el-checkbox>
|
<el-checkbox value="1" name="type" disabled>站内信</el-checkbox>
|
||||||
<el-checkbox label="2" name="type">邮件</el-checkbox>
|
<el-checkbox value="2" name="type">邮件</el-checkbox>
|
||||||
<el-checkbox label="3" name="type">短信</el-checkbox>
|
<el-checkbox value="3" name="type">短信</el-checkbox>
|
||||||
</el-checkbox-group>
|
</el-checkbox-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-if="task.businessStatus === 'waiting'" label="附件">
|
<el-form-item v-if="task.flowStatus === 'waiting'" label="附件">
|
||||||
<fileUpload v-model="form.fileId" :file-type="['doc', 'xls', 'ppt', 'txt', 'pdf', 'xlsx', 'docx', 'zip']" :file-size="'20'" />
|
<fileUpload v-model="form.fileId" :file-type="['png', 'jpg', 'jpeg', 'doc', 'docx', 'xlsx', 'xls', 'ppt', 'txt', 'pdf']" :file-size="20" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="抄送">
|
<el-form-item label="抄送">
|
||||||
<el-button type="primary" icon="Plus" circle @click="openUserSelectCopy" />
|
<el-button type="primary" icon="Plus" circle @click="openUserSelectCopy" />
|
||||||
<el-tag v-for="user in selectCopyUserList" :key="user.userId" closable style="margin: 2px" @close="handleCopyCloseTag(user)">
|
<el-tag v-for="user in selectCopyUserList" :key="user.userId" closable style="margin: 2px" @close="handleCopyCloseTag(user)">
|
||||||
{{ user.userName }}
|
{{ user.nickName }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-if="task.businessStatus === 'waiting'" label="审批意见">
|
<el-form-item v-if="task.flowStatus === 'waiting'" label="审批意见">
|
||||||
<el-input v-model="form.message" type="textarea" resize="none" />
|
<el-input v-model="form.message" type="textarea" resize="none" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button :disabled="buttonDisabled" type="primary" @click="handleCompleteTask"> 提交 </el-button>
|
<el-button :disabled="buttonDisabled" type="primary" @click="handleCompleteTask"> 提交 </el-button>
|
||||||
<el-button v-if="task.businessStatus === 'waiting'" :disabled="buttonDisabled" type="primary" @click="openDelegateTask"> 委托 </el-button>
|
<el-button v-if="task.flowStatus === 'waiting'" :disabled="buttonDisabled" type="primary" @click="openDelegateTask"> 委托 </el-button>
|
||||||
<el-button v-if="task.businessStatus === 'waiting'" :disabled="buttonDisabled" type="primary" @click="openTransferTask"> 转办 </el-button>
|
<el-button v-if="task.flowStatus === 'waiting'" :disabled="buttonDisabled" type="primary" @click="openTransferTask"> 转办 </el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="task.businessStatus === 'waiting' && task.multiInstance"
|
v-if="task.flowStatus === 'waiting' && Number(task.nodeRatio) > 0"
|
||||||
:disabled="buttonDisabled"
|
:disabled="buttonDisabled"
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="addMultiInstanceUser"
|
@click="openMultiInstanceUser"
|
||||||
>
|
>
|
||||||
加签
|
加签
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="task.businessStatus === 'waiting' && task.multiInstance"
|
v-if="task.flowStatus === 'waiting' && Number(task.nodeRatio) > 0"
|
||||||
:disabled="buttonDisabled"
|
:disabled="buttonDisabled"
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="deleteMultiInstanceUser"
|
@click="handleTaskUser"
|
||||||
>
|
>
|
||||||
减签
|
减签
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button v-if="task.businessStatus === 'waiting'" :disabled="buttonDisabled" type="danger" @click="handleTerminationTask"> 终止 </el-button>
|
<el-button v-if="task.flowStatus === 'waiting'" :disabled="buttonDisabled" type="danger" @click="handleTerminationTask"> 终止 </el-button>
|
||||||
<el-button v-if="task.businessStatus === 'waiting'" :disabled="buttonDisabled" type="danger" @click="handleBackProcessOpen"> 退回 </el-button>
|
<el-button v-if="task.flowStatus === 'waiting'" :disabled="buttonDisabled" type="danger" @click="handleBackProcessOpen"> 退回 </el-button>
|
||||||
<el-button :disabled="buttonDisabled" @click="cancel">取消</el-button>
|
<el-button :disabled="buttonDisabled" @click="cancel">取消</el-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
@ -54,14 +54,14 @@
|
|||||||
<!-- 委托 -->
|
<!-- 委托 -->
|
||||||
<UserSelect ref="delegateTaskRef" :multiple="false" @confirm-call-back="handleDelegateTask"></UserSelect>
|
<UserSelect ref="delegateTaskRef" :multiple="false" @confirm-call-back="handleDelegateTask"></UserSelect>
|
||||||
<!-- 加签组件 -->
|
<!-- 加签组件 -->
|
||||||
<multiInstanceUser ref="multiInstanceUserRef" :title="title" @submit-callback="closeDialog" />
|
<UserSelect ref="multiInstanceUserRef" :multiple="true" @confirm-call-back="addMultiInstanceUser"></UserSelect>
|
||||||
|
|
||||||
<!-- 驳回开始 -->
|
<!-- 驳回开始 -->
|
||||||
<el-dialog v-model="backVisible" draggable title="驳回" width="40%" :close-on-click-modal="false">
|
<el-dialog v-model="backVisible" draggable title="驳回" width="40%" :close-on-click-modal="false">
|
||||||
<el-form v-if="task.businessStatus === 'waiting'" v-loading="backLoading" :model="backForm" label-width="120px">
|
<el-form v-if="task.flowStatus === 'waiting'" v-loading="backLoading" :model="backForm" label-width="120px">
|
||||||
<el-form-item label="驳回节点">
|
<el-form-item label="驳回节点">
|
||||||
<el-select v-model="backForm.targetActivityId" clearable placeholder="请选择" style="width: 300px">
|
<el-select v-model="backForm.nodeCode" clearable placeholder="请选择" style="width: 300px">
|
||||||
<el-option v-for="item in taskNodeList" :key="item.nodeId" :label="item.nodeName" :value="item.nodeId" />
|
<el-option v-for="item in taskNodeList" :key="item.nodeCode" :label="item.nodeName" :value="item.nodeCode" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="消息提醒">
|
<el-form-item label="消息提醒">
|
||||||
@ -83,6 +83,19 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<!-- 驳回结束 -->
|
<!-- 驳回结束 -->
|
||||||
|
<el-dialog v-model="deleteSignatureVisible" draggable title="减签人员" width="700px" height="400px" append-to-body :close-on-click-modal="false">
|
||||||
|
<div>
|
||||||
|
<el-table :data="deleteUserList" border>
|
||||||
|
<el-table-column prop="nodeName" label="任务名称" />
|
||||||
|
<el-table-column prop="nickName" label="办理人" />
|
||||||
|
<el-table-column label="操作" align="center" width="160">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button type="danger" size="small" icon="Delete" @click="deleteMultiInstanceUser(scope.row)">删除 </el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -90,18 +103,17 @@
|
|||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { ComponentInternalInstance } from 'vue';
|
import { ComponentInternalInstance } from 'vue';
|
||||||
import { ElForm } from 'element-plus';
|
import { ElForm } from 'element-plus';
|
||||||
import { completeTask, backProcess, getTaskById, transferTask, terminationTask, getTaskNodeList, delegateTask } from '@/api/workflow/task';
|
import { completeTask, backProcess, getTask, taskOperation, terminationTask, getBackTaskNode, currentTaskAllUser } from '@/api/workflow/task';
|
||||||
import UserSelect from '@/components/UserSelect';
|
import UserSelect from '@/components/UserSelect';
|
||||||
import MultiInstanceUser from '@/components/Process/multiInstanceUser.vue';
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
import { UserVO } from '@/api/system/user/types';
|
import { UserVO } from '@/api/system/user/types';
|
||||||
import { TaskVO } from '@/api/workflow/task/types';
|
import { FlowTaskVO, TaskOperationBo } from '@/api/workflow/task/types';
|
||||||
|
|
||||||
const userSelectCopyRef = ref<InstanceType<typeof UserSelect>>();
|
const userSelectCopyRef = ref<InstanceType<typeof UserSelect>>();
|
||||||
const transferTaskRef = ref<InstanceType<typeof UserSelect>>();
|
const transferTaskRef = ref<InstanceType<typeof UserSelect>>();
|
||||||
const delegateTaskRef = ref<InstanceType<typeof UserSelect>>();
|
const delegateTaskRef = ref<InstanceType<typeof UserSelect>>();
|
||||||
|
const multiInstanceUserRef = ref<InstanceType<typeof UserSelect>>();
|
||||||
//加签组件
|
|
||||||
const multiInstanceUserRef = ref<InstanceType<typeof MultiInstanceUser>>();
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
taskVariables: {
|
taskVariables: {
|
||||||
@ -119,65 +131,53 @@ const taskId = ref<string>('');
|
|||||||
const selectCopyUserList = ref<UserVO[]>([]);
|
const selectCopyUserList = ref<UserVO[]>([]);
|
||||||
//抄送人id
|
//抄送人id
|
||||||
const selectCopyUserIds = ref<string>(undefined);
|
const selectCopyUserIds = ref<string>(undefined);
|
||||||
// 驳回是否显示
|
//可减签的人员
|
||||||
|
const deleteUserList = ref<any>([]);
|
||||||
|
//驳回是否显示
|
||||||
const backVisible = ref(false);
|
const backVisible = ref(false);
|
||||||
const backLoading = ref(true);
|
const backLoading = ref(true);
|
||||||
const backButtonDisabled = ref(true);
|
const backButtonDisabled = ref(true);
|
||||||
// 可驳回得任务节点
|
// 可驳回得任务节点
|
||||||
const taskNodeList = ref([]);
|
const taskNodeList = ref([]);
|
||||||
//任务
|
//任务
|
||||||
const task = ref<TaskVO>({
|
const task = ref<FlowTaskVO>({
|
||||||
id: undefined,
|
id: undefined,
|
||||||
name: undefined,
|
createTime: undefined,
|
||||||
description: undefined,
|
updateTime: undefined,
|
||||||
priority: undefined,
|
|
||||||
owner: undefined,
|
|
||||||
assignee: undefined,
|
|
||||||
assigneeName: undefined,
|
|
||||||
processInstanceId: undefined,
|
|
||||||
executionId: undefined,
|
|
||||||
taskDefinitionId: undefined,
|
|
||||||
processDefinitionId: undefined,
|
|
||||||
endTime: undefined,
|
|
||||||
taskDefinitionKey: undefined,
|
|
||||||
dueDate: undefined,
|
|
||||||
category: undefined,
|
|
||||||
parentTaskId: undefined,
|
|
||||||
tenantId: undefined,
|
tenantId: undefined,
|
||||||
claimTime: undefined,
|
definitionId: undefined,
|
||||||
businessStatus: undefined,
|
instanceId: undefined,
|
||||||
businessStatusName: undefined,
|
flowName: undefined,
|
||||||
processDefinitionName: undefined,
|
businessId: undefined,
|
||||||
processDefinitionKey: undefined,
|
nodeCode: undefined,
|
||||||
participantVo: undefined,
|
nodeName: undefined,
|
||||||
multiInstance: undefined,
|
flowCode: undefined,
|
||||||
businessKey: undefined,
|
flowStatus: undefined,
|
||||||
wfNodeConfigVo: undefined
|
formCustom: undefined,
|
||||||
|
formPath: undefined,
|
||||||
|
nodeType: undefined,
|
||||||
|
nodeRatio: undefined
|
||||||
});
|
});
|
||||||
//加签 减签标题
|
|
||||||
const title = ref('');
|
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
visible: false,
|
visible: false,
|
||||||
title: '提示'
|
title: '提示'
|
||||||
});
|
});
|
||||||
|
//减签弹窗
|
||||||
|
const deleteSignatureVisible = ref(false);
|
||||||
const form = ref<Record<string, any>>({
|
const form = ref<Record<string, any>>({
|
||||||
taskId: undefined,
|
taskId: undefined,
|
||||||
message: undefined,
|
message: undefined,
|
||||||
variables: {},
|
variables: {},
|
||||||
messageType: ['1'],
|
messageType: ['1'],
|
||||||
wfCopyList: []
|
flowCopyList: []
|
||||||
});
|
});
|
||||||
const backForm = ref<Record<string, any>>({
|
const backForm = ref<Record<string, any>>({
|
||||||
taskId: undefined,
|
taskId: undefined,
|
||||||
targetActivityId: undefined,
|
nodeCode: undefined,
|
||||||
message: undefined,
|
message: undefined,
|
||||||
variables: {},
|
variables: {},
|
||||||
messageType: ['1']
|
messageType: ['1']
|
||||||
});
|
});
|
||||||
const closeDialog = () => {
|
|
||||||
dialog.visible = false;
|
|
||||||
};
|
|
||||||
//打开弹窗
|
//打开弹窗
|
||||||
const openDialog = (id?: string) => {
|
const openDialog = (id?: string) => {
|
||||||
selectCopyUserIds.value = undefined;
|
selectCopyUserIds.value = undefined;
|
||||||
@ -189,7 +189,7 @@ const openDialog = (id?: string) => {
|
|||||||
loading.value = true;
|
loading.value = true;
|
||||||
buttonDisabled.value = true;
|
buttonDisabled.value = true;
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
getTaskById(taskId.value).then((response) => {
|
getTask(taskId.value).then((response) => {
|
||||||
task.value = response.data;
|
task.value = response.data;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
buttonDisabled.value = false;
|
buttonDisabled.value = false;
|
||||||
@ -205,15 +205,15 @@ const handleCompleteTask = async () => {
|
|||||||
form.value.taskId = taskId.value;
|
form.value.taskId = taskId.value;
|
||||||
form.value.taskVariables = props.taskVariables;
|
form.value.taskVariables = props.taskVariables;
|
||||||
if (selectCopyUserList.value && selectCopyUserList.value.length > 0) {
|
if (selectCopyUserList.value && selectCopyUserList.value.length > 0) {
|
||||||
let wfCopyList = [];
|
let flowCopyList = [];
|
||||||
selectCopyUserList.value.forEach((e) => {
|
selectCopyUserList.value.forEach((e) => {
|
||||||
let copyUser = {
|
let copyUser = {
|
||||||
userId: e.userId,
|
userId: e.userId,
|
||||||
userName: e.nickName
|
userName: e.nickName
|
||||||
};
|
};
|
||||||
wfCopyList.push(copyUser);
|
flowCopyList.push(copyUser);
|
||||||
});
|
});
|
||||||
form.value.wfCopyList = wfCopyList;
|
form.value.flowCopyList = flowCopyList;
|
||||||
}
|
}
|
||||||
await proxy?.$modal.confirm('是否确认提交?');
|
await proxy?.$modal.confirm('是否确认提交?');
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
@ -236,11 +236,11 @@ const handleBackProcessOpen = async () => {
|
|||||||
backVisible.value = true;
|
backVisible.value = true;
|
||||||
backLoading.value = true;
|
backLoading.value = true;
|
||||||
backButtonDisabled.value = true;
|
backButtonDisabled.value = true;
|
||||||
let data = await getTaskNodeList(task.value.processInstanceId);
|
let data = await getBackTaskNode(task.value.definitionId, task.value.nodeCode);
|
||||||
taskNodeList.value = data.data;
|
taskNodeList.value = data.data;
|
||||||
backLoading.value = false;
|
backLoading.value = false;
|
||||||
backButtonDisabled.value = false;
|
backButtonDisabled.value = false;
|
||||||
backForm.value.targetActivityId = taskNodeList.value[0].nodeId;
|
backForm.value.nodeCode = taskNodeList.value[0].nodeCode;
|
||||||
};
|
};
|
||||||
/** 驳回流程 */
|
/** 驳回流程 */
|
||||||
const handleBackProcess = async () => {
|
const handleBackProcess = async () => {
|
||||||
@ -249,7 +249,10 @@ const handleBackProcess = async () => {
|
|||||||
loading.value = true;
|
loading.value = true;
|
||||||
backLoading.value = true;
|
backLoading.value = true;
|
||||||
backButtonDisabled.value = true;
|
backButtonDisabled.value = true;
|
||||||
await backProcess(backForm.value).finally(() => (loading.value = false));
|
await backProcess(backForm.value).finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
buttonDisabled.value = false;
|
||||||
|
});
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
backLoading.value = false;
|
backLoading.value = false;
|
||||||
backButtonDisabled.value = false;
|
backButtonDisabled.value = false;
|
||||||
@ -282,18 +285,48 @@ const handleCopyCloseTag = (user: UserVO) => {
|
|||||||
selectCopyUserIds.value = selectCopyUserList.value.map((item) => item.userId).join(',');
|
selectCopyUserIds.value = selectCopyUserList.value.map((item) => item.userId).join(',');
|
||||||
};
|
};
|
||||||
//加签
|
//加签
|
||||||
const addMultiInstanceUser = () => {
|
const openMultiInstanceUser = async () => {
|
||||||
if (multiInstanceUserRef.value) {
|
multiInstanceUserRef.value.open();
|
||||||
title.value = '加签人员';
|
};
|
||||||
multiInstanceUserRef.value.getAddMultiInstanceList(taskId.value, []);
|
//加签
|
||||||
|
const addMultiInstanceUser = async (data) => {
|
||||||
|
if (data && data.length > 0) {
|
||||||
|
const taskOperationBo = reactive<TaskOperationBo>({
|
||||||
|
userIds: data.map((e) => e.userId),
|
||||||
|
taskId: taskId.value,
|
||||||
|
message: form.value.message
|
||||||
|
});
|
||||||
|
await proxy?.$modal.confirm('是否确认提交?');
|
||||||
|
loading.value = true;
|
||||||
|
buttonDisabled.value = true;
|
||||||
|
await taskOperation(taskOperationBo, 'addSignature').finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
buttonDisabled.value = false;
|
||||||
|
});
|
||||||
|
dialog.visible = false;
|
||||||
|
emits('submitCallback');
|
||||||
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
|
} else {
|
||||||
|
proxy?.$modal.msgWarning('请选择用户!');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
//减签
|
//减签
|
||||||
const deleteMultiInstanceUser = () => {
|
const deleteMultiInstanceUser = async (row) => {
|
||||||
if (multiInstanceUserRef.value) {
|
await proxy?.$modal.confirm('是否确认提交?');
|
||||||
title.value = '减签人员';
|
loading.value = true;
|
||||||
multiInstanceUserRef.value.getDeleteMultiInstanceList(taskId.value);
|
buttonDisabled.value = true;
|
||||||
}
|
const taskOperationBo = reactive<TaskOperationBo>({
|
||||||
|
userIds: [row.userId],
|
||||||
|
taskId: taskId.value,
|
||||||
|
message: form.value.message
|
||||||
|
});
|
||||||
|
await taskOperation(taskOperationBo, 'reductionSignature').finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
buttonDisabled.value = false;
|
||||||
|
});
|
||||||
|
dialog.visible = false;
|
||||||
|
emits('submitCallback');
|
||||||
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
};
|
};
|
||||||
//打开转办
|
//打开转办
|
||||||
const openTransferTask = () => {
|
const openTransferTask = () => {
|
||||||
@ -302,15 +335,18 @@ const openTransferTask = () => {
|
|||||||
//转办
|
//转办
|
||||||
const handleTransferTask = async (data) => {
|
const handleTransferTask = async (data) => {
|
||||||
if (data && data.length > 0) {
|
if (data && data.length > 0) {
|
||||||
let params = {
|
const taskOperationBo = reactive<TaskOperationBo>({
|
||||||
taskId: taskId.value,
|
|
||||||
userId: data[0].userId,
|
userId: data[0].userId,
|
||||||
comment: form.value.message
|
taskId: taskId.value,
|
||||||
};
|
message: form.value.message
|
||||||
|
});
|
||||||
await proxy?.$modal.confirm('是否确认提交?');
|
await proxy?.$modal.confirm('是否确认提交?');
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
buttonDisabled.value = true;
|
buttonDisabled.value = true;
|
||||||
await transferTask(params).finally(() => (loading.value = false));
|
await taskOperation(taskOperationBo, 'transferTask').finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
buttonDisabled.value = false;
|
||||||
|
});
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
emits('submitCallback');
|
emits('submitCallback');
|
||||||
proxy?.$modal.msgSuccess('操作成功');
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
@ -326,15 +362,18 @@ const openDelegateTask = () => {
|
|||||||
//委托
|
//委托
|
||||||
const handleDelegateTask = async (data) => {
|
const handleDelegateTask = async (data) => {
|
||||||
if (data && data.length > 0) {
|
if (data && data.length > 0) {
|
||||||
let params = {
|
const taskOperationBo = reactive<TaskOperationBo>({
|
||||||
taskId: taskId.value,
|
|
||||||
userId: data[0].userId,
|
userId: data[0].userId,
|
||||||
nickName: data[0].nickName
|
taskId: taskId.value,
|
||||||
};
|
message: form.value.message
|
||||||
|
});
|
||||||
await proxy?.$modal.confirm('是否确认提交?');
|
await proxy?.$modal.confirm('是否确认提交?');
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
buttonDisabled.value = true;
|
buttonDisabled.value = true;
|
||||||
await delegateTask(params).finally(() => (loading.value = false));
|
await taskOperation(taskOperationBo, 'delegateTask').finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
buttonDisabled.value = false;
|
||||||
|
});
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
emits('submitCallback');
|
emits('submitCallback');
|
||||||
proxy?.$modal.msgSuccess('操作成功');
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
@ -343,7 +382,7 @@ const handleDelegateTask = async (data) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
//终止任务
|
//终止任务
|
||||||
const handleTerminationTask = async (data) => {
|
const handleTerminationTask = async () => {
|
||||||
let params = {
|
let params = {
|
||||||
taskId: taskId.value,
|
taskId: taskId.value,
|
||||||
comment: form.value.message
|
comment: form.value.message
|
||||||
@ -351,11 +390,24 @@ const handleTerminationTask = async (data) => {
|
|||||||
await proxy?.$modal.confirm('是否确认终止?');
|
await proxy?.$modal.confirm('是否确认终止?');
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
buttonDisabled.value = true;
|
buttonDisabled.value = true;
|
||||||
await terminationTask(params).finally(() => (loading.value = false));
|
await terminationTask(params).finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
buttonDisabled.value = false;
|
||||||
|
});
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
emits('submitCallback');
|
emits('submitCallback');
|
||||||
proxy?.$modal.msgSuccess('操作成功');
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
};
|
};
|
||||||
|
const handleTaskUser = async () => {
|
||||||
|
let data = await currentTaskAllUser(taskId.value);
|
||||||
|
deleteUserList.value = data.data;
|
||||||
|
if (deleteUserList.value && deleteUserList.value.length > 0) {
|
||||||
|
deleteUserList.value.forEach((e) => {
|
||||||
|
e.nodeName = task.value.nodeName;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
deleteSignatureVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对外暴露子组件方法
|
* 对外暴露子组件方法
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
</vxe-column>
|
</vxe-column>
|
||||||
<vxe-column field="createTime" title="创建时间" align="center">
|
<vxe-column field="createTime" title="创建时间" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
<span>{{ proxy.parseTime(scope.row.createTime) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</vxe-column>
|
</vxe-column>
|
||||||
</vxe-table>
|
</vxe-table>
|
||||||
|
@ -91,8 +91,8 @@ const activeMenu = computed(() => {
|
|||||||
let activePath = path;
|
let activePath = path;
|
||||||
if (path !== undefined && path.lastIndexOf('/') > 0 && hideList.indexOf(path) === -1) {
|
if (path !== undefined && path.lastIndexOf('/') > 0 && hideList.indexOf(path) === -1) {
|
||||||
const tmpPath = path.substring(1, path.length);
|
const tmpPath = path.substring(1, path.length);
|
||||||
activePath = '/' + tmpPath.substring(0, tmpPath.indexOf('/'));
|
|
||||||
if (!route.meta.link) {
|
if (!route.meta.link) {
|
||||||
|
activePath = '/' + tmpPath.substring(0, tmpPath.indexOf('/'));
|
||||||
appStore.toggleSideBarHide(false);
|
appStore.toggleSideBarHide(false);
|
||||||
}
|
}
|
||||||
} else if (!route.children) {
|
} else if (!route.children) {
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<template v-if="prop.multiple" #header>
|
<template v-if="prop.multiple" #header>
|
||||||
<el-tag v-for="user in selectUserList" :key="user.userId" closable style="margin: 2px" @close="handleCloseTag(user)">
|
<el-tag v-for="user in selectUserList" :key="user.userId" closable style="margin: 2px" @close="handleCloseTag(user)">
|
||||||
{{ user.userName }}
|
{{ user.nickName }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -100,14 +100,14 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import api from '@/api/system/user';
|
import api from '@/api/system/user';
|
||||||
import { UserQuery, UserVO } from '@/api/system/user/types';
|
import { UserQuery, UserVO } from '@/api/system/user/types';
|
||||||
import { DeptVO } from '@/api/system/dept/types';
|
import { DeptTreeVO, DeptVO } from '@/api/system/dept/types';
|
||||||
import { VxeTableInstance } from 'vxe-table';
|
import { VxeTableInstance } from 'vxe-table';
|
||||||
import useDialog from '@/hooks/useDialog';
|
import useDialog from '@/hooks/useDialog';
|
||||||
|
|
||||||
interface PropType {
|
interface PropType {
|
||||||
modelValue?: UserVO[] | UserVO | undefined;
|
modelValue?: UserVO[] | UserVO | undefined;
|
||||||
multiple?: boolean;
|
multiple?: boolean;
|
||||||
data?: string | number | (string | number)[];
|
data?: string | number | (string | number)[] | undefined;
|
||||||
}
|
}
|
||||||
const prop = withDefaults(defineProps<PropType>(), {
|
const prop = withDefaults(defineProps<PropType>(), {
|
||||||
multiple: true,
|
multiple: true,
|
||||||
@ -125,7 +125,7 @@ const showSearch = ref(true);
|
|||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
||||||
const deptName = ref('');
|
const deptName = ref('');
|
||||||
const deptOptions = ref<DeptVO[]>([]);
|
const deptOptions = ref<DeptTreeVO[]>([]);
|
||||||
const selectUserList = ref<UserVO[]>([]);
|
const selectUserList = ref<UserVO[]>([]);
|
||||||
|
|
||||||
const deptTreeRef = ref<ElTreeInstance>();
|
const deptTreeRef = ref<ElTreeInstance>();
|
||||||
@ -166,7 +166,7 @@ const confirm = () => {
|
|||||||
|
|
||||||
const computedIds = (data) => {
|
const computedIds = (data) => {
|
||||||
if (data instanceof Array) {
|
if (data instanceof Array) {
|
||||||
return [...data];
|
return data.map(item => String(item));
|
||||||
} else if (typeof data === 'string') {
|
} else if (typeof data === 'string') {
|
||||||
return data.split(',');
|
return data.split(',');
|
||||||
} else if (typeof data === 'number') {
|
} else if (typeof data === 'number') {
|
||||||
|
@ -31,7 +31,7 @@ export const hasRoles: Directive = {
|
|||||||
const { roles } = useUserStore();
|
const { roles } = useUserStore();
|
||||||
if (value && value instanceof Array && value.length > 0) {
|
if (value && value instanceof Array && value.length > 0) {
|
||||||
const hasRole = roles.some((role: string) => {
|
const hasRole = roles.some((role: string) => {
|
||||||
return role === 'admin' || value.includes(role);
|
return role === 'superadmin' || role === 'admin' || value.includes(role);
|
||||||
});
|
});
|
||||||
if (!hasRole) {
|
if (!hasRole) {
|
||||||
el.parentNode && el.parentNode.removeChild(el);
|
el.parentNode && el.parentNode.removeChild(el);
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
export enum SettingTypeEnum {
|
|
||||||
TITLE = 'title',
|
|
||||||
THEME = 'theme',
|
|
||||||
SIDE_THEME = 'sideTheme',
|
|
||||||
SHOW_SETTINGS = 'showSettings',
|
|
||||||
TOP_NAV = 'topNav',
|
|
||||||
TAGS_VIEW = 'tagsView',
|
|
||||||
FIXED_HEADER = 'fixedHeader',
|
|
||||||
SIDEBAR_LOGO = 'sidebarLogo',
|
|
||||||
DYNAMIC_TITLE = 'dynamicTitle',
|
|
||||||
ANIMATION_ENABLE = 'animationEnable',
|
|
||||||
LAYOUT = 'layout',
|
|
||||||
DARK = 'dark',
|
|
||||||
|
|
||||||
LAYOUT_SETTING = 'layout-setting'
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
export enum AllocationTypeEnum {
|
|
||||||
USER = 'user',
|
|
||||||
CANDIDATE = 'candidate',
|
|
||||||
YOURSELF = 'yourself',
|
|
||||||
SPECIFY = 'specify'
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum SpecifyDescEnum {
|
|
||||||
SPECIFY_MULTIPLE = 'specifyMultiple',
|
|
||||||
SPECIFY_SINGLE = 'specifySingle'
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum MultiInstanceTypeEnum {
|
|
||||||
SERIAL = 'serial',
|
|
||||||
PARALLEL = 'parallel',
|
|
||||||
NONE = 'none'
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
export enum ThemeEnum {
|
|
||||||
DARK = 'theme-dark',
|
|
||||||
LIGHT = 'theme-light'
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
{
|
|
||||||
"route": {
|
|
||||||
"dashboard": "Dashboard",
|
|
||||||
"document": "Document"
|
|
||||||
},
|
|
||||||
"login": {
|
|
||||||
"username": "Username",
|
|
||||||
"password": "Password",
|
|
||||||
"login": "Login",
|
|
||||||
"code": "Verification Code",
|
|
||||||
"copyright": ""
|
|
||||||
},
|
|
||||||
"navbar": {
|
|
||||||
"full": "Full Screen",
|
|
||||||
"language": "Language",
|
|
||||||
"dashboard": "Dashboard",
|
|
||||||
"document": "Document",
|
|
||||||
"message": "Message",
|
|
||||||
"layoutSize": "Layout Size",
|
|
||||||
"selectTenant": "Select Tenant",
|
|
||||||
"layoutSetting": "Layout Setting",
|
|
||||||
"personalCenter": "Personal Center",
|
|
||||||
"logout": "Logout"
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,11 +6,68 @@ export default {
|
|||||||
},
|
},
|
||||||
// 登录页面国际化
|
// 登录页面国际化
|
||||||
login: {
|
login: {
|
||||||
|
selectPlaceholder: 'Please select/enter a company name',
|
||||||
username: 'Username',
|
username: 'Username',
|
||||||
password: 'Password',
|
password: 'Password',
|
||||||
login: 'Login',
|
login: 'Login',
|
||||||
|
logging: 'Logging...',
|
||||||
code: 'Verification Code',
|
code: 'Verification Code',
|
||||||
copyright: ''
|
rememberPassword: 'Remember me',
|
||||||
|
switchRegisterPage: 'Sign up now',
|
||||||
|
rule: {
|
||||||
|
tenantId: {
|
||||||
|
required: 'Please enter your tenant id'
|
||||||
|
},
|
||||||
|
username: {
|
||||||
|
required: 'Please enter your account'
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
required: 'Please enter your password'
|
||||||
|
},
|
||||||
|
code: {
|
||||||
|
required: 'Please enter a verification code'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
social: {
|
||||||
|
wechat: 'Wechat Login',
|
||||||
|
maxkey: 'MaxKey Login',
|
||||||
|
topiam: 'TopIam Login',
|
||||||
|
gitee: 'Gitee Login',
|
||||||
|
github: 'Github Login'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 注册页面国际化
|
||||||
|
register: {
|
||||||
|
selectPlaceholder: 'Please select/enter a company name',
|
||||||
|
username: 'Username',
|
||||||
|
password: 'Password',
|
||||||
|
confirmPassword: 'Confirm Password',
|
||||||
|
register: 'Register',
|
||||||
|
registering: 'Registering...',
|
||||||
|
registerSuccess: 'Congratulations, your {username} account has been registered!',
|
||||||
|
code: 'Verification Code',
|
||||||
|
switchLoginPage: 'Log in with an existing account',
|
||||||
|
rule: {
|
||||||
|
tenantId: {
|
||||||
|
required: 'Please enter your tenant id'
|
||||||
|
},
|
||||||
|
username: {
|
||||||
|
required: 'Please enter your account',
|
||||||
|
length: 'The length of the user account must be between {min} and {max}'
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
required: 'Please enter your password',
|
||||||
|
length: 'The user password must be between {min} and {max} in length',
|
||||||
|
pattern: "Can't contain illegal characters: {strings}"
|
||||||
|
},
|
||||||
|
code: {
|
||||||
|
required: 'Please enter a verification code'
|
||||||
|
},
|
||||||
|
confirmPassword: {
|
||||||
|
required: 'Please enter your password again',
|
||||||
|
equalToPassword: 'The password entered twice is inconsistent'
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// 导航栏国际化
|
// 导航栏国际化
|
||||||
navbar: {
|
navbar: {
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
import { createI18n } from 'vue-i18n';
|
import { createI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { LanguageEnum } from '@/enums/LanguageEnum';
|
import { LanguageEnum } from '@/enums/LanguageEnum';
|
||||||
import messages from '@intlify/unplugin-vue-i18n/messages';
|
import zh_CN from '@/lang/zh_CN';
|
||||||
|
import en_US from '@/lang/en_US';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前语言
|
* 获取当前语言
|
||||||
@ -21,7 +22,12 @@ const i18n = createI18n({
|
|||||||
allowComposition: true,
|
allowComposition: true,
|
||||||
legacy: false,
|
legacy: false,
|
||||||
locale: getLanguage(),
|
locale: getLanguage(),
|
||||||
messages
|
messages: {
|
||||||
|
zh_CN: zh_CN,
|
||||||
|
en_US: en_US
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export default i18n;
|
export default i18n;
|
||||||
|
|
||||||
|
export type LanguageType = typeof zh_CN;
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
{
|
|
||||||
"route": {
|
|
||||||
"dashboard": "首页",
|
|
||||||
"document": "项目文档"
|
|
||||||
},
|
|
||||||
"login": {
|
|
||||||
"username": "用户名",
|
|
||||||
"password": "密码",
|
|
||||||
"login": "登 录",
|
|
||||||
"code": "请输入验证码",
|
|
||||||
"copyright": ""
|
|
||||||
},
|
|
||||||
"navbar": {
|
|
||||||
"full": "全屏",
|
|
||||||
"language": "语言",
|
|
||||||
"dashboard": "首页",
|
|
||||||
"document": "项目文档",
|
|
||||||
"message": "消息",
|
|
||||||
"layoutSize": "布局大小",
|
|
||||||
"selectTenant": "选择租户",
|
|
||||||
"layoutSetting": "布局设置",
|
|
||||||
"personalCenter": "个人中心",
|
|
||||||
"logout": "退出登录"
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,12 +6,70 @@ export default {
|
|||||||
},
|
},
|
||||||
// 登录页面国际化
|
// 登录页面国际化
|
||||||
login: {
|
login: {
|
||||||
|
selectPlaceholder: '请选择/输入公司名称',
|
||||||
username: '用户名',
|
username: '用户名',
|
||||||
password: '密码',
|
password: '密码',
|
||||||
login: '登 录',
|
login: '登 录',
|
||||||
code: '请输入验证码',
|
logging: '登 录 中...',
|
||||||
copyright: ''
|
code: '验证码',
|
||||||
|
rememberPassword: '记住我',
|
||||||
|
switchRegisterPage: '立即注册',
|
||||||
|
rule: {
|
||||||
|
tenantId: {
|
||||||
|
required: '请输入您的租户编号'
|
||||||
|
},
|
||||||
|
username: {
|
||||||
|
required: '请输入您的账号'
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
required: '请输入您的密码'
|
||||||
|
},
|
||||||
|
code: {
|
||||||
|
required: '请输入验证码'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
social: {
|
||||||
|
wechat: '微信登录',
|
||||||
|
maxkey: 'MaxKey登录',
|
||||||
|
topiam: 'TopIam登录',
|
||||||
|
gitee: 'Gitee登录',
|
||||||
|
github: 'Github登录'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
// 注册页面国际化
|
||||||
|
register: {
|
||||||
|
selectPlaceholder: '请选择/输入公司名称',
|
||||||
|
username: '用户名',
|
||||||
|
password: '密码',
|
||||||
|
confirmPassword: '确认密码',
|
||||||
|
register: '注 册',
|
||||||
|
registering: '注 册 中...',
|
||||||
|
registerSuccess: '恭喜你,您的账号 {username} 注册成功!',
|
||||||
|
code: '验证码',
|
||||||
|
switchLoginPage: '使用已有账户登录',
|
||||||
|
rule: {
|
||||||
|
tenantId: {
|
||||||
|
required: '请输入您的租户编号'
|
||||||
|
},
|
||||||
|
username: {
|
||||||
|
required: '请输入您的账号',
|
||||||
|
length: '用户账号长度必须介于 {min} 和 {max} 之间'
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
required: '请输入您的密码',
|
||||||
|
length: '用户密码长度必须介于 {min} 和 {max} 之间',
|
||||||
|
pattern: '不能包含非法字符:{strings}'
|
||||||
|
},
|
||||||
|
code: {
|
||||||
|
required: '请输入验证码'
|
||||||
|
},
|
||||||
|
confirmPassword: {
|
||||||
|
required: '请再次输入您的密码',
|
||||||
|
equalToPassword: '两次输入的密码不一致'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 导航栏国际化
|
||||||
navbar: {
|
navbar: {
|
||||||
full: '全屏',
|
full: '全屏',
|
||||||
language: '语言',
|
language: '语言',
|
||||||
|
@ -20,6 +20,7 @@ import useTagsViewStore from '@/store/modules/tagsView';
|
|||||||
|
|
||||||
import IframeToggle from './IframeToggle/index.vue';
|
import IframeToggle from './IframeToggle/index.vue';
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
const route = useRoute();
|
||||||
const tagsViewStore = useTagsViewStore();
|
const tagsViewStore = useTagsViewStore();
|
||||||
|
|
||||||
// 随机动画集合
|
// 随机动画集合
|
||||||
@ -37,6 +38,20 @@ watch(
|
|||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
addIframe()
|
||||||
|
})
|
||||||
|
|
||||||
|
watchEffect((route) => {
|
||||||
|
addIframe()
|
||||||
|
})
|
||||||
|
|
||||||
|
function addIframe() {
|
||||||
|
if (route.meta.link) {
|
||||||
|
useTagsViewStore().addIframeView(route)
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
clearable
|
clearable
|
||||||
filterable
|
filterable
|
||||||
reserve-keyword
|
reserve-keyword
|
||||||
:placeholder="$t('navbar.selectTenant')"
|
:placeholder="proxy.$t('navbar.selectTenant')"
|
||||||
@change="dynamicTenantEvent"
|
@change="dynamicTenantEvent"
|
||||||
@clear="dynamicClearEvent"
|
@clear="dynamicClearEvent"
|
||||||
>
|
>
|
||||||
@ -29,7 +29,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<!-- 消息 -->
|
<!-- 消息 -->
|
||||||
<el-tooltip :content="$t('navbar.message')" effect="dark" placement="bottom">
|
<el-tooltip :content="proxy.$t('navbar.message')" effect="dark" placement="bottom">
|
||||||
<div>
|
<div>
|
||||||
<el-popover placement="bottom" trigger="click" transition="el-zoom-in-top" :width="300" :persistent="false">
|
<el-popover placement="bottom" trigger="click" transition="el-zoom-in-top" :width="300" :persistent="false">
|
||||||
<template #reference>
|
<template #reference>
|
||||||
@ -47,19 +47,19 @@
|
|||||||
<ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
|
<ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
<el-tooltip :content="$t('navbar.document')" effect="dark" placement="bottom">
|
<el-tooltip :content="proxy.$t('navbar.document')" effect="dark" placement="bottom">
|
||||||
<ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
|
<ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
<el-tooltip :content="$t('navbar.full')" effect="dark" placement="bottom">
|
<el-tooltip :content="proxy.$t('navbar.full')" effect="dark" placement="bottom">
|
||||||
<screenfull id="screenfull" class="right-menu-item hover-effect" />
|
<screenfull id="screenfull" class="right-menu-item hover-effect" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
<el-tooltip :content="$t('navbar.language')" effect="dark" placement="bottom">
|
<el-tooltip :content="proxy.$t('navbar.language')" effect="dark" placement="bottom">
|
||||||
<lang-select id="lang-select" class="right-menu-item hover-effect" />
|
<lang-select id="lang-select" class="right-menu-item hover-effect" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
<el-tooltip :content="$t('navbar.layoutSize')" effect="dark" placement="bottom">
|
<el-tooltip :content="proxy.$t('navbar.layoutSize')" effect="dark" placement="bottom">
|
||||||
<size-select id="size-select" class="right-menu-item hover-effect" />
|
<size-select id="size-select" class="right-menu-item hover-effect" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
@ -72,13 +72,13 @@
|
|||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<router-link v-if="!dynamic" to="/user/profile">
|
<router-link v-if="!dynamic" to="/user/profile">
|
||||||
<el-dropdown-item>{{ $t('navbar.personalCenter') }}</el-dropdown-item>
|
<el-dropdown-item>{{ proxy.$t('navbar.personalCenter') }}</el-dropdown-item>
|
||||||
</router-link>
|
</router-link>
|
||||||
<el-dropdown-item v-if="settingsStore.showSettings" command="setLayout">
|
<el-dropdown-item v-if="settingsStore.showSettings" command="setLayout">
|
||||||
<span>{{ $t('navbar.layoutSetting') }}</span>
|
<span>{{ proxy.$t('navbar.layoutSetting') }}</span>
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item divided command="logout">
|
<el-dropdown-item divided command="logout">
|
||||||
<span>{{ $t('navbar.logout') }}</span>
|
<span>{{ proxy.$t('navbar.logout') }}</span>
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</template>
|
</template>
|
||||||
@ -98,6 +98,7 @@ import { getTenantList } from '@/api/login';
|
|||||||
import { dynamicClear, dynamicTenant } from '@/api/system/tenant';
|
import { dynamicClear, dynamicTenant } from '@/api/system/tenant';
|
||||||
import { TenantVO } from '@/api/types';
|
import { TenantVO } from '@/api/types';
|
||||||
import notice from './notice/index.vue';
|
import notice from './notice/index.vue';
|
||||||
|
import router from '@/router';
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
@ -126,23 +127,23 @@ const dynamicTenantEvent = async (tenantId: string) => {
|
|||||||
if (companyName.value != null && companyName.value !== '') {
|
if (companyName.value != null && companyName.value !== '') {
|
||||||
await dynamicTenant(tenantId);
|
await dynamicTenant(tenantId);
|
||||||
dynamic.value = true;
|
dynamic.value = true;
|
||||||
proxy?.$tab.closeAllPage();
|
await proxy?.$router.push('/');
|
||||||
proxy?.$router.push('/');
|
await proxy?.proxy.$tab.closeAllPage();
|
||||||
proxy?.$tab.refreshPage();
|
await proxy?.proxy.$tab.refreshPage();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const dynamicClearEvent = async () => {
|
const dynamicClearEvent = async () => {
|
||||||
await dynamicClear();
|
await dynamicClear();
|
||||||
dynamic.value = false;
|
dynamic.value = false;
|
||||||
proxy?.$tab.closeAllPage();
|
await proxy?.$router.push('/');
|
||||||
proxy?.$router.push('/');
|
await proxy?.proxy.$tab.closeAllPage();
|
||||||
proxy?.$tab.refreshPage();
|
await proxy?.proxy.$tab.refreshPage();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 租户列表 */
|
/** 租户列表 */
|
||||||
const initTenantList = async () => {
|
const initTenantList = async () => {
|
||||||
const { data } = await getTenantList();
|
const { data } = await getTenantList(true);
|
||||||
tenantEnabled.value = data.tenantEnabled === undefined ? true : data.tenantEnabled;
|
tenantEnabled.value = data.tenantEnabled === undefined ? true : data.tenantEnabled;
|
||||||
if (tenantEnabled.value) {
|
if (tenantEnabled.value) {
|
||||||
tenantList.value = data.voList;
|
tenantList.value = data.voList;
|
||||||
@ -163,8 +164,14 @@ const logout = async () => {
|
|||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
});
|
});
|
||||||
await userStore.logout();
|
userStore.logout().then(() => {
|
||||||
location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index';
|
router.replace({
|
||||||
|
path: '/login',
|
||||||
|
query: {
|
||||||
|
redirect: encodeURIComponent(router.currentRoute.value.fullPath || '/')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const emits = defineEmits(['setLayout']);
|
const emits = defineEmits(['setLayout']);
|
||||||
|
@ -59,11 +59,9 @@ const hasOneShowingChild = (parent: RouteRecordRaw, children?: RouteRecordRaw[])
|
|||||||
const showingChildren = children.filter((item) => {
|
const showingChildren = children.filter((item) => {
|
||||||
if (item.hidden) {
|
if (item.hidden) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
|
||||||
// Temp set(will be used if only has one showing child)
|
|
||||||
onlyOneChild.value = item;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
onlyOneChild.value = item;
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
// When there is only one child router, the child router is displayed by default
|
// When there is only one child router, the child router is displayed by default
|
||||||
|
@ -70,8 +70,8 @@ const isActive = (r: RouteLocationNormalized): boolean => {
|
|||||||
const activeStyle = (tag: RouteLocationNormalized) => {
|
const activeStyle = (tag: RouteLocationNormalized) => {
|
||||||
if (!isActive(tag)) return {};
|
if (!isActive(tag)) return {};
|
||||||
return {
|
return {
|
||||||
'background-color': theme.value,
|
'background-color': 'var(--tags-view-active-bg)',
|
||||||
'border-color': theme.value
|
'border-color': 'var(--tags-view-active-border-color)'
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
const isAffix = (tag: RouteLocationNormalized) => {
|
const isAffix = (tag: RouteLocationNormalized) => {
|
||||||
@ -135,11 +135,7 @@ const addTags = () => {
|
|||||||
}
|
}
|
||||||
if (name) {
|
if (name) {
|
||||||
useTagsViewStore().addView(route as any);
|
useTagsViewStore().addView(route as any);
|
||||||
if (route.meta.link) {
|
|
||||||
useTagsViewStore().addIframeView(route as any);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
const moveToCurrentTag = () => {
|
const moveToCurrentTag = () => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
|
@ -66,7 +66,7 @@ const closeSearch = () => {
|
|||||||
state.isShowSearch = false;
|
state.isShowSearch = false;
|
||||||
};
|
};
|
||||||
// 菜单搜索数据过滤
|
// 菜单搜索数据过滤
|
||||||
const menuSearch = (queryString: string, cb: Function) => {
|
const menuSearch = (queryString: string, cb: (options: any[]) => void) => {
|
||||||
let options = state.menuList.filter((item) => {
|
let options = state.menuList.filter((item) => {
|
||||||
return item.title.indexOf(queryString) > -1;
|
return item.title.indexOf(queryString) > -1;
|
||||||
});
|
});
|
||||||
|
@ -27,7 +27,7 @@ import { AppMain, Navbar, Settings, TagsView } from './components';
|
|||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
import useSettingsStore from '@/store/modules/settings';
|
import useSettingsStore from '@/store/modules/settings';
|
||||||
import { initWebSocket } from '@/utils/websocket';
|
import { initWebSocket } from '@/utils/websocket';
|
||||||
import { initSSE } from "@/utils/sse";
|
import { initSSE } from '@/utils/sse';
|
||||||
|
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
const theme = computed(() => settingsStore.theme);
|
const theme = computed(() => settingsStore.theme);
|
||||||
|
@ -3,14 +3,18 @@ import router from './router';
|
|||||||
import NProgress from 'nprogress';
|
import NProgress from 'nprogress';
|
||||||
import 'nprogress/nprogress.css';
|
import 'nprogress/nprogress.css';
|
||||||
import { getToken } from '@/utils/auth';
|
import { getToken } from '@/utils/auth';
|
||||||
import { isHttp } from '@/utils/validate';
|
import { isHttp, isPathMatch } from '@/utils/validate';
|
||||||
import { isRelogin } from '@/utils/request';
|
import { isRelogin } from '@/utils/request';
|
||||||
import useUserStore from '@/store/modules/user';
|
import useUserStore from '@/store/modules/user';
|
||||||
import useSettingsStore from '@/store/modules/settings';
|
import useSettingsStore from '@/store/modules/settings';
|
||||||
import usePermissionStore from '@/store/modules/permission';
|
import usePermissionStore from '@/store/modules/permission';
|
||||||
|
|
||||||
NProgress.configure({ showSpinner: false });
|
NProgress.configure({ showSpinner: false });
|
||||||
const whiteList = ['/login', '/register', '/social-callback'];
|
const whiteList = ['/login', '/register', '/social-callback', '/register*', '/register/*'];
|
||||||
|
|
||||||
|
const isWhiteList = (path: string) => {
|
||||||
|
return whiteList.some(pattern => isPathMatch(pattern, path))
|
||||||
|
}
|
||||||
|
|
||||||
router.beforeEach(async (to, from, next) => {
|
router.beforeEach(async (to, from, next) => {
|
||||||
NProgress.start();
|
NProgress.start();
|
||||||
@ -20,7 +24,7 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
if (to.path === '/login') {
|
if (to.path === '/login') {
|
||||||
next({ path: '/' });
|
next({ path: '/' });
|
||||||
NProgress.done();
|
NProgress.done();
|
||||||
} else if (whiteList.indexOf(to.path as string) !== -1) {
|
} else if (isWhiteList(to.path)) {
|
||||||
next();
|
next();
|
||||||
} else {
|
} else {
|
||||||
if (useUserStore().roles.length === 0) {
|
if (useUserStore().roles.length === 0) {
|
||||||
@ -40,7 +44,7 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
router.addRoute(route); // 动态添加可访问路由表
|
router.addRoute(route); // 动态添加可访问路由表
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// @ts-ignore
|
// @ts-expect-error hack方法 确保addRoutes已完成
|
||||||
next({ path: to.path, replace: true, params: to.params, query: to.query, hash: to.hash, name: to.name as string }); // hack方法 确保addRoutes已完成
|
next({ path: to.path, replace: true, params: to.params, query: to.query, hash: to.hash, name: to.name as string }); // hack方法 确保addRoutes已完成
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -49,7 +53,7 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 没有token
|
// 没有token
|
||||||
if (whiteList.indexOf(to.path as string) !== -1) {
|
if (isWhiteList(to.path)) {
|
||||||
// 在免登录白名单,直接进入
|
// 在免登录白名单,直接进入
|
||||||
next();
|
next();
|
||||||
} else {
|
} else {
|
||||||
|
@ -26,6 +26,7 @@ const sessionCache = {
|
|||||||
if (value != null) {
|
if (value != null) {
|
||||||
return JSON.parse(value);
|
return JSON.parse(value);
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
},
|
},
|
||||||
remove(key: string) {
|
remove(key: string) {
|
||||||
sessionStorage.removeItem(key);
|
sessionStorage.removeItem(key);
|
||||||
@ -59,6 +60,7 @@ const localCache = {
|
|||||||
if (value != null) {
|
if (value != null) {
|
||||||
return JSON.parse(value);
|
return JSON.parse(value);
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
},
|
},
|
||||||
remove(key: string) {
|
remove(key: string) {
|
||||||
localStorage.removeItem(key);
|
localStorage.removeItem(key);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
import {RouteLocationMatched, RouteLocationNormalized, RouteLocationRaw} from 'vue-router';
|
import { RouteLocationMatched, RouteLocationNormalized, RouteLocationRaw } from 'vue-router';
|
||||||
import useTagsViewStore from '@/store/modules/tagsView';
|
import useTagsViewStore from '@/store/modules/tagsView';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -103,7 +103,7 @@ export const dynamicRoutes: RouteRecordRaw[] = [
|
|||||||
path: 'role/:userId(\\d+)',
|
path: 'role/:userId(\\d+)',
|
||||||
component: () => import('@/views/system/user/authRole.vue'),
|
component: () => import('@/views/system/user/authRole.vue'),
|
||||||
name: 'AuthRole',
|
name: 'AuthRole',
|
||||||
meta: { title: '分配角色', activeMenu: '/system/user', icon: '' }
|
meta: { title: '分配角色', activeMenu: '/system/user', icon: '', noCache: true }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -117,7 +117,7 @@ export const dynamicRoutes: RouteRecordRaw[] = [
|
|||||||
path: 'user/:roleId(\\d+)',
|
path: 'user/:roleId(\\d+)',
|
||||||
component: () => import('@/views/system/role/authUser.vue'),
|
component: () => import('@/views/system/role/authUser.vue'),
|
||||||
name: 'AuthUser',
|
name: 'AuthUser',
|
||||||
meta: { title: '分配用户', activeMenu: '/system/role', icon: '' }
|
meta: { title: '分配用户', activeMenu: '/system/role', icon: '', noCache: true }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -131,7 +131,7 @@ export const dynamicRoutes: RouteRecordRaw[] = [
|
|||||||
path: 'index/:dictId(\\d+)',
|
path: 'index/:dictId(\\d+)',
|
||||||
component: () => import('@/views/system/dict/data.vue'),
|
component: () => import('@/views/system/dict/data.vue'),
|
||||||
name: 'Data',
|
name: 'Data',
|
||||||
meta: { title: '字典数据', activeMenu: '/system/dict', icon: '' }
|
meta: { title: '字典数据', activeMenu: '/system/dict', icon: '', noCache: true }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -145,7 +145,7 @@ export const dynamicRoutes: RouteRecordRaw[] = [
|
|||||||
path: 'index',
|
path: 'index',
|
||||||
component: () => import('@/views/system/oss/config.vue'),
|
component: () => import('@/views/system/oss/config.vue'),
|
||||||
name: 'OssConfig',
|
name: 'OssConfig',
|
||||||
meta: { title: '配置管理', activeMenu: '/system/oss', icon: '' }
|
meta: { title: '配置管理', activeMenu: '/system/oss', icon: '', noCache: true }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -176,6 +176,20 @@ export const dynamicRoutes: RouteRecordRaw[] = [
|
|||||||
meta: { title: '请假申请', activeMenu: '/workflow/leave', noCache: true }
|
meta: { title: '请假申请', activeMenu: '/workflow/leave', noCache: true }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/workflow/design',
|
||||||
|
component: Layout,
|
||||||
|
hidden: true,
|
||||||
|
permissions: ['workflow:leave:edit'],
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'index',
|
||||||
|
component: () => import('@/views/workflow/processDefinition/design.vue'),
|
||||||
|
name: 'design',
|
||||||
|
meta: { title: '流程设计', activeMenu: '/workflow/processDefinition', noCache: true }
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -189,9 +203,8 @@ const router = createRouter({
|
|||||||
scrollBehavior(to, from, savedPosition) {
|
scrollBehavior(to, from, savedPosition) {
|
||||||
if (savedPosition) {
|
if (savedPosition) {
|
||||||
return savedPosition;
|
return savedPosition;
|
||||||
} else {
|
|
||||||
return { top: 0 };
|
|
||||||
}
|
}
|
||||||
|
return { top: 0 };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,29 +1,15 @@
|
|||||||
export const useDictStore = defineStore('dict', () => {
|
export const useDictStore = defineStore('dict', () => {
|
||||||
const dict = ref<
|
const dict = ref<Map<string, DictDataOption[]>>(new Map());
|
||||||
Array<{
|
|
||||||
key: string;
|
|
||||||
value: DictDataOption[];
|
|
||||||
}>
|
|
||||||
>([]);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取字典
|
* 获取字典
|
||||||
* @param _key 字典key
|
* @param _key 字典key
|
||||||
*/
|
*/
|
||||||
const getDict = (_key: string): DictDataOption[] | null => {
|
const getDict = (_key: string): DictDataOption[] | null => {
|
||||||
if (_key == null && _key == '') {
|
if (!_key) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
return dict.value.get(_key) || null;
|
||||||
for (let i = 0; i < dict.value.length; i++) {
|
|
||||||
if (dict.value[i].key == _key) {
|
|
||||||
return dict.value[i].value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,11 +18,15 @@ export const useDictStore = defineStore('dict', () => {
|
|||||||
* @param _value 字典value
|
* @param _value 字典value
|
||||||
*/
|
*/
|
||||||
const setDict = (_key: string, _value: DictDataOption[]) => {
|
const setDict = (_key: string, _value: DictDataOption[]) => {
|
||||||
if (_key !== null && _key !== '') {
|
if (!_key) {
|
||||||
dict.value.push({
|
return false;
|
||||||
key: _key,
|
}
|
||||||
value: _value
|
try {
|
||||||
});
|
dict.value.set(_key, _value);
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error in setDict:', e);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -45,25 +35,22 @@ export const useDictStore = defineStore('dict', () => {
|
|||||||
* @param _key
|
* @param _key
|
||||||
*/
|
*/
|
||||||
const removeDict = (_key: string): boolean => {
|
const removeDict = (_key: string): boolean => {
|
||||||
let bln = false;
|
if (!_key) {
|
||||||
try {
|
return false;
|
||||||
for (let i = 0; i < dict.value.length; i++) {
|
}
|
||||||
if (dict.value[i].key == _key) {
|
try {
|
||||||
dict.value.splice(i, 1);
|
return dict.value.delete(_key);
|
||||||
return true;
|
} catch (e) {
|
||||||
}
|
console.error('Error in removeDict:', e);
|
||||||
}
|
return false;
|
||||||
} catch (e) {
|
|
||||||
bln = false;
|
|
||||||
}
|
}
|
||||||
return bln;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清空字典
|
* 清空字典
|
||||||
*/
|
*/
|
||||||
const cleanDict = (): void => {
|
const cleanDict = (): void => {
|
||||||
dict.value = [];
|
dict.value.clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -1,76 +0,0 @@
|
|||||||
import type { Modeler, Modeling, Canvas, ElementRegistry, Moddle, BpmnFactory } from 'bpmn';
|
|
||||||
|
|
||||||
type ModelerStore = {
|
|
||||||
modeler: Modeler | undefined;
|
|
||||||
moddle: Moddle | undefined;
|
|
||||||
modeling: Modeling | undefined;
|
|
||||||
canvas: Canvas | undefined;
|
|
||||||
elementRegistry: ElementRegistry | undefined;
|
|
||||||
bpmnFactory: BpmnFactory | undefined;
|
|
||||||
// 流程定义根节点信息
|
|
||||||
procDefId: string | undefined;
|
|
||||||
procDefName: string | undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
const defaultState: ModelerStore = {
|
|
||||||
modeler: undefined,
|
|
||||||
moddle: undefined,
|
|
||||||
modeling: undefined,
|
|
||||||
canvas: undefined,
|
|
||||||
elementRegistry: undefined,
|
|
||||||
bpmnFactory: undefined,
|
|
||||||
procDefId: undefined,
|
|
||||||
procDefName: undefined
|
|
||||||
};
|
|
||||||
export const useModelerStore = defineStore('modeler', () => {
|
|
||||||
let modeler = defaultState.modeler;
|
|
||||||
let moddle = defaultState.moddle;
|
|
||||||
let modeling = defaultState.modeling;
|
|
||||||
let canvas = defaultState.canvas;
|
|
||||||
let elementRegistry = defaultState.elementRegistry;
|
|
||||||
let bpmnFactory = defaultState.bpmnFactory;
|
|
||||||
const procDefId = ref(defaultState.procDefId);
|
|
||||||
const procDefName = ref(defaultState.procDefName);
|
|
||||||
|
|
||||||
const getModeler = () => modeler;
|
|
||||||
const getModdle = () => moddle;
|
|
||||||
const getModeling = (): Modeling | undefined => modeling;
|
|
||||||
const getCanvas = (): Canvas | undefined => canvas;
|
|
||||||
const getElRegistry = (): ElementRegistry | undefined => elementRegistry;
|
|
||||||
const getBpmnFactory = (): BpmnFactory | undefined => bpmnFactory;
|
|
||||||
const getProcDefId = (): string | undefined => procDefId.value;
|
|
||||||
const getProcDefName = (): string | undefined => procDefName.value;
|
|
||||||
|
|
||||||
// 设置根节点
|
|
||||||
const setModeler = (modelers: Modeler | undefined) => {
|
|
||||||
if (modelers) {
|
|
||||||
modeler = modelers;
|
|
||||||
modeling = modelers.get<Modeling>('modeling');
|
|
||||||
moddle = modelers.get<Moddle>('moddle');
|
|
||||||
canvas = modelers.get<Canvas>('canvas');
|
|
||||||
bpmnFactory = modelers.get<BpmnFactory>('bpmnFactory');
|
|
||||||
elementRegistry = modelers.get<ElementRegistry>('elementRegistry');
|
|
||||||
} else {
|
|
||||||
modeling = moddle = canvas = elementRegistry = bpmnFactory = undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 设置流程定义根节点信息
|
|
||||||
const setProcDef = (modeler: Modeler | undefined) => {
|
|
||||||
procDefId.value = modeler.get<Canvas>('canvas').getRootElement().businessObject.get('id');
|
|
||||||
procDefName.value = modeler.get<Canvas>('canvas').getRootElement().businessObject.get('name');
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
getModeler,
|
|
||||||
getModdle,
|
|
||||||
getModeling,
|
|
||||||
getCanvas,
|
|
||||||
getElRegistry,
|
|
||||||
getBpmnFactory,
|
|
||||||
getProcDefId,
|
|
||||||
getProcDefName,
|
|
||||||
setModeler,
|
|
||||||
setProcDef
|
|
||||||
};
|
|
||||||
});
|
|
||||||
export default useModelerStore;
|
|
@ -158,9 +158,12 @@ export const filterDynamicRoutes = (routes: RouteRecordRaw[]) => {
|
|||||||
export const loadView = (view: any, name: string) => {
|
export const loadView = (view: any, name: string) => {
|
||||||
let res;
|
let res;
|
||||||
for (const path in modules) {
|
for (const path in modules) {
|
||||||
const dir = path.split('views/')[1].split('.vue')[0];
|
const viewsIndex = path.indexOf('/views/');
|
||||||
|
let dir = path.substring(viewsIndex + 7);
|
||||||
|
dir = dir.substring(0, dir.lastIndexOf('.vue'));
|
||||||
if (dir === view) {
|
if (dir === view) {
|
||||||
res = createCustomNameComponent(modules[path], { name });
|
res = createCustomNameComponent(modules[path], { name });
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
@ -31,7 +31,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
|||||||
const delIframeView = (view: RouteLocationNormalized): Promise<RouteLocationNormalized[]> => {
|
const delIframeView = (view: RouteLocationNormalized): Promise<RouteLocationNormalized[]> => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
iframeViews.value = iframeViews.value.filter((item: RouteLocationNormalized) => item.path !== view.path);
|
iframeViews.value = iframeViews.value.filter((item: RouteLocationNormalized) => item.path !== view.path);
|
||||||
resolve([...iframeViews.value as RouteLocationNormalized[]]);
|
resolve([...(iframeViews.value as RouteLocationNormalized[])]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const addVisitedView = (view: RouteLocationNormalized): void => {
|
const addVisitedView = (view: RouteLocationNormalized): void => {
|
||||||
@ -54,7 +54,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
|||||||
delCachedView(view);
|
delCachedView(view);
|
||||||
}
|
}
|
||||||
resolve({
|
resolve({
|
||||||
visitedViews: [...visitedViews.value as RouteLocationNormalized[]],
|
visitedViews: [...(visitedViews.value as RouteLocationNormalized[])],
|
||||||
cachedViews: [...cachedViews.value]
|
cachedViews: [...cachedViews.value]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -68,7 +68,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resolve([...visitedViews.value as RouteLocationNormalized[]]);
|
resolve([...(visitedViews.value as RouteLocationNormalized[])]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const delCachedView = (view?: RouteLocationNormalized): Promise<string[]> => {
|
const delCachedView = (view?: RouteLocationNormalized): Promise<string[]> => {
|
||||||
@ -92,7 +92,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
|||||||
delOthersVisitedViews(view);
|
delOthersVisitedViews(view);
|
||||||
delOthersCachedViews(view);
|
delOthersCachedViews(view);
|
||||||
resolve({
|
resolve({
|
||||||
visitedViews: [...visitedViews.value as RouteLocationNormalized[]],
|
visitedViews: [...(visitedViews.value as RouteLocationNormalized[])],
|
||||||
cachedViews: [...cachedViews.value]
|
cachedViews: [...cachedViews.value]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -103,7 +103,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
|||||||
visitedViews.value = visitedViews.value.filter((v: RouteLocationNormalized) => {
|
visitedViews.value = visitedViews.value.filter((v: RouteLocationNormalized) => {
|
||||||
return v.meta?.affix || v.path === view.path;
|
return v.meta?.affix || v.path === view.path;
|
||||||
});
|
});
|
||||||
resolve([...visitedViews.value as RouteLocationNormalized[]]);
|
resolve([...(visitedViews.value as RouteLocationNormalized[])]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const delOthersCachedViews = (view: RouteLocationNormalized): Promise<string[]> => {
|
const delOthersCachedViews = (view: RouteLocationNormalized): Promise<string[]> => {
|
||||||
@ -124,7 +124,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
|||||||
delAllVisitedViews();
|
delAllVisitedViews();
|
||||||
delAllCachedViews();
|
delAllCachedViews();
|
||||||
resolve({
|
resolve({
|
||||||
visitedViews: [...visitedViews.value as RouteLocationNormalized[]],
|
visitedViews: [...(visitedViews.value as RouteLocationNormalized[])],
|
||||||
cachedViews: [...cachedViews.value]
|
cachedViews: [...cachedViews.value]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -132,7 +132,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
|||||||
const delAllVisitedViews = (): Promise<RouteLocationNormalized[]> => {
|
const delAllVisitedViews = (): Promise<RouteLocationNormalized[]> => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
visitedViews.value = visitedViews.value.filter((tag: RouteLocationNormalized) => tag.meta?.affix);
|
visitedViews.value = visitedViews.value.filter((tag: RouteLocationNormalized) => tag.meta?.affix);
|
||||||
resolve([...visitedViews.value as RouteLocationNormalized[]]);
|
resolve([...(visitedViews.value as RouteLocationNormalized[])]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
resolve([...visitedViews.value as RouteLocationNormalized[]]);
|
resolve([...(visitedViews.value as RouteLocationNormalized[])]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const delLeftTags = (view: RouteLocationNormalized): Promise<RouteLocationNormalized[]> => {
|
const delLeftTags = (view: RouteLocationNormalized): Promise<RouteLocationNormalized[]> => {
|
||||||
@ -186,7 +186,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
resolve([...visitedViews.value as RouteLocationNormalized[]]);
|
resolve([...(visitedViews.value as RouteLocationNormalized[])]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
13
src/types/bpmn/editor/global.d.ts
vendored
13
src/types/bpmn/editor/global.d.ts
vendored
@ -1,13 +0,0 @@
|
|||||||
import { MessageApiInjection } from 'naive-ui/lib/message/src/MessageProvider';
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface Window {
|
|
||||||
bpmnInstances: any;
|
|
||||||
__messageBox: MessageApiInjection;
|
|
||||||
URL: any;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare interface Window {
|
|
||||||
bpmnInstances: any;
|
|
||||||
}
|
|
15
src/types/bpmn/index.d.ts
vendored
15
src/types/bpmn/index.d.ts
vendored
@ -1,15 +0,0 @@
|
|||||||
declare module 'bpmn' {
|
|
||||||
import type modeler from 'bpmn-js/lib/Modeler';
|
|
||||||
import type modeling from 'bpmn-js/lib/features/modeling/Modeling';
|
|
||||||
import type canvas from 'diagram-js/lib/core/Canvas';
|
|
||||||
import type elementRegistry from 'diagram-js/lib/core/ElementRegistry';
|
|
||||||
import type bpmnFactory from 'bpmn-js/lib/features/modeling/BpmnFactory';
|
|
||||||
|
|
||||||
export type Modeler = modeler;
|
|
||||||
export type Modeling = modeling;
|
|
||||||
export type Canvas = canvas;
|
|
||||||
export type ElementRegistry = elementRegistry;
|
|
||||||
export type Moddle = import('moddle').Moddle;
|
|
||||||
export type ModdleElement = import('moddle').ModdleElement;
|
|
||||||
export type BpmnFactory = bpmnFactory;
|
|
||||||
}
|
|
37
src/types/bpmn/moddle.d.ts
vendored
37
src/types/bpmn/moddle.d.ts
vendored
@ -1,37 +0,0 @@
|
|||||||
declare module 'moddle' {
|
|
||||||
import type { Element as element } from 'bpmn-js/lib/model/Types';
|
|
||||||
|
|
||||||
export type Element = {
|
|
||||||
get<T>(name: string): T;
|
|
||||||
|
|
||||||
set(name: string, value: any): void;
|
|
||||||
} & element;
|
|
||||||
|
|
||||||
export interface ModdleElement extends Element {
|
|
||||||
$model: Moddle;
|
|
||||||
readonly $type: string;
|
|
||||||
$attrs: object | {};
|
|
||||||
$parent: any;
|
|
||||||
businessObject: ModdleElement;
|
|
||||||
type: string;
|
|
||||||
|
|
||||||
[field: string]: any;
|
|
||||||
|
|
||||||
hasType(element: ModdleElement, type?: string): boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Package {
|
|
||||||
name: string;
|
|
||||||
prefix: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Moddle {
|
|
||||||
typeCache: Record<string, ModdleElement>;
|
|
||||||
|
|
||||||
getPackage: typeof Registry.prototype.getPackage;
|
|
||||||
|
|
||||||
getPackages: typeof Registry.prototype.getPackages;
|
|
||||||
|
|
||||||
create(type: string, attrs?: any): ModdleElement;
|
|
||||||
}
|
|
||||||
}
|
|
92
src/types/bpmn/panel.d.ts
vendored
92
src/types/bpmn/panel.d.ts
vendored
@ -1,92 +0,0 @@
|
|||||||
declare module 'bpmnDesign' {
|
|
||||||
import { AllocationTypeEnum, SpecifyDescEnum, MultiInstanceTypeEnum } from '@/enums/bpmn/IndexEnums';
|
|
||||||
|
|
||||||
export interface ParamVO {
|
|
||||||
type: string;
|
|
||||||
name: string;
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TaskListenerVO {
|
|
||||||
event: string;
|
|
||||||
type: string;
|
|
||||||
name: string;
|
|
||||||
className: string;
|
|
||||||
params: ParamVO[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ExecutionListenerVO {
|
|
||||||
event: string;
|
|
||||||
type: string;
|
|
||||||
className: string;
|
|
||||||
params: ParamVO[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface BasePanel {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
export interface ProcessPanel extends BasePanel {}
|
|
||||||
|
|
||||||
export interface TaskPanel extends BasePanel {
|
|
||||||
allocationType: AllocationTypeEnum;
|
|
||||||
specifyDesc: SpecifyDescEnum;
|
|
||||||
multiInstanceType: MultiInstanceTypeEnum;
|
|
||||||
async?: boolean;
|
|
||||||
priority?: number;
|
|
||||||
formKey?: string;
|
|
||||||
skipExpression?: string;
|
|
||||||
isForCompensation?: boolean;
|
|
||||||
triggerServiceTask?: boolean;
|
|
||||||
autoStoreVariables?: boolean;
|
|
||||||
ruleVariablesInput?: string;
|
|
||||||
excludeTaskListener?: boolean;
|
|
||||||
exclude?: boolean;
|
|
||||||
class?: string;
|
|
||||||
dueDate?: string;
|
|
||||||
fixedAssignee?: string;
|
|
||||||
|
|
||||||
candidateUsers?: string;
|
|
||||||
assignee?: string;
|
|
||||||
candidateGroups?: string;
|
|
||||||
collection?: string;
|
|
||||||
elementVariable?: string;
|
|
||||||
completionCondition?: string;
|
|
||||||
isSequential?: boolean;
|
|
||||||
|
|
||||||
loopCharacteristics?: {
|
|
||||||
collection: string;
|
|
||||||
elementVariable: string;
|
|
||||||
isSequential: boolean;
|
|
||||||
completionCondition: {
|
|
||||||
body: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface StartEndPanel extends BasePanel {}
|
|
||||||
export interface GatewayPanel extends BasePanel {}
|
|
||||||
export interface SequenceFlowPanel extends BasePanel {
|
|
||||||
conditionExpression: {
|
|
||||||
body: string;
|
|
||||||
};
|
|
||||||
conditionExpressionValue: string;
|
|
||||||
skipExpression: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ParticipantPanel extends BasePanel {}
|
|
||||||
export interface SubProcessPanel extends BasePanel {
|
|
||||||
multiInstanceType: MultiInstanceTypeEnum;
|
|
||||||
collection?: string;
|
|
||||||
elementVariable?: string;
|
|
||||||
completionCondition?: string;
|
|
||||||
loopCharacteristics?: {
|
|
||||||
collection: string;
|
|
||||||
elementVariable: string;
|
|
||||||
isSequential: boolean;
|
|
||||||
completionCondition: {
|
|
||||||
body: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
22
src/types/module.d.ts
vendored
22
src/types/module.d.ts
vendored
@ -8,10 +8,11 @@ import { useDict } from '@/utils/dict';
|
|||||||
import { handleTree, addDateRange, selectDictLabel, selectDictLabels, parseTime } from '@/utils/ruoyi';
|
import { handleTree, addDateRange, selectDictLabel, selectDictLabels, parseTime } from '@/utils/ruoyi';
|
||||||
import { getConfigKey, updateConfigByKey } from '@/api/system/config';
|
import { getConfigKey, updateConfigByKey } from '@/api/system/config';
|
||||||
import { download as rd } from '@/utils/request';
|
import { download as rd } from '@/utils/request';
|
||||||
|
import type { LanguageType } from '@/lang';
|
||||||
|
|
||||||
export {};
|
export {};
|
||||||
|
|
||||||
declare module 'vue' {
|
declare module '@vue/runtime-core' {
|
||||||
interface ComponentCustomProperties {
|
interface ComponentCustomProperties {
|
||||||
// 全局方法声明
|
// 全局方法声明
|
||||||
$modal: typeof modal;
|
$modal: typeof modal;
|
||||||
@ -20,6 +21,11 @@ declare module 'vue' {
|
|||||||
$auth: typeof auth;
|
$auth: typeof auth;
|
||||||
$cache: typeof cache;
|
$cache: typeof cache;
|
||||||
animate: typeof animate;
|
animate: typeof animate;
|
||||||
|
/**
|
||||||
|
* i18n $t方法支持ts类型提示
|
||||||
|
* @param key i18n key
|
||||||
|
*/
|
||||||
|
$t(key: ObjKeysToUnion<LanguageType>): string;
|
||||||
|
|
||||||
useDict: typeof useDict;
|
useDict: typeof useDict;
|
||||||
addDateRange: typeof addDateRange;
|
addDateRange: typeof addDateRange;
|
||||||
@ -33,7 +39,13 @@ declare module 'vue' {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module 'vform3-builds' {
|
/**
|
||||||
const content: any;
|
* { a: 1, b: { ba: { baa: 1, bab: 2 }, bb: 2} } ---> a | b.ba.baa | b.ba.bab | b.bb
|
||||||
export = content;
|
* https://juejin.cn/post/7280062870670606397
|
||||||
}
|
*/
|
||||||
|
export type ObjKeysToUnion<T, P extends string = ''> = T extends object
|
||||||
|
? {
|
||||||
|
[K in keyof T]: ObjKeysToUnion<T[K], P extends '' ? `${K & string}` : `${P}.${K & string}`>;
|
||||||
|
}[keyof T]
|
||||||
|
: P;
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user