main
徐景良 2024-03-08 09:49:33 +08:00
commit a1fab2bf8a
83 changed files with 7869 additions and 17 deletions

View File

@ -184,5 +184,8 @@
".eslintrc.cjs": ".eslintignore,.prettierignore,.stylelintignore,.commitlintrc.*,.prettierrc.*,.stylelintrc.*"
},
"terminal.integrated.scrollback": 10000,
"nuxt.isNuxtApp": false
"nuxt.isNuxtApp": false,
"[javascript]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
}
}

View File

@ -79,17 +79,23 @@
"@zxcvbn-ts/core": "^3.0.4",
"ant-design-vue": "^4.0.8",
"axios": "^1.6.4",
"bpmn-js": "^17.0.2",
"bpmn-js-properties-panel": "^5.13.0",
"bpmn-js-token-simulation": "^0.33.1",
"codemirror": "^5.65.16",
"cropperjs": "^1.6.1",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.10",
"diagram-js": "^14.1.0",
"driver.js": "^1.3.1",
"echarts": "^5.4.3",
"exceljs": "^4.4.0",
"highlight.js": "^11.9.0",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"mars3d": "^3.7.0",
"mars3d-cesium": "^1.113.0",
"min-dash": "^4.2.1",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"path-to-regexp": "^6.2.1",
@ -118,7 +124,8 @@
"xe-utils": "^3.5.14",
"xlsx": "^0.18.5",
"kml-geojson": "^1.2.2",
"localforage": "^1.10.0"
"localforage": "^1.10.0",
"xml-js": "^1.6.11"
},
"devDependencies": {
"@commitlint/cli": "^18.4.4",

View File

@ -3,7 +3,6 @@
* @Date: 2024-01-13 13:04:15
* @LastEditors: Do not edit
* @LastEditTime: 2024-02-05 16:06:58
* @FilePath: \e:\\vue-vben-admin\src\api\sys\user.ts
* @Description:
*/
import { defHttp } from '@/utils/http/axios';

View File

@ -0,0 +1,13 @@
/*
* @Author:
* @Date: 2024-03-01 15:55:24
* @LastEditors: Do not edit
* @LastEditTime: 2024-03-02 16:08:00
* @Description:
*/
import { withInstall } from '@/utils';
import bWflowViewer from './src/bWflowViewer.vue'
export const BWflowViewer = withInstall(bWflowViewer);

View File

@ -0,0 +1,130 @@
<template>
<div id="app">
<a-button class="ml-2" title="撤销" :icon="h(RedoOutlined)" @click="handleUndo"> </a-button>
<a-button title="复原" :icon="h(UndoOutlined)" @click="handleRedo"> </a-button>
<a-button class="ml-2" title=" 重做" :icon="h(StopOutlined)"> </a-button>
<a-button title="放大" :icon="h(PlusCircleOutlined)"> </a-button>
<a-button title="缩小" :icon="h(MinusCircleOutlined)"> </a-button>
<a-button title="下载" :icon="h(SearchOutlined)" @click="handleDownload"> </a-button>
<div id="container"></div>
</div>
</template>
<script lang="ts" setup>
import { h, ref, onMounted, reactive } from 'vue';
import { RedoOutlined, UndoOutlined, StopOutlined, PlusCircleOutlined, MinusCircleOutlined, SearchOutlined } from '@ant-design/icons-vue';
import { Button } from 'ant-design-vue';
import BpmnModeler from 'bpmn-js/lib/Modeler';
import camundaExtension from './js/camunda.json'; //
import customTranslate from "./js/customTranslate.js";//
import EventEmitter from './utils/EventEmitter'
const state = reactive({
containerEl: null,
bpmnModeler: null,
fileList: [],
});
EventEmitter.instance.on('modeler-init', (modeler) => {
modeler.on('element.click', (element) => {
console.log(element)
currentElement.value = element
})
})
function create() {
state.bpmnModeler.createDiagram(() => {
state.bpmnModeler.get('canvas').zoom('fit-viewport');
});
}
function handleRemove(file) {
for (let i = 0; i < state.fileList.length; i++) {
if (file.name === state.fileList[i].name) {
state.fileList.splice(i, 1);
}
}
}
function beforeRemove(file) {
return this.$confirm(`确定移除 ${file.name}`);
}
// 退
function handleUndo() {
state.bpmnModeler.get('commandStack').undo();
}
//
function handleRedo() {
state.bpmnModeler.get('commandStack').redo();
}
function handleDownload() {
console.log(state.bpmnModeler)
state.bpmnModeler.saveXML({ format: true }, (err, data) => {
console.log(data)
// const dataTrack = 'bpmn';
// const a = document.createElement('a');
// const name = `diagram.${dataTrack}`;
// a.setAttribute(
// 'href',
// `data:application/bpmn20-xml;charset=UTF-8,${encodeURIComponent(data)}`
// );
// a.setAttribute('target', '_blank');
// a.setAttribute('dataTrack', `diagram:download-${dataTrack}`);
// a.setAttribute('download', name);
// document.body.appendChild(a);
// a.click();
// document.body.removeChild(a);
});
}
function handleOnchangeFile(file) {
const reader = new FileReader();
let data = '';
reader.readAsText(file.raw);
reader.onload = (event) => {
data = event.target.result;
state.bpmnModeler.importXML(data, (err) => {
if (err) {
this.$message.info('导入失败');
} else {
this.$message.success('导入成功');
}
});
};
}
onMounted(() => {
let customTranslateModule = {
translate: ["value", customTranslate]
};
state.containerEl = document.querySelector('#container');
state.bpmnModeler = new BpmnModeler({
container: state.containerEl,
moddleExtensions: { camunda: camundaExtension },
additionalModules: [
//
customTranslateModule,
],
});
create();
})
</script>
<style>
#app {
width: 100%;
height: 100%;
}
body,
html {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
#container {
height: calc(100% - 50px);
background-size: 20px 20px, 20px 20px, 10px 10px, 10px 10px;
background-image: linear-gradient(to right, #dfdfdf 1px, transparent 1px), linear-gradient(to bottom, #dfdfdf 1px, transparent 1px), linear-gradient(to right, #f1f1f1 1px, transparent 1px), linear-gradient(to bottom, #f1f1f1 1px, transparent 1px);
background-position: left -1px top -1px, left -1px top -1px, left -1px top -1px, left -1px top -1px;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
import translations from './translations';
export default function customTranslate(template, replacements) {
replacements = replacements || {};
// Translate
template = translations[template] || template;
// Replace
return template.replace(/{([^}]+)}/g, function(_, key) {
return replacements[key] || '{' + key + '}';
});
}

View File

@ -0,0 +1,240 @@
export default {
// hong
// Labels
'Activate the global connect tool' : '激活全局连接工具',
'Append {type}': '追加 {type}',
'Append EndEvent': '追加 结束事件 ',
'Append Task':'追加 任务',
'Append Gateway':'追加 网关',
'Append Intermediate/Boundary Event':'追加 中间/边界 事件',
'Add Lane above': '在上面添加道',
'Divide into two Lanes': '分割成两个道',
'Divide into three Lanes': '分割成三个道',
'Add Lane below': '在下面添加道',
'Append compensation activity': '追加补偿活动',
'Change type': '修改类型',
'Connect using Association': '使用关联连接',
'Connect using Sequence/MessageFlow or Association': '使用顺序/消息流或者关联连接',
'Connect using DataInputAssociation': '使用数据输入关联连接',
'Remove': '移除',
'Activate the hand tool': '激活抓手工具',
'Activate the lasso tool': '激活套索工具',
'Activate the create/remove space tool': '激活创建/删除空间工具',
'Create expanded SubProcess': '创建扩展子过程',
'Create IntermediateThrowEvent/BoundaryEvent' : '创建中间抛出事件/边界事件',
'Create Pool/Participant': '创建池/参与者',
'Parallel Multi Instance': '并行多重事件',
'Sequential Multi Instance': '时序多重事件',
'DataObjectReference':'数据对象参考',
'DataStoreReference':'数据存储参考',
'Loop': '循环',
'Ad-hoc': '即席',
'Create {type}': '创建 {type}',
'Create Task':'创建任务',
'Create StartEvent':'创建开始事件',
'Create EndEvent':'创建结束事件',
'Create Group':'创建组',
'Task': '任务',
'Send Task': '发送任务',
'Receive Task': '接收任务',
'User Task': '用户任务',
'Manual Task': '手工任务',
'Business Rule Task': '业务规则任务',
'Service Task': '服务任务',
'Script Task': '脚本任务',
'Call Activity': '调用活动',
'Sub Process (collapsed)': '子流程(折叠的)',
'Sub Process (expanded)': '子流程(展开的)',
'Start Event': '开始事件',
'StartEvent': '开始事件',
'Intermediate Throw Event': '中间事件',
'End Event': '结束事件',
'EndEvent': '结束事件',
'Create Gateway': '创建网关',
'GateWay':'网关',
'Create Intermediate/Boundary Event': '创建中间/边界事件',
'Message Start Event': '消息开始事件',
'Timer Start Event': '定时开始事件',
'Conditional Start Event': '条件开始事件',
'Signal Start Event': '信号开始事件',
'Error Start Event': '错误开始事件',
'Escalation Start Event': '升级开始事件',
'Compensation Start Event': '补偿开始事件',
'Message Start Event (non-interrupting)': '消息开始事件(非中断)',
'Timer Start Event (non-interrupting)': '定时开始事件(非中断)',
'Conditional Start Event (non-interrupting)': '条件开始事件(非中断)',
'Signal Start Event (non-interrupting)': '信号开始事件(非中断)',
'Escalation Start Event (non-interrupting)': '升级开始事件(非中断)',
'Message Intermediate Catch Event': '消息中间捕获事件',
'Message Intermediate Throw Event': '消息中间抛出事件',
'Timer Intermediate Catch Event': '定时中间捕获事件',
'Escalation Intermediate Throw Event': '升级中间抛出事件',
'Conditional Intermediate Catch Event': '条件中间捕获事件',
'Link Intermediate Catch Event': '链接中间捕获事件',
'Link Intermediate Throw Event': '链接中间抛出事件',
'Compensation Intermediate Throw Event': '补偿中间抛出事件',
'Signal Intermediate Catch Event': '信号中间捕获事件',
'Signal Intermediate Throw Event': '信号中间抛出事件',
'Message End Event': '消息结束事件',
'Escalation End Event': '定时结束事件',
'Error End Event': '错误结束事件',
'Cancel End Event': '取消结束事件',
'Compensation End Event': '补偿结束事件',
'Signal End Event': '信号结束事件',
'Terminate End Event': '终止结束事件',
'Message Boundary Event': '消息边界事件',
'Message Boundary Event (non-interrupting)': '消息边界事件(非中断)',
'Timer Boundary Event': '定时边界事件',
'Timer Boundary Event (non-interrupting)': '定时边界事件(非中断)',
'Escalation Boundary Event': '升级边界事件',
'Escalation Boundary Event (non-interrupting)': '升级边界事件(非中断)',
'Conditional Boundary Event': '条件边界事件',
'Conditional Boundary Event (non-interrupting)': '条件边界事件(非中断)',
'Error Boundary Event': '错误边界事件',
'Cancel Boundary Event': '取消边界事件',
'Signal Boundary Event': '信号边界事件',
'Signal Boundary Event (non-interrupting)': '信号边界事件(非中断)',
'Compensation Boundary Event': '补偿边界事件',
'Exclusive Gateway': '互斥网关',
'Parallel Gateway': '并行网关',
'Inclusive Gateway': '相容网关',
'Complex Gateway': '复杂网关',
'Event based Gateway': '事件网关',
'Transaction': '转运',
'Sub Process': '子流程',
'Event Sub Process': '事件子流程',
'Collapsed Pool': '折叠池',
'Expanded Pool': '展开池',
// Errors
'no parent for {element} in {parent}': '在{parent}里,{element}没有父类',
'no shape type specified': '没有指定的形状类型',
'flow elements must be children of pools/participants': '流元素必须是池/参与者的子类',
'out of bounds release': 'out of bounds release',
'more than {count} child lanes': '子道大于{count} ',
'element required': '元素不能为空',
'diagram not part of bpmn:Definitions': '流程图不符合bpmn规范',
'no diagram to display': '没有可展示的流程图',
'no process or collaboration to display': '没有可展示的流程/协作',
'element {element} referenced by {referenced}#{property} not yet drawn': '由{referenced}#{property}引用的{element}元素仍未绘制',
'already rendered {element}': '{element} 已被渲染',
'failed to import {element}': '导入{element}失败',
//属性面板的参数
'Id':'编号',
'Name':'名称',
'General':'常规',
'Details':'详情',
'Message Name':'消息名称',
'Message':'消息',
'Initiator':'创建者',
'Asynchronous Continuations':'持续异步',
'Asynchronous Before':'异步前',
'Asynchronous After':'异步后',
'Job Configuration':'工作配置',
'Exclusive':'排除',
'Job Priority':'工作优先级',
'Retry Time Cycle':'重试时间周期',
'Documentation':'文档',
'Element Documentation':'元素文档',
'History Configuration':'历史配置',
'History Time To Live':'历史的生存时间',
'Forms':'表单',
'Form Key':'表单key',
'Form Fields':'表单字段',
'Business Key':'业务key',
'Form Field':'表单字段',
'ID':'编号',
'Type':'类型',
'Label':'名称',
'Default Value':'默认值',
'Validation':'校验',
'Add Constraint':'添加约束',
'Config':'配置',
'Properties':'属性',
'Add Property':'添加属性',
'Value':'值',
'Add':'添加',
'Values':'值',
'Add Value':'添加值',
'Listeners':'监听器',
'Execution Listener':'执行监听',
'Event Type':'事件类型',
'Listener Type':'监听器类型',
'Java Class':'Java类',
'Expression':'表达式',
'Must provide a value':'必须提供一个值',
'Delegate Expression':'代理表达式',
'Script':'脚本',
'Script Format':'脚本格式',
'Script Type':'脚本类型',
'Inline Script':'内联脚本',
'External Script':'外部脚本',
'Resource':'资源',
'Field Injection':'字段注入',
'Extensions':'扩展',
'Input/Output':'输入/输出',
'Input Parameters':'输入参数',
'Output Parameters':'输出参数',
'Parameters':'参数',
'Output Parameter':'输出参数',
'Timer Definition Type':'定时器定义类型',
'Timer Definition':'定时器定义',
'Date':'日期',
'Duration':'持续',
'Cycle':'循环',
'Signal':'信号',
'Signal Name':'信号名称',
'Escalation':'升级',
'Error':'错误',
'Link Name':'链接名称',
'Condition':'条件名称',
'Variable Name':'变量名称',
'Variable Event':'变量事件',
'Specify more than one variable change event as a comma separated list.':'多个变量事件以逗号隔开',
'Wait for Completion':'等待完成',
'Activity Ref':'活动参考',
'Version Tag':'版本标签',
'Executable':'可执行文件',
'External Task Configuration':'扩展任务配置',
'Task Priority':'任务优先级',
'External':'外部',
'Connector':'连接器',
'Must configure Connector':'必须配置连接器',
'Connector Id':'连接器编号',
'Implementation':'实现方式',
'Field Injections':'字段注入',
'Fields':'字段',
'Result Variable':'结果变量',
'Topic':'主题',
'Configure Connector':'配置连接器',
'Input Parameter':'输入参数',
'Assignee':'代理人',
'Candidate Users':'候选用户',
'Candidate Groups':'候选组',
'Due Date':'到期时间',
'Follow Up Date':'跟踪日期',
'Priority':'优先级',
'The follow up date as an EL expression (e.g. ${someDate} or an ISO date (e.g. 2015-06-26T09:54:00)':'跟踪日期必须符合EL表达式 ${someDate} ,或者一个ISO标准日期2015-06-26T09:54:00',
'The due date as an EL expression (e.g. ${someDate} or an ISO date (e.g. 2015-06-26T09:54:00)':'跟踪日期必须符合EL表达式 ${someDate} ,或者一个ISO标准日期2015-06-26T09:54:00',
'Variables':'变量',
'Candidate Starter Configuration':'候选开始配置',
'Task Listener':'任务监听器',
'Candidate Starter Groups':'候选开始组',
'Candidate Starter Users':'候选开始用户',
'Tasklist Configuration':'任务列表配置',
'Startable':'启动',
'Specify more than one group as a comma separated list.':'指定多个组,用逗号分隔',
'Specify more than one user as a comma separated list.':'指定多个用户,用逗号分隔',
'This maps to the process definition key.':'这会映射为流程定义的键',
'CallActivity Type':'调用活动类型',
'Condition Type':'条件类型',
'Create UserTask':'创建用户任务',
'Create CallActivity':'创建调用活动',
'Called Element':'调用元素',
'Create DataObjectReference':'创建数据对象引用',
'Create DataStoreReference':'创建数据存储引用',
'Multi Instance':'多实例',
'Loop Cardinality':'实例数量',
'Collection':'任务参与人列表',
'Element Variable':'元素变量',
'Completion Condition':'完成条件'
};

View File

@ -0,0 +1,21 @@
declare class EventEmitter {
private _events;
private static _instance;
static instance(): EventEmitter;
constructor();
private _addListener;
addListener(type: string, fn: any, context?: any): this;
on(type: string, fn: any, context?: any): this;
once(type: string, fn: any, context?: any): this;
emit(type: any, ...rest: any[]): boolean;
removeListener(type: any, fn: any): this;
removeAllListeners(type: any): this;
listeners(type: any): Function[];
listenerCount(type: any): number;
eventNames(): string[];
}
declare const _default: {
EventEmitter: typeof EventEmitter;
instance: EventEmitter;
};
export default _default;

View File

@ -0,0 +1,141 @@
import { getRawType, notNull } from './tools';
const isArray = (obj) => getRawType(obj) === 'array';
const isNullOrUndefined = (obj) => !notNull(obj);
class EventEmitter {
_events = {};
static _instance = null;
static instance() {
// 单例模式
if (!this._instance) {
this._instance = new EventEmitter();
}
return this._instance;
}
constructor() {
if (this._events === undefined) {
this._events = Object.create(null);
}
}
_addListener(type, fn, context, once) {
if (typeof fn !== 'function') {
throw new TypeError('fn must be a function');
}
fn.context = context;
fn.once = !!once;
const event = this._events[type];
// only one, let `this._events[type]` to be a function
if (isNullOrUndefined(event)) {
this._events[type] = fn;
}
else if (typeof event === 'function') {
// already has one function, `this._events[type]` must be a function before
this._events[type] = [event, fn];
}
else if (isArray(event)) {
// already has more than one function, just push
this._events[type].push(fn);
}
return this;
}
addListener(type, fn, context) {
return this._addListener(type, fn, context);
}
on(type, fn, context) {
return this.addListener(type, fn, context);
}
once(type, fn, context) {
return this._addListener(type, fn, context, true);
}
emit(type, ...rest) {
if (isNullOrUndefined(type)) {
throw new Error('emit must receive at lease one argument');
}
const event = this._events[type];
if (isNullOrUndefined(event))
return false;
if (typeof event === 'function') {
event.call(event.context || null, ...rest);
if (event.once) {
this.removeListener(type, event);
}
}
else if (isArray(event)) {
event.map((e) => {
e.call(e.context || null, ...rest);
if (e.once) {
this.removeListener(type, e);
}
});
}
return true;
}
removeListener(type, fn) {
if (isNullOrUndefined(this._events))
return this;
// if type is undefined or null, nothing to do, just return this
if (isNullOrUndefined(type))
return this;
if (typeof fn !== 'function') {
throw new Error('fn must be a function');
}
const events = this._events[type];
if (typeof events === 'function') {
events === fn && delete this._events[type];
}
else {
const findIndex = events.findIndex((e) => e === fn);
if (findIndex === -1)
return this;
// match the first one, shift faster than splice
if (findIndex === 0) {
events.shift();
}
else {
events.splice(findIndex, 1);
}
// just left one listener, change Array to Function
if (events.length === 1) {
// @ts-ignore
this._events[type] = events[0];
}
}
return this;
}
removeAllListeners(type) {
if (isNullOrUndefined(this._events))
return this;
// if not provide type, remove all
if (isNullOrUndefined(type))
this._events = Object.create(null);
const events = this._events[type];
if (!isNullOrUndefined(events)) {
// check if `type` is the last one
if (Object.keys(this._events).length === 1) {
this._events = Object.create(null);
}
else {
delete this._events[type];
}
}
return this;
}
listeners(type) {
if (isNullOrUndefined(this._events))
return [];
const events = this._events[type];
// use `map` because we need to return a new array
return isNullOrUndefined(events) ? [] : typeof events === 'function' ? [events] : events.map((o) => o);
}
listenerCount(type) {
if (isNullOrUndefined(this._events))
return 0;
const events = this._events[type];
return isNullOrUndefined(events) ? 0 : typeof events === 'function' ? 1 : events.length;
}
eventNames() {
if (isNullOrUndefined(this._events))
return [];
return Object.keys(this._events);
}
}
export default { EventEmitter, instance: EventEmitter.instance() };

View File

@ -0,0 +1,163 @@
import { getRawType, notNull } from './tools'
const isArray = (obj) => getRawType(obj) === 'array'
const isNullOrUndefined = (obj) => !notNull(obj)
class EventEmitter {
private _events: { [key: string]: Function[] } = {}
private static _instance: null | EventEmitter = null
static instance(): EventEmitter {
// 单例模式
if (!this._instance) {
this._instance = new EventEmitter()
}
return this._instance
}
constructor() {
if (this._events === undefined) {
this._events = Object.create(null)
}
}
private _addListener(type: string, fn: any, context?: any, once?) {
if (typeof fn !== 'function') {
throw new TypeError('fn must be a function')
}
fn.context = context
fn.once = !!once
const event = this._events[type]
// only one, let `this._events[type]` to be a function
if (isNullOrUndefined(event)) {
this._events[type] = fn
} else if (typeof event === 'function') {
// already has one function, `this._events[type]` must be a function before
this._events[type] = [event, fn]
} else if (isArray(event)) {
// already has more than one function, just push
this._events[type].push(fn)
}
return this
}
addListener(type: string, fn: any, context?: any) {
return this._addListener(type, fn, context)
}
on(type: string, fn: any, context?: any) {
return this.addListener(type, fn, context)
}
once(type: string, fn: any, context?: any) {
return this._addListener(type, fn, context, true)
}
emit(type, ...rest) {
if (isNullOrUndefined(type)) {
throw new Error('emit must receive at lease one argument')
}
const event: any = this._events[type]
if (isNullOrUndefined(event)) return false
if (typeof event === 'function') {
event.call(event.context || null, ...rest)
if (event.once) {
this.removeListener(type, event)
}
} else if (isArray(event)) {
event.map((e) => {
e.call(e.context || null, ...rest)
if (e.once) {
this.removeListener(type, e)
}
})
}
return true
}
removeListener(type, fn) {
if (isNullOrUndefined(this._events)) return this
// if type is undefined or null, nothing to do, just return this
if (isNullOrUndefined(type)) return this
if (typeof fn !== 'function') {
throw new Error('fn must be a function')
}
const events = this._events[type]
if (typeof events === 'function') {
events === fn && delete this._events[type]
} else {
const findIndex = events.findIndex((e) => e === fn)
if (findIndex === -1) return this
// match the first one, shift faster than splice
if (findIndex === 0) {
events.shift()
} else {
events.splice(findIndex, 1)
}
// just left one listener, change Array to Function
if (events.length === 1) {
// @ts-ignore
this._events[type] = events[0]
}
}
return this
}
removeAllListeners(type) {
if (isNullOrUndefined(this._events)) return this
// if not provide type, remove all
if (isNullOrUndefined(type)) this._events = Object.create(null)
const events = this._events[type]
if (!isNullOrUndefined(events)) {
// check if `type` is the last one
if (Object.keys(this._events).length === 1) {
this._events = Object.create(null)
} else {
delete this._events[type]
}
}
return this
}
listeners(type) {
if (isNullOrUndefined(this._events)) return []
const events = this._events[type]
// use `map` because we need to return a new array
return isNullOrUndefined(events) ? [] : typeof events === 'function' ? [events] : events.map((o) => o)
}
listenerCount(type) {
if (isNullOrUndefined(this._events)) return 0
const events = this._events[type]
return isNullOrUndefined(events) ? 0 : typeof events === 'function' ? 1 : events.length
}
eventNames() {
if (isNullOrUndefined(this._events)) return []
return Object.keys(this._events)
}
}
export default { EventEmitter, instance: EventEmitter.instance() }

View File

@ -0,0 +1,2 @@
declare const _default: (key: string, name: string, type?: string | undefined) => string;
export default _default;

View File

@ -0,0 +1,25 @@
export default (key, name, type) => {
if (!type)
type = 'camunda';
const TYPE_TARGET = {
activiti: 'http://activiti.org/bpmn',
camunda: 'http://bpmn.io/schema/bpmn',
flowable: 'http://flowable.org/bpmn'
};
return `<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
id="diagram_${key}"
targetNamespace="${TYPE_TARGET[type]}">
<bpmn2:process id="${key}" name="${name}" isExecutable="true">
</bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="${key}">
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>`;
};

View File

@ -0,0 +1,24 @@
export default (key: string, name: string, type?: string): string => {
if (!type) type = 'camunda'
const TYPE_TARGET = {
activiti: 'http://activiti.org/bpmn',
camunda: 'http://bpmn.io/schema/bpmn',
flowable: 'http://flowable.org/bpmn'
}
return `<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
id="diagram_${key}"
targetNamespace="${TYPE_TARGET[type]}">
<bpmn2:process id="${key}" name="${name}" isExecutable="true">
</bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="${key}">
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>`
}

View File

@ -0,0 +1,7 @@
declare function setLocal(key: string, value: any): void;
declare function getLocal(key: string): any;
declare const _default: {
setLocal: typeof setLocal;
getLocal: typeof getLocal;
};
export default _default;

View File

@ -0,0 +1,10 @@
function setLocal(key, value) {
localStorage.setItem(key, JSON.stringify(value));
}
function getLocal(key) {
return JSON.parse(localStorage.getItem(key) || '');
}
export default {
setLocal,
getLocal
};

View File

@ -0,0 +1,12 @@
function setLocal(key: string, value: any) {
localStorage.setItem(key, JSON.stringify(value))
}
function getLocal(key: string) {
return JSON.parse(localStorage.getItem(key) || '')
}
export default {
setLocal,
getLocal
}

View File

@ -0,0 +1,14 @@
export declare function noop(): void;
/**
*
* @param {*} val
* @return boolean
*/
export declare function notEmpty(val: any): any;
export declare function notNull(val: any): boolean;
/**
*
* @param value
* @return { 'string' | 'array' | 'boolean' | 'number' | 'object' | 'function' } type
*/
export declare function getRawType(value: any): string;

View File

@ -0,0 +1,30 @@
/* 空函数 */
export function noop() { }
/**
* 校验非空
* @param {*} val
* @return boolean
*/
export function notEmpty(val) {
if (!notNull(val)) {
return false;
}
if (getRawType(val) === 'array') {
return val.length;
}
if (getRawType(val) === 'object') {
return Reflect.ownKeys(val).length;
}
return true;
}
export function notNull(val) {
return val !== undefined && val !== null;
}
/**
* 返回数据原始类型
* @param value
* @return { 'string' | 'array' | 'boolean' | 'number' | 'object' | 'function' } type
*/
export function getRawType(value) {
return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}

View File

@ -0,0 +1,32 @@
/* 空函数 */
export function noop() {}
/**
*
* @param {*} val
* @return boolean
*/
export function notEmpty(val) {
if (!notNull(val)) {
return false
}
if (getRawType(val) === 'array') {
return val.length
}
if (getRawType(val) === 'object') {
return Reflect.ownKeys(val).length
}
return true
}
export function notNull(val) {
return val !== undefined && val !== null
}
/**
*
* @param value
* @return { 'string' | 'array' | 'boolean' | 'number' | 'object' | 'function' } type
*/
export function getRawType(value) {
return Object.prototype.toString.call(value).slice(8, -1).toLowerCase()
}

View File

@ -3,7 +3,6 @@
* @Date: 2024-01-25 10:05:50
* @LastEditors: Do not edit
* @LastEditTime: 2024-01-26 09:52:37
* @FilePath: \费县天空地大屏正式代码e:\新架构\vue-vben-admin\src\components\PermissionBtn\index.vue
* @Description:
-->
<template>
@ -18,7 +17,6 @@
import { router } from '@/router';
import { defineEmits } from 'vue'
const btnList = router.currentRoute.value.meta.elements ?router.currentRoute.value.meta.elements :[]
console.log(btnList)
btnList.sort((a, b) => {
return (a.sort || 0) - (b.sort || 0);
});

View File

@ -0,0 +1,114 @@
<template>
<div class="process-design" :style="'display: flex; height:' + data.height">
<bpmn-process-designer v-model="data.xmlString" v-bind="data.controlForm" keyboard ref="processDesigner" :events="[
'element.click',
'connection.added',
'connection.removed',
'connection.changed'
]" @element-click="elementClick" @init-finished="initModeler" @event="handlerEvent" @save="onSaveProcess" />
<!-- 属性面板 -->
<bmpn-process-penal :element="data.element" :bpmn-modeler="data.modeler" :prefix="data.controlForm.prefix" class="process-panel" />
</div>
</template>
<script lang="ts" setup>
import { h, reactive, onMounted, defineProps, computed, defineEmits } from 'vue';
import './package/theme/index.scss';
//
import { BpmnProcessDesigner, BmpnProcessPenal } from './package/index';
import 'highlight.js/styles/atom-one-dark-reasonable.css';
const emit = defineEmits(['save']);
// Vue.use(vuePlugin);
const props = defineProps({
bpmnXml: {
type: String,
required: true
},
designerForm: {
type: Object,
required: true
}
})
const data = reactive({
height: document.documentElement.clientHeight - 94.5 + "px;",
xmlString: props.bpmnXml,
modeler: null,
controlForm: {
processId: props.designerForm.processKey || '',
processName: props.designerForm.processName || '',
simulation: false,
labelEditing: false,
labelVisible: false,
prefix: 'flowable',
headerButtonSize: 'small',
// additionalModel: [CustomContentPadProvider, CustomPaletteProvider]
},
element:null,
})
function elementClick(element) {
data.element = element;
}
function initModeler(modeler) {
setTimeout(() => {
data.modeler = modeler;
}, 10);
}
function handlerEvent(eventName, element) {
}
function onSaveProcess(saveData) {
emit('save', saveData);
}
</script>
<style lang="scss" scoped>
body {
overflow: auto !important;
margin: 0;
box-sizing: border-box;
}
body,
body * {
/* 滚动条 */
&::-webkit-scrollbar-track-piece {
background-color: #fff;
/*滚动条的背景颜色*/
-webkit-border-radius: 0;
/*滚动条的圆角宽度*/
}
&::-webkit-scrollbar {
width: 10px;
/*滚动条的宽度*/
height: 8px;
/*滚动条的高度*/
}
&::-webkit-scrollbar-thumb:vertical {
/*垂直滚动条的样式*/
height: 50px;
background-color: rgba(153, 153, 153, 0.5);
-webkit-border-radius: 4px;
outline: 2px solid #fff;
outline-offset: -2px;
border: 2px solid #fff;
}
&::-webkit-scrollbar-thumb {
/*滚动条的hover样式*/
background-color: rgba(159, 159, 159, 0.3);
-webkit-border-radius: 4px;
}
&::-webkit-scrollbar-thumb:hover {
/*滚动条的hover样式*/
background-color: rgba(159, 159, 159, 0.5);
-webkit-border-radius: 4px;
}
}
.process-panel{
height: 100%;
}
</style>

View File

@ -0,0 +1,340 @@
<template>
<div class="my-process-designer">
<div class="my-process-designer__header">
<slot name="control-header"></slot>
<template v-if="!$slots['control-header']">
<div slot="content">
<a-button :type="headerButtonType" :icon="h(SaveOutlined)" @click="onSave" class="ml-2">保存流程
</a-button>
<a-button :type="headerButtonType" @click="previewProcessXML" class="ml-2">预览XML</a-button>
<a-button :type="headerButtonType" @click="previewProcessJson" class="ml-2">预览JSON</a-button>
<a-space>
<a-tooltip placement="bottom" class="ml-2" title="缩小视图">
<a-button :disabled="defaultZoom <= 0.3" :icon="h(ZoomOutOutlined)" @click="processZoomOut()"></a-button>
</a-tooltip>
<a-button>{{ Math.floor(process.defaultZoom * 10 * 10) + "%" }}</a-button>
<a-tooltip placement="bottom" title="放大视图">
<a-button :disabled="defaultZoom >= 3.9" :icon="h(ZoomInOutlined)" @click="processZoomIn()"></a-button>
</a-tooltip>
<a-tooltip placement="bottom" title="撤销" class="ml-2">
<a-button :icon="h(RotateLeftOutlined)" @click="processUndo()"></a-button>
</a-tooltip>
<a-tooltip placement="bottom" title="恢复">
<a-button :icon="h(RotateRightOutlined)" @click="processRedo()"></a-button>
</a-tooltip>
<a-tooltip placement="bottom" title="重新绘制">
<a-button :icon="h(ClearOutlined)" @click="processRestart()"></a-button>
</a-tooltip>
</a-space>
</div>
</template>
<div>
</div>
</div>
<div class="my-process-designer__container">
<div class="my-process-designer__canvas" ref="bpmn-canvas" id="bpmn-canvas"></div>
</div>
<a-modal v-model:open="process.previewModelVisible" width="60%" title="预览">
<highlightjs :language="process.previewType" :code="process.previewResult" style="height: 60vh" />
</a-modal>
</div>
</template>
<script lang="ts" setup>
import { h,provide, reactive, onMounted, defineProps, computed, defineEmits } from 'vue';
import { SaveOutlined, ZoomOutOutlined, ZoomInOutlined, RotateLeftOutlined, RotateRightOutlined, ClearOutlined } from '@ant-design/icons-vue';
//
import BpmnModeler from "bpmn-js/lib/Modeler";
import DefaultEmptyXML from "./plugins/defaultEmpty.ts";
// ()
import customTranslate from "./plugins/translate/customTranslate.ts";
import MoveModule from 'diagram-js/lib/features/move'
import ModelingModule from 'bpmn-js/lib/features/modeling'
import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas'
const emit = defineEmits(['init-finished', 'event', 'commandStack-changed', 'input', 'change', 'canvas-viewbox-changed', 'destroy', 'save', 'element-click', 'connection-added', 'connection-removed', 'connection-changed']);
// json
import convert from "xml-js";
const process = reactive({
defaultZoom: 1,
previewModelVisible: false,
simulationStatus: false,
previewResult: "",
previewType: "xml",
recoverable: false,
revocable: false,
bpmnModeler: null
})
const props = defineProps({
value: String, // xml
processId: String,
processName: String,
translations: Object, //
additionalModel: [Object, Array], // model
moddleExtension: Object, // moddle
onlyCustomizeAddi: {
type: Boolean,
default: false
},
onlyCustomizeModdle: {
type: Boolean,
default: false
},
simulation: {
type: Boolean,
default: true
},
keyboard: {
type: Boolean,
default: true
},
prefix: {
type: String,
default: "flowable"
},
events: {
type: Array,
default: () => ["element.click"]
},
headerButtonSize: {
type: String,
default: "small",
validator: value => ["default", "medium", "small", "mini"].indexOf(value) !== -1
},
headerButtonType: {
type: String,
default: "primary",
validator: value => ["default", "primary", "success", "warning", "danger", "info"].indexOf(value) !== -1
}
})
onMounted(() => {
initBpmnModeler();
console.log(props.value)
createNewDiagram(props.value);
})
function onSave() {
return new Promise((resolve, reject) => {
console.log(process.bpmnModeler)
if (process.bpmnModeler == null) {
reject();
}
process.bpmnModeler.saveXML({ format: true }).then(({ xml }) => {
emit('save', xml);
resolve(xml);
});
})
}
function initBpmnModeler() {
if (process.bpmnModeler) return;
const containerEl = document.querySelector('#bpmn-canvas');
process.bpmnModeler = new BpmnModeler({
container: '#bpmn-canvas',
additionalModules: [
{
translate: ['value', customTranslate]
},
],
});
console.log(process.bpmnModeler)
emit("init-finished", process.bpmnModeler);
initModelListeners();
}
function initModelListeners() {
const EventBus = process.bpmnModeler.get("eventBus");
const that = this;
// , . - ,
props.events.forEach(event => {
EventBus.on(event, function (eventObj) {
console.log(eventObj)
provide('wfdesign',eventObj)
let eventName = event.replace(/\./g, "-");
let element = eventObj ? eventObj.element : null;
emit(eventName, element, eventObj);
emit('event', eventName, element, eventObj);
});
});
// xml
EventBus.on("commandStack.changed", async event => {
try {
process.recoverable = process.bpmnModeler.get("commandStack").canRedo();
process.revocable = process.bpmnModeler.get("commandStack").canUndo();
let { xml } = await process.bpmnModeler.saveXML({ format: true });
emit("commandStack-changed", event);
emit("input", xml);
emit("change", xml);
} catch (e) {
console.error(`[Process Designer Warn]: ${e.message || e}`);
}
});
//
process.bpmnModeler.on("canvas.viewbox.changed", ({ viewbox }) => {
emit("canvas-viewbox-changed", { viewbox });
const { scale } = viewbox;
process.defaultZoom = Math.floor(scale * 100) / 100;
});
}
/* 创建新的流程图 */
async function createNewDiagram(xml) {
//
let newId = props.processId || `Process_${new Date().getTime()}`;
let newName = props.processName || `业务流程_${new Date().getTime()}`;
let xmlString = xml || DefaultEmptyXML(newId, newName, props.prefix);
try {
let { warnings } = await process.bpmnModeler.importXML(xmlString);
if (warnings && warnings.length) {
warnings.forEach(warn => console.warn(warn));
}
} catch (e) {
console.error(`[Process Designer Warn]: ${e.message || e}`);
}
}
//
async function downloadProcess(type, name) {
try {
const _this = this;
//
if (type === "xml" || type === "bpmn") {
const { err, xml } = await process.bpmnModeler.saveXML();
//
if (err) {
console.error(`[Process Designer Warn ]: ${err.message || err}`);
}
let { href, filename } = setEncoded(type.toUpperCase(), name, xml);
downloadFunc(href, filename);
} else {
const { err, svg } = await process.bpmnModeler.saveSVG();
//
if (err) {
return console.error(err);
}
let { href, filename } = setEncoded("SVG", name, svg);
downloadFunc(href, filename);
}
} catch (e) {
console.error(`[Process Designer Warn ]: ${e.message || e}`);
}
//
function downloadFunc(href, filename) {
if (href && filename) {
let a = document.createElement("a");
a.download = filename; //
a.href = href; // URL
a.click(); //
URL.revokeObjectURL(a.href); // URL
}
}
}
//
function setEncoded(type, filename = "diagram", data) {
const encodedData = encodeURIComponent(data);
return {
filename: `${filename}.${type}`,
href: `data:application/${type === "svg" ? "text/xml" : "bpmn20-xml"};charset=UTF-8,${encodedData}`,
data: data
};
}
//
function importLocalFile() {
const that = this;
const file = this.$refs.refFile.files[0];
const reader = new FileReader();
reader.readAsText(file);
reader.onload = function () {
let xmlStr = this.result;
createNewDiagram(xmlStr);
};
}
/* ------------------------------------------------ refs methods ------------------------------------------------------ */
function downloadProcessAsXml() {
downloadProcess("xml");
}
function downloadProcessAsBpmn() {
downloadProcess("bpmn");
}
function downloadProcessAsSvg() {
downloadProcess("svg");
}
function processSimulation() {
process.simulationStatus = !process.simulationStatus;
props.simulation && process.bpmnModeler.get("toggleMode").toggleMode();
}
function processRedo() {
process.bpmnModeler.get("commandStack").redo();
}
function processUndo() {
process.bpmnModeler.get("commandStack").undo();
}
function processZoomIn(zoomStep = 0.1) {
let newZoom = Math.floor(process.defaultZoom * 100 + zoomStep * 100) / 100;
if (newZoom > 4) {
throw new Error("[Process Designer Warn ]: The zoom ratio cannot be greater than 4");
}
process.defaultZoom = newZoom;
process.bpmnModeler.get("canvas").zoom(process.defaultZoom);
}
function processZoomOut(zoomStep = 0.1) {
let newZoom = Math.floor(process.defaultZoom * 100 - zoomStep * 100) / 100;
if (newZoom < 0.2) {
throw new Error("[Process Designer Warn ]: The zoom ratio cannot be less than 0.2");
}
process.defaultZoom = newZoom;
process.bpmnModeler.get("canvas").zoom(process.defaultZoom);
}
function processZoomTo(newZoom = 1) {
if (newZoom < 0.2) {
throw new Error("[Process Designer Warn ]: The zoom ratio cannot be less than 0.2");
}
if (newZoom > 4) {
throw new Error("[Process Designer Warn ]: The zoom ratio cannot be greater than 4");
}
process.defaultZoom = newZoom;
process.bpmnModeler.get("canvas").zoom(newZoom);
}
function processReZoom() {
process.defaultZoom = 1;
process.bpmnModeler.get("canvas").zoom("fit-viewport", "auto");
}
function processRestart() {
process.recoverable = false;
process.revocable = false;
createNewDiagram(null).then(() => process.bpmnModeler.get("canvas").zoom(1, "auto"));
}
function elementsAlign(align) {
const Align = process.bpmnModeler.get("alignElements");
const Selection = process.bpmnModeler.get("selection");
const SelectedElements = Selection.get();
if (!SelectedElements || SelectedElements.length <= 1) {
this.$message.warning("请按住 Ctrl 键选择多个元素对齐");
return;
}
this.$confirm("自动对齐可能造成图形变形,是否继续?", "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => Align.trigger(SelectedElements, align));
}
/*----------------------------- 方法结束 ---------------------------------*/
function previewProcessXML() {
process.bpmnModeler.saveXML({ format: true }).then(({ xml }) => {
process.previewResult = xml;
process.previewType = "xml";
process.previewModelVisible = true;
});
}
function previewProcessJson() {
process.bpmnModeler.saveXML({ format: true }).then(({ xml }) => {
console.log(convert.xml2json(xml, { spaces: 2 }))
process.previewResult = convert.xml2json(xml, { spaces: 2 });
process.previewType = "json";
process.previewModelVisible = true;
});
}
</script>

View File

@ -0,0 +1,7 @@
import BpmnProcessDesigner from "./ProcessDesigner.vue";
BpmnProcessDesigner.install = function(Vue) {
Vue.component(BpmnProcessDesigner.name, BpmnProcessDesigner);
};
export default BpmnProcessDesigner;

View File

@ -0,0 +1,27 @@
export default (key, name, type) => {
if (!type) type = "camunda";
const TYPE_TARGET = {
activiti: "http://activiti.org/bpmn",
camunda: "http://bpmn.io/schema/bpmn",
flowable: "http://flowable.org/bpmn"
};
return `
<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd"
id="diagram_${key}"
targetNamespace="${TYPE_TARGET[type]}">
<bpmn2:process id="${key}" name="${name}" isExecutable="true">
</bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="${key}">
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>
`;
};

View File

@ -0,0 +1,9 @@
import translations from './zh.ts'
export default function customTranslate(template, replacements) {
replacements = replacements || {}
template = translations[template] || template
return template.replace(/{([^}]+)}/g, function (_, key) {
return replacements[key] || '{' + key + '}'
})
}

View File

@ -0,0 +1,252 @@
export default {
"Activate hand tool": "激活抓手工具",
"Activate lasso tool": "激活套索工具",
"Activate create/remove space tool": "激活创建/删除空间工具",
"Activate global connect tool": "激活全局连接工具",
"Create start event": "创建开始事件",
"Create end event": "创建结束事件",
"Create task": "创建任务",
"Create user task": "创建用户任务",
"Create gateway": "创建网关",
"Create data object reference": "创建数据对象",
"Create data store reference": "创建数据存储",
"Create group": "创建分组",
"Create intermediate/boundary event": "创建中间/边界事件",
"Create expanded sub-process": "创建扩展子过程",
"Create pool/participant": "创建池/参与者",
"Change element": "修改类型",
"Delete": "移除",
"Append end event": "追加结束事件",
"Append gateway": "追加网关",
"Append task": "追加任务",
"Append intermediate/boundary event": "追加中间抛出事件/边界事件",
"Add text annotation": "添加 text annotation",
"Connect using association": "使用关联连接",
"Connect to other element": "消息关联",
"Start event": "开始事件",
"End event": "结束事件",
"Message intermediate catch event": "消息中间捕获事件",
"Message intermediate throw event": "消息中间抛出事件",
"Timer intermediate catch event": "定时中间捕获事件",
"Escalation intermediate throw event": "升级中间抛出事件",
"Conditional intermediate catch event": "条件中间捕获事件",
"Link intermediate catch event": "链接中间捕获事件",
"Link intermediate throw event": "链接中间抛出事件",
"Compensation intermediate throw event": "补偿中间抛出事件",
"Signal intermediate catch event": "信号中间捕获事件",
"Signal intermediate throw event": "信号中间抛出事件",
"User task": "用户任务",
"Service task": "服务任务",
"Send task": "发送任务",
"Receive task": "、接收任务",
"Manual task": "手动任务",
"Business rule task": "业务规则任务",
"Script task": "脚本任务",
"Call activity": "调用活动",
"Sub-process (collapsed)": "子流程(已折叠)",
"Sub-process (expanded)": "子流程(扩大)",
"Intermediate throw event": "中间抛出事件",
"Message start event": "消息开始事件",
"Timer start event": "定时开始事件",
"Conditional start event": "条件开始事件",
"Signal start event": "信号开始事件",
"Parallel gateway":"并行网关",
"Inclusive gateway":"包容网关",
"Complex gateway":"复杂网关",
"Event-based gateway":"事件网关",
"Message end event":"消息结束事件",
"Escalation end event":"升级结束事件",
"Error end event":"错误结束事件",
"Compensation end event":"补偿结束事件",
"Signal end event":"信号结束事件",
"Terminate end event":"终止结束事件",
"Process": "业务流程",
"Append EndEvent": "追加结束事件",
"Append Gateway": "追加网关",
"Append Task": "追加任务",
"Append Intermediate/Boundary Event": "追加中间抛出事件/边界事件",
"Activate the global connect tool": "激活全局连接工具",
"Append {type}": "添加 {type}",
"Add Lane above": "在上面添加道",
"Divide into two Lanes": "分割成两个道",
"Divide into three Lanes": "分割成三个道",
"Add Lane below": "在下面添加道",
"Append compensation activity": "追加补偿活动",
"Change type": "修改类型",
"Connect using Association": "使用关联连接",
"Connect using Sequence/MessageFlow or Association": "使用顺序/消息流或者关联连接",
"Connect using DataInputAssociation": "使用数据输入关联连接",
"Remove": "移除",
"Activate the hand tool": "激活抓手工具",
"Activate the lasso tool": "激活套索工具",
"Activate the create/remove space tool": "激活创建/删除空间工具",
"Create expanded SubProcess": "创建扩展子过程",
"Create IntermediateThrowEvent/BoundaryEvent": "创建中间抛出事件/边界事件",
"Create Pool/Participant": "创建池/参与者",
"Parallel Multi Instance": "并行多重事件",
"Sequential Multi Instance": "时序多重事件",
"DataObjectReference": "数据对象参考",
"DataStoreReference": "数据存储参考",
"Loop": "循环",
"Ad-hoc": "即席",
"Create {type}": "创建 {type}",
"Create StartEvent": "创建开始事件",
"Create EndEvent": "创建结束事件",
"Create Task": "创建任务",
"Create User Task": "创建用户任务",
"Create Gateway": "创建网关",
"Create DataObjectReference": "创建数据对象",
"Create DataStoreReference": "创建数据存储",
"Create Group": "创建分组",
"Create Intermediate/Boundary Event": "创建中间/边界事件",
"Message Start Event": "消息开始事件",
"Timer Start Event": "定时开始事件",
"Conditional Start Event": "条件开始事件",
"Signal Start Event": "信号开始事件",
"Error Start Event": "错误开始事件",
"Escalation Start Event": "升级开始事件",
"Compensation Start Event": "补偿开始事件",
"Message Start Event (non-interrupting)": "消息开始事件(非中断)",
"Timer Start Event (non-interrupting)": "定时开始事件(非中断)",
"Conditional Start Event (non-interrupting)": "条件开始事件(非中断)",
"Signal Start Event (non-interrupting)": "信号开始事件(非中断)",
"Escalation Start Event (non-interrupting)": "升级开始事件(非中断)",
"Message Intermediate Catch Event": "消息中间捕获事件",
"Message Intermediate Throw Event": "消息中间抛出事件",
"Timer Intermediate Catch Event": "定时中间捕获事件",
"Escalation Intermediate Throw Event": "升级中间抛出事件",
"Conditional Intermediate Catch Event": "条件中间捕获事件",
"Link Intermediate Catch Event": "链接中间捕获事件",
"Link Intermediate Throw Event": "链接中间抛出事件",
"Compensation Intermediate Throw Event": "补偿中间抛出事件",
"Signal Intermediate Catch Event": "信号中间捕获事件",
"Signal Intermediate Throw Event": "信号中间抛出事件",
"Collapsed Pool": "折叠池",
"Expanded Pool": "展开池",
"no parent for {element} in {parent}": "在{parent}里,{element}没有父类",
"no shape type specified": "没有指定的形状类型",
"flow elements must be children of pools/participants": "流元素必须是池/参与者的子类",
"out of bounds release": "out of bounds release",
"more than {count} child lanes": "子道大于{count} ",
"element required": "元素不能为空",
"diagram not part of bpmn:Definitions": "流程图不符合bpmn规范",
"no diagram to display": "没有可展示的流程图",
"no process or collaboration to display": "没有可展示的流程/协作",
"element {element} referenced by {referenced}#{property} not yet drawn":
"由{referenced}#{property}引用的{element}元素仍未绘制",
"already rendered {element}": "{element} 已被渲染",
"failed to import {element}": "导入{element}失败",
"Id": "编号",
"Name": "名称",
"General": "常规",
"Details": "详情",
"Message Name": "消息名称",
"Message": "消息",
"Initiator": "创建者",
"Asynchronous Continuations": "持续异步",
"Asynchronous Before": "异步前",
"Asynchronous After": "异步后",
"Job Configuration": "工作配置",
"Exclusive": "排除",
"Job Priority": "工作优先级",
"Retry Time Cycle": "重试时间周期",
"Documentation": "文档",
"Element Documentation": "元素文档",
"History Configuration": "历史配置",
"History Time To Live": "历史的生存时间",
"Forms": "表单",
"Form Key": "表单key",
"Form Fields": "表单字段",
"Business Key": "业务key",
"Form Field": "表单字段",
"ID": "编号",
"Type": "类型",
"Label": "名称",
"Default Value": "默认值",
"Default Flow": "默认流转路径",
"Conditional Flow": "条件流转路径",
"Sequence Flow": "普通流转路径",
"Validation": "校验",
"Add Constraint": "添加约束",
"Config": "配置",
"Properties": "属性",
"Add Property": "添加属性",
"Value": "值",
"Listeners": "监听器",
"Execution Listener": "执行监听",
"Event Type": "事件类型",
"Listener Type": "监听器类型",
"Java Class": "Java类",
"Expression": "表达式",
"Must provide a value": "必须提供一个值",
"Delegate Expression": "代理表达式",
"Script": "脚本",
"Script Format": "脚本格式",
"Script Type": "脚本类型",
"Inline Script": "内联脚本",
"External Script": "外部脚本",
"Resource": "资源",
"Field Injection": "字段注入",
"Extensions": "扩展",
"Input/Output": "输入/输出",
"Input Parameters": "输入参数",
"Output Parameters": "输出参数",
"Parameters": "参数",
"Output Parameter": "输出参数",
"Timer Definition Type": "定时器定义类型",
"Timer Definition": "定时器定义",
"Date": "日期",
"Duration": "持续",
"Cycle": "循环",
"Signal": "信号",
"Signal Name": "信号名称",
"Escalation": "升级",
"Error": "错误",
"Link Name": "链接名称",
"Condition": "条件名称",
"Variable Name": "变量名称",
"Variable Event": "变量事件",
"Specify more than one variable change event as a comma separated list.": "多个变量事件以逗号隔开",
"Wait for Completion": "等待完成",
"Activity Ref": "活动参考",
"Version Tag": "版本标签",
"Executable": "可执行文件",
"External Task Configuration": "扩展任务配置",
"Task Priority": "任务优先级",
"External": "外部",
"Connector": "连接器",
"Must configure Connector": "必须配置连接器",
"Connector Id": "连接器编号",
"Implementation": "实现方式",
"Field Injections": "字段注入",
"Fields": "字段",
"Result Variable": "结果变量",
"Topic": "主题",
"Configure Connector": "配置连接器",
"Input Parameter": "输入参数",
"Assignee": "代理人",
"Candidate Users": "候选用户",
"Candidate Groups": "候选组",
"Due Date": "到期时间",
"Follow Up Date": "跟踪日期",
"Priority": "优先级",
"The follow up date as an EL expression (e.g. ${someDate} or an ISO date (e.g. 2015-06-26T09:54:00)":
"跟踪日期必须符合EL表达式 ${someDate} ,或者一个ISO标准日期2015-06-26T09:54:00",
"The due date as an EL expression (e.g. ${someDate} or an ISO date (e.g. 2015-06-26T09:54:00)":
"跟踪日期必须符合EL表达式 ${someDate} ,或者一个ISO标准日期2015-06-26T09:54:00",
"Variables": "变量",
"Candidate Starter Configuration": "候选人起动器配置",
"Candidate Starter Groups": "候选人起动器组",
"This maps to the process definition key.": "这映射到流程定义键。",
"Candidate Starter Users": "候选人起动器的用户",
"Specify more than one user as a comma separated list.": "指定多个用户作为逗号分隔的列表。",
"Tasklist Configuration": "Tasklist配置",
"Startable": "启动",
"Specify more than one group as a comma separated list.": "指定多个组作为逗号分隔的列表。",
"Execution listeners": "执行监听器"
};

View File

@ -0,0 +1,12 @@
/*
* @Author:
* @Date: 2024-03-04 13:39:52
* @LastEditors: Do not edit
* @LastEditTime: 2024-03-05 16:07:51
* @Description:
*/
const hljs = require("highlight.js/lib/core");
hljs.registerLanguage("xml", require("highlight.js/lib/languages/xml"));
hljs.registerLanguage("json", require("highlight.js/lib/languages/json"));
export default hljs;

View File

@ -0,0 +1,7 @@
import BpmnProcessDesigner from "./designer/index.ts";
import BmpnProcessPenal from "./penal";
export {
BpmnProcessDesigner,
BmpnProcessPenal
}

View File

@ -0,0 +1,150 @@
<!--
* @Author: 刘妍
* @Date: 2024-03-05 17:09:44
* @LastEditors: Do not edit
* @LastEditTime: 2024-03-07 14:52:13
* @Description:
-->
<template>
<div :class="prefixCls" :style="{ width: `${props.width}px` }">
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="1" tab="流程属性">
<shcemeinfo-config ref="shcemeinfo" :disabled="true"></shcemeinfo-config>
</a-tab-pane>
<a-tab-pane key="2" tab="发起权限" force-render>
<auth-config ref="auth"></auth-config>
</a-tab-pane>
<a-tab-pane key="3" tab="开始节点">
<start-event-option ref="start" :element="data.elementData"></start-event-option>
</a-tab-pane>
<a-tab-pane key="4" tab="审核节点">
<user-task-option ref="task"></user-task-option>
</a-tab-pane>
</a-tabs>
<!-- <el-tabs v-model="configActiveName" :stretch="true">
<el-tab-pane :label="$t(wfNodeName[currentWfNode.type])" name="tab01" v-if="currentWfNode != undefined">
<component :disabled="true" ref="wfcongfig" :is="`${currentWfNode.type}Option`"></component>
</el-tab-pane>
<el-tab-pane label="流程属性" name="tab02">
<shcemeinfo-config ref="shcemeinfo" :disabled="true"></shcemeinfo-config>
</el-tab-pane>
</el-tabs> -->
<!-- <Tabs v-model:activeKey="configActiveName">
<Tabs.TabPane :label="$t(wfNodeName[currentWfNode.type])" name="tab01" v-if="currentWfNode != undefined">
<component :disabled="true" ref="wfcongfig" :is="`${currentWfNode.type}Option`"></component>
</Tabs.TabPane>
<Tabs.TabPane label="流程属性" name="tab02">
<shcemeinfo-config ref="shcemeinfo" :disabled="true"></shcemeinfo-config>
</Tabs.TabPane>
</Tabs> -->
</div>
</template>
<script lang="ts" setup>
import { h, reactive, onMounted, defineProps, computed, defineEmits, provide, watch, ref } from 'vue';
import { SaveOutlined, ZoomOutOutlined, ZoomInOutlined, RotateLeftOutlined, RotateRightOutlined, ClearOutlined } from '@ant-design/icons-vue';
import { Tabs } from 'ant-design-vue';
import { PageWrapper } from '@/components/Page';
import { useDesign } from '@/hooks/web/useDesign';
const { prefixCls } = useDesign('process-property');
//
import shcemeinfoConfig from './shcemeInfo/index.vue'
//
import authConfig from './auth/index.vue'
//
import startEventOption from './startEvent/index.vue'
//
import userTaskOption from './userTask/index.vue'
//
import endEventOption from './config/endEvent.vue'
import gatewayAndOption from './config/gatewayAnd.vue'
import gatewayInclusiveOption from './config/gatewayInclusive.vue'
import gatewayXorOption from './config/gatewayXor.vue'
import scriptTaskOption from './config/scriptTask.vue'
import subprocessOption from './config/subprocess.vue'
import mylineOption from './config/myline.vue'
/**
* 侧边栏
* @Author MiyueFE
* @Home https://github.com/miyuesc
* @Date 2021年3月31日18:57:51
*/
const props = defineProps({
bpmnModeler: Object,
prefix: {
type: String,
default: "camunda"
},
width: {
type: Number,
default: 520
},
idEditDisabled: {
type: Boolean,
default: false
},
element: Object
})
provide('prefix', props.prefix)
provide('width', props.width)
const activeKey = ref("4")
const data = reactive({
configActiveName: 'tab02',
currentWfNode: undefined,
wfNodeName: {
startEvent: '开始节点',
endEvent: '结束节点',
gatewayAnd: '并行网关',
gatewayInclusive: '包含网关',
gatewayXor: '排他网关',
scriptTask: '脚本节点',
userTask: '审核节点',
subprocess: '子流程',
myline: '线条'
},
elementData:{}
})
watch(
() => props.element,
(newVal, oldVal) => {
data.elementData = newVal
}
)
const achieveList = ref([
{
key: '1',
name: '文章',
component: 'startEventOption',
},
{
key: '2',
name: '应用',
component: 'startEventOption',
},
])
const tabs = {
startEventOption,
startEventOption,
};
</script>
<style lang="less" scoped>
@prefix-cls: ~'@{namespace}-process-property';
.@{prefix-cls} {
background-color: @component-background;
}
::v-deep .ant-tabs {
height: 100%;
width: 100%;
padding: 0 20px;
}
::v-deep .ant-tabs-content-holder {
overflow-y: auto;
}
</style>

View File

@ -0,0 +1,137 @@
<!--
* @Author: 刘妍
* @Date: 2024-03-05 17:09:44
* @LastEditors: Do not edit
* @LastEditTime: 2024-03-07 15:37:16
* @Description:
-->
<template>
<div class="auth-config">
<a-tabs v-model:activeKey="f_AuthType" type="card" size="small">
<a-tab-pane key="1" tab="所有成员">
<a-alert message="权限说明" description="所有人员指不限制流程模版的发起人员,表示每个人都能发起该流程模版。" type="info" show-icon />
</a-tab-pane>
<a-tab-pane key="2" tab="指定成员">
<a-space>
<a-radio-group>
<a-radio-button value="1" @click="handlePostClick"></a-radio-button>
<a-radio-button value="2" @click="handleRoleClick"></a-radio-button>
<a-radio-button value="3" @click="handleAccountClick"></a-radio-button>
</a-radio-group>
<a-button danger :size="size">清空</a-button>
</a-space>
<a-table size="small" :columns="columns" :data-source="dataSource" bordered :pagination="false">
<template #bodyCell="{ column, text, record }">
<template v-if="['name', 'type'].includes(column.dataIndex)">
<div>
{{ text }}
</div>
</template>
<template v-else-if="column.dataIndex === 'operation'">
<a-popconfirm v-if="dataSource.length" title="Sure to delete?"
@confirm="onDelete(record.key)">
<a>Delete</a>
</a-popconfirm>
</template>
</template>
</a-table>
</a-tab-pane>
</a-tabs>
<a-modal width="60%" v-model:open="data.postOpen" title="添加岗位" @ok="postHandleOk">
<SelectPos ref="posRef"></SelectPos>
</a-modal>
<a-modal width="60%" v-model:open="data.roleOpen" title="添加角色" @ok="roleHandleOk">
<SelectRole ref="roleRef"></SelectRole>
</a-modal>
<a-modal width="60%" v-model:open="data.accountOpen" title="添加角色" @ok="accountHandleOk">
<SelectAccount ref="accountRef"></SelectAccount>
</a-modal>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref, onMounted, nextTick, unref } from 'vue';
const f_AuthType = ref("1")
import { cloneDeep } from 'lodash-es';
import type { UnwrapRef } from 'vue';
import SelectPos from '@/components/SelectPos/index.vue';
import SelectRole from '@/components/SelectRole/index.vue';
import SelectAccount from '@/components/SelectAccount/index.vue';
const columns = [
{
title: '名称',
dataIndex: 'name',
},
{
title: '类型',
dataIndex: 'type',
},
{
title: '操作',
dataIndex: 'operation',
},
];
const dataSource = [
{
id: 0,
name: "王五",
type: "管理员",
},
{
id: 1,
name: "王五",
type: "管理员",
},
]
const data = reactive({
postOpen: false,
roleOpen: false,
accountOpen: false,
})
//
const posRef = ref < any > ()
function handlePostClick() {
data.postOpen = true;
}
function postHandleOk() {
console.log(roleRef.value.getRow())
}
//
const roleRef = ref < any > ()
function handleRoleClick() {
data.roleOpen = true;
}
function roleHandleOk() {
console.log(roleRef.value.getRow())
}
//
const accountRef = ref < any > ()
function handleAccountClick() {
data.accountOpen = true;
}
function accountHandleOk() {
console.log(accountRef.value.getRow())
}
</script>
<style lang="less" scoped>
.site-space-compact-wrapper {
width: 100%;
.ant-select {
width: 100%;
}
}
::v-deep .ant-tabs {
padding: 0 !important;
}
::v-deep .ant-table-content {
margin-top: 10px;
}
</style>

View File

@ -0,0 +1,145 @@
<template>
<div class="l-from-body" >
<el-form :model="formData" :rules="rules" size="mini" ref="form" label-width="120px" >
<el-col :span="24">
<el-form-item label="条件名称" prop="name">
<el-input v-model="formData.name" >
</el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="数据库" prop="dbCode">
<el-select v-model="formData.dbCode" placeholder="请选择">
<el-option-group
v-for="group in lr_dblinkTree"
:key="group.id"
:label="group.label">
<el-option
v-for="item in group.children"
:key="item.id"
:label="item.label"
:value="item.id">
</el-option>
</el-option-group>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="数据表" prop="table">
<l-codetable-select
@change="handleTableChange"
:dbCode="formData.dbCode"
v-model="formData.table"></l-codetable-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="关联流程字段" prop="rfield">
<l-select :options="formData.columns" valueKey="name" labelKey="coment" v-model="formData.rfield" >
</l-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="比较字段" prop="cfield">
<l-select :options="formData.columns" valueKey="name" labelKey="coment" v-model="formData.cfield" >
</l-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="比较类型" prop="compareType">
<l-select :options="options" v-model="formData.compareType" >
</l-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="数据值" prop="value">
<el-input v-model="formData.value" >
</el-input>
</el-form-item>
</el-col>
</el-form>
</div>
</template>
<script>
export default {
name:'condition-formula',
props:{
},
data(){
return {
formData:{
dbCode:'',
table:'',
columns:[],
rfield:'',
cfield:'',
compareType:'',
value:'',
name:''
},
rules: {
dbCode: [
{ required: true, message: '请选择数据库' }
],
table: [
{ required: true, message: '请选择数据表' }
],
rfield: [
{ required: true, message: '请选择关联字段' }
],
cfield: [
{ required: true, message: '请选择比较字段' }
],
compareType: [
{ required: true, message: '请选择比较类型' }
],
value: [
{ required: true, message: '请填写值' }
],
name: [
{ required: true, message: '请填写条件名称' }
]
},
options:[
{ value: '1', label: '等于' },
{ value: '2', label: '不等于' },
{ value: '3', label: '大于' },
{ value: '4', label: '大于等于' },
{ value: '5', label: '小于' },
{ value: '6', label: '小于等于' },
{ value: '7', label: '包含' },
{ value: '8', label: '不包含' },
{ value: '9', label: '包含于' },
{ value: '10', label: '不包含于' }]
};
},
computed:{
},
created () {
},
methods:{
handleTableChange(table){
this.formData.columns = table.columns;
console.log(table);
},
resetForm(){
this.formData.columns = [];
this.$refs.form && this.$refs.form.resetFields();
},
//
validateForm(callback){
this.$refs.form.validate((valid) => {
if(valid){
callback();
}
});
},
setForm(data){
this.formData = this.$deepClone(data);
},
getForm(){
let formData = this.$deepClone(this.formData);
return formData;
}
}
}
</script>

View File

@ -0,0 +1,98 @@
<template>
<div class="l-from-body" >
<el-form :model="formData" :rules="rules" size="mini" ref="form" label-width="120px" >
<el-col :span="24">
<el-form-item label="条件名称" prop="name">
<el-input v-model="formData.name" >
</el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="数据库" prop="dbCode">
<el-select v-model="formData.dbCode" placeholder="请选择">
<el-option-group
v-for="group in lr_dblinkTree"
:key="group.id"
:label="group.label">
<el-option
v-for="item in group.children"
:key="item.id"
:label="item.label"
:value="item.id">
</el-option>
</el-option-group>
</el-select>
</el-form-item>
</el-col>
<div style="padding:0 0 16px 120px;">
<el-alert
title="sql语句说明"
type="warning"
description="请在开发人员指导下进行配置SQL语句{processId}流程发起实例主键{userId}流程发起用户Id{userAccount}流程发起用户账号{companyId}流程发起用户公司{departmentId}流程发起用户部门)!"
show-icon
:closable="false"
>
</el-alert>
</div>
<el-col :span="24">
<el-form-item label="SQL语句" prop="sql">
<el-input v-model="formData.sql" type="textarea"
:autosize="{ minRows: 8}" >
</el-input>
</el-form-item>
</el-col>
</el-form>
</div>
</template>
<script>
export default {
name:'condition-sql',
props:{
},
data(){
return {
formData:{
dbCode:'',
sql:'',
name:''
},
rules: {
dbCode: [
{ required: true, message: '请选择数据库' }
],
sql: [
{ required: true, message: '请填写sql语句' }
],
name: [
{ required: true, message: '请填写条件名称' }
]
},
};
},
computed:{
},
created () {
},
methods:{
resetForm(){
this.$refs.form && this.$refs.form.resetFields();
},
//
validateForm(callback){
this.$refs.form.validate((valid) => {
if(valid){
callback();
}
});
},
setForm(data){
this.formData = this.$deepClone(data);
},
getForm(){
let formData = this.$deepClone(this.formData);
return formData;
}
}
}
</script>

View File

@ -0,0 +1,32 @@
<!-- 开始节点配置 -->
<template>
<el-form
class="l-form-config"
label-width="88px"
label-position="left"
size="mini"
>
<el-form-item label="节点标识">
<el-input v-model="node.id" readonly ></el-input>
</el-form-item>
</el-form>
</template>
<script>
export default {
name:'end-event-option',
data () {
return {
}
},
computed: {
node(){
return this.wfdesign.currentWfNode;
}
},
inject: ["wfdesign"]
}
</script>
<style>
</style>

View File

@ -0,0 +1,42 @@
<!-- 开始节点配置 -->
<template>
<el-form
class="l-form-config"
label-width="88px"
label-position="left"
size="mini"
>
<el-form-item label="节点标识">
<el-input v-model="node.id" readonly ></el-input>
</el-form-item>
<div style="padding:0 16px;">
<el-alert
title="并行网关说明"
type="info"
description="并行网关会等待所有分支汇入才往下执行,所有出口分支都会被执行"
show-icon
:closable="false"
>
</el-alert>
</div>
</el-form>
</template>
<script>
export default {
name:'gateway-and-option',
data () {
return {
}
},
computed: {
node(){
return this.wfdesign.currentWfNode;
}
},
inject: ["wfdesign"]
}
</script>
<style>
</style>

View File

@ -0,0 +1,211 @@
<template>
<l-layout :top="180" >
<template #top>
<el-form
class="l-form-config"
label-width="88px"
label-position="left"
size="mini"
>
<el-form-item label="节点标识">
<el-input v-model="node.id" readonly ></el-input>
</el-form-item>
<div style="padding:0 16px;">
<el-alert
title="包容网关说明"
type="info"
description="包容网关会等待所有分支汇入才往下执行出口分支能执行多条条件为true"
show-icon
:closable="false"
>
</el-alert>
</div>
</el-form>
</template>
<l-layout :top="40">
<template #top v-if="!disabled">
<div style="padding-left:8px;float:left;" >
<el-button-group>
<el-button size="mini" icon="el-icon-plus" @click="handleFormulaClick">{{$t('')}}</el-button>
<el-button size="mini" icon="el-icon-plus" @click="handleSQlClick">{{$t('sql')}}</el-button>
</el-button-group>
</div>
<div style="padding-right:8px;float:right;">
<el-button size="mini" type="danger" icon="el-icon-delete" @click="handleClearClick">{{$t('')}}</el-button>
</div>
</template>
<l-table :columns="columns" :dataSource="node.conditions" >
<template v-slot:type="scope" >
{{typeFormat(scope.row.type)}}
</template>
<l-table-btns v-if="!disabled" :btns="tableBtns" @click="handleTableBtnClick" ></l-table-btns>
</l-table>
</l-layout>
<l-dialog
:title="$t('添加公式条件')"
:visible.sync="formulaVisible"
:height="480"
@ok="handleFormulaOk"
@closed="handleFormulaClosed"
@opened="handleFormulaOpened"
>
<condition-formula ref="conditionFormula" ></condition-formula>
</l-dialog>
<l-dialog
:title="$t('添加sql条件')"
:visible.sync="sqlVisible"
:height="480"
@ok="handleSqlOk"
@closed="handleSqlClosed"
@opened="handleSqlOpened"
>
<condition-sql ref="conditionSql" ></condition-sql>
</l-dialog>
</l-layout>
</template>
<script>
import conditionFormula from './conditionFormula.vue'
import conditionSql from './conditionSql.vue'
export default {
name:'gateway-inclusive-option',
props:{
disabled:{
type:Boolean,
default:false
}
},
components: {
conditionFormula,
conditionSql
},
data () {
return {
tableBtns:[
{prop:'Edit',label:'编辑'},
{prop:'Delete',label:'删除'}
],
columns:[
{label:'类型',prop:'type',width:'80', align: 'center'},
{label:'名称',prop:'name',minWidth:'100'},
],
tableData:[],
formulaVisible:false,
sqlVisible:false,
editRow:null,
isEdit:false,
rowIndex:0,
}
},
computed: {
node(){
return this.wfdesign.currentWfNode;
}
},
inject: ["wfdesign"],
methods:{
typeFormat(type){
switch(type){
case '1':
return '表达式'
case '2':
return 'sql语句'
}
},
handleTableBtnClick(btn){
switch(btn.type){
case 'Edit':
this.isEdit = true;
this.editRow = btn.row;
this.rowIndex = btn.rowIndex;
if(this.editRow.type == '1'){
this.formulaVisible = true;
}
else{
this.sqlVisible = true;
}
break;
case 'Delete':
this.node.conditions.splice(btn.rowIndex,1);
break;
}
console.log(btn);
//this.tableData.splice(btn.rowIndex,1);
},
handleFormulaClick(){
this.isEdit = false;
this.formulaVisible = true;
},
handleSQlClick(){
this.isEdit = false;
this.sqlVisible = true;
},
handleClearClick(){
this.node.conditions = [];
},
handleFormulaOk(){
this.$refs.conditionFormula.validateForm(()=>{
let formData = this.$refs.conditionFormula.getForm();
formData.type = '1';
if(this.isEdit){
this.node.conditions[this.rowIndex] = formData;
}
else{
formData.code = this.$uuid();
this.node.conditions.push(formData);
}
this.formulaVisible = false;
})
},
handleFormulaOpened(){
if(this.isEdit){
this.$refs.conditionFormula.setForm(this.editRow);
}
},
handleFormulaClosed(){
this.$refs.conditionFormula.resetForm();
},
handleSqlOk(){
this.$refs.conditionSql.validateForm(()=>{
let formData = this.$refs.conditionSql.getForm();
formData.type = '2';
if(this.isEdit){
this.node.conditions[this.rowIndex] = formData;
}
else{
formData.code = this.$uuid();
this.node.conditions.push(formData);
}
this.sqlVisible = false;
})
},
handleSqlOpened(){
if(this.isEdit){
this.$refs.conditionSql.setForm(this.editRow);
}
},
handleSqlClosed(){
this.$refs.conditionSql.resetForm();
},
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,212 @@
<!-- 开始节点配置 -->
<template>
<l-layout :top="180" >
<template #top>
<el-form
class="l-form-config"
label-width="88px"
label-position="left"
size="mini"
>
<el-form-item label="节点标识">
<el-input v-model="node.id" readonly ></el-input>
</el-form-item>
<div style="padding:0 16px;">
<el-alert
title="排他网关说明"
type="info"
description="排他网关不会等待所有分支汇入才往下执行只要有分支汇入就会往下执行出口分支只会执行一条条件为true如果多条出口分支条件为true也执行一条"
show-icon
:closable="false"
>
</el-alert>
</div>
</el-form>
</template>
<l-layout :top="40">
<template #top v-if="!disabled">
<div style="padding-left:8px;float:left;" >
<el-button-group>
<el-button size="mini" icon="el-icon-plus" @click="handleFormulaClick">{{$t('')}}</el-button>
<el-button size="mini" icon="el-icon-plus" @click="handleSQlClick">{{$t('sql')}}</el-button>
</el-button-group>
</div>
<div style="padding-right:8px;float:right;">
<el-button size="mini" type="danger" icon="el-icon-delete" @click="handleClearClick">{{$t('')}}</el-button>
</div>
</template>
<l-table :columns="columns" :dataSource="node.conditions" >
<template v-slot:type="scope" >
{{typeFormat(scope.row.type)}}
</template>
<l-table-btns v-if="!disabled" :btns="tableBtns" @click="handleTableBtnClick" ></l-table-btns>
</l-table>
</l-layout>
<l-dialog
:title="$t('添加公式条件')"
:visible.sync="formulaVisible"
:height="480"
@ok="handleFormulaOk"
@closed="handleFormulaClosed"
@opened="handleFormulaOpened"
>
<condition-formula ref="conditionFormula" ></condition-formula>
</l-dialog>
<l-dialog
:title="$t('添加sql条件')"
:visible.sync="sqlVisible"
:height="480"
@ok="handleSqlOk"
@closed="handleSqlClosed"
@opened="handleSqlOpened"
>
<condition-sql ref="conditionSql" ></condition-sql>
</l-dialog>
</l-layout>
</template>
<script>
import conditionFormula from './conditionFormula.vue'
import conditionSql from './conditionSql.vue'
export default {
name:'gateway-xor-option',
props:{
disabled:{
type:Boolean,
default:false
}
},
components: {
conditionFormula,
conditionSql
},
data () {
return {
tableBtns:[
{prop:'Edit',label:'编辑'},
{prop:'Delete',label:'删除'}
],
columns:[
{label:'类型',prop:'type',width:'80', align: 'center'},
{label:'名称',prop:'name',minWidth:'100'},
],
tableData:[],
formulaVisible:false,
sqlVisible:false,
editRow:null,
isEdit:false,
rowIndex:0,
}
},
computed: {
node(){
return this.wfdesign.currentWfNode;
}
},
inject: ["wfdesign"],
methods:{
typeFormat(type){
switch(type){
case '1':
return '表达式'
case '2':
return 'sql语句'
}
},
handleTableBtnClick(btn){
switch(btn.type){
case 'Edit':
this.isEdit = true;
this.editRow = btn.row;
this.rowIndex = btn.rowIndex;
if(this.editRow.type == '1'){
this.formulaVisible = true;
}
else{
this.sqlVisible = true;
}
break;
case 'Delete':
this.node.conditions.splice(btn.rowIndex,1);
break;
}
console.log(btn);
//this.tableData.splice(btn.rowIndex,1);
},
handleFormulaClick(){
this.isEdit = false;
this.formulaVisible = true;
},
handleSQlClick(){
this.isEdit = false;
this.sqlVisible = true;
},
handleClearClick(){
this.node.conditions = [];
},
handleFormulaOk(){
this.$refs.conditionFormula.validateForm(()=>{
let formData = this.$refs.conditionFormula.getForm();
formData.type = '1';
if(this.isEdit){
this.node.conditions[this.rowIndex] = formData;
}
else{
formData.code = this.$uuid();
this.node.conditions.push(formData);
}
this.formulaVisible = false;
})
},
handleFormulaOpened(){
if(this.isEdit){
this.$refs.conditionFormula.setForm(this.editRow);
}
},
handleFormulaClosed(){
this.$refs.conditionFormula.resetForm();
},
handleSqlOk(){
this.$refs.conditionSql.validateForm(()=>{
let formData = this.$refs.conditionSql.getForm();
formData.type = '2';
if(this.isEdit){
this.node.conditions[this.rowIndex] = formData;
}
else{
formData.code = this.$uuid();
this.node.conditions.push(formData);
}
this.sqlVisible = false;
})
},
handleSqlOpened(){
if(this.isEdit){
this.$refs.conditionSql.setForm(this.editRow);
}
},
handleSqlClosed(){
this.$refs.conditionSql.resetForm();
},
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,120 @@
<!-- 开始节点配置 -->
<template>
<el-form
class="l-form-config"
label-width="88px"
label-position="left"
size="mini">
<el-form-item label="节点标识">
<el-input v-model="node.id" readonly ></el-input>
</el-form-item>
<el-form-item v-if="conditionsOptions && conditionsOptions.length >0" label="流转条件">
<l-select
:disabled="disabled"
v-model="value"
:options="conditionsOptions"
labelKey="name"
valueKey="code"
:multiple="true"
placeholder="不选择,默认流转条件为true"
></l-select>
</el-form-item>
</el-form>
</template>
<script>
export default {
name:'line-option',
props:{
disabled:{
type:Boolean,
default:false
}
},
data () {
return {
conditionsOptions:[],
value2:''
}
},
computed: {
node(){
return this.wfdesign.currentWfNode;
},
value:{
get(){
return this.value2;
},
set(val){
this.value2 = val;
this.node.lineConditions = val;
}
}
},
inject: ["wfdesign"],
created(){
this.getConditions()
},
methods:{
getConditions(){
let wfdata = this.wfdesign.handleGetWFData();
let fromNode = wfdata.find(t=>t.id == this.node.from);
/**
* startEvent:'开始节点',
endEvent:'结束节点',
gatewayAnd:'并行网关',
gatewayInclusive:'包含网关',
gatewayXor:'排他网关',
scriptTask:'脚本节点',
userTask:'审核节点',
subprocess:'子流程',
*/
switch(fromNode.type){
case 'startEvent':
case 'endEvent':
case 'gatewayAnd':
case 'scriptTask':
case 'subprocess':
this.node.lineConditions = ''
this.conditionsOptions = []
break
case 'gatewayInclusive':
case 'gatewayXor':
this.conditionsOptions = fromNode.conditions
//
this.filterValue()
break
case 'userTask':
this.conditionsOptions = fromNode.btnlist.filter(t=>!t.hidden)
//
this.filterValue()
break
}
this.value2 = this.node.lineConditions
},
filterValue(){
const vlist = this.node.lineConditions.split(',')
const res = []
vlist.forEach(item => {
if(this.conditionsOptions.findIndex(t=>t.code == item) != -1){
res.push(item)
}
})
this.node.lineConditions = String(res)
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,124 @@
<!-- 开始节点配置 -->
<template>
<el-form
class="l-form-config"
label-width="88px"
label-position="left"
size="mini">
<el-form-item label="节点标识">
<el-input v-model="node.id" readonly ></el-input>
</el-form-item>
<el-divider>执行操作</el-divider>
<div style="text-align: center;margin-bottom:16px;" >
<el-radio-group v-model="node.executeType" size="mini" :disabled="disabled">
<el-radio-button label="1">执行SQL</el-radio-button>
<el-radio-button label="2">.NET方法</el-radio-button>
<el-radio-button label="3">第三方接口</el-radio-button>
</el-radio-group>
</div>
<template v-if="node.executeType == '1'" >
<div style="padding:0 0 16px 0;">
<el-alert
title="sql参数说明"
type="info"
description="参数有 @processId流程进程主键 @code上一步执行码 @userId流程发起人Id @userAccount流程发起人账号 @companyId流程发起人公司 @departmentId流程发起人部门;
@userId2上一步审核人Id @userAccount2上一步审核人账号 @companyId2上一步审核人公司 @departmentId2上一步审核人部门;
"
show-icon
:closable="false"
>
</el-alert>
</div>
<el-form-item label-width="0">
<el-select v-model="node.sqlDb" placeholder="请选择执行SQL数据库" :disabled="disabled">
<el-option-group
v-for="group in lr_dblinkTree"
:key="group.id"
:label="group.label">
<el-option
v-for="item in group.children"
:key="item.id"
:label="item.label"
:value="item.id">
</el-option>
</el-option-group>
</el-select>
</el-form-item>
<el-form-item label-width="0">
<el-input :readonly="disabled" type="textarea" v-model="node.sqlStr" rows="8" placeholder="请填写SQL语句" ></el-input>
</el-form-item>
<el-form-item label-width="0">
<el-input :readonly="disabled" type="textarea" v-model="node.sqlStrRevoke" rows="8" placeholder="请填写SQL语句撤销" ></el-input>
</el-form-item>
</template>
<template v-if="node.executeType == '2'" >
<div style="padding:0 0 16px 0;">
<el-alert
title="IOC说明"
type="info"
description="注意编写一个继承IWorkFlowMethod的类
"
show-icon
:closable="false"
>
</el-alert>
</div>
<el-form-item label-width="0">
<el-input :readonly="disabled" type="textarea" v-model="node.ioc" rows="4" placeholder="ioc名称" ></el-input>
</el-form-item>
<el-form-item label-width="0">
<el-input :readonly="disabled" type="textarea" v-model="node.iocRevoke" rows="4" placeholder="ioc名称撤销" ></el-input>
</el-form-item>
</template>
<template v-if="node.executeType == '3'" >
<div style="padding:0 0 16px 0;">
<el-alert
title="接口参数说明"
type="info"
description="注意配置支持Post方法的接口,json数据格式{
processId:'流程发起实例主键',userId:'流程发起人Id',userAccount:'流程发起人账号',companyId:'流程发起人公司',departmentId:'流程发起人部门',code:'上一步执行码',
userId2:'上一步审核人Id',userAccount2:'上一步审核人账号',companyId2:'上一步审核人公司',departmentId2:'上一步审核人部门'
}
"
show-icon
:closable="false"
>
</el-alert>
</div>
<el-form-item label-width="0">
<el-input :readonly="disabled" type="textarea" v-model="node.apiUrl" rows="4" placeholder="接口地址" ></el-input>
</el-form-item>
<el-form-item label-width="0">
<el-input :readonly="disabled" type="textarea" v-model="node.apiUrlRevoke" rows="4" placeholder="接口地址(撤销)" ></el-input>
</el-form-item>
</template>
</el-form>
</template>
<script>
export default {
name:'script-task-option',
props:{
disabled:{
type:Boolean,
default:false
}
},
data () {
return {
}
},
computed: {
node(){
return this.wfdesign.currentWfNode;
}
},
inject: ["wfdesign"]
}
</script>
<style>
</style>

View File

@ -0,0 +1,77 @@
<!--
* @Author: 刘妍
* @Date: 2024-02-29 13:56:45
* @LastEditors: Do not edit
* @LastEditTime: 2024-02-29 14:34:53
* @Description:
-->
<!-- 开始节点配置 -->
<template>
<el-form
class="l-form-config"
label-width="88px"
label-position="left"
size="mini">
<el-form-item label="节点标识">
<el-input v-model="node.id" readonly ></el-input>
</el-form-item>
<el-form-item label="是否异步">
<el-switch :disabled="disabled" v-model="node.isAsync">
</el-switch>
</el-form-item>
<el-form-item label="流程模版">
<l-select :disabled="disabled" v-model="node.wfschemeId" :options="list">
</l-select>
</el-form-item>
<el-form-item label="流程版本">
<l-select :disabled="disabled" v-model="node.wfVersionId" :options="verisons">
</l-select>
</el-form-item>
</el-form>
</template>
<script>
// const api = window.$api.workflow.scheme
export default {
name:'subprocess-option',
props:{
disabled:{
type:Boolean,
default:false
}
},
data () {
return {
}
},
asyncComputed:{
list:{
async get(){
const data = []
// const data = await this.$awaitWraper(api.getList())
const res = data || []
return res.filter(t=>t.f_Id != this.wfdesign.schemeinfoId).map(t=>{return {label:t.f_Name,value:t.f_Id}})
}
},
verisons:{
async get(){
let res = []
if(!this.$validatenull(this.node.wfschemeId)){
// res = await this.$awaitWraper(api.getHistoryList(this.node.wfschemeId))
}
return (res || []).map(t=>{return { label:this.lr_dateFormat(t.f_CreateDate),value:t.f_Id }})
}
}
},
computed: {
node(){
return this.wfdesign.currentWfNode;
}
},
inject: ["wfdesign"]
}
</script>
<style>
</style>

View File

@ -0,0 +1,7 @@
import BpmnPropertiesPanel from "./PropertiesPanel.vue";
BpmnPropertiesPanel.install = function(Vue) {
Vue.component(BpmnPropertiesPanel.name, BpmnPropertiesPanel);
};
export default BpmnPropertiesPanel;

View File

@ -0,0 +1,220 @@
<template>
<div class="shceme-info">
<a-form ref="formRef" :rules="rules" :model="formState" labelAlign="left" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-form-item label="模板编号" name="f_Code">
<a-input v-model:value="formState.f_Code" placeholder="请输入" />
</a-form-item>
<a-form-item label="模板名称" name="f_Name">
<a-input v-model:value="formState.f_Name" placeholder="请输入" />
</a-form-item>
<a-form-item label="模板图标" name="f_Icon">
<IconPicker :value="formState.f_Icon" />
</a-form-item>
<a-form-item label="图标颜色" name="f_Color">
<a-input type="color" v-model="formState.f_Color" placeholder="请输入"></a-input>
</a-form-item>
<a-form-item label="模板分类" name="f_Category">
<a-select v-model:value="formState.f_Category" placeholder="please select your zone">
<a-select-option value="shanghai">Zone one</a-select-option>
<a-select-option value="beijing">Zone two</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="我的任务创建">
<a-radio-group v-model:value="formState.f_Mark" name="radioGroup">
<a-radio v-for="item in data.optionsNotOrOk" :value="item.value">{{item.label}}</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="移动端创建">
<a-radio-group v-model:value="formState.f_IsInApp" name="radioGroup">
<a-radio v-for="item in data.optionsNotOrOk" :value="item.value">{{item.label}}</a-radio>
</a-radio-group>
</a-form-item>
<a-textarea v-model:value="formState.f_Description" placeholder="请填写备注"
:auto-size="{ minRows: 5, maxRows: 8 }" />
<a-divider plain="true">撤销操作</a-divider>
<a-tabs v-model:activeKey="formState.undoType" type="card" size="small" centered="true">
<a-tab-pane key="1" tab="执行SQL">
<a-space direction="vertical" size="middle" class="site-space-compact-wrapper">
<a-space-compact block>
<a-select v-model:value="formState.undoDbCode" placeholder="请选择执行SQL数据库">
<a-select-option value="shanghai">Zone one</a-select-option>
<a-select-option value="beijing">Zone two</a-select-option>
</a-select>
</a-space-compact>
<a-space-compact block>
<a-textarea v-model:value="formState.undoDbSQL"
placeholder="请填写SQL语句参数有 @processId流程进程主键 @userId用户Id @userAccount用户账号 @companyId用户公司 @departmentId用户部门"
:auto-size="{ minRows: 5, maxRows: 8 }" />
</a-space-compact>
</a-space>
</a-tab-pane>
<a-tab-pane key="2" tab=".NET方法">
<a-space direction="vertical" size="middle" class="site-space-compact-wrapper">
<a-space-compact block>
<a-textarea v-model:value="formState.undoIOCName" placeholder="请填写.NET方法IOC别名"
:auto-size="{ minRows: 5, maxRows: 8 }" />
</a-space-compact>
</a-space>
</a-tab-pane>
<a-tab-pane key="3" tab="第三方接口">
<a-space direction="vertical" size="middle" class="site-space-compact-wrapper">
<a-space-compact block>
<a-textarea v-model:value="formState.undoUrl"
placeholder="请填写第三方接口地址(POST),JSON 格式,参数有 userId用户Id,userAccount用户账号,companyId用户公司,departmentId用户部门"
:auto-size="{ minRows: 5, maxRows: 8 }" />
</a-space-compact>
</a-space>
</a-tab-pane>
</a-tabs>
<a-divider plain="true">作废操作</a-divider>
<a-tabs v-model:activeKey="formState.deleteType" type="card" size="small" centered="true">
<a-tab-pane key="1" tab="执行SQL">
<a-space direction="vertical" size="middle" class="site-space-compact-wrapper">
<a-space-compact block>
<a-select v-model:value="formState.deleteDbCode" placeholder="请选择执行SQL数据库">
<a-select-option value="shanghai">Zone one</a-select-option>
<a-select-option value="beijing">Zone two</a-select-option>
</a-select>
</a-space-compact>
<a-space-compact block>
<a-textarea v-model:value="formState.deleteDbSQL"
placeholder="请填写SQL语句参数有 @processId流程进程主键 @userId用户Id @userAccount用户账号 @companyId用户公司 @departmentId用户部门"
:auto-size="{ minRows: 5, maxRows: 8 }" />
</a-space-compact>
</a-space>
</a-tab-pane>
<a-tab-pane key="2" tab=".NET方法">
<a-space direction="vertical" size="middle" class="site-space-compact-wrapper">
<a-space-compact block>
<a-textarea v-model:value="formState.deleteIOCName" placeholder="请填写.NET方法IOC别名"
:auto-size="{ minRows: 5, maxRows: 8 }" />
</a-space-compact>
</a-space>
</a-tab-pane>
<a-tab-pane key="3" tab="第三方接口">
<a-space direction="vertical" size="middle" class="site-space-compact-wrapper">
<a-space-compact block>
<a-textarea v-model:value="formState.undoUrl"
placeholder="请填写第三方接口地址(POST),JSON 格式,参数有 userId用户Id,userAccount用户账号,companyId用户公司,departmentId用户部门"
:auto-size="{ minRows: 5, maxRows: 8 }" />
</a-space-compact>
</a-space>
</a-tab-pane>
</a-tabs>
<a-divider plain="true">删除草稿</a-divider>
<a-tabs v-model:activeKey="formState.deleteDraftType" type="card" size="small" centered="true">
<a-tab-pane key="1" tab="执行SQL">
<a-space direction="vertical" size="middle" class="site-space-compact-wrapper">
<a-space-compact block>
<a-select v-model:value="formState.deleteDraftDbCode" placeholder="请选择执行SQL数据库">
<a-select-option value="shanghai">Zone one</a-select-option>
<a-select-option value="beijing">Zone two</a-select-option>
</a-select>
</a-space-compact>
<a-space-compact block>
<a-textarea v-model:value="formState.deleteDraftDbSQL"
placeholder="请填写SQL语句参数有 @processId流程进程主键 @userId用户Id @userAccount用户账号 @companyId用户公司 @departmentId用户部门"
:auto-size="{ minRows: 5, maxRows: 8 }" />
</a-space-compact>
</a-space>
</a-tab-pane>
<a-tab-pane key="2" tab=".NET方法">
<a-space direction="vertical" size="middle" class="site-space-compact-wrapper">
<a-space-compact block>
<a-textarea v-model:value="formState.deleteDraftIOCName" placeholder="请填写.NET方法IOC别名"
:auto-size="{ minRows: 5, maxRows: 8 }" />
</a-space-compact>
</a-space>
</a-tab-pane>
<a-tab-pane key="3" tab="第三方接口">
<a-space direction="vertical" size="middle" class="site-space-compact-wrapper">
<a-space-compact block>
<a-textarea v-model:value="formState.undoUrl"
placeholder="请填写第三方接口地址(POST),JSON 格式,参数有 userId用户Id,userAccount用户账号,companyId用户公司,departmentId用户部门"
:auto-size="{ minRows: 5, maxRows: 8 }" />
</a-space-compact>
</a-space>
</a-tab-pane>
</a-tabs>
</a-form>
</div>
</template>
<script lang="ts" setup>
import { Dayjs } from 'dayjs';
import { reactive, ref, toRaw } from 'vue';
import type { UnwrapRef } from 'vue';
import type { Rule } from 'ant-design-vue/es/form';
import { IconPicker } from '/@/components/Icon';
const formRef = ref();
const labelCol = { span: 7 };
const wrapperCol = { span: 17 };
const activeKey = ref('1')
const data = reactive({
optionsNotOrOk: [{ label: '允许', value: 1 }, { label: '不允许', value: 2 }],
})
const formState = reactive({
f_Code: '',
f_Name: '',
f_Category: '',
f_Mark: 1,
f_IsInApp: 2,
f_Description: '',
titleRules: '',
undoType: "1",
undoDbCode: '',
undoDbSQL: '',
undoIOCName: '',
undoUrl: '',
deleteType: "1",
deleteDbCode: '',
deleteDbSQL: '',
deleteIOCName: '',
deleteUrl: '',
deleteDraftType: "1",
deleteDraftDbCode: '',
deleteDraftDbSQL: '',
deleteDraftIOCName: '',
deleteDraftUrl: '',
f_Icon: '',
f_Color: '#409EFF',
});
const rules: Record<string, Rule[]> = {
f_Code: [
{ required: true, message: '请输入模板编号' },
// { validator: lr_existDbFiled, keyValue: () => { return data.formData.f_Id }, tableName: 'lr_wf_schemeinfo', keyName: 'f_Id', trigger: 'blur' }
],
f_Name: [
{ required: true, message: '请输入模板名称' }
],
f_Category: [
{ required: true, message: '请选择模板分类' }
],
f_Icon: [
{ required: true, message: '请选择图标' }
],
f_Color: [
{ required: true, message: '请选择颜色' }
],
};
</script>
<style lang="less" scoped>
.site-space-compact-wrapper {
width: 100%;
.ant-select {
width: 100%;
}
}
::v-deep .ant-tabs {
padding: 0!important;
}
</style>

View File

@ -0,0 +1,351 @@
<!-- 开始节点配置 -->
<template>
<div class="start-event">
<a-form ref="formRef" :rules="rules" :model="node" labelAlign="left" :label-col="labelCol"
:wrapper-col="wrapperCol">
<a-form-item label="节点标识">
<a-input v-model:value="node.id" placeholder="请输入" readonly />
</a-form-item>
<a-form-item label="下一审核人">
<a-switch v-model:checked="node.isNextAuditor" />
</a-form-item>
<a-form-item label="自定义标题">
<a-switch v-model:checked="node.isCustmerTitle" />
</a-form-item>
<a-form-item label="通知策略" name="f_Color">
<a-checkbox-group v-model:value="node.messageType" name="checkboxgroup"
:options="[{value:'1',label:'短信'},{value:'2',label:'邮箱'},{value:'3',label:'微信'},{value:'4',label:'站内消息'}]" />
</a-form-item>
<a-divider plain="true">表单添加</a-divider>
<a-tabs v-model:activeKey="node.formType" type="card" size="small" centered="true">
<a-tab-pane key="1" tab="自定义表单">
<a-space direction="vertical" size="middle" class="site-space-compact-wrapper">
<a-space-compact block>
<a-select v-model:value="node.formVerison" placeholder="请选择表单版本">
<a-select-option value="shanghai">Zone one</a-select-option>
<a-select-option value="beijing">Zone two</a-select-option>
</a-select>
</a-space-compact>
<a-space-compact block>
<a-select v-model:value="node.formRelationId" placeholder="请选择流程关联字段">
<a-select-option value="shanghai">Zone one</a-select-option>
<a-select-option value="beijing">Zone two</a-select-option>
</a-select>
</a-space-compact>
</a-space>
</a-tab-pane>
<a-tab-pane key="2" tab="系统表单">
<a-space direction="vertical" size="middle" class="site-space-compact-wrapper">
<a-space-compact block>
<a-input v-model:value="node.formUrl" placeholder="请输入PC端表单地址" />
</a-space-compact>
<a-space-compact block>
<a-input v-model:value="node.formAppUrl" placeholder="请输入APP端表单地址" />
</a-space-compact>
</a-space>
</a-tab-pane>
</a-tabs>
<a-divider plain="true">表单字段权限</a-divider>
<a-table :columns="data.columns" :data-source="node.authFields" bordered :pagination="false"
v-if="node.formType == 1">
<template #bodyCell="{ column, text, record }">
<template v-if="['label', 'field'].includes(column.dataIndex)">
<div>
{{ text }}
</div>
</template>
<template v-else-if="['required', 'isEdit','isLook'].includes(column.dataIndex)">
<div>
<a-switch v-model:checked="record[column.dataIndex]" />
</div>
</template>
</template>
</a-table>
<a-table :columns="data.columns" :data-source="node.authFields" bordered :pagination="false" v-else>
<template #bodyCell="{ column, text, record }">
<template v-if="['label', 'field'].includes(column.dataIndex)">
<div>
{{ text }}
</div>
</template>
<template v-else-if="['required', 'isEdit','isLook'].includes(column.dataIndex)">
<div>
<a-switch v-model:checked="record[column.dataIndex]" />
</div>
</template>
<template v-else-if="column.dataIndex === 'operation'">
<delete-outlined two-tone-color='#eb2f96' @click='handleDeleteAuthField(record.field)' />
</template>
</template>
</a-table>
<a-divider plain="true"></a-divider>
<a-space v-if="node.formType!=1">
<a-button @click="handleAddAuthField" width="100%" type="dashed" danger :icon="h(PlusOutlined)">添加字段</a-button>
</a-space>
<!-- <a-table :columns="data.columns" :data-source="node.authField" bordered :pagination="false">
<template #bodyCell="{ column, text, record }">
<template v-if="['name', 'type'].includes(column.dataIndex)">
<div>
<a-input
v-model:value="text"
style="margin: -5px 0"
/>
</div>
</template>
<template v-else-if="column.dataIndex === 'operation'">
<a>删除</a>
</template>
</template>
</a-table> -->
</a-form>
</div>
</template>
<script lang="ts" setup>
import { reactive, defineProps, computed, inject, ref, watch, h } from 'vue'
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons-vue'
const labelCol = { span: 7 };
const wrapperCol = { span: 17 };
const props = defineProps({
disabled: {
type: Boolean,
default: false
},
element: Object
})
const data = reactive({
columns: [
{
title: '名称',
dataIndex: 'label',
},
{
title: '字段',
dataIndex: 'field',
},
{
title: '必填',
dataIndex: 'required',
},
{
title: '编辑',
dataIndex: 'isEdit',
},
{
title: '查看',
dataIndex: 'isLook',
},
],
formRelations: [],
elementData: props.element
})
const node = reactive({
id: data.elementData.id,
type: data.elementData.type,
isNextAuditor: false,
isCustmerTitle: false,
formRelations: [],
formType: "1",
formCode: "",
formVerison: "",
formRelationId: "",
formUrl: "",
formAppUrl: "",
authFields: [
{
label: '测试',
field: 'ceshi',
required: true,
isEdit: true,
isLook: true,
}
],
messageType: "",
isInit: true
})
watch(
() => props.element,
(newVal, oldVal) => {
data.elementData = newVal
node.id = data.elementData.id
node.type = data.elementData.type
}
)
watch(
() => node.formType,
(newVal, oldVal) => {
if (newVal == 1) {
data.columns = data.columns.filter(item => item.dataIndex !== 'operation');
} else {
data.columns.push({
title: '',
dataIndex: 'operation',
})
}
}
)
async function custmerformChange(val) {
this.$set(this.node, 'formRelationId', '')
if (val == null) {
this.node.authFields = [];
this.node.formVerison = ''
return;
}
if (this.$validatenull(this.wfdesign.custmerformSchemes[val.f_SchemeId])) {
// const {f_SchemeInfoId,f_Scheme,f_Id} = (await this.$awaitWraper(apiForm.getHistory(val.f_SchemeId))) || {}
this.wfdesign.custmerformSchemes[f_Id] = { f_Scheme }
if (this.node.formCode == f_SchemeInfoId) {
this.loadFormScheme(f_Scheme)
}
}
else {
this.loadFormScheme(this.wfdesign.custmerformSchemes[val.f_SchemeId].f_Scheme);
}
this.node.formVerison = val.f_SchemeId
}
async function custmerformVerisonChange(val) {
this.$set(this.node, 'formRelationId', '')
if (this.$validatenull(val)) {
this.node.authFields = []
return
}
if (this.$validatenull(this.wfdesign.custmerformSchemes[val.value])) {
// const {f_Scheme,f_Id} = (await this.$awaitWraper(apiForm.getHistory(val.value))) || {}
this.wfdesign.custmerformSchemes[f_Id] = { f_Scheme }
if (this.node.formVerison == f_Id) {
this.loadFormScheme(f_Scheme)
}
}
else {
this.loadFormScheme(this.wfdesign.custmerformSchemes[val.value].f_Scheme);
}
}
function loadFormScheme(strScheme) {
const scheme = JSON.parse(strScheme)
const fields = []
const rfields = []
scheme.formInfo.tabList.forEach(tab => {
tab.components.forEach(component => {
if (['guid'].includes(component.type)) {
rfields.push({ label: component.label, value: component.prop })
}
if (!['gridtable', 'divider'].includes(component.type) && component.display) {
fields.push({
prop: component.prop,
field: component.field,
label: component.label,
table: component.table,
required: component.required,
isEdit: true,
isLook: true
})
}
else if (['gridtable'].includes(component.type)) {
fields.push({
prop: `${component.prop}_add`,
label: `${component.label || '表格'}-添加按钮`,
required: false,
isEdit: true,
isLook: false,
type: 'grid'
})
fields.push({
prop: `${component.prop}_remove`,
label: `${component.label || '表格'}-删除按钮`,
required: false,
isEdit: true,
isLook: false,
type: 'grid'
})
fields.push({
prop: `${component.prop}_required`,
label: `${component.label || '表格'}-数据`,
required: component.required,
isEdit: false,
isLook: false,
type: 'gridrequired'
})
fields.push(...component.children.filter(t => t.display).map(t => {
return {
gridprop: component.prop,
prop: t.prop,
field: t.field,
label: `${component.label || '表格'}-${t.label}`,
table: component.table,
required: t.required,
isEdit: true,
isLook: true
}
}))
}
})
})
this.node.formRelations = rfields
this.node.authFields = fields
}
function handleFormTypeChange() {
this.node.formCode = ''
this.node.formUrl = ''
this.node.formAppUrl = ''
this.node.authFields = []
this.node.formRelations = []
this.$set(this.node, 'formRelationId', '')
}
function handleAddAuthField() {
node.authFields.push({
field: '',
label: '',
required: true,
isEdit: true,
isLook: true
})
}
function handleDeleteAuthField(key) {
node.authFields = node.authFields.filter(item => item.field !== key);
}
</script>
<style lang="less" scoped>
.site-space-compact-wrapper {
width: 100%;
.ant-select {
width: 100%;
}
}
::v-deep .ant-tabs {
padding: 0 !important;
}
::v-deep .ant-space {
width: 90%;
margin-left: 5%;
.ant-space-item {
width: 100%;
button {
width: 100%;
}
}
}
</style>

View File

@ -0,0 +1,673 @@
<!-- 开始节点配置 -->
<template>
<el-form label-width="96px" label-position="left" size="mini">
<el-collapse v-model="activeNames" accordion>
<el-collapse-item :title="$t('基础配置')" name="1">
<div style="padding:0 16px;">
<el-form-item label="节点标识">
<el-input v-model="node.id" readonly></el-input>
</el-form-item>
<el-form-item label="继承表单">
<el-switch :disabled="disabled" v-model="node.isInherit">
</el-switch>
</el-form-item>
<el-form-item label="允许加签">
<el-switch :disabled="disabled" v-model="node.isAddSign">
</el-switch>
</el-form-item>
<el-form-item label="允许转移">
<el-switch :disabled="disabled" v-model="node.isTransfer">
</el-switch>
</el-form-item>
<el-form-item label="允许批量审核">
<el-switch :disabled="disabled" v-model="node.isBatchAudit">
</el-switch>
</el-form-item>
<el-form-item label="自动同意规则">
<l-select multiple :disabled="disabled" v-model="node.autoAgree" :options="atuoAgreeOptions">
</l-select>
</el-form-item>
<el-form-item label="无对应处理人">
<l-select :disabled="disabled" v-model="node.noAuditor" :options="noAuditorOptions">
</l-select>
</el-form-item>
<el-form-item label="驳回策略">
<l-radio :disabled="disabled" v-model="node.rejectType"
:options="[{value:'1',label:'驳回节点固定'},{value:'2',label:'能驳回到任何执行过节点'}]">
</l-radio>
</el-form-item>
<el-form-item label="通知策略">
<l-checkbox :disabled="disabled" v-model="node.messageType"
:options="[{value:'1',label:'短信'},{value:'2',label:'邮箱'},{value:'3',label:'微信'},{value:'4',label:'站内消息'}]">
</l-checkbox>
</el-form-item>
</div>
</el-collapse-item>
<el-collapse-item :title="$t('审核人员设置')" name="2">
<el-button-group style="padding:0 0 8px 8px" v-if="!disabled">
<el-button size="mini" @click="handlePostClick(false)">{{$t('')}}</el-button>
<el-button size="mini" @click="handleRoleClick(false)">{{$t('')}}</el-button>
<el-button size="mini" @click="handleUserClick(false)">{{$t('')}}</el-button>
<el-button size="mini" @click="handleLevelClick(false)">{{$t('')}}</el-button>
<el-button size="mini" @click="handleNodeAuditorClick(false)">{{$t('')}}</el-button>
<el-button size="mini" @click="handleAuditorSqlClick(false)">{{$t('')}}</el-button>
</el-button-group>
<l-table height="notset" :isShowNum="false" :columns="userColumns" :dataSource="node.auditUsers">
<template v-slot:type="scope">
{{typeFormat(scope.row.type)}}
</template>
<template v-slot:condition="scope">
<l-select :disabled="disabled" size="mini" v-if="scope.row.type == '2'"
:options="conditionOptions" v-model="scope.row.condition"></l-select>
</template>
<l-table-btns v-if="!disabled" :isFixed="false" :btns="tableBtns" @click="handleTableBtnClick">
</l-table-btns>
</l-table>
</el-collapse-item>
<el-collapse-item :title="$t('传阅人员设置')" name="3">
<el-button-group style="padding:0 0 8px 8px" v-if="!disabled">
<el-button size="mini" @click="handlePostClick(true)">{{$t('')}}</el-button>
<el-button size="mini" @click="handleRoleClick(true)">{{$t('')}}</el-button>
<el-button size="mini" @click="handleUserClick(true)">{{$t('')}}</el-button>
<el-button size="mini" @click="handleLevelClick(true)">{{$t('')}}</el-button>
<el-button size="mini" @click="handleNodeAuditorClick(true)">{{$t('')}}</el-button>
<el-button size="mini" @click="handleAuditorSqlClick(true)">{{$t('')}}</el-button>
</el-button-group>
<l-table height="notset" :isShowNum="false" :columns="userColumns" :dataSource="node.lookUsers">
<template v-slot:type="scope">
{{typeFormat(scope.row.type)}}
</template>
<template v-slot:condition="scope">
<l-select :disabled="disabled" size="mini" v-if="scope.row.type == '2'"
:options="conditionOptions" v-model="scope.row.condition"></l-select>
</template>
<l-table-btns v-if="!disabled" :isFixed="false" :btns="tableBtns" @click="handleTableBtnClick2">
</l-table-btns>
</l-table>
</el-collapse-item>
<el-collapse-item v-if="!node.isInherit" :title="$t('表单设置')" name="4">
<div style="padding:0 16px;">
<div style="text-align: center;margin-bottom:16px;">
<el-radio-group :disabled="disabled" v-model="node.formType" size="mini"
@change="handleFormTypeChange">
<el-radio-button label="1">自定义表单</el-radio-button>
<el-radio-button label="2">系统表单</el-radio-button>
</el-radio-group>
</div>
<div v-show="node.formType === '1'">
<el-form-item label-width="0px">
<l-custmerform-select v-model="node.formCode" @change="custmerformChange"
:disabled="disabled">
</l-custmerform-select>
</el-form-item>
<el-form-item label-width="0px">
<l-select v-model="node.formVerison" :disabled="disabled" :options="formVerisons"
@change="custmerformVerisonChange" placeholder="请选择表单版本">
</l-select>
</el-form-item>
<el-form-item label-width="0px">
<l-select v-model="node.formRelationId" :disabled="disabled" :options="node.formRelations"
placeholder="请选择流程关联字段">
</l-select>
</el-form-item>
</div>
<div v-show="node.formType === '2'">
<el-form-item label-width="0px">
<el-input v-model="node.formUrl" placeholder="请输入PC端表单地址" :readonly="disabled">
</el-input>
</el-form-item>
<el-form-item label-width="0px">
<el-input v-model="node.formAppUrl" placeholder="请输入APP端表单地址" :readonly="disabled">
</el-input>
</el-form-item>
</div>
<el-divider>表单字段权限</el-divider>
<template v-if="node.formType === '1'">
<l-table height="notset" :isShowNum="false" :columns="columns" :dataSource="node.authFields"
ref="authField">
<template v-slot:required="scope">
<el-switch v-model="scope.row.required"
:disabled="disabled || scope.row.type == 'grid'">
</el-switch>
</template>
<template v-slot:isEdit="scope">
<el-switch v-model="scope.row.isEdit"
:disabled="disabled || scope.row.type == 'gridrequired'">
</el-switch>
</template>
<template v-slot:isLook="scope">
<el-switch v-model="scope.row.isLook"
:disabled="disabled || scope.row.type == 'grid' || scope.row.type == 'gridrequired'">
</el-switch>
</template>
</l-table>
</template>
<template v-else>
<l-edit-table addBtnText="添加字段" :dataSource="node.authFields" :isShowNum="false"
:isAddBtn="!disabled" :isRemoveBtn="!disabled" @addRow="handleAddAuthField"
@deleteRow="handleDeleteAuthField">
<el-table-column prop="label" label="名称" minWidth="100">
<template slot-scope="scope">
<el-input :readonly="disabled" size="mini" v-model="scope.row.label"
placeholder="请输入名称"></el-input>
</template>
</el-table-column>
<el-table-column prop="field" label="字段" minWidth="100">
<template slot-scope="scope">
<el-input :readonly="disabled" size="mini" v-model="scope.row.field"
placeholder="请输入字段"></el-input>
</template>
</el-table-column>
<el-table-column prop="required" label="必填" width="64">
<template slot-scope="scope">
<el-switch v-model="scope.row.required" :disabled="disabled">
</el-switch>
</template>
</el-table-column>
<el-table-column prop="isEdit" label="编辑" width="64">
<template slot-scope="scope">
<el-switch v-model="scope.row.isEdit" :disabled="disabled">
</el-switch>
</template>
</el-table-column>
<el-table-column prop="isLook" label="查看" width="64">
<template slot-scope="scope">
<el-switch v-model="scope.row.isLook" :disabled="disabled">
</el-switch>
</template>
</el-table-column>
</l-edit-table>
</template>
</div>
</el-collapse-item>
<el-collapse-item :title="$t('按钮设置')" name="5">
<l-edit-table addBtnText="添加按钮" :dataSource="node.btnlist" :isShowNum="false"
:hasDeleteBtn="hasBtnsDeleteBtn" :isAddBtn="!disabled" :isRemoveBtn="!disabled"
@addRow="handleAddBtns" @deleteRow="handleDeleteBtns">
<el-table-column prop="name" label="名称" minWidth="100">
<template slot-scope="scope">
<el-input :readonly="disabled" v-if="!scope.row.isSys" size="mini" v-model="scope.row.name"
placeholder="请输入名称"></el-input>
<span v-else>{{scope.row.name}}</span>
</template>
</el-table-column>
<el-table-column prop="code" label="编码" minWidth="100">
<template slot-scope="scope">
<el-input :readonly="disabled" v-if="!scope.row.isSys" size="mini" v-model="scope.row.code"
placeholder="请输入编码"></el-input>
<span v-else>{{scope.row.code}}</span>
</template>
</el-table-column>
<el-table-column align="center" prop="hidden" label="隐藏" width="64">
<template slot-scope="scope">
<el-switch v-model="scope.row.hidden" :disabled="disabled">
</el-switch>
</template>
</el-table-column>
<el-table-column align="center" prop="isSign" label="签章" width="64">
<template slot-scope="scope">
<el-switch v-model="scope.row.isSign" :disabled="disabled">
</el-switch>
</template>
</el-table-column>
<el-table-column align="center" prop="isNextAuditor" label="下一审核人" width="80">
<template slot-scope="scope">
<el-switch v-if="scope.row.code != 'disagree'" v-model="scope.row.isNextAuditor"
:disabled="disabled">
</el-switch>
</template>
</el-table-column>
</l-edit-table>
</el-collapse-item>
<el-collapse-item :title="$t('会签设置')" name="6">
<div style="padding:0 16px">
<el-form-item label="是否会签">
<el-switch v-model="node.isCountersign" :disabled="disabled">
</el-switch>
</el-form-item>
<template v-if="node.isCountersign">
<el-form-item label="审核方式">
<l-radio :disabled="disabled" v-model="node.countersignType"
:options="[{value:'1',label:'并行'},{value:'2',label:'串行'}]">
</l-radio>
</el-form-item>
<el-form-item v-if="node.countersignType == '1'" label="是否等待">
<!--并行才有这个设置-->
<el-switch v-model="node.isCountersignAll" :disabled="disabled">
</el-switch>
</el-form-item>
<el-form-item v-if="node.countersignType == '1'" label="通过百分比">
<el-input-number :disabled="disabled" :min="1" :max="100" v-model="node.countersignAllType">
</el-input-number>
</el-form-item>
<el-form-item label="再次审核">
<l-radio :disabled="disabled" v-model="node.countersignAgian"
:options="[{value:'1',label:'已同意不需要审核'},{value:'2',label:'已同意需要审核'}]">
</l-radio>
</el-form-item>
</template>
</div>
</el-collapse-item>
<el-collapse-item :title="$t('超时设置')" name="7">
<div style="padding:0 16px">
<el-form-item label="超时通知">
<el-switch :disabled="disabled" v-model="node.isOvertimeMessage">
</el-switch>
</el-form-item>
<template v-if="node.isOvertimeMessage">
<el-form-item label="第一次通知(时)">
<el-input-number :disabled="disabled" :min="1" v-model="node.overtimeMessageStart">
</el-input-number>
</el-form-item>
<el-form-item label="通知间隔(时)">
<el-input-number :disabled="disabled" :min="1" v-model="node.overtimeMessageInterval">
</el-input-number>
</el-form-item>
<el-form-item label="超时流转时间(时)">
<el-input-number :disabled="disabled" :min="1" v-model="node.overtimeGo">
</el-input-number>
</el-form-item>
<el-form-item label="超时通知策略">
<l-checkbox :disabled="disabled" v-model="node.overtimeMessageType"
:options="[{value:'1',label:'短信'},{value:'2',label:'邮箱'},{value:'3',label:'微信'},{value:'4',label:'站内消息'}]">
</l-checkbox>
</el-form-item>
</template>
</div>
</el-collapse-item>
</el-collapse>
<l-dialog :title="$t('添加岗位')" :visible.sync="selectPostVisible" :height="480" width="1024px"
@ok="handlePostSelectOk" @closed="handlePostSelectClosed">
<l-post-select-panel ref="postSelectPanel"></l-post-select-panel>
</l-dialog>
<l-dialog :title="$t('添加角色')" :visible.sync="selectRoleVisible" :height="480" width="800px"
@ok="handleRoleSelectOk" @closed="handleRoleSelectClosed">
<l-role-select-panel ref="roleSelectPanel"></l-role-select-panel>
</l-dialog>
<l-dialog :title="$t('添加用户')" :visible.sync="selectUserVisible" :height="480" width="1024px"
@ok="handleUserSelectOk" @closed="handleUserSelectClosed">
<l-user-select-panel ref="userSelectPanel"></l-user-select-panel>
</l-dialog>
<!--上下级选择-->
<l-dialog :title="$t('上下级选择')" :visible.sync="levelVisible" :height="200" width="500px" @ok="handleLevelOk"
@closed="handleLevelClosed">
<!-- <auditor-level-form ref="auditorLevelForm"></auditor-level-form> -->
</l-dialog>
<!--流程节点选择-->
<l-dialog :title="$t('流程节点选择')" :visible.sync="nodeAuditorVisible" :height="200" width="500px"
@ok="handleNodeAuditorOk" @closed="handleNodeAuditorClosed" @opened="handleNodeAuditorOpened">
<!-- <node-auditor-form ref="nodeAuditorForm"></node-auditor-form> -->
</l-dialog>
<!--流程节点选择-->
<l-dialog :title="$t('数据表字段选择')" :visible.sync="auditorSqlVisible" width="500px" :height="300"
@ok="handleAuditorSqlOk" @closed="handleAuditorSqlClosed">
<!-- <auditor-sql-form ref="auditorSqlForm"></auditor-sql-form> -->
</l-dialog>
</el-form>
</template>
<script>
// const apiForm = window.$api.custmerForm.scheme
// import auditorLevelForm from './auditorLevel.vue'
// import nodeAuditorForm from './auditorNode.vue'
// import auditorSqlForm from './auditorSql.vue'
export default {
name: 'user-task-option',
props: {
disabled: {
type: Boolean,
default: false
}
},
components: {
// auditorLevelForm,
// nodeAuditorForm,
// auditorSqlForm
},
data() {
return {
activeNames: ['1'],
columns: [
{ label: '名称', prop: 'label', minWidth: '100' },
{ label: '字段', prop: 'field', minWidth: '100' },
{ label: '必填', prop: 'required', width: '64', align: 'center' },
{ label: '编辑', prop: 'isEdit', width: '64', align: 'center' },
{ label: '查看', prop: 'isLook', width: '64', align: 'center' },
],
tableBtns: [
{ prop: 'Delete', label: '删除' }
],
atuoAgreeOptions: [{ value: '1', label: '处理人就是提交人' }, { value: '2', label: '处理人和上一步的处理人相同' }, { value: '3', label: '处理人审批过' }],
noAuditorOptions: [{ value: '1', label: '超级管理员处理' }, { value: '2', label: '跳过此步骤' }, { value: '3', label: '不能提交' }],
userColumns: [
{ label: '类型', prop: 'type', width: '64' },
{ label: '名称', prop: 'name', minWidth: '100' },
{ label: '附加条件', prop: 'condition', minWidth: '100' }
],
conditionOptions: [{ value: '1', label: '同一个部门' }, { value: '2', label: '同一个公司' }, { value: '3', label: '发起人上级' }, { value: '4', label: '发起人下级' }],
selectPostVisible: false,
selectRoleVisible: false,
selectUserVisible: false,
levelVisible: false,
nodeAuditorVisible: false,
auditorSqlVisible: false,
isLooker: false,
}
},
asyncComputed: {
formVerisons: {
async get() {
let res = []
if (!this.$validatenull(this.node.formCode) && this.node.formType == '1') {
// res = await this.$awaitWraper(apiForm.getHistoryList(this.node.formCode))
}
return (res || []).map(t => { return { label: this.lr_dateFormat(t.f_CreateDate), value: t.f_Id } })
}
}
},
computed: {
node() {
return this.wfdesign.currentWfNode;
}
},
inject: ["wfdesign"],
methods: {
async custmerformChange(val) {
this.$set(this.node, 'formRelationId', '')
if (val == null) {
this.node.authFields = [];
this.node.formVerison = ''
return;
}
if (this.$validatenull(this.wfdesign.custmerformSchemes[val.f_SchemeId])) {
// const {f_SchemeInfoId,f_Scheme,f_Id} = (await this.$awaitWraper(apiForm.getHistory(val.f_SchemeId))) || {}
const { f_SchemeInfoId, f_Scheme, f_Id } = {}
this.wfdesign.custmerformSchemes[f_Id] = { f_Scheme }
if (this.node.formCode == f_SchemeInfoId) {
this.loadFormScheme(f_Scheme)
}
}
else {
this.loadFormScheme(this.wfdesign.custmerformSchemes[val.f_SchemeId].f_Scheme);
}
this.node.formVerison = val.f_SchemeId
},
async custmerformVerisonChange(val) {
this.$set(this.node, 'formRelationId', '')
if (this.$validatenull(val)) {
this.node.authFields = []
return
}
if (this.$validatenull(this.wfdesign.custmerformSchemes[val.value])) {
// const {f_Scheme,f_Id} = (await this.$awaitWraper(apiForm.getHistory(val.value))) || {}
const { f_Scheme, f_Id } = {}
this.wfdesign.custmerformSchemes[f_Id] = { f_Scheme }
if (this.node.formVerison == f_Id) {
this.loadFormScheme(f_Scheme)
}
}
else {
this.loadFormScheme(this.wfdesign.custmerformSchemes[val.value].f_Scheme);
}
},
loadFormScheme(strScheme) {
const scheme = JSON.parse(strScheme)
const fields = []
const rfields = []
scheme.formInfo.tabList.forEach(tab => {
tab.components.forEach(component => {
if (['guid'].includes(component.type)) {
rfields.push({ label: component.label, value: component.prop })
}
if (!['gridtable', 'divider'].includes(component.type) && component.display) {
fields.push({
prop: component.prop,
field: component.field,
label: component.label,
table: component.table,
required: component.required,
isEdit: true,
isLook: true
})
}
else if (['gridtable'].includes(component.type)) {
fields.push({
prop: `${component.prop}_add`,
label: `${component.label || '表格'}-添加按钮`,
required: false,
isEdit: true,
isLook: false,
type: 'grid'
})
fields.push({
prop: `${component.prop}_remove`,
label: `${component.label || '表格'}-删除按钮`,
required: false,
isEdit: true,
isLook: false,
type: 'grid'
})
fields.push({
prop: `${component.prop}_required`,
label: `${component.label || '表格'}-数据`,
required: component.required,
isEdit: false,
isLook: false,
type: 'gridrequired'
})
fields.push(...component.children.filter(t => t.display).map(t => {
return {
gridprop: component.prop,
prop: t.prop,
field: t.field,
label: `${component.label || '表格'}-${t.label}`,
table: component.table,
required: t.required,
isEdit: true,
isLook: true
}
}))
}
})
})
this.node.formRelations = rfields
this.node.authFields = fields
},
handleFormTypeChange() {
this.node.formCode = ''
this.node.formUrl = ''
this.node.formAppUrl = ''
this.node.authFields = []
this.node.formRelations = []
this.$set(this.node, 'formRelationId', '')
},
handleAddAuthField() {
this.node.authFields.push({
field: '',
label: '',
required: true,
isEdit: true,
isLook: true
})
},
handleDeleteAuthField(row) {
this.node.authFields.splice(row.index, 1);
},
handleTableBtnClick(btn) {
this.node.auditUsers.splice(btn.rowIndex, 1);
},
handleTableBtnClick2(btn) {
this.node.lookUsers.splice(btn.rowIndex, 1);
},
typeFormat(type) {
switch (type) {
case '1':
return '岗位'
case '2':
return '角色'
case '3':
return '用户'
case '4':
return '上下级'
case '5':
return '节点'
case '6':
return '表字段'
}
},
addTableData(selectData) {
if (this.isLooker) {
let addData2 = selectData.filter(t => this.node.lookUsers.findIndex(t2 => t2.id == t.id && t2.type == t.type) == -1);
this.node.lookUsers = this.node.lookUsers.concat(addData2);
}
else {
let addData = selectData.filter(t => this.node.auditUsers.findIndex(t2 => t2.id == t.id && t2.type == t.type) == -1);
this.node.auditUsers = this.node.auditUsers.concat(addData);
}
},
handlePostClick(isLooker) {
this.selectPostVisible = true;
this.isLooker = isLooker;
},
handlePostSelectClosed() {
this.$refs.postSelectPanel.resetForm();
},
handlePostSelectOk() {
let selectData = this.$refs.postSelectPanel.getForm().map(t => { return { type: '1', id: t.f_PostId, name: t.name } });
this.addTableData(selectData);
this.selectPostVisible = false;
},
handleRoleClick(isLooker) {
this.selectRoleVisible = true;
this.isLooker = isLooker;
},
handleRoleSelectClosed() {
this.$refs.roleSelectPanel.resetForm();
},
handleRoleSelectOk() {
let selectData = this.$refs.roleSelectPanel.getForm().map(t => { return { type: '2', id: t.f_RoleId, name: t.f_FullName, condition: '' } });
this.addTableData(selectData);
this.selectRoleVisible = false;
},
handleUserClick(isLooker) {
this.selectUserVisible = true;
this.isLooker = isLooker;
},
handleUserSelectClosed() {
this.$refs.userSelectPanel.resetForm();
},
handleUserSelectOk() {
let selectData = this.$refs.userSelectPanel.getForm().map(t => { return { type: '3', id: t.f_UserId, name: t.name } });
this.addTableData(selectData);
this.selectUserVisible = false;
},
handleLevelClick(isLooker) {
this.levelVisible = true;
this.isLooker = isLooker;
},
handleLevelClosed() {
this.$refs.auditorLevelForm.resetForm();
},
handleLevelOk() {
this.$refs.auditorLevelForm.validateForm(() => {
let data = this.$refs.auditorLevelForm.getForm();
this.addTableData([data]);
this.levelVisible = false;
});
},
handleNodeAuditorClick(isLooker) {
this.nodeAuditorVisible = true;
this.isLooker = isLooker;
},
handleNodeAuditorOk() {
this.$refs.nodeAuditorForm.validateForm(() => {
let data = this.$refs.nodeAuditorForm.getForm();
this.addTableData([data]);
this.nodeAuditorVisible = false;
});
},
handleNodeAuditorClosed() {
this.$refs.nodeAuditorForm.resetForm();
},
handleNodeAuditorOpened() {
let wfdata = this.wfdesign.handleGetWFData();
this.$refs.nodeAuditorForm.setForm(wfdata.filter(t => t.type = 'userTask' && t.id != this.node.id));
},
handleAuditorSqlClick(isLooker) {
this.auditorSqlVisible = true;
this.isLooker = isLooker;
},
handleAuditorSqlOk() {
this.$refs.auditorSqlForm.validateForm(() => {
let data = this.$refs.auditorSqlForm.getForm();
data.name = `${data.table}${data.auditorField}`
this.addTableData([data]);
this.auditorSqlVisible = false;
});
},
handleAuditorSqlClosed() {
this.$refs.auditorSqlForm.resetForm();
},
hasBtnsDeleteBtn(row) {
if (row.isSys) {
return false;
}
else {
return true;
}
},
handleAddBtns() {
this.node.btnlist.push({ code: '', name: '', hidden: false, isNextAuditor: false, isSign: false })
},
handleDeleteBtns(row) {
this.node.btnlist.splice(row.index, 1);
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,275 @@
<!--
* @Author: 刘妍
* @Date: 2024-03-05 17:09:44
* @LastEditors: Do not edit
* @LastEditTime: 2024-03-07 16:14:52
* @Description:
-->
<!-- 开始节点配置 -->
<template>
<div class="user-task">
<a-form ref="formRef" :rules="rules" :model="formState" labelAlign="left" :label-col="labelCol"
:wrapper-col="wrapperCol">
<a-collapse v-model:activeKey="activeKey" accordion ghost>
<a-collapse-panel key="1" header="基础配置">
<a-form-item label="节点标识">
<a-input v-model:value="node.id" placeholder="请输入" readonly />
</a-form-item>
<a-form-item label="继承表单">
<a-switch v-model:checked="node.isInherit" />
</a-form-item>
<a-form-item label="允许加签">
<a-switch v-model:checked="node.isAddSign" />
</a-form-item>
<a-form-item label="允许转移">
<a-switch v-model:checked="node.isBatchAudit" />
</a-form-item>
<a-form-item label="允许批量审核">
<a-switch v-model:checked="node.isBatchAudit" />
</a-form-item>
<a-form-item label="自动同意规则">
<a-select v-model:value="node.autoAgree" :options="data.atuoAgreeOptions">
</a-select>
</a-form-item>
<a-form-item label="无对应处理人">
<a-select v-model:value="node.rejectType"
:options="[{value:'1',label:'驳回节点固定'},{value:'2',label:'能驳回到任何执行过节点'}]">
</a-select>
</a-form-item>
<a-form-item label="驳回策略">
<a-radio-group v-model:value="node.rejectType" name="checkboxgroup"
:options="[{value:'1',label:'驳回节点固定'},{value:'2',label:'能驳回到任何执行过节点'}]" />
</a-form-item>
<a-form-item label="通知策略">
<a-checkbox-group v-model:value="node.messageType" name="checkboxgroup"
:options="[{value:'1',label:'短信'},{value:'2',label:'邮箱'},{value:'3',label:'微信'},{value:'4',label:'站内消息'}]" />
</a-form-item>
</a-collapse-panel>
<a-collapse-panel key="2" header="审核人员设置">
<a-space>
<a-radio-group size="small">
<a-radio-button value="1" @click="handlePostClick"></a-radio-button>
<a-radio-button value="2" @click="handleRoleClick"></a-radio-button>
<a-radio-button value="3" @click="handleAccountClick"></a-radio-button>
<a-radio-button value="3" @click="handleLevelClick"></a-radio-button>
<a-radio-button value="3" @click="handleNodeAuditorClick"></a-radio-button>
<a-radio-button value="3" @click="handleAuditorSqlClick"></a-radio-button>
</a-radio-group>
</a-space>
<a-table size="small" :columns="columns" :data-source="dataSource" bordered :pagination="false">
<template #bodyCell="{ column, text, record }">
<template v-if="['name', 'type'].includes(column.dataIndex)">
<div>
{{ text }}
</div>
</template>
<template v-else-if="column.dataIndex === 'operation'">
<a-popconfirm v-if="dataSource.length" title="Sure to delete?"
@confirm="onDelete(record.key)">
<a>Delete</a>
</a-popconfirm>
</template>
</template>
</a-table>
</a-collapse-panel>
<a-collapse-panel key="3" header="This is panel header 3">
<p>{{ text }}</p>
</a-collapse-panel>
<a-collapse-panel key="4" header="This is panel header 3">
<p>{{ text }}</p>
</a-collapse-panel>
<a-collapse-panel key="5" header="This is panel header 3">
<p>{{ text }}</p>
</a-collapse-panel>
<a-collapse-panel key="6" header="This is panel header 3">
<p>{{ text }}</p>
</a-collapse-panel>
</a-collapse>
</a-form>
<a-modal width="60%" v-model:open="data.postOpen" title="添加岗位" @ok="postHandleOk">
<SelectPos ref="posRef"></SelectPos>
</a-modal>
<a-modal width="60%" v-model:open="data.roleOpen" title="添加角色" @ok="roleHandleOk">
<SelectRole ref="roleRef"></SelectRole>
</a-modal>
<a-modal width="60%" v-model:open="data.accountOpen" title="添加角色" @ok="accountHandleOk">
<SelectAccount ref="accountRef"></SelectAccount>
</a-modal>
<a-modal width="60%" v-model:open="data.levelOpen" title="添加角色" @ok="accountHandleOk">
<AuditorLevel ref="levelRef"></AuditorLevel>
</a-modal>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref, onMounted, nextTick, unref } from 'vue';
import { BasicTree, TreeItem } from '@/components/Tree';
import SelectPos from '@/components/SelectPos/index.vue';
import SelectRole from '@/components/SelectRole/index.vue';
import SelectAccount from '@/components/SelectAccount/index.vue';
import AuditorLevel from './src/auditorLevel.vue'
import { getOrgPositonTree, userOrgs } from '@/api/demo/system';
const labelCol = { span: 7 };
const wrapperCol = { span: 17 };
const data = reactive({
activeKey: '1',
atuoAgreeOptions: [{ value: '1', label: '处理人就是提交人' }, { value: '2', label: '处理人和上一步的处理人相同' }, { value: '3', label: '处理人审批过' }],
postOpen: false,
roleOpen: false,
accountOpen: false,
levelOpen:false,
})
const node = reactive({
id: "edb713be-7a25-44a2-8048-1f9abc638680",
type: "userTask",
isAddSign: false,
isTransfer: false,
isBatchAudit: false,
autoAgree: "",
noAuditor: "1",
rejectType: "1",
messageType: "",
auditUsers: [],
lookUsers: [],
formRelations: [],
formType: "1",
formCode: "",
formVerison: "",
formRelationId: "",
formUrl: "",
formAppUrl: "",
authFields: [],
name: "审核节点",
btnlist: [
{
code: "agree",
name: "同意",
hidden: false,
isNextAuditor: false,
isSign: false,
isSys: true
},
{
code: "disagree",
name: "驳回",
hidden: false,
isNextAuditor: false,
isSign: false,
isSys: true
}
],
isCountersign: false,
isCountersignAll: false,
countersignAgian: "1",
countersignType: "1",
countersignAllType: 100,
isOvertimeMessage: false,
overtimeMessageType: "",
overtimeMessageStart: 1,
overtimeMessageInterval: 1,
overtimeGo: 12,
isInherit: true,
isInit: true
})
const columns = [
{
title: '名称',
dataIndex: 'name',
},
{
title: '类型',
dataIndex: 'type',
},
{
title: '操作',
dataIndex: 'operation',
},
];
const dataSource = [
{
id: 0,
name: "王五",
type: "管理员",
},
{
id: 1,
name: "王五",
type: "管理员",
},
]
//
const posRef = ref < any > ()
function handlePostClick() {
data.postOpen = true;
}
function postHandleOk() {
console.log(posRef.value.getRow())
}
//
const roleRef = ref < any > ()
function handleRoleClick() {
data.roleOpen = true;
}
function roleHandleOk() {
console.log(roleRef.value.getRow())
}
//
const accountRef = ref < any > ()
function handleAccountClick() {
data.accountOpen = true;
}
function accountHandleOk() {
console.log(accountRef.value.getRow())
}
//
const levelRef = ref < any > ()
function handleLevelClick() {
data.levelOpen = true;
}
function levelHandleOk() {
console.log(levelRef.value.getRow())
}
</script>
<style lang="less" scoped>
.site-space-compact-wrapper {
width: 100%;
.ant-select {
width: 100%;
}
}
::v-deep .ant-tabs {
padding: 0 !important;
}
::v-deep .ant-space {
width: 90%;
margin-left: 5%;
.ant-space-item {
width: 100%;
button {
width: 100%;
}
}
}
::v-deep .ant-table-content {
margin-top: 10px;
}
</style>

View File

@ -0,0 +1,50 @@
<template>
<div class="l-from-body">
<a-form ref="formRef" :rules="data.rules" :model="data.formData" labelAlign="left" :label-col="labelCol"
:wrapper-col="wrapperCol">
<a-form-item label="上下级" name="id">
<a-select v-model:value="data.formData.id" placeholder="请选择上下级" :options="data.options">
</a-select>
</a-form-item>
</a-form>
</div>
</template>
<script lang="ts" setup>
import {reactive} from 'vue'
const data = reactive({
formData: {
name: '',
type: '4',
id: '',
},
rules: {
id: [
{ required: true, message: '请选择上下级' }
]
},
options: [
{ value: '1', label: '上一级' },
{ value: '2', label: '上二级' },
{ value: '3', label: '上三级' },
{ value: '4', label: '上四级' },
{ value: '5', label: '上五级' },
{ value: '6', label: '下一级' },
{ value: '7', label: '下二级' },
{ value: '8', label: '下三级' },
{ value: '9', label: '下四级' },
{ value: '10', label: '下五级' }
]
})
function getRow() {
let rows = data.value.formData
return rows
}
defineExpose({
getRow
})
</script>
<style scoped>
.l-from-body{
padding: 10px;
}
</style>

View File

@ -0,0 +1,56 @@
<template>
<div class="l-from-body" >
<el-form :model="formData" :rules="rules" size="mini" ref="form" label-width="80px" >
<el-col :span="24">
<el-form-item label="节点" prop="id">
<l-select v-model="formData.id" placeholder="请选择节点" valueKey="id" labelKey="name" :options="options" @change="handleChange" ></l-select>
</el-form-item>
</el-col>
</el-form>
</div>
</template>
<script>
export default {
name:'node-auditor-form',
data(){
return {
formData:{
name:'',
type:'5',
id:'',
},
rules: {
id: [
{ required: true, message: '请选择节点' }
]
},
options: []
};
},
created () {
},
methods:{
resetForm(){
this.$refs.form && this.$refs.form.resetFields();
},
//
validateForm(callback){
this.$refs.form.validate((valid) => {
if(valid){
callback();
}
});
},
setForm(wfdata){
//console.log(wfdata,'')
this.options = wfdata.filter(t=>t.name);
},
getForm(){
return this.$deepClone(this.formData);
},
handleChange(val){
this.formData.name = this.options.find(t=>t.id == val).name;
}
}
}
</script>

View File

@ -0,0 +1,104 @@
<template>
<div class="l-from-body" >
<el-form :model="formData" :rules="rules" size="mini" ref="form" label-width="120px" >
<el-col :span="24">
<el-form-item label="数据库" prop="dbCode">
<el-select v-model="formData.dbCode" placeholder="请选择">
<el-option-group
v-for="group in lr_dblinkTree"
:key="group.id"
:label="group.label">
<el-option
v-for="item in group.children"
:key="item.id"
:label="item.label"
:value="item.id">
</el-option>
</el-option-group>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="数据表" prop="table">
<l-codetable-select
@change="handleTableChange"
:dbCode="formData.dbCode"
v-model="formData.table"></l-codetable-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="关联流程字段" prop="rfield">
<l-select :options="columns" valueKey="name" labelKey="coment" v-model="formData.rfield" >
</l-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="审核人字段" prop="auditorField">
<l-select :options="columns" valueKey="name" labelKey="coment" v-model="formData.auditorField" >
</l-select>
</el-form-item>
</el-col>
</el-form>
</div>
</template>
<script>
export default {
name:'auditor-sql-form',
props:{
},
data(){
return {
formData:{
dbCode:'',
table:'',
rfield:'',
auditorField:'',
type:'6'
},
rules: {
dbCode: [
{ required: true, message: '请选择数据库' }
],
table: [
{ required: true, message: '请选择数据表' }
],
rfield: [
{ required: true, message: '请选择关联字段' }
],
auditorField: [
{ required: true, message: '请选择审核人字段' }
]
},
columns:[],
};
},
computed:{
},
created () {
},
methods:{
handleTableChange(table){
this.columns = table.columns
},
resetForm(){
this.columns = [];
this.$refs.form && this.$refs.form.resetFields()
},
//
validateForm(callback){
this.$refs.form.validate((valid) => {
if(valid){
callback()
}
});
},
setForm(data){
this.formData = this.$deepClone(data)
},
getForm(){
let formData = this.$deepClone(this.formData)
return formData
}
}
}
</script>

View File

@ -0,0 +1,63 @@
/* 改变主题色变量 */
// $--color-primary: #1890ff;
// $--color-danger: #ff4d4f;
/* 改变 icon 字体路径变量,必需 */
.process-drawer .el-drawer__header {
padding: 16px 16px 8px 16px;
margin: 0;
line-height: 24px;
font-size: 18px;
color: #303133;
box-sizing: border-box;
border-bottom: 1px solid #e8e8e8;
}
div[class^="el-drawer"]:focus,
span:focus {
outline: none;
}
.process-drawer .el-drawer__body {
box-sizing: border-box;
padding: 16px;
width: 100%;
overflow-y: auto;
}
.process-design {
.el-table td,
.el-table th {
color: #333;
}
.el-dialog__header {
padding: 16px 16px 8px 16px;
box-sizing: border-box;
border-bottom: 1px solid #e8e8e8;
}
.el-dialog__body {
padding: 16px;
max-height: 80vh;
box-sizing: border-box;
overflow-y: auto;
}
.el-dialog__footer {
padding: 16px;
box-sizing: border-box;
border-top: 1px solid #e8e8e8;
}
.el-dialog__close {
font-weight: 600;
}
.el-select {
width: 100%;
}
.el-divider:not(.el-divider--horizontal) {
margin: 0 8px ;
}
.el-divider.el-divider--horizontal {
margin: 16px 0;
}
}

View File

@ -0,0 +1,171 @@
@import "./flow-element-variables.scss";
@import "bpmn-js-token-simulation/assets/css/bpmn-js-token-simulation.css";
// @import "bpmn-js-token-simulation/assets/css/font-awesome.min.css";
// @import "bpmn-js-token-simulation/assets/css/normalize.css";
@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 "./process-designer.scss";
@import "./process-panel.scss";
$success-color: #4eb819;
$primary-color: #409EFF;
$warning-color: #E6A23C;
$danger-color: #F56C6C;
$cancel-color: #909399;
.process-viewer {
position: relative;
border: 1px solid #EFEFEF;
background: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PHBhdHRlcm4gaWQ9ImEiIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgcGF0dGVyblVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGggZD0iTTAgMTBoNDBNMTAgMHY0ME0wIDIwaDQwTTIwIDB2NDBNMCAzMGg0ME0zMCAwdjQwIiBmaWxsPSJub25lIiBzdHJva2U9IiNlMGUwZTAiIG9wYWNpdHk9Ii4yIi8+PHBhdGggZD0iTTQwIDBIMHY0MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZTBlMGUwIi8+PC9wYXR0ZXJuPjwvZGVmcz48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2EpIi8+PC9zdmc+') repeat!important;
.success-arrow {
fill: $success-color;
stroke: $success-color;
}
.success-conditional {
fill: white;
stroke: $success-color;
}
.fail-arrow {
fill: $warning-color;
stroke: $warning-color;
}
.fail-conditional {
fill: white;
stroke: $warning-color;
}
.success.djs-connection {
.djs-visual path {
stroke: $success-color!important;
marker-end: url(#sequenceflow-end-white-success)!important;
}
}
.success.djs-connection.condition-expression {
.djs-visual path {
marker-start: url(#conditional-flow-marker-white-success)!important;
}
}
.success.djs-shape {
.djs-visual rect {
stroke: $success-color!important;
fill: $success-color!important;
fill-opacity: 0.15!important;
}
.djs-visual polygon {
stroke: $success-color!important;
}
.djs-visual path:nth-child(2) {
stroke: $success-color!important;
fill: $success-color!important;
}
.djs-visual circle {
stroke: $success-color!important;
fill: $success-color!important;
fill-opacity: 0.15!important;
}
}
.primary.djs-shape {
.djs-visual rect {
stroke: $primary-color!important;
fill: $primary-color!important;
fill-opacity: 0.15!important;
}
.djs-visual polygon {
stroke: $primary-color!important;
}
.djs-visual circle {
stroke: $primary-color!important;
fill: $primary-color!important;
fill-opacity: 0.15!important;
}
}
.warning.djs-connection {
.djs-visual path {
stroke: $warning-color!important;
marker-end: url(#sequenceflow-end-white-fail)!important;
}
}
.warning.djs-connection.condition-expression {
.djs-visual path {
marker-start: url(#conditional-flow-marker-white-fail)!important;
}
}
.warning.djs-shape {
.djs-visual rect {
stroke: $warning-color!important;
fill: $warning-color!important;
fill-opacity: 0.15!important;
}
.djs-visual polygon {
stroke: $warning-color!important;
}
.djs-visual path:nth-child(2) {
stroke: $warning-color!important;
fill: $warning-color!important;
}
.djs-visual circle {
stroke: $warning-color!important;
fill: $warning-color!important;
fill-opacity: 0.15!important;
}
}
.danger.djs-shape {
.djs-visual rect {
stroke: $danger-color!important;
fill: $danger-color!important;
fill-opacity: 0.15!important;
}
.djs-visual polygon {
stroke: $danger-color!important;
}
.djs-visual circle {
stroke: $danger-color!important;
fill: $danger-color!important;
fill-opacity: 0.15!important;
}
}
.cancel.djs-shape {
.djs-visual rect {
stroke: $cancel-color!important;
fill: $cancel-color!important;
fill-opacity: 0.15!important;
}
.djs-visual polygon {
stroke: $cancel-color!important;
}
.djs-visual circle {
stroke: $cancel-color!important;
fill: $cancel-color!important;
fill-opacity: 0.15!important;
}
}
}
.process-viewer .djs-tooltip-container, .process-viewer .djs-overlay-container, .process-viewer .djs-palette {
display: none;
}

View File

@ -0,0 +1,153 @@
// token-simulation
.djs-palette {
background: var(--palette-background-color);
border: solid 1px var(--palette-border-color) !important;
border-radius: 2px;
}
.my-process-designer {
padding: 5px 0 10px 10px;
display: flex;
flex-direction: column;
width: 70%;
height: 100%;
box-sizing: border-box;
.my-process-designer__header {
width: 100%;
min-height: 36px;
.el-button {
text-align: center;
}
.el-button-group {
margin: 4px;
}
.el-tooltip__popper {
.el-button {
width: 100%;
text-align: left;
padding-left: 8px;
padding-right: 8px;
}
.el-button:hover {
background: rgba(64, 158, 255, 0.8);
color: #ffffff;
}
}
.align {
position: relative;
i {
&:after {
content: "|";
position: absolute;
transform: rotate(90deg) translate(200%, 60%);
}
}
}
.align.align-left i {
transform: rotate(90deg);
}
.align.align-right i {
transform: rotate(-90deg);
}
.align.align-top i {
transform: rotate(180deg);
}
.align.align-bottom i {
transform: rotate(0deg);
}
.align.align-center i {
transform: rotate(90deg);
&:after {
transform: rotate(90deg) translate(0, 60%);
}
}
.align.align-middle i {
transform: rotate(0deg);
&:after {
transform: rotate(90deg) translate(0, 60%);
}
}
}
.my-process-designer__container {
display: inline-flex;
width: 100%;
flex: 1;
.my-process-designer__canvas {
flex: 1;
height: 100%;
position: relative;
background: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PHBhdHRlcm4gaWQ9ImEiIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgcGF0dGVyblVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHBhdGggZD0iTTAgMTBoNDBNMTAgMHY0ME0wIDIwaDQwTTIwIDB2NDBNMCAzMGg0ME0zMCAwdjQwIiBmaWxsPSJub25lIiBzdHJva2U9IiNlMGUwZTAiIG9wYWNpdHk9Ii4yIi8+PHBhdGggZD0iTTQwIDBIMHY0MCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZTBlMGUwIi8+PC9wYXR0ZXJuPjwvZGVmcz48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2EpIi8+PC9zdmc+")
repeat !important;
div.toggle-mode {
display: none;
}
}
.my-process-designer__property-panel {
height: 100%;
overflow: scroll;
overflow-y: auto;
z-index: 10;
* {
box-sizing: border-box;
}
}
svg {
width: 100%;
height: 100%;
min-height: 100%;
overflow: hidden;
}
}
}
//
.djs-palette.open {
.djs-palette-entries {
div[class^="bpmn-icon-"]:before,
div[class*="bpmn-icon-"]:before {
line-height: unset;
}
div.entry {
position: relative;
}
div.entry:hover {
&::after {
width: max-content;
content: attr(title);
vertical-align: text-bottom;
position: absolute;
right: -10px;
top: 0;
bottom: 0;
overflow: hidden;
transform: translateX(100%);
font-size: 0.5em;
display: inline-block;
text-decoration: inherit;
font-variant: normal;
text-transform: none;
background: #fafafa;
box-shadow: 0 0 6px #eeeeee;
border: 1px solid #cccccc;
box-sizing: border-box;
padding: 0 16px;
border-radius: 4px;
z-index: 100;
}
}
}
}
pre {
margin: 0;
height: 100%;
overflow: hidden;
max-height: calc(80vh - 32px);
overflow-y: auto;
}
.hljs {
word-break: break-word;
white-space: pre-wrap;
}
.hljs * {
font-family: Consolas, Monaco, monospace;
}

View File

@ -0,0 +1,110 @@
.process-design {
.process-panel__container {
box-sizing: border-box;
padding: 0 8px;
border-left: 1px solid #eeeeee;
box-shadow: 0 0 8px #cccccc;
max-height: 100%;
overflow-y: scroll;
}
.panel-tab__title {
font-weight: 600;
padding: 0 8px;
font-size: 1.1em;
line-height: 1.2em;
i {
margin-right: 8px;
font-size: 1.2em;
}
}
.panel-tab__content {
width: 100%;
box-sizing: border-box;
border-top: 1px solid #eeeeee;
padding: 8px 16px;
.panel-tab__content--title {
display: flex;
justify-content: space-between;
padding-bottom: 8px;
span {
flex: 1;
text-align: left;
}
}
}
.element-property {
width: 100%;
display: flex;
align-items: flex-start;
margin: 8px 0;
.element-property__label {
display: block;
width: 90px;
text-align: right;
overflow: hidden;
padding-right: 12px;
line-height: 32px;
font-size: 14px;
box-sizing: border-box;
}
.element-property__value {
flex: 1;
line-height: 32px;
}
.el-form-item {
width: 100%;
margin-bottom: 0;
padding-bottom: 18px;
}
}
.list-property {
flex-direction: column;
.element-listener-item {
width: 100%;
display: inline-grid;
grid-template-columns: 16px auto 32px 32px;
grid-column-gap: 8px;
}
.element-listener-item + .element-listener-item {
margin-top: 8px;
}
}
.listener-filed__title {
display: inline-flex;
width: 100%;
justify-content: space-between;
align-items: center;
margin-top: 0;
span {
width: 200px;
text-align: left;
font-size: 14px;
}
i {
margin-right: 8px;
}
}
.element-drawer__button {
margin-top: 8px;
width: 100%;
display: inline-flex;
justify-content: space-around;
}
.element-drawer__button > .el-button {
width: 100%;
}
.el-collapse-item__content {
padding-bottom: 0;
}
.el-input.is-disabled .el-input__inner {
color: #999999;
}
.el-form-item.el-form-item--mini {
margin-bottom: 0;
& + .el-form-item {
margin-top: 16px;
}
}
}

View File

@ -0,0 +1,69 @@
// 创建监听器实例
export function createListenerObject(options, isTask, prefix) {
const listenerObj = Object.create(null);
listenerObj.event = options.event;
// isTask && (listenerObj.id = options.id); // 任务监听器特有的 id 字段
switch (options.listenerType) {
case "scriptListener":
listenerObj.script = createScriptObject(options, prefix);
break;
case "expressionListener":
listenerObj.expression = options.expression;
break;
case "delegateExpressionListener":
listenerObj.delegateExpression = options.delegateExpression;
break;
default:
listenerObj.class = options.class;
}
// 注入字段
if (options.fields) {
listenerObj.fields = options.fields.map(field => {
return createFieldObject(field, prefix);
});
}
// 任务监听器的 定时器 设置
if (isTask && options.event === "timeout" && !!options.eventDefinitionType) {
const timeDefinition = window.bpmnInstances.moddle.create("bpmn:FormalExpression", { body: options.eventTimeDefinitions });
const TimerEventDefinition = window.bpmnInstances.moddle.create("bpmn:TimerEventDefinition", {
id: `TimerEventDefinition_${uuid(8)}`,
[`time${options.eventDefinitionType.replace(/^\S/, s => s.toUpperCase())}`]: timeDefinition
});
listenerObj.eventDefinitions = [TimerEventDefinition];
}
return window.bpmnInstances.moddle.create(`${prefix}:${isTask ? "TaskListener" : "ExecutionListener"}`, listenerObj);
}
// 创建 监听器的注入字段 实例
export function createFieldObject(option, prefix) {
const { name, fieldType, string, expression } = option;
const fieldConfig = fieldType === "string" ? { name, string } : { name, expression };
return window.bpmnInstances.moddle.create(`${prefix}:Field`, fieldConfig);
}
// 创建脚本实例
export function createScriptObject(options, prefix) {
const { scriptType, scriptFormat, value, resource } = options;
const scriptConfig = scriptType === "inlineScript" ? { scriptFormat, value } : { scriptFormat, resource };
return window.bpmnInstances.moddle.create(`${prefix}:Script`, scriptConfig);
}
// 更新元素扩展属性
export function updateElementExtensions(element, extensionList) {
const extensions = window.bpmnInstances.moddle.create("bpmn:ExtensionElements", {
values: extensionList
});
window.bpmnInstances.modeling.updateProperties(element, {
extensionElements: extensions
});
}
// 创建一个id
export function uuid(length = 8, chars) {
let result = "";
let charsString = chars || "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (let i = length; i > 0; --i) {
result += charsString[Math.floor(Math.random() * charsString.length)];
}
return result;
}

View File

@ -0,0 +1,38 @@
<!--
* @Author: 刘妍
* @Date: 2024-03-07 10:43:34
* @LastEditors: Do not edit
* @LastEditTime: 2024-03-07 10:49:15
* @Description:
-->
<template>
<div class="m-4 mr-0 overflow-hidden bg-white">
<BasicTree title="部门列表" toolbar treeWrapperClassName="h-[calc(100%-35px)] overflow-auto" loadData
:clickRowToExpand="false" :treeData="treeData" :fieldNames="{ key: 'id', title: 'name' }"
@select="handleSelect" />
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import { BasicTree, TreeItem } from '@/components/Tree';
import { getDeptList } from '@/api/demo/system';
defineOptions({ name: 'DeptTree' });
const emit = defineEmits(['select']);
const treeData = ref < TreeItem[] > ([]);
async function fetch() {
treeData.value = (await getDeptList()) as unknown as TreeItem[];
}
function handleSelect(keys) {
emit('select', keys[0]);
}
onMounted(() => {
fetch();
});
</script>

View File

@ -0,0 +1,55 @@
/*
* @Author:
* @Date: 2024-03-07 10:43:34
* @LastEditors: Do not edit
* @LastEditTime: 2024-03-07 10:48:39
* @Description:
*/
import { getAllRoleList, isAccountExist } from '@/api/demo/system';
import { BasicColumn, FormSchema } from '@/components/Table';
/**
* transform mock data
* {
* 0: '华东分部',
* '0-0': '华东分部-研发部'
* '0-1': '华东分部-市场部',
* ...
* }
*/
export const columns: BasicColumn[] = [
{
title: '用户名',
dataIndex: 'account',
width: 120,
},
{
title: '昵称',
dataIndex: 'name',
width: 120,
},
{
title: '所属部门',
dataIndex: 'organizations',
// customRender: ({ value }) => {
// return deptMap[value];
// },
},
];
export const searchFormSchema: FormSchema[] = [
{
field: 'account',
label: '用户名',
component: 'Input',
colProps: { span: 8 },
},
{
field: 'nickname',
label: '昵称',
component: 'Input',
colProps: { span: 8 },
},
];

View File

@ -0,0 +1,66 @@
<!--
* @Author: 刘妍
* @Date: 2024-03-07 10:43:34
* @LastEditors: Do not edit
* @LastEditTime: 2024-03-07 10:56:46
* @Description:
-->
<template>
<!-- <PageWrapper dense contentFullHeight fixedHeight contentClass="flex"> -->
<div class="select-account">
<DeptTree class="w-1/4 xl:w-1/5" @select="handleSelect" />
<BasicTable @register="registerTable" class="w-3/4 xl:w-4/5" :searchInfo="searchInfo"> </BasicTable>
</div>
<!-- </PageWrapper> -->
</template>
<script lang="ts" setup>
import { reactive } from 'vue';
import { BasicTable, useTable, TableAction } from '@/components/Table';
import { getAccountList, deleteAccount } from '@/api/demo/system';
import { PageWrapper } from '@/components/Page';
import DeptTree from './DeptTree.vue';
import { useMessage } from '/@/hooks/web/useMessage';
import { columns, searchFormSchema } from './account.data';
defineOptions({ name: 'AccountManagement' });
const searchInfo = reactive < Recordable > ({});
const [registerTable, { reload, updateTableDataRecord, getSelectRows, clearSelectedRowKeys }] = useTable({
title: '账号列表',
api: getAccountList,
rowKey: 'id',
columns,
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
autoSubmitOnEnter: true,
},
rowSelection: {//
type: 'checkbox',
},
useSearchForm: true,
showTableSetting: false,
bordered: true,
tableSetting: { fullScreen: true },
isCanResizeParent: true,
handleSearchInfoFn(info) {
console.log('handleSearchInfoFn', info);
return info;
},
});
function getRow() {
let rows = getSelectRows();
return rows
}
defineExpose({
getRow
})
</script>
<style scoped>
.select-account{
display: flex;
}
</style>

View File

@ -0,0 +1,82 @@
<!--
* @Author: 刘妍
* @Date: 2024-03-07 10:00:26
* @LastEditors: Do not edit
* @LastEditTime: 2024-03-07 15:37:30
* @Description:
-->
<template>
<div>
<BasicTree ref="asyncExpandTreeRef" title="部门和职级列表" toolbar treeWrapperClassName="h-[calc(100%-35px)] overflow-auto"
loadData :clickRowToExpand="false" :treeData="treeData"
:fieldNames="{ key: 'id', title: 'name' ,disabled:'disabled'}" :defaultExpandAll="true" :checkable="true"
:checkStrictly="true" @check="handleSelect" />
</div>
</template>
<script lang="ts" setup>
import { reactive, ref, onMounted, nextTick, unref } from 'vue';
import { BasicTree, TreeItem } from '@/components/Tree';
import { getOrgPositonTree, userOrgs } from '@/api/demo/system';
defineOptions({ name: 'RoleManagement' });
const treeData = ref < TreeItem[] > ([]);
const asyncExpandTreeRef = ref < Nullable < TreeActionType >> (null);
const posData = ref([])
function treeIterator(tree) {
tree.forEach((node) => {
if (node.key == 0) {
node.name = "部门--" + node.name
node.disableCheckbox = true
} else {
node.name = "职级--" + node.name
// parentName
posData.value.push(node)
}
node.children && treeIterator(node.children)
})
}
async function fetch() {
const data = (await getOrgPositonTree()) as unknown as TreeItem[];
treeIterator(data)
treeData.value = await data
//
nextTick(() => {
unref(asyncExpandTreeRef)?.expandAll(true);
});
}
onMounted(() => {
fetch();
});
let orgList = ref([])
let posList = ref([])
function handleSelect(checkedKeys, e: { checked: bool, checkedNodes, node, event }) {
const list = e.checkedNodes
console.log(e.node)
console.log(checkedKeys)
orgList.value = []
posList.value = []
list.forEach(element => {
if (element.key > 0) {
posList.value.push({
orgId: Number(element.tag),
posId: element.id,
})
} else {
orgList.value.push({
orgId: element.id,
posId: 0,
})
}
});
}
function getRow() {
let rows = getSelectRows();
return rows
}
defineExpose({
getRow
})
</script>

View File

@ -0,0 +1,79 @@
<!--
* @Author: 刘妍
* @Date: 2024-03-07 10:00:26
* @LastEditors: Do not edit
* @LastEditTime: 2024-03-07 10:50:39
* @Description:
-->
<template>
<div>
<BasicTable @register="registerTable" :searchInfo="searchInfo"> </BasicTable>
</div>
</template>
<script lang="ts" setup>
import { reactive, } from 'vue';
import { BasicTable, useTable, TableAction } from '@/components/Table';
import { getRoleListByPage, deleteRole } from '@/api/demo/system';
defineOptions({ name: 'RoleManagement' });
const searchInfo = reactive < Recordable > ({});
const [registerTable, { reload, getSelectRows, clearSelectedRowKeys }] = useTable({
//
title: '角色列表',
//
api: getRoleListByPage,
// BasicColumn[]
columns: [
{
title: '角色名称',
dataIndex: 'name',
width: 200,
},
{
title: '创建时间',
dataIndex: 'createTime',
width: 180,
},
],
rowKey: 'id',
formConfig: {
labelWidth: 120,
schemas: [{
field: 'key',
label: '关键字',
component: 'Input',
colProps: { span: 8 },
}],
},
// 使
useSearchForm: true,
//
showTableSetting: false,
//
bordered: true,
//
showIndexColumn: false,
//
rowSelection: {//
type: 'checkbox',
},
tableSetting: { fullScreen: true },
isCanResizeParent: true,
//
handleSearchInfoFn(info) {
return info;
},
});
function getRow() {
let rows = getSelectRows();
return rows
}
defineExpose({
getRow
})
</script>

View File

@ -3,7 +3,6 @@
* @Date: 2024-01-13 13:04:15
* @LastEditors: Do not edit
* @LastEditTime: 2024-01-19 14:50:22
* @FilePath: \e:\\vue-vben-admin\src\enums\httpEnum.ts
* @Description:
*/
/**

View File

@ -176,5 +176,8 @@
"authColumn": "权限列",
"resizeParentHeightTable": "继承父元素高度",
"vxeTable": "VxeTable"
},
"workflow":{
"scheme_preview":"流程模板设计"
}
}

View File

@ -2,8 +2,7 @@
* @Author:
* @Date: 2024-01-13 13:04:15
* @LastEditors: Do not edit
* @LastEditTime: 2024-01-25 13:24:08
* @FilePath: \e:\\vue-vben-admin\src\main.ts
* @LastEditTime: 2024-03-06 10:56:44
* @Description:
*/
import 'uno.css';
@ -34,16 +33,25 @@ import App from './App.vue';
import "mars3d-cesium/Build/Cesium/Widgets/widgets.css"
import "mars3d/dist/mars3d.css"
import MarsUIInstall from "@/mars/components/mars-ui"
import "@/mars/components/mars-ui/common"
import 'bpmn-js/dist/assets/diagram-js.css';
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';
import Antd from "ant-design-vue"
async function bootstrap() {
const app = createApp(App);
app.use(Antd)
// Configure store
// 配置 store
setupStore(app);
// Initialize internal system configuration
// 初始化内部系统配置
initAppConfigStore();

View File

@ -3,7 +3,6 @@
* @Date: 2024-01-17 15:24:04
* @LastEditors: Do not edit
* @LastEditTime: 2024-01-18 08:41:32
* @FilePath: \费县天空地大屏正式代码e:\新架构\vue-vben-admin\src\mars\components\mars-work\main-view.vue
* @Description:
-->
<!--

View File

@ -3,7 +3,6 @@
* @Date: 2024-01-17 15:24:04
* @LastEditors: Do not edit
* @LastEditTime: 2024-01-18 08:40:39
* @FilePath: \费县天空地大屏正式代码e:\新架构\vue-vben-admin\src\mars\views\index.vue
* @Description:
-->
<template>

View File

@ -3,7 +3,6 @@
* @Date: 2024-01-13 13:04:15
* @LastEditors: Do not edit
* @LastEditTime: 2024-01-25 09:30:23
* @FilePath: \e:\\vue-vben-admin\src\router\routes\index.ts
* @Description:
*/
import type { AppRouteRecordRaw, AppRouteModule } from '@/router/types';

View File

@ -1,3 +1,10 @@
/*
* @Author:
* @Date: 2024-01-13 13:04:15
* @LastEditors: Do not edit
* @LastEditTime: 2024-03-01 14:24:28
* @Description:
*/
import type { AppRouteModule } from '@/router/types';
import { LAYOUT } from '@/router/constant';
@ -23,6 +30,18 @@ const dashboard: AppRouteModule = {
title: t('routes.dashboard.analysis'),
},
},
{
path: 'scheme_preview/:id',
name: 'AccountDetail',
meta: {
hideMenu: true,
title: t('routes.demo.workflow.scheme_preview'),
ignoreKeepAlive: true,
showMenu: false,
currentActiveMenu: '/workflow/scheme',
},
component: () => import('@/views/demo/workflow/scheme/preview.vue'),
},
],
};

View File

@ -3,7 +3,6 @@
* @Date: 2024-01-13 13:04:15
* @LastEditors: Do not edit
* @LastEditTime: 2024-01-22 08:55:09
* @FilePath: \e:\\vue-vben-admin\src\utils\http\axios\helper.ts
* @Description:
*/
import { isObject, isString } from '@/utils/is';

View File

@ -3,7 +3,6 @@
* @Date: 2024-01-16 13:48:53
* @LastEditors: Do not edit
* @LastEditTime: 2024-01-17 16:53:26
* @FilePath: \费县天空地大屏正式代码e:\新架构\vue-vben-admin\src\views\demo\charts\mars3d\index.vue
* @Description:
-->
<template>

View File

@ -3,7 +3,6 @@
* @Date: 2024-01-27 10:58:29
* @LastEditors: Do not edit
* @LastEditTime: 2024-01-27 14:15:31
* @FilePath: \费县天空地大屏正式代码e:\新架构\vue-vben-admin\src\views\demo\system\account\AssignRoleModal.vue
* @Description:
-->
<template>

View File

@ -3,7 +3,6 @@
* @Date: 2024-01-29 08:58:01
* @LastEditors: Do not edit
* @LastEditTime: 2024-01-30 08:44:07
* @FilePath: \费县天空地大屏正式代码e:\新架构\vue-vben-admin\src\views\demo\system\account\OrgPositonModal.vue
* @Description:
-->
<template>

View File

@ -0,0 +1,84 @@
<template>
<BasicDrawer v-bind="$attrs" @register="registerDrawer" showFooter :title="getTitle" width="50%" @ok="handleSubmit">
<BasicForm @register="registerForm" />
</BasicDrawer>
</template>
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicForm, useForm } from '@/components/Form';
import { formSchema } from './menu.data';
import { BasicDrawer, useDrawerInner } from '@/components/Drawer';
import { getMenuList, addMenu, editMenu, addButton, editButton } from '@/api/demo/system';
defineOptions({ name: 'MenuDrawer' });
const emit = defineEmits(['success', 'register']);
const isUpdate = ref(true);
const [registerForm, { resetFields, setFieldsValue, updateSchema, validate }] = useForm({
labelWidth: 100,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { lg: 12, md: 24 },
});
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
resetFields();
setDrawerProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
setFieldsValue({
...data.record,
});
}
const treeData = await getMenuList();
updateSchema({
field: 'parentId',
componentProps: { treeData },
});
updateSchema({
field: 'moduleId',
componentProps: { treeData },
});
});
const getTitle = computed(() => (!unref(isUpdate) ? '新增菜单' : '编辑菜单'));
async function handleSubmit() {
try {
const values = await validate();
setDrawerProps({ confirmLoading: true });
// TODO custom api
console.log(values)
if (values.type == '1') {
console.log("新增菜单")
delete values.type
//
if (!unref(isUpdate)) {
const data = await addMenu(values);
} else {
const data = await editMenu(values);
}
closeDrawer();
emit('success');
} else {
console.log("新增按钮")
//
delete values.type
if (!unref(isUpdate)) {
const data = await addButton(values);
} else {
const data = await editButton(values);
}
closeDrawer();
emit('success');
}
} finally {
setDrawerProps({ confirmLoading: false });
}
}
</script>

View File

@ -0,0 +1,95 @@
<template>
<div class="m-4 mr-0 overflow-hidden bg-white">
<BasicTree ref="asyncExpandTreeRef" title="菜单列表" toolbar search
treeWrapperClassName="h-[calc(100%-35px)] overflow-auto" loadData :actionList="actionList"
:renderIcon="createIcon" :clickRowToExpand="false" :treeData="treeData" :fieldNames="{ key: 'id', title: 'name' }"
:defaultExpandAll="true" @select="handleSelect" />
<BasicModal @register="register" title="删除" :helpMessage="['提示1', '提示2']" @ok="handleSubmit">
确认要删除菜单吗
</BasicModal>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref, h, nextTick, unref } from 'vue';
import { BasicTree, TreeItem, TreeActionItem } from '@/components/Tree';
import { getMenuList, deleteMenu } from '@/api/demo/system';
import { FormOutlined, DeleteOutlined } from '@ant-design/icons-vue';
import { BasicModal, useModal } from '@/components/Modal';
import { router } from '@/router';
const [register, { closeModal, openModal }] = useModal();
defineOptions({ name: 'DeptTree' });
const emit = defineEmits(['select', 'edit']);
const treeData = ref < TreeItem[] > ([]);
let selectItemId = ref('')
const asyncExpandTreeRef = ref < Nullable < TreeActionType >> (null);
async function handleSubmit() {
var query = [selectItemId.value]
const data = await deleteMenu(query);
closeModal();
}
async function fetch() {
treeData.value = (await getMenuList()) as unknown as TreeItem[];
//
nextTick(() => {
unref(asyncExpandTreeRef)?.expandAll(true);
});
}
function handleSelect(keys) {
emit('select', keys[0]);
}
const btnList = router.currentRoute.value.meta.elements
const actionList: TreeActionItem[] = []
btnList.forEach(element => {
if (element.domId == 'btnEdit') {
actionList.push({
render: (node) => {
return h(FormOutlined, {
class: 'ml-2',
onClick: () => {
emit('edit', node);
},
});
},
})
} else if (element.domId == 'btnDelete') {
actionList.push({
render: (node) => {
return h(DeleteOutlined, {
class: 'ml-2',
onClick: () => {
selectItemId.value = node.id
openModal(true, {
isUpdate: false,
});
},
});
},
})
}
});
function createIcon({ level }) {
if (level === 1) {
return 'ion:git-compare-outline';
}
if (level === 2) {
return 'ion:home';
}
if (level === 3) {
return 'ion:airplane';
}
return '';
}
onMounted(() => {
fetch();
});
defineExpose({
fetch
})
</script>

View File

@ -0,0 +1,135 @@
<template>
<PageWrapper dense contentFullHeight fixedHeight contentClass="flex">
<MenuTree ref="childRef" class="w-1/4 xl:w-1/5" @select="handleSelect" @edit="editMenu" />
<BasicTable class="w-3/4 xl:w-4/5" @register="registerTable" @fetch-success="onFetchSuccess"
:searchInfo="searchInfo">
<template #toolbar>
<!-- <a-button type="primary" @click="handleCreate"> </a-button> -->
<PermissionBtn @btnEvent="onBtnClicked"></PermissionBtn>
</template>
</BasicTable>
<MenuDrawer @register="registerDrawer" @success="handleSuccess" />
</PageWrapper>
</template>
<script lang="ts" setup>
import { reactive, nextTick, ref } from 'vue';
import { BasicTable, useTable, TableAction } from '@/components/Table';
import { getMenuList, getButtonList, getMenuDetail, deleteButton } from '@/api/demo/system';
import { PageWrapper } from '@/components/Page';
import MenuTree from './MenuTree.vue';
import { useDrawer } from '@/components/Drawer';
import MenuDrawer from './MenuDrawer.vue';
import { columns, searchFormSchema } from './menu.data';
import PermissionBtn from '@/components/PermissionBtn/index.vue'
import { useMessage } from '@/hooks/web/useMessage';
const { createConfirm,createMessage } = useMessage();
defineOptions({ name: 'MenuManagement' });
const searchInfo = reactive < Recordable > ({});
const [registerDrawer, { openDrawer }] = useDrawer();
const [registerTable, { reload, expandAll, getSelectRows,clearSelectedRowKeys }] = useTable({
title: '按钮列表',
api: getButtonList,
columns,
rowKey:'id',
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
},
isTreeTable: true,
striped: false,
useSearchForm: true,
showTableSetting: true,
bordered: true,
showIndexColumn: false,
rowSelection: {//
// type: 'checkbox',
type: 'radio',
},
handleSearchInfoFn(info) {
return info;
},
});
const childRef = ref < any > ()
function handleCreate() {
openDrawer(true, {
isUpdate: false,
});
}
function handleEdit() {
let rows = getSelectRows();
if(rows.length == 0){
return createMessage.warn('请选择一个按钮进行编辑');
}
const record = rows[0]
record.type = '2'
openDrawer(true, {
record,
isUpdate: true,
});
}
async function editMenu(node: Recordable) {
var query = {
id: node.id
}
const record = await getMenuDetail(query);
record.type = '1'
openDrawer(true, {
record,
isUpdate: true,
});
}
function handleSelect(ModuleId = '') {
searchInfo.ModuleId = ModuleId;
clearSelectedRowKeys()
reload();
}
async function handleDelete(record: Recordable) {
let rows = getSelectRows();
if(rows.length == 0){
return createMessage.warn('请选择一个按钮进行删除');
}
const query = [rows[0].id]
createConfirm({
iconType: 'info',
title: '删除',
content: '确定要删除当前按钮吗',
onOk: async () => {
const data = await deleteButton(query);
reload();
},
});
}
function handleSuccess() {
childRef.value.fetch();
clearSelectedRowKeys()
reload();
}
function onFetchSuccess() {
//
nextTick(expandAll);
}
function onBtnClicked(domId) {
console.log(domId)
switch (domId) {
case 'btnAdd':
handleCreate()
break;
case 'btnEdit':
handleEdit()
break;
case 'btnDelete':
handleDelete()
break;
default:
break;
}
}
</script>

View File

@ -0,0 +1,198 @@
import { BasicColumn, FormSchema } from '@/components/Table';
import { h } from 'vue';
import { Tag } from 'ant-design-vue';
import Icon from '@/components/Icon/Icon.vue';
export const columns: BasicColumn[] = [
{
title: '按钮名称',
dataIndex: 'name',
},
{
title: 'DOMID',
dataIndex: 'domId',
},
{
title: '排序',
dataIndex: 'sort',
},
];
const isDir = (type: string) => type === '0';
const isMenu = (type: string) => type === '1';
const isButton = (type: string) => type === '2';
export const searchFormSchema: FormSchema[] = [
{
field: 'key',
label: '关键字',
component: 'Input',
colProps: { span: 8 },
},
];
export const formSchema: FormSchema[] = [
{
field: 'type',
label: '类型',
component: 'RadioButtonGroup',
defaultValue: '1',
componentProps: {
options: [
// { label: '目录', value: '0' },
{ label: '菜单', value: '1' },
{ label: '按钮', value: '2' },
],
},
colProps: { lg: 24, md: 24 },
},
{
field: 'id',
label: '名称',
component: 'Input',
ifShow:false
},
{
field: 'name',
label: '名称',
component: 'Input',
required: true,
},
{
field: 'parentId',
label: '上级',
component: 'TreeSelect',
componentProps: {
fieldNames: {
label: 'name',
key: 'id',
value: 'id',
},
getPopupContainer: () => document.body,
},
ifShow: ({ values }) => !isButton(values.type),
},
{
field: 'moduleId',
label: '菜单',
component: 'TreeSelect',
componentProps: {
fieldNames: {
label: 'name',
key: 'id',
value: 'id',
},
getPopupContainer: () => document.body,
},
ifShow: ({ values }) => isButton(values.type),
required: true,
},
{
field: 'domId',
label: 'DMOID',
component: 'Input',
required: true,
ifShow: ({ values }) => isButton(values.type),
},
{
field: 'sortNo',
label: '排序',
component: 'InputNumber',
ifShow: ({ values }) => !isButton(values.type),
},
{
field: 'sort',
label: '排序',
component: 'InputNumber',
ifShow: ({ values }) => isButton(values.type),
},
{
field: 'class',
helpMessage: ['参考参数值', 'success、warning、error'],
label: '样式',
component: 'Input',
ifShow: ({ values }) => isButton(values.type),
},
{
field: 'iconName',
label: '图标',
component: 'IconPicker',
ifShow: ({ values }) => !isButton(values.type),
},
{
field: 'url',
label: '路由地址',
component: 'Input',
required: true,
ifShow: ({ values }) => !isButton(values.type),
},
// {
// field: 'component',
// label: '组件路径',
// component: 'Input',
// ifShow: ({ values }) => isMenu(values.type),
// },
{
field: 'code',
label: '权限标识',
component: 'Input',
ifShow: ({ values }) => !isButton(values.type),
},
{
field: 'status',
label: '是否系统',
component: 'RadioButtonGroup',
defaultValue: 1,
componentProps: {
options: [
{ label: '是', value: 0 },
{ label: '否', value: 1 },
],
},
ifShow: ({ values }) => !isButton(values.type),
},
// {
// field: 'isExt',
// label: '是否外链',
// component: 'RadioButtonGroup',
// defaultValue: '0',
// componentProps: {
// options: [
// { label: '否', value: '0' },
// { label: '是', value: '1' },
// ],
// },
// ifShow: ({ values }) => !isButton(values.type),
// },
// {
// field: 'keepalive',
// label: '是否缓存',
// component: 'RadioButtonGroup',
// defaultValue: '0',
// componentProps: {
// options: [
// { label: '否', value: '0' },
// { label: '是', value: '1' },
// ],
// },
// ifShow: ({ values }) => isMenu(values.type),
// },
// {
// field: 'show',
// label: '是否显示',
// component: 'RadioButtonGroup',
// defaultValue: '0',
// componentProps: {
// options: [
// { label: '是', value: '0' },
// { label: '否', value: '1' },
// ],
// },
// ifShow: ({ values }) => !isButton(values.type),
// },
];

View File

@ -3,7 +3,6 @@
* @Date: 2024-02-01 09:07:48
* @LastEditors: Do not edit
* @LastEditTime: 2024-02-01 16:55:15
* @FilePath: \费县天空地大屏正式代码e:\新架构\vue-vben-admin\src\views\demo\system\role\AccountModal.vue
* @Description:
-->
<template>

View File

@ -3,7 +3,6 @@
* @Date: 2024-01-29 08:58:01
* @LastEditors: Do not edit
* @LastEditTime: 2024-01-30 13:39:08
* @FilePath: \费县天空地大屏正式代码e:\新架构\vue-vben-admin\src\views\demo\system\role\ModulesModal.vue
* @Description:
-->
<template>

View File

@ -0,0 +1,10 @@
<!--
* @Author: 刘妍
* @Date: 2024-02-26 13:22:28
* @LastEditors: Do not edit
* @LastEditTime: 2024-02-26 13:23:09
* @Description:
-->
<template>
流程发起
</template>

View File

@ -0,0 +1,91 @@
<!--
* @Author: 刘妍
* @Date: 2024-02-27 09:06:43
* @LastEditors: Do not edit
* @LastEditTime: 2024-02-27 10:49:01
* @Description:
-->
<template>
<BasicDrawer v-bind="$attrs" @register="registerDrawer" showFooter :title="getTitle" width="500px" @ok="handleSubmit">
<BasicForm @register="registerForm" />
</BasicDrawer>
</template>
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicForm, useForm } from '@/components/Form';
import { formSchema } from './scheme.data';
import { BasicDrawer, useDrawerInner } from '@/components/Drawer';
import { getMenuList, addMenu, editMenu, addButton, editButton } from '@/api/demo/system';
defineOptions({ name: 'SchemeDrawer' });
const emit = defineEmits(['success', 'register']);
const isUpdate = ref(true);
const [registerForm, { resetFields, setFieldsValue, updateSchema, validate }] = useForm({
labelWidth: 90,
baseColProps: { span: 24 },
schemas: formSchema,
showActionButtonGroup: false,
});
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
resetFields();
setDrawerProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
setFieldsValue({
...data.record,
});
}
const treeData = await getMenuList();
updateSchema({
field: 'parentId',
componentProps: { treeData },
});
updateSchema({
field: 'moduleId',
componentProps: { treeData },
});
});
const getTitle = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
async function handleSubmit() {
try {
const values = await validate();
setDrawerProps({ confirmLoading: true });
// TODO custom api
console.log(values)
if (values.type == '1') {
console.log("新增菜单")
delete values.type
//
if (!unref(isUpdate)) {
const data = await addMenu(values);
} else {
const data = await editMenu(values);
}
closeDrawer();
emit('success');
} else {
console.log("新增按钮")
//
delete values.type
if (!unref(isUpdate)) {
const data = await addButton(values);
} else {
const data = await editButton(values);
}
closeDrawer();
emit('success');
}
} finally {
setDrawerProps({ confirmLoading: false });
}
}
</script>

View File

@ -0,0 +1,116 @@
<!--
* @Author: 刘妍
* @Date: 2024-02-27 09:06:43
* @LastEditors: Do not edit
* @LastEditTime: 2024-03-05 16:00:45
* @Description:
-->
<template>
<div class="m-4 mr-0 overflow-hidden bg-white">
<BasicTree ref="asyncExpandTreeRef" title="流程分类" toolbar search
treeWrapperClassName="h-[calc(100%-35px)] overflow-auto" loadData :actionList="actionList"
:renderIcon="createIcon" :clickRowToExpand="false" :treeData="treeData" :fieldNames="{ key: 'id', title: 'name' }"
:defaultExpandAll="true" @select="handleSelect" />
<BasicModal @register="register" title="删除" :helpMessage="['提示1', '提示2']" @ok="handleSubmit">
确认要删除流程分类吗
</BasicModal>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref, h, nextTick, unref } from 'vue';
import { BasicTree, TreeItem, TreeActionItem } from '@/components/Tree';
import { getMenuList, deleteMenu } from '@/api/demo/system';
import { PlusOutlined, FormOutlined, DeleteOutlined } from '@ant-design/icons-vue';
import { Card, Row, Col, Spin } from 'ant-design-vue';
import { BasicModal, useModal } from '@/components/Modal';
import { router } from '@/router';
const [register, { closeModal, openModal }] = useModal();
defineOptions({ name: 'DeptTree' });
const emit = defineEmits(['select', 'edit']);
const treeData = ref < TreeItem[] > ([]);
let selectItemId = ref('')
const asyncExpandTreeRef = ref < Nullable < TreeActionType >> (null);
const treeLoading = ref(false);
async function handleSubmit() {
var query = [selectItemId.value]
const data = await deleteMenu(query);
closeModal();
}
async function fetch() {
treeLoading.value = true;
treeData.value = (await getMenuList()) as unknown as TreeItem[];
//
nextTick(() => {
treeLoading.value = false;
unref(asyncExpandTreeRef)?.expandAll(true);
});
}
function handleSelect(keys) {
emit('select', keys[0]);
}
const btnList = router.currentRoute.value.meta.elements
const actionList: TreeActionItem[] = []
btnList.forEach(element => {
if(element.domId=='btnAdd'){
actionList.push({
render: (node) => {
return h(PlusOutlined, {
class: 'ml-2',
onClick: () => {
emit('add', node);
},
});
},
})
}else if (element.domId == 'btnEdit') {
actionList.push({
render: (node) => {
return h(FormOutlined, {
class: 'ml-2',
onClick: () => {
emit('edit', node);
},
});
},
})
} else if (element.domId == 'btnDelete') {
actionList.push({
render: (node) => {
return h(DeleteOutlined, {
class: 'ml-2',
onClick: () => {
selectItemId.value = node.id
openModal(true, {
isUpdate: false,
});
},
});
},
})
}
});
function createIcon({ level }) {
if (level === 1) {
return 'ion:git-compare-outline';
}
if (level === 2) {
return 'ion:home';
}
if (level === 3) {
return 'ion:airplane';
}
return '';
}
onMounted(() => {
fetch();
});
defineExpose({
fetch
})
</script>

View File

@ -0,0 +1,161 @@
<template>
<PageWrapper dense contentFullHeight fixedHeight contentClass="flex">
<SchemeTree ref="childRef" class="w-1/4 xl:w-1/5" @select="handleSelect" @edit="editMenu" @add='handleCreate'/>
<BasicTable class="w-3/4 xl:w-4/5" @register="registerTable" @fetch-success="onFetchSuccess"
:searchInfo="searchInfo">
<template #toolbar>
<!-- <a-button type="primary" @click="handleCreate"> </a-button> -->
<PermissionBtn @btnEvent="onBtnClicked"></PermissionBtn>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction
:actions="[
{
icon: 'clarity:info-standard-line',
tooltip: '查看历史记录',
onClick: handleView.bind(null, record),
}
]"
/>
</template>
</template>
</BasicTable>
<SchemeDrawer @register="registerDrawer" @success="handleSuccess" />
</PageWrapper>
</template>
<script lang="ts" setup>
import { reactive, nextTick, ref } from 'vue';
import { BasicTable, useTable, TableAction } from '@/components/Table';
import { getMenuList, getButtonList, getMenuDetail, deleteButton } from '@/api/demo/system';
import { PageWrapper } from '@/components/Page';
import SchemeTree from './SchemeTree.vue';
import { useDrawer } from '@/components/Drawer';
import SchemeDrawer from './SchemeDrawer.vue';
import { columns, searchFormSchema } from './scheme.data';
import PermissionBtn from '@/components/PermissionBtn/index.vue'
import { useMessage } from '@/hooks/web/useMessage';
const { createConfirm,createMessage } = useMessage();
import { useGo } from '@/hooks/web/usePage';
const go = useGo();
defineOptions({ name: 'SchemeManagement' });
const searchInfo = reactive < Recordable > ({});
const [registerDrawer, { openDrawer }] = useDrawer();
const [registerTable, { reload, expandAll, getSelectRows,clearSelectedRowKeys }] = useTable({
title: '模板列表',
api: getButtonList,
columns,
rowKey:'id',
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
},
isTreeTable: true,
striped: false,
useSearchForm: true,
showTableSetting: true,
bordered: true,
showIndexColumn: false,
rowSelection: {//
// type: 'checkbox',
type: 'radio',
},
handleSearchInfoFn(info) {
return info;
},
actionColumn: {
width: 100,
title: '操作',
dataIndex: 'action',
// slots: { customRender: 'action' },
},
});
const childRef = ref < any > ()
function handleCreate() {
openDrawer(true, {
isUpdate: false,
});
}
function handleView(record: Recordable) {
go('/dashboard/scheme_preview/' + record.id);
}
function handleEdit() {
let rows = getSelectRows();
if(rows.length == 0){
return createMessage.warn('请选择一个按钮进行编辑');
}
const record = rows[0]
record.type = '2'
openDrawer(true, {
record,
isUpdate: true,
});
}
async function editMenu(node: Recordable) {
var query = {
id: node.id
}
const record = await getMenuDetail(query);
record.type = '1'
openDrawer(true, {
record,
isUpdate: true,
});
}
function handleSelect(ModuleId = '') {
searchInfo.ModuleId = ModuleId;
clearSelectedRowKeys()
reload();
}
async function handleDelete(record: Recordable) {
let rows = getSelectRows();
if(rows.length == 0){
return createMessage.warn('请选择一个按钮进行删除');
}
const query = [rows[0].id]
createConfirm({
iconType: 'info',
title: '删除',
content: '确定要删除当前按钮吗',
onOk: async () => {
const data = await deleteButton(query);
reload();
},
});
}
function handleSuccess() {
childRef.value.fetch();
clearSelectedRowKeys()
reload();
}
function onFetchSuccess() {
//
nextTick(expandAll);
}
function onBtnClicked(domId) {
console.log(domId)
switch (domId) {
case 'btnAdd':
go('/dashboard/scheme_preview/add');
break;
case 'btnEdit':
handleEdit()
break;
case 'btnDelete':
handleDelete()
break;
default:
break;
}
}
</script>

View File

@ -0,0 +1,104 @@
<!--
* @Author: 刘妍
* @Date: 2024-03-01 14:18:39
* @LastEditors: Do not edit
* @LastEditTime: 2024-03-05 10:18:49
* @Description:
-->
<template>
<!-- <process-viewer :key="`designer-${processView.index}`" :xml="processView.xmlData" :style="{height: '400px'}" /> -->
<process-designer :key="designerOpen" style="border:1px solid rgba(0, 0, 0, 0.1);" ref="modelDesigner"
v-loading="designerData.loading" :bpmnXml="designerData.bpmnXml" :designerForm="designerData.form"
@save="onSaveDesigner" />
</template>
<script>
import ProcessDesigner from '@/components/ProcessDesigner/index.vue';
// import ProcessViewer from '@/components/ProcessViewer/index.vue'
export default {
name: "Model",
components: {
ProcessDesigner,
// ProcessViewer,
},
data() {
return {
designerOpen: false,
designerData: {
loading: false,
bpmnXml: '',
modelId: null,
form: {
processName: null,
processKey: null
}
},
designerModelId: null,
processView: {
title: '',
open: false,
index: undefined,
xmlData: "",
},
};
},
created() {
},
methods: {
/** 查看流程图 */
handleProcessView(row) {
let modelId = row.modelId;
this.processView.title = "流程图";
this.processView.index = modelId;
// xml
getBpmnXml(modelId).then(response => {
this.processView.xmlData = response.data;
})
this.processView.open = true;
},
/** 设计按钮操作 */
handleDesigner(row) {
this.designerData.bpmnXml = '';
this.designerData.title = "流程设计 - " + row.modelName;
// this.designerData.modelId = row.modelId;
// this.designerData.form = {
// processName: row.modelName,
// processKey: row.modelKey
// }
// if (row.modelId) {
// this.designerData.loading = true;
// getBpmnXml(row.modelId).then(response => {
// this.designerData.bpmnXml = response.data || '';
// this.designerData.loading = false;
// this.designerOpen = true;
// })
// }
},
onSaveDesigner(bpmnXml) {
console.log(bpmnXml)
// this.bpmnXml = bpmnXml;
// let dataBody = {
// modelId: this.designerData.modelId,
// bpmnXml: this.bpmnXml
// }
// this.$confirm("", "", {
// distinguishCancelAndClose: true,
// confirmButtonText: '',
// cancelButtonText: ''
// }).then(() => {
// this.confirmSave(dataBody, true)
// }).catch(action => {
// if (action === 'cancel') {
// this.confirmSave(dataBody, false)
// }
// })
},
}
};
</script>

View File

@ -0,0 +1,80 @@
import { BasicColumn, FormSchema } from '@/components/Table';
import { h } from 'vue';
import { Tag } from 'ant-design-vue';
import Icon from '@/components/Icon/Icon.vue';
export const columns: BasicColumn[] = [
{
title: '编号',
dataIndex: 'domId',
},
{
title: '名称',
dataIndex: 'name',
},
{
title: '分类',
dataIndex: 'name',
},
{
title: '排序',
dataIndex: 'sort',
},
];
const isDir = (type: string) => type === '0';
const isMenu = (type: string) => type === '1';
const isButton = (type: string) => type === '2';
export const searchFormSchema: FormSchema[] = [
{
field: 'key',
label: '关键字',
component: 'Input',
colProps: { span: 8 },
},
];
export const formSchema: FormSchema[] = [
{
field: 'id',
label: '名称',
component: 'Input',
ifShow:false
},
{
field: 'name',
label: '名称',
component: 'Input',
required: true,
},
{
field: 'value',
label: '值',
component: 'Input',
required: true,
},
{
field: 'sortNo',
label: '排序',
component: 'InputNumber',
},
{
field: 'status',
label: '是否有效',
component: 'RadioButtonGroup',
defaultValue: 1,
componentProps: {
options: [
{ label: '是', value: 0 },
{ label: '否', value: 1 },
],
},
},
{
field: 'remark',
label: '备注',
component: 'InputTextArea',
},
];

View File

@ -0,0 +1,10 @@
<!--
* @Author: 刘妍
* @Date: 2024-02-26 13:22:28
* @LastEditors: Do not edit
* @LastEditTime: 2024-03-05 15:59:12
* @Description:
-->
<template>
流程任务
</template>

View File

@ -2,7 +2,11 @@
* @Author:
* @Date: 2024-01-13 13:04:15
* @LastEditors: Do not edit
<<<<<<< HEAD
* @LastEditTime: 2024-03-08 09:17:00
=======
* @LastEditTime: 2024-03-05 15:57:29
>>>>>>> ly
* @Description:
*/
import { defineApplicationConfig } from '@vben/vite-config';