Browse Source

工作流基础布局

v2
超级管理员 2 years ago
parent
commit
a9864e2733
  1. 4
      package.json
  2. 23
      src/api/workflowapi/index.ts
  3. 9
      src/api/workflowapi/types.ts
  4. 249
      src/components/workflow/addNode.vue
  5. 299
      src/components/workflow/nodeWrap.vue
  6. 5
      src/main.ts
  7. 52
      src/store/workflow/index.ts
  8. 114
      src/styles/workflowcss/override-element-ui.css
  9. 1730
      src/styles/workflowcss/workflow.css
  10. 38
      src/utils/workflow/const.ts
  11. 157
      src/utils/workflow/index.ts
  12. 12
      src/views/sysworkflow/codepage/index.vue
  13. 129
      src/views/sysworkflow/flow/flowcanvas.vue
  14. 161
      src/views/sysworkflow/flow/index.vue
  15. 6
      src/views/taskplatform/taskmanagement/edittaskcustomerform.vue
  16. 6
      src/views/taskplatform/taskmanagement/taskcustomerform.vue
  17. 12
      src/views/taskplatform/taskmanagement/tasklist.vue

4
package.json

@ -50,13 +50,14 @@
"clipboard": "^2.0.11",
"echarts": "^5.2.2",
"element-plus": "^2.3.4",
"font-awesome": "^4.7.0",
"js-beautify": "^1.14.8",
"js-md5": "^0.7.3",
"md5": "^2.3.0",
"nprogress": "^0.2.0",
"path-browserify": "^1.0.1",
"path-to-regexp": "^6.2.0",
"pinia": "^2.0.33",
"pinia": "^2.1.6",
"screenfull": "^6.0.0",
"tinymce": "^6.7.0",
"ts-md5": "^1.3.1",
@ -84,6 +85,7 @@
"eslint-plugin-vue": "^9.13.0",
"fast-glob": "^3.2.11",
"husky": "^8.0.3",
"less": "^4.2.0",
"lint-staged": "^13.2.2",
"postcss": "^8.4.23",
"postcss-html": "^1.5.0",

23
src/api/workflowapi/index.ts

@ -0,0 +1,23 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import {
formTableName
} from '@/api/workflowapi/types'
//初始化工作流
export function initializeWorkFlow(data: formTableName) {
return request({
url: '/systemapi/task_flow/init_workflow',
method: 'post',
data: data
});
}
//保存工作流
export function setWorkFlowData(data: any):any {
return request({
url: '/systemapi/task_flow/init_workflow',
method: 'post',
data: data
});
}

9
src/api/workflowapi/types.ts

@ -0,0 +1,9 @@
//表单名称
export interface formTableName{
name?: string;
}
//错误提示
export interface tipListStrucr{
}

249
src/components/workflow/addNode.vue

@ -0,0 +1,249 @@
<!--
@ 作者: 秦东
@ 时间: 2023-10-10 14:23:45
@ 备注: 添加节点弹窗
-->
<script lang='ts' setup>
let props = defineProps({
childNodeP: {
type: Object,
default: ()=> ({})
}
})
let emits = defineEmits(['update:childNodeP'])
let visible = ref(false)
//
const addType = (type)=> {
visible.value = false;
if (type != 4) {
var data;
if (type == 1) {
data = {
"nodeName": "审核人",
"error": true,
"type": 1,
"settype": 1,
"selectMode": 0,
"selectRange": 0,
"directorLevel": 1,
"examineMode": 1,
"noHanderAction": 1,
"examineEndDirectorLevel": 0,
"childNode": props.childNodeP,
"nodeUserList": []
}
} else if (type == 2) {
data = {
"nodeName": "抄送人",
"type": 2,
"ccSelfSelectFlag": 1,
"childNode": props.childNodeP,
"nodeUserList": []
}
}else if (type == 3) {
data = {
"nodeName": "审核人",
"error": true,
"type": 3,
"settype": 1,
"selectMode": 0,
"selectRange": 0,
"directorLevel": 1,
"examineMode": 1,
"noHanderAction": 1,
"examineEndDirectorLevel": 0,
"childNode": props.childNodeP,
"nodeUserList": []
}
}
emits("update:childNodeP", data)
} else {
emits("update:childNodeP", {
"nodeName": "路由",
"type": 5,
"childNode": null,
"conditionNodes": [{
"nodeName": "条件1",
"error": true,
"type": 3,
"priorityLevel": 1,
"conditionList": [],
"nodeUserList": [],
"childNode": props.childNodeP,
}, {
"nodeName": "条件2",
"type": 3,
"priorityLevel": 2,
"conditionList": [],
"nodeUserList": [],
"childNode": null
}]
})
}
}
</script>
<template>
<div class="add-node-btn-box">
<div class="add-node-btn">
<el-popover v-model="visible" placement="right-start" width="auto">
<div class="add-node-popover-body">
<a class="add-node-popover-item approver" @click="addType(1)">
<div class="item-wrapper">
<span class="iconfont"><el-icon><Stamp /></el-icon></span>
</div>
<p>审批人</p>
</a>
<a class="add-node-popover-item notifier" @click="addType(2)">
<div class="item-wrapper">
<span class="iconfont"><i class="fa fa-send"></i></span>
</div>
<p>抄送人</p>
</a>
<a class="add-node-popover-item approver" @click="addType(3)">
<div class="item-wrapper">
<span class="iconfont"><i class="fa fa-pencil-square-o"></i></span>
</div>
<p>处理</p>
</a>
<a class="add-node-popover-item condition" @click="addType(4)">
<div class="item-wrapper">
<span class="iconfont"><i class="fa fa-sitemap"></i></span>
</div>
<p>条件分支</p>
</a>
</div>
<template #reference>
<button class="btn" type="button">
<span class="iconfont"></span>
</button>
</template>
</el-popover>
</div>
</div>
</template>
<style lang='scss' scoped>
</style>
<style scoped lang="less">
.add-node-btn-box {
width: 240px;
display: -webkit-inline-box;
display: -ms-inline-flexbox;
display: inline-flex;
-ms-flex-negative: 0;
flex-shrink: 0;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
position: relative;
&:before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -1;
margin: auto;
width: 2px;
height: 100%;
background-color: #cacaca
}
.add-node-btn {
user-select: none;
width: 240px;
padding: 20px 0 32px;
display: flex;
-webkit-box-pack: center;
justify-content: center;
flex-shrink: 0;
-webkit-box-flex: 1;
flex-grow: 1;
.btn {
outline: none;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .1);
width: 30px;
height: 30px;
background: #3296fa;
border-radius: 50%;
position: relative;
border: none;
line-height: 30px;
-webkit-transition: all .3s cubic-bezier(.645, .045, .355, 1);
transition: all .3s cubic-bezier(.645, .045, .355, 1);
.iconfont {
color: #fff;
font-size: 16px
}
&:hover {
transform: scale(1.3);
box-shadow: 0 13px 27px 0 rgba(0, 0, 0, .1)
}
&:active {
transform: none;
background: #1e83e9;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .1)
}
}
}
}
</style>
<style lang="less">
.add-node-popover-body {
display: flex;
.add-node-popover-item {
margin-right: 10px;
cursor: pointer;
text-align: center;
flex: 1;
color: #191f25!important;
.item-wrapper {
user-select: none;
display: inline-block;
width: 80px;
height: 80px;
margin-bottom: 5px;
background: #fff;
border: 1px solid #e2e2e2;
border-radius: 50%;
transition: all .3s cubic-bezier(.645, .045, .355, 1);
.iconfont {
font-size: 35px;
line-height: 80px
}
}
&.approver{
.item-wrapper {
color: #ff943e
}
}
&.notifier{
.item-wrapper {
color: #3296fa
}
}
&.condition{
.item-wrapper {
color: #15bc83
}
}
&:hover{
.item-wrapper {
background: #3296fa;
box-shadow: 0 10px 20px 0 rgba(50, 150, 250, .4)
}
.iconfont {
color: #fff
}
}
&:active{
.item-wrapper {
box-shadow: none;
background: #eaeaea
}
.iconfont {
color: inherit
}
}
}
}
</style>

299
src/components/workflow/nodeWrap.vue

@ -0,0 +1,299 @@
<!--
@ 作者: 秦东
@ 时间: 2023-10-10 11:30:42
@ 备注: 工作流引擎主干
-->
<script lang='ts' setup>
import $func from '@/utils/workflow/index'
import { useStore } from '@/store/workflow/index'
import { bgColors, placeholderList } from '@/utils/workflow/const'
let _uid = getCurrentInstance().uid;
let props = defineProps({
nodeConfig: {
type: Object,
default: () => ({}),
},
flowPermission: {
type: Object,
// eslint-disable-next-line vue/require-valid-default-prop
default: () => [],
},
});
//pinia
let store = useStore();
let {
setPromoter,
setApprover,
setCopyer,
setCondition,
setFlowPermission,
setApproverConfig,
setCopyerConfig,
setConditionsConfig,
} = store;
let isTried = computed(()=> store.isTried)
let flowPermission1 = computed(()=> store.flowPermission1)
let approverConfig1 = computed(()=> store.approverConfig1)
let copyerConfig1 = computed(()=> store.copyerConfig1)
let conditionsConfig1 = computed(()=> store.conditionsConfig1)
let defaultText = computed(() => {
return placeholderList[props.nodeConfig.type]
});
let showText = computed(() => {
if (props.nodeConfig.type == 0) return $func.arrToStr(props.flowPermission) || '所有人'
if (props.nodeConfig.type == 1) return $func.setApproverStr(props.nodeConfig)
return $func.copyerStr(props.nodeConfig)
});
let isInputList = ref([]);
let isInput = ref(false);
const resetConditionNodesErr = () => {
for (var i = 0; i < props.nodeConfig.conditionNodes.length; i++) {
// eslint-disable-next-line vue/no-mutating-props
props.nodeConfig.conditionNodes[i].error = $func.conditionStr(props.nodeConfig, i) == "请设置条件" && i != props.nodeConfig.conditionNodes.length - 1;
}
}
const clickEvent = (index) => {
if (index || index === 0) {
isInputList.value[index] = true;
} else {
isInput.value = true;
}
};
const blurEvent = (index) => {
if (index || index === 0) {
isInputList.value[index] = false;
// eslint-disable-next-line vue/no-mutating-props
props.nodeConfig.conditionNodes[index].nodeName = props.nodeConfig.conditionNodes[index].nodeName || "条件";
} else {
isInput.value = false;
// eslint-disable-next-line vue/no-mutating-props
props.nodeConfig.nodeName = props.nodeConfig.nodeName || defaultText
}
};
//
const delNode = () => {
emits("update:nodeConfig", props.nodeConfig.childNode);
};
let emits = defineEmits(["update:flowPermission", "update:nodeConfig"]);
const addTerm = () => {
let len = props.nodeConfig.conditionNodes.length + 1;
// eslint-disable-next-line vue/no-mutating-props
props.nodeConfig.conditionNodes.push({
nodeName: "条件" + len,
type: 3,
priorityLevel: len,
conditionList: [],
nodeUserList: [],
childNode: null,
});
resetConditionNodesErr()
emits("update:nodeConfig", props.nodeConfig);
};
const delTerm = (index) => {
// eslint-disable-next-line vue/no-mutating-props
props.nodeConfig.conditionNodes.splice(index, 1);
props.nodeConfig.conditionNodes.map((item, index) => {
item.priorityLevel = index + 1;
item.nodeName = `条件${index + 1}`;
});
resetConditionNodesErr()
emits("update:nodeConfig", props.nodeConfig);
if (props.nodeConfig.conditionNodes.length == 1) {
if (props.nodeConfig.childNode) {
if (props.nodeConfig.conditionNodes[0].childNode) {
reData(props.nodeConfig.conditionNodes[0].childNode, props.nodeConfig.childNode);
} else {
// eslint-disable-next-line vue/no-mutating-props
props.nodeConfig.conditionNodes[0].childNode = props.nodeConfig.childNode;
}
}
emits("update:nodeConfig", props.nodeConfig.conditionNodes[0].childNode);
}
};
const reData = (data, addData) => {
if (!data.childNode) {
data.childNode = addData;
} else {
reData(data.childNode, addData);
}
};
const setPerson = (priorityLevel) => {
var { type } = props.nodeConfig;
if (type == 0) {
setPromoter(true);
setFlowPermission({
value: props.flowPermission,
flag: false,
id: _uid,
});
} else if (type == 1) {
setApprover(true);
setApproverConfig({
value: {
...JSON.parse(JSON.stringify(props.nodeConfig)),
...{ settype: props.nodeConfig.settype ? props.nodeConfig.settype : 1 },
},
flag: false,
id: _uid,
});
} else if (type == 2) {
setCopyer(true);
setCopyerConfig({
value: JSON.parse(JSON.stringify(props.nodeConfig)),
flag: false,
id: _uid,
});
} else {
setCondition(true);
setConditionsConfig({
value: JSON.parse(JSON.stringify(props.nodeConfig)),
priorityLevel,
flag: false,
id: _uid,
});
}
};
const arrTransfer = (index, type = 1) => {
//-1,1
// eslint-disable-next-line vue/no-mutating-props
props.nodeConfig.conditionNodes[index] = props.nodeConfig.conditionNodes.splice(
index + type,
1,
props.nodeConfig.conditionNodes[index]
)[0];
props.nodeConfig.conditionNodes.map((item, index) => {
item.priorityLevel = index + 1;
});
resetConditionNodesErr()
emits("update:nodeConfig", props.nodeConfig);
};
//
watch(flowPermission1, (flow) => {
if (flow.flag && flow.id === _uid) {
emits("update:flowPermission", flow.value);
}
});
watch(approverConfig1, (approver) => {
if (approver.flag && approver.id === _uid) {
emits("update:nodeConfig", approver.value);
}
});
watch(copyerConfig1, (copyer) => {
if (copyer.flag && copyer.id === _uid) {
emits("update:nodeConfig", copyer.value);
}
});
watch(conditionsConfig1, (condition) => {
if (condition.flag && condition.id === _uid) {
emits("update:nodeConfig", condition.value);
}
});
onMounted(() => {
if (props.nodeConfig.type == 1) {
// eslint-disable-next-line vue/no-mutating-props
props.nodeConfig.error = !$func.setApproverStr(props.nodeConfig);
} else if (props.nodeConfig.type == 2) {
// eslint-disable-next-line vue/no-mutating-props
props.nodeConfig.error = !$func.copyerStr(props.nodeConfig);
} else if (props.nodeConfig.type == 4) {
resetConditionNodesErr()
}
})
</script>
<template>
<!--通用模块0 发起人 1审批 2抄送 3处理 4条件 5路由-->
<div v-if="nodeConfig.type < 4" class="node-wrap" >
<div class="node-wrap-box" :class="(nodeConfig.type == 0 ? 'start-node ' : '') +(isTried && nodeConfig.error ? 'active error' : '')">
<!--标签头部-->
<div class="title" :style="`background: rgb(${bgColors[nodeConfig.type]});`">
<span v-if="nodeConfig.type == 0">{{ nodeConfig.nodeName }}</span>
<template v-else>
<span class="iconfont">{{nodeConfig.type == 1?'':''}}</span>
<input
v-if="isInput"
v-model="nodeConfig.nodeName"
type="text"
class="ant-input editable-title-input"
@blur="blurEvent()"
@focus="$event.currentTarget.select()"
v-focus
:placeholder="defaultText"
/>
<span v-else class="editable-title" @click="clickEvent()">{{ nodeConfig.nodeName }}</span>
<i class="anticon anticon-close close" @click="delNode"></i>
</template>
</div>
<!--标签主体-->
<div class="content" @click="setPerson">
<div class="text">
<span class="placeholder" v-if="!showText">请选择{{defaultText}}</span>
{{showText}}
</div>
<i class="anticon anticon-right arrow"></i>
</div>
<!--标签错误提示-->
<div class="error_tip" v-if="isTried && nodeConfig.error">
<i class="anticon anticon-exclamation-circle"></i>
</div>
</div>
<addNode v-model:childNodeP="nodeConfig.childNode" />
</div>
<!--路由模块-->
<div v-if="nodeConfig.type == 5" class="node-wrap" >
<div class="branch-box-wrap">
<div class="branch-box">
<button class="add-branch" @click="addTerm">添加条件</button>
<div class="col-box" v-for="(item, index) in nodeConfig.conditionNodes" :key="index">
<div class="condition-node">
<div class="condition-node-box">
<div class="auto-judge" :class="isTried && item.error ? 'error active' : ''">
<div class="sort-left" v-if="index != 0" @click="arrTransfer(index, -1)">&lt;</div>
<div class="title-wrapper">
<input
v-if="isInputList[index]"
type="text"
class="ant-input editable-title-input"
@blur="blurEvent(index)"
@focus="$event.currentTarget.select()"
v-focus
v-model="item.nodeName"
/>
<span v-else class="editable-title" @click="clickEvent(index)">{{ item.nodeName }}</span>
<span class="priority-title" @click="setPerson(item.priorityLevel)">优先级{{ item.priorityLevel }}</span>
<i class="anticon anticon-close close" @click="delTerm(index)"></i>
</div>
<div class="sort-right" v-if="index != nodeConfig.conditionNodes.length - 1" @click="arrTransfer(index)">&gt;</div>
<div class="content" @click="setPerson(item.priorityLevel)">{{ $func.conditionStr(nodeConfig, index) }}</div>
<div class="error_tip" v-if="isTried && item.error">
<i class="anticon anticon-exclamation-circle"></i>
</div>
</div>
<addNode v-model:childNodeP="item.childNode" />
</div>
</div>
<nodeWrap v-if="item.childNode" v-model:nodeConfig="item.childNode" />
<template v-if="index == 0">
<div class="top-left-cover-line"></div>
<div class="bottom-left-cover-line"></div>
</template>
<template v-if="index == nodeConfig.conditionNodes.length - 1">
<div class="top-right-cover-line"></div>
<div class="bottom-right-cover-line"></div>
</template>
</div>
</div>
<addNode v-model:childNodeP="nodeConfig.childNode" />
</div>
</div>
<!--循环组件-->
<nodeWrap v-if="nodeConfig.childNode" v-model:nodeConfig="nodeConfig.childNode"/>
</template>
<style lang='scss' scoped>
</style>

5
src/main.ts

@ -15,10 +15,13 @@ import 'virtual:svg-icons-register';
// 国际化
import i18n from '@/lang/index';
// 样式
// 样式
import 'font-awesome/css/font-awesome.min.css'
import 'element-plus/es/components/message/style/css';
import 'element-plus/theme-chalk/dark/css-vars.css';
import '@/styles/index.scss';
import 'uno.css';
import '@/styles/workflowcss/override-element-ui.css'
import ComComponents from '@/components/DesignForm/index'

52
src/store/workflow/index.ts

@ -0,0 +1,52 @@
/**
*
*/
import { defineStore } from 'pinia';
export const useStore = defineStore('store', {
state: () => ({
tableId: '',
isTried: false,
promoterDrawer: false,
flowPermission1: {},
approverDrawer: false,
approverConfig1: {},
copyerDrawer: false,
copyerConfig1: {},
conditionDrawer: false,
conditionsConfig1: {
conditionNodes: [],
},
}),
actions: {
setTableId(payload:any) {
this.tableId = payload
},
setIsTried(payload:any) {
this.isTried = payload
},
setPromoter(payload:any) {
this.promoterDrawer = payload
},
setFlowPermission(payload:any) {
this.flowPermission1 = payload
},
setApprover(payload:any) {
this.approverDrawer = payload
},
setApproverConfig(payload:any) {
this.approverConfig1 = payload
},
setCopyer(payload:any) {
this.copyerDrawer = payload
},
setCopyerConfig(payload:any) {
this.copyerConfig1 = payload
},
setCondition(payload:any) {
this.conditionDrawer = payload
},
setConditionsConfig(payload:any) {
this.conditionsConfig1 = payload
},
}
})

114
src/styles/workflowcss/override-element-ui.css

@ -0,0 +1,114 @@
.el-drawer__header {
margin-bottom: 0 !important;
padding: 14px 5px 14px 5px !important;
/* border-bottom: 1px solid #f2f2f2 !important; */
color: #323232 !important;
font-size: 16px !important;
}
.el-drawer__header .el-drawer__title{
font-size: 16px !important;
}
.demo-drawer__content {
display: flex !important;
flex-direction: column !important;
height: 100% !important;
}
.drawer_content {
flex: 1 !important;
}
.demo-drawer__content>div {
border-top: 1px solid #F2F2F2 !important;
}
/* .el-button {
min-width: 79px !important;
padding: 8px 12px !important;
font-size: 12px !important;
border-radius: 2px !important;
color: #323232 !important;
background: #f2f2f2 !important;
height: 30px !important;
}
.el-button.el-button--primary {
background: #46A6FE !important;
color: #fff !important;
} */
.demo-drawer__footer {
padding: 10px 30px !important;
border-top: 1px solid #F2F2F2 !important;
}
.demo-drawer__footer .el-button {
float: right !important;
margin-right: 10px !important;
}
/* .el-dialog {
width: 520px;
border: 1px solid #DDE1E5 !important;
border-radius: 3px !important;
}
.el-dialog__header {
padding: 0 0 0 20px !important;
line-height: 50px !important;
height: 50px !important;
background: #fff !important;
border-bottom: 1px solid #F2F2F2 !important;
}
.el-dialog__header .el-dialog__title {
font-size: 16px !important;
line-height: 50px !important;
color: #333333 !important;
}
.el-dialog__header .el-dialog__headerbtn {
height: 12px !important;
width: 12px !important;
}
.el-dialog__header .el-icon-close {
width: 12px !important;
height: 12px !important;
float: left !important;
} */
/* .el-dialog__header .el-icon-close::before {
display: block !important;
width: 12px !important;
height: 12px !important;
background: url(~@/assets/images/add-close.png) no-repeat center !important;
background-size: 100% 100% !important;
content: "" !important;
} */
.el-drawer__body {
padding: 0 !important;
}
/* .el-dialog__footer {
border-top: 1px solid #F2F2F2 !important;
padding-bottom: 10px !important;
} */
/* .el-checkbox,
.el-checkbox__input.is-checked+.el-checkbox__label,
.el-radio,
.el-radio__input.is-checked+.el-radio__label,
.el-dialog__body,
.el-tree {
color: #333 !important;
}
.el-radio__label, .el-checkbox__label {
font-size: 12px !important;
}
.my-el-custom-spinner {
display: inline-block !important;
width: 80px !important;
height: 80px !important;
background: url(~@/assets/images/loading.gif) no-repeat center !important;
} */

1730
src/styles/workflowcss/workflow.css

File diff suppressed because it is too large

38
src/utils/workflow/const.ts

@ -0,0 +1,38 @@
/**
*
*/
export let bgColors = ['87, 106, 149', '255, 148, 62', '50, 150, 250','255,102,0','255,255,255']
export let placeholderList = ["发起人", "审核人", "抄送人", "执行人"];
export let setTypes = [
{value: 1, label: '指定成员'},
{value: 2, label: '主管'},
{value: 4, label: '发起人自选'},
{value: 5, label: '发起人自己'},
{value: 7, label: '连续多级主管'},
]
export let selectModes = [
{value: 1, label: '选一个人'},
{value: 2, label: '选多个人'},
]
export let selectRanges = [
{value: 1, label: '全公司'},
{value: 2, label: '指定成员'},
{value: 3, label: '指定角色'},
]
export let optTypes = [
{value: '1', label: '小于'},
{value: '2', label: '大于'},
{value: '3', label: '小于等于'},
{value: '4', label: '等于'},
{value: '5', label: '大于等于'},
{value: '6', label: '介于两个数之间'},
]
export let opt1s = [
{value: '<', label: '<'},
{value: '≤', label: '≤'},
]

157
src/utils/workflow/index.ts

@ -0,0 +1,157 @@
function All() {}
All.prototype = {
timer: "",
debounce(fn:any, delay = 500) {
var _this = this;
return (arg: any) => {
//获取函数的作用域和变量
let that = this;
let args = arg;
clearTimeout(_this.timer) // 清除定时器
_this.timer = setTimeout(function() {
fn.call(that, args)
}, delay)
}
},
setCookie(val:any) { //cookie设置[{key:value}]、获取key、清除['key1','key2']
for (var i = 0, len = val.length; i < len; i++) {
for (var key in val[i]) {
document.cookie = key + '=' + encodeURIComponent(val[i][key]) + "; path=/";
}
}
},
getCookie(name:any) {
var strCookie = document.cookie;
var arrCookie = strCookie.split("; ");
for (var i = 0, len = arrCookie.length; i < len; i++) {
var arr = arrCookie[i].split("=");
if (name == arr[0]) {
return decodeURIComponent(arr[1]);
}
}
},
clearCookie(name:any) {
var myDate = new Date();
myDate.setTime(-1000); //设置时间
for (var i = 0, len = name.length; i < len; i++) {
document.cookie = "" + name[i] + "=''; path=/; expires=" + myDate.toUTCString();
}
},
arrToStr(arr:any) {
if (arr) {
return arr.map((item: { name: any; }) => { return item.name }).toString()
}
},
toggleClass(arr:any, elem:any, key = 'id') {
return arr.some((item: { [x: string]: any; }) => { return item[key] == elem[key] });
},
toChecked(arr:any, elem:any, key = 'id') {
var isIncludes = this.toggleClass(arr, elem, key);
!isIncludes ? arr.push(elem) : this.removeEle(arr, elem, key);
},
removeEle(arr:any, elem:any, key = 'id') {
var includesIndex;
arr.map((item:any, index:any) => {
if (item[key] == elem[key]) {
includesIndex = index
}
});
arr.splice(includesIndex, 1);
},
setApproverStr(nodeConfig:any) {
if (nodeConfig.settype == 1) {
if (nodeConfig.nodeUserList.length == 1) {
return nodeConfig.nodeUserList[0].name
} else if (nodeConfig.nodeUserList.length > 1) {
if (nodeConfig.examineMode == 1) {
return this.arrToStr(nodeConfig.nodeUserList)
} else if (nodeConfig.examineMode == 2) {
return nodeConfig.nodeUserList.length + "人会签"
}
}
} else if (nodeConfig.settype == 2) {
let level = nodeConfig.directorLevel == 1 ? '直接主管' : '第' + nodeConfig.directorLevel + '级主管'
if (nodeConfig.examineMode == 1) {
return level
} else if (nodeConfig.examineMode == 2) {
return level + "会签"
}
} else if (nodeConfig.settype == 4) {
if (nodeConfig.selectRange == 1) {
return "发起人自选"
} else {
if (nodeConfig.nodeUserList.length > 0) {
if (nodeConfig.selectRange == 2) {
return "发起人自选"
} else {
return '发起人从' + nodeConfig.nodeUserList[0].name + '中自选'
}
} else {
return "";
}
}
} else if (nodeConfig.settype == 5) {
return "发起人自己"
} else if (nodeConfig.settype == 7) {
return '从直接主管到通讯录中级别最高的第' + nodeConfig.examineEndDirectorLevel + '个层级主管'
}
},
dealStr(str:any, obj:any) {
let arr: any[] = [];
let list = str.split(",");
for (var elem in obj) {
list.map((item: string) => {
if (item == elem) {
arr.push(obj[elem].value)
}
})
}
return arr.join("或")
},
conditionStr(nodeConfig:any, index:any) {
var { conditionList, nodeUserList } = nodeConfig.conditionNodes[index];
if (conditionList.length == 0) {
return (index == nodeConfig.conditionNodes.length - 1) && nodeConfig.conditionNodes[0].conditionList.length != 0 ? '其他条件进入此流程' : '请设置条件'
} else {
let str = ""
for (var i = 0; i < conditionList.length; i++) {
var { columnId, columnType, showType, showName, optType, zdy1, opt1, zdy2, opt2, fixedDownBoxValue } = conditionList[i];
if (columnId == 0) {
if (nodeUserList.length != 0) {
str += '发起人属于:'
str += nodeUserList.map((item: { name: any; }) => { return item.name }).join("或") + " 并且 "
}
}
if (columnType == "String" && showType == "3") {
if (zdy1) {
str += showName + '属于:' + this.dealStr(zdy1, JSON.parse(fixedDownBoxValue)) + " 并且 "
}
}
if (columnType == "Double") {
if (optType != 6 && zdy1) {
var optTypeStr = ["", "<", ">", "≤", "=", "≥"][optType]
str += `${showName} ${optTypeStr} ${zdy1} 并且 `
} else if (optType == 6 && zdy1 && zdy2) {
str += `${zdy1} ${opt1} ${showName} ${opt2} ${zdy2} 并且 `
}
}
}
return str ? str.substring(0, str.length - 4) : '请设置条件'
}
},
copyerStr(nodeConfig:any) {
if (nodeConfig.nodeUserList.length != 0) {
return this.arrToStr(nodeConfig.nodeUserList)
} else {
if (nodeConfig.ccSelfSelectFlag == 1) {
return "发起人自选"
}
}
},
toggleStrClass(item: { zdy1: string; }, key: any) {
let a = item.zdy1 ? item.zdy1.split(",") : []
return a.some((item: any) => { return item == key });
},
}
export default new (All as any)();

12
src/views/sysworkflow/codepage/index.vue

@ -11,7 +11,7 @@ import CreateForm from '@/views/sysworkflow/codepage/createform.vue'
import SetupConfig from '@/views/sysworkflow/codepage/setupconfig.vue'
import DataTableStructure from '@/views/sysworkflow/codepage/datatablestructure.vue'
const contbody = ref()
const queryParams = reactive<SearchForm>({
page: 1,
pagesize:15
@ -23,7 +23,7 @@ const show =ref(false); //加载表单
const drawerOpenOrClose = ref(false);
const total = ref(0); //
const contList = ref<customerFormCont[]>()
const drawerWith = ref<number>(0);
const drawerWith = ref();
const editid = ref<string>("")
const formConfigCont = reactive<customerFormConfig>({
formname:"",
@ -48,6 +48,7 @@ function resetQuery(){
//
function openDialog(){
formId.value = ""
drawerWith.value = contbody.value?.clientWidth
getProductionMarkForm()
.then(({data})=>{
formConfigCont.formlogo = data.formlogo
@ -122,14 +123,15 @@ function setupCustomerForm(cont:customerFormCont){
}
onMounted(()=>{
handleQuery();
drawerWith.value = window.innerWidth - 220
// drawerWith.value = window.innerWidth - 220
});
window.addEventListener("resize", function(){
drawerWith.value = window.innerWidth -220
// drawerWith.value = window.innerWidth -220
// console.log("-->",window.innerWidth);
})
//
function editCustomerForm(cont:customerFormCont){
drawerWith.value = contbody.value?.clientWidth
formId.value = cont.id.toString();
drawerOpenOrClose.value = true;
}
@ -143,7 +145,7 @@ const openDataTableStructure = (cont:customerFormCont) =>{
}
</script>
<template>
<div class="app-container">
<div ref="contbody" class="app-container">
<div class="search">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="关键字" prop="keywords">

129
src/views/sysworkflow/flow/flowcanvas.vue

@ -0,0 +1,129 @@
<!--
@ 作者: 秦东
@ 时间: 2023-05-26 09:19:46
@ 备注:
-->
<script lang='ts' setup>
import '@/styles/workflowcss/workflow.css'
import { useStore } from '@/store/workflow/index'
import { tipListStrucr } from '@/api/workflowapi/types'
import { initializeWorkFlow,setWorkFlowData } from '@/api/workflowapi/index'
let { setTableId, setIsTried } = useStore()
let tipList = ref<any>([]);
let tipVisible = ref(false);
let nowVal = ref(100); //
let processConfig = ref<any>({});
let nodeConfig = ref({});
let workFlowDef = ref({});
let flowPermission = ref([]);
let directorMaxLevel = ref(0);
//
onMounted(async ()=>{
let { data } = await initializeWorkFlow({name:""})
console.log("data",data)
let {
nodeConfig: nodes,
flowPermission: flows,
directorMaxLevel: directors,
workFlowDef: works,
tableId,
} = data;
nodeConfig.value = nodes;
flowPermission.value = flows;
directorMaxLevel.value = directors;
workFlowDef.value = works;
setTableId(tableId);
})
//
const reErr = ({ childNode }:any) => {
if (childNode) {
let { type, error, nodeName, conditionNodes } = childNode;
if (type == 1 || type == 2 || type == 3) {
if (error) {
tipList.value.push({
name: nodeName,
type: ["", "审核人", "抄送人", "执行人"][type],
});
}
reErr(childNode);
} else if (type == 4) {
reErr(childNode);
} else if (type == 5) {
reErr(childNode);
for (var i = 0; i < conditionNodes.length; i++) {
if (conditionNodes[i].error) {
tipList.value.push({ name: conditionNodes[i].nodeName, type: "条件" });
}
reErr(conditionNodes[i]);
}
}
} else {
childNode = null;
}
};
//
const saveSet = async () => {
setIsTried(true);
tipList.value = [];
reErr(nodeConfig.value);
if (tipList.value.length != 0) {
tipVisible.value = true;
return;
}
processConfig.value.flowPermission = flowPermission.value;
// eslint-disable-next-line no-console
console.log(JSON.stringify(processConfig.value));
let res = await setWorkFlowData(processConfig.value);
if (res.code == 200) {
ElMessage.success("设置成功")
setTimeout(function () {
window.location.href = "";
}, 200);
}
};
//
const zoomSize = (type:number) => {
if (type == 1) {
if (nowVal.value == 50) {
return;
}
nowVal.value -= 10;
} else {
if (nowVal.value == 300) {
return;
}
nowVal.value += 10;
}
};
</script>
<template>
<div class="canvas_body">
<div class="fd-nav-content-new">
<!--画板-->
<section class="dingflow-design">
<div class="zoom">
<div class="zoom-out" :class="nowVal == 50 && 'disabled'" @click="zoomSize(1)"></div>
<span>{{ nowVal }}%</span>
<div class="zoom-in" :class="nowVal == 300 && 'disabled'" @click="zoomSize(2)"></div>
</div>
<div class="box-scale" :style="`transform: scale(${ nowVal / 100});`">
<nodeWrap v-model:nodeConfig="nodeConfig" v-model:flowPermission="flowPermission" />
<div class="end-node">
<div class="end-node-circle"></div>
<div class="end-node-text">流程结束</div>
</div>
</div>
</section>
</div>
</div>
</template>
<style lang='scss' scoped>
.canvas_body{
height: 100%;
width: inherit;
}
</style>

161
src/views/sysworkflow/flow/index.vue

@ -4,11 +4,170 @@
@ 备注:
-->
<script lang='ts' setup>
import '@/styles/workflowcss/workflow.css'
import { useStore } from '@/store/workflow/index'
import { tipListStrucr } from '@/api/workflowapi/types'
import { initializeWorkFlow,setWorkFlowData } from '@/api/workflowapi/index'
const flowcont = ref()
const drawer = ref(false)
const drawerWidht = ref()
const openfloaw = ()=>{
drawerWidht.value = flowcont.value?.clientWidth
console.log("clientHeight--->",drawerWidht.value)
drawer.value = true
}
let { setTableId, setIsTried } = useStore()
let tipList = ref<any>([]);
let tipVisible = ref(false);
let nowVal = ref(100); //
let processConfig = ref<any>({});
let nodeConfig = ref({});
let workFlowDef = ref({});
let flowPermission = ref([]);
let directorMaxLevel = ref(0);
//
onMounted(async ()=>{
initWorkFlowData()
})
//
const initWorkFlowData = async() => {
let { data } = await initializeWorkFlow({name:""})
console.log("data",data)
let {
nodeConfig: nodes,
flowPermission: flows,
directorMaxLevel: directors,
workFlowDef: works,
tableId,
} = data;
nodeConfig.value = nodes;
flowPermission.value = flows;
directorMaxLevel.value = directors;
workFlowDef.value = works;
setTableId(tableId);
}
//
const reErr = ({ childNode }:any) => {
if (childNode) {
let { type, error, nodeName, conditionNodes } = childNode;
if (type == 1 || type == 2 || type == 3) {
if (error) {
tipList.value.push({
name: nodeName,
type: ["", "审核人", "抄送人", "执行人"][type],
});
}
reErr(childNode);
} else if (type == 4) {
reErr(childNode);
} else if (type == 5) {
reErr(childNode);
for (var i = 0; i < conditionNodes.length; i++) {
if (conditionNodes[i].error) {
tipList.value.push({ name: conditionNodes[i].nodeName, type: "条件" });
}
reErr(conditionNodes[i]);
}
}
} else {
childNode = null;
}
};
//
const saveSet = async () => {
setIsTried(true);
tipList.value = [];
reErr(nodeConfig.value);
if (tipList.value.length != 0) {
tipVisible.value = true;
return;
}
processConfig.value.flowPermission = flowPermission.value;
// eslint-disable-next-line no-console
console.log(JSON.stringify(processConfig.value));
let res = await setWorkFlowData(processConfig.value);
if (res.code == 200) {
ElMessage.success("设置成功")
setTimeout(function () {
window.location.href = "";
}, 200);
}
};
//
const zoomSize = (type:number) => {
if (type == 1) {
if (nowVal.value == 50) {
return;
}
nowVal.value -= 10;
} else {
if (nowVal.value == 300) {
return;
}
nowVal.value += 10;
}
};
//
const clearCanvas = () =>{
ElMessageBox.confirm('确定要清空画布?')
.then(() => {
initWorkFlowData()
setIsTried(false);
tipList.value = []
})
}
</script>
<template>
<div>流程</div>
<div ref="flowcont">
<el-button type="primary" @click="openfloaw">添加</el-button>
<el-drawer v-model="drawer" :size="drawerWidht" :show-close="false">
<template #header="{ close, titleId, titleClass }">
<h4 :id="titleId" :class="titleClass">创建流程</h4>
<el-button type="warning" @click="clearCanvas">
<el-icon class="el-icon--left"><CircleCloseFilled /></el-icon>
清空
</el-button>
<el-button type="primary" @click="saveSet">
<el-icon class="el-icon--left"><CircleCloseFilled /></el-icon>
发布
</el-button>
<el-button type="danger" @click="close">
<el-icon class="el-icon--left"><CircleCloseFilled /></el-icon>
关闭
</el-button>
</template>
<div class="canvas_body">
<div class="fd-nav-content-new">
<!--画板-->
<section class="dingflow-design">
<div class="zoom">
<div class="zoom-out" :class="nowVal == 50 && 'disabled'" @click="zoomSize(1)"></div>
<span>{{ nowVal }}%</span>
<div class="zoom-in" :class="nowVal == 300 && 'disabled'" @click="zoomSize(2)"></div>
</div>
<div class="box-scale" :style="`transform: scale(${ nowVal / 100});`">
<nodeWrap v-model:nodeConfig="nodeConfig" v-model:flowPermission="flowPermission" />
<div class="end-node">
<div class="end-node-circle"></div>
<div class="end-node-text">流程结束</div>
</div>
</div>
</section>
</div>
</div>
</el-drawer>
</div>
</template>
<style lang='scss' scoped>
.canvas_body{
height: 100%;
width: inherit;
}
</style>

6
src/views/taskplatform/taskmanagement/edittaskcustomerform.vue

@ -39,6 +39,10 @@ const props = defineProps({
infoid:{
type:String,
default:""
},
drawerwith:{
type:Number,
default:0
}
})
const submitButton = {
@ -217,7 +221,7 @@ watch(()=>props.iseditopen,()=>{
})
</script>
<template>
<el-drawer v-model="isShow" v-loading="loadingData" :title="versiontitle" :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true" :size="drawerWith" class="drawerClass" >
<el-drawer v-model="isShow" v-loading="loadingData" :title="versiontitle" :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true" :size="props.drawerwith" class="drawerClass" >
<div class="drawerBody">
<ak-form
ref="formEl"

6
src/views/taskplatform/taskmanagement/taskcustomerform.vue

@ -35,6 +35,10 @@ const props = defineProps({
infoid:{
type:String,
default:""
},
drawerwith:{
type:Number,
default:0
}
})
const submitButton = {
@ -162,7 +166,7 @@ watch(()=>props.isopen,()=>{
})
</script>
<template>
<el-drawer v-model="drawerOpenOrClose" v-loading="loadingData" :title="versiontitle" :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true" :size="drawerWith" class="drawerClass" >
<el-drawer v-model="drawerOpenOrClose" v-loading="loadingData" :title="versiontitle" :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true" :size="props.drawerwith" class="drawerClass" >
<div class="drawerBody">
<ak-form
ref="formEl"

12
src/views/taskplatform/taskmanagement/tasklist.vue

@ -64,6 +64,7 @@ function handleSelectionChange(selection: any) {
}
//
const addDialog = () =>{
drawerWith.value = contbody.value?.clientWidth
openTaskDialog.value = true;
}
//
@ -72,7 +73,7 @@ const batchDeleteLog = () =>{
}
//
const editFormLogDialog = (val:any) =>{
console.log("编辑表单",val)
drawerWith.value = contbody.value?.clientWidth
versionId.value = val.version_id.toString()
versionTitle.value = val.title
mastersKey.value = val.mastersKeyStr.toString()
@ -86,9 +87,12 @@ const DeleteFormLog = (id:any) =>{
searchQuery();
})
}
const contbody = ref()
const drawerWith = ref<number>(0);
//
onMounted(() => {
searchQuery();
drawerWith.value = contbody.value?.clientWidth
});
//
@ -100,6 +104,7 @@ const openCustomerForm = (id:string,title:string) =>{
}
</script>
<template>
<div ref="contbody">
<div class="app-container">
<div class="search">
<el-form ref="searckFormRef" :model="searchData" :inline="true">
@ -174,9 +179,10 @@ const openCustomerForm = (id:string,title:string) =>{
/>
</el-card>
<TaskEntry v-model:isshow="openTaskDialog" @opencustomerform="openCustomerForm" />
<TaskCustomerForm v-model:isopen="openTaskDrawer" :versionid="versionId" :versiontitle="versionTitle" @searchquery="searchQuery" />
<EditTaskCustomerForm v-model:iseditopen="openEditTaskDrawer" :versionid="versionId" :versiontitle="versionTitle" :masterskey="mastersKey" infoid="2" @searchquery="searchQuery" />
<TaskCustomerForm v-model:isopen="openTaskDrawer" :versionid="versionId" :versiontitle="versionTitle" :drawerwith="drawerWith" @searchquery="searchQuery" />
<EditTaskCustomerForm v-model:iseditopen="openEditTaskDrawer" :versionid="versionId" :versiontitle="versionTitle" :masterskey="mastersKey" infoid="2" :drawerwith="drawerWith" @searchquery="searchQuery" />
</div>
</div>
</template>
<style lang='scss' scoped>

Loading…
Cancel
Save