Browse Source

整合流程文件

master
超级管理员 3 years ago
parent
commit
c83e8b41f3
  1. 44102
      package-lock.json
  2. 14
      package.json
  3. 10
      src/components/Table/PropTable/index.vue
  4. 220
      src/components/addNode.vue
  5. 46
      src/components/dialog/common.js
  6. 122
      src/components/dialog/employeesDialog.vue
  7. 160
      src/components/dialog/employeesRoleDialog.vue
  8. 77
      src/components/dialog/errorDialog.vue
  9. 96
      src/components/dialog/roleDialog.vue
  10. 231
      src/components/drawer/approverDrawer.vue
  11. 363
      src/components/drawer/conditionDrawer.vue
  12. 95
      src/components/drawer/copyerDrawer.vue
  13. 85
      src/components/drawer/promoterDrawer.vue
  14. 311
      src/components/nodeWrap.vue
  15. 82
      src/components/selectBox.vue
  16. 98
      src/components/selectResult.vue
  17. 2
      src/router/index.ts
  18. 23
      src/router/modules/workflow.ts
  19. 14
      src/views/workflow/index.vue
  20. 6
      tsconfig.json
  21. 6728
      yarn.lock

44102
package-lock.json

File diff suppressed because it is too large

14
package.json

@ -58,7 +58,7 @@
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.32.0", "@typescript-eslint/eslint-plugin": "^5.32.0",
"@typescript-eslint/parser": "^5.32.0", "@typescript-eslint/parser": "^5.32.0",
"@vitejs/plugin-vue": "^3.0.0", "@vitejs/plugin-vue": "^3.0.1",
"consola": "^2.15.3", "consola": "^2.15.3",
"dart-sass": "^1.25.0", "dart-sass": "^1.25.0",
"eslint": "^8.21.0", "eslint": "^8.21.0",
@ -68,14 +68,18 @@
"fast-glob": "^3.2.11", "fast-glob": "^3.2.11",
"prettier": "^2.7.1", "prettier": "^2.7.1",
"typescript": "^4.6.4", "typescript": "^4.6.4",
"unplugin-auto-import": "^0.10.3", "unplugin-auto-import": "^0.11.2",
"unplugin-vue-components": "^0.21.2", "unplugin-vue-components": "^0.22.4",
"unplugin-vue-define-options": "^0.7.3", "unplugin-vue-define-options": "^0.7.3",
"vite": "^3.0.0", "vite": "^3.0.4",
"vite-plugin-compression": "^0.5.1", "vite-plugin-compression": "^0.5.1",
"vite-plugin-style-import": "^2.0.0", "vite-plugin-style-import": "^2.0.0",
"vite-plugin-svg-icons": "^2.0.1", "vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-vue-setup-extend": "^0.4.0", "vite-plugin-vue-setup-extend": "^0.4.0",
"vue-tsc": "^0.38.4" "vue-tsc": "^0.38.4",
"@vue/cli-plugin-vuex": "~4.5.7",
"less": "^4.1.3",
"less-loader": "^11.0.0",
"vue-cli-plugin-axios": "~0.0.4"
} }
} }

10
src/components/Table/PropTable/index.vue

@ -198,10 +198,8 @@ const deleteAction = (row) => {
box-shadow: 0 0 12px rgb(0 0 0 / 5%); box-shadow: 0 0 12px rgb(0 0 0 / 5%);
.search-form{ .search-form{
flex: 1; flex: 1;
::v-deep{ ::v-deep(.el-input--default){
.el-input--default{
width: 200px; width: 200px;
}
} }
} }
.search{ .search{
@ -231,12 +229,12 @@ const deleteAction = (row) => {
height: 100%; height: 100%;
} }
} }
::v-deep{ ::v-deep(.el-table__header) th{
.el-table__header th{
font-size: 15px; font-size: 15px;
font-weight: 700; font-weight: 700;
color: #252525; color: #252525;
}
} }
.pagination{ .pagination{
width: 100%; width: 100%;

220
src/components/addNode.vue

@ -0,0 +1,220 @@
<template>
<div class="add-node-btn-box">
<div class="add-node-btn">
<el-popover placement="right-start" v-model="visible" 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"></span>
</div>
<p>审批人</p>
</a>
<a class="add-node-popover-item notifier" @click="addType(2)">
<div class="item-wrapper">
<span class="iconfont"></span>
</div>
<p>抄送人</p>
</a>
<a class="add-node-popover-item condition" @click="addType(4)">
<div class="item-wrapper">
<span class="iconfont"></span>
</div>
<p>条件分支</p>
</a>
</div>
<template #reference>
<button class="btn" type="button">
<span class="iconfont"></span>
</button>
</template>
</el-popover>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
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": []
}
}
emits("update:childNodeP", data)
} else {
emits("update:childNodeP", {
"nodeName": "路由",
"type": 4,
"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>
<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>

46
src/components/dialog/common.js

@ -0,0 +1,46 @@
/*
* @Date: 2022-08-29 14:00:42
* @LastEditors: StavinLi 495727881@qq.com
* @LastEditTime: 2023-03-29 15:53:05
* @FilePath: /Workflow-Vue3/src/components/dialog/common.js
*/
import { getRoles, getDepartments, getEmployees } from '@/api/index.js'
import $func from '@/utils/index.js'
import { ref } from 'vue'
export let searchVal = ref('')
export let departments = ref({
titleDepartments: [],
childDepartments: [],
employees: [],
})
export let roles = ref({})
export let getRoleList = async () => {
let { data: { list } } = await getRoles()
roles.value = list;
}
export let getDepartmentList = async (parentId = 0) => {
let { data } = await getDepartments({ parentId })
departments.value = data;
}
export let getDebounceData = (event, type = 1) => {
$func.debounce(async () => {
if (event.target.value) {
let data = {
searchName: event.target.value,
pageNum: 1,
pageSize: 30
}
if (type == 1) {
departments.value.childDepartments = [];
let res = await getEmployees(data)
departments.value.employees = res.data.list
} else {
let res = await getRoles(data)
roles.value = res.data.list
}
} else {
type == 1 ? await getDepartmentList() : await getRoleList();
}
})()
}

122
src/components/dialog/employeesDialog.vue

@ -0,0 +1,122 @@
<template>
<el-dialog title="选择成员" v-model="visibleDialog" :width="600" append-to-body class="promoter_person">
<div class="person_body clear">
<div class="person_tree l">
<input type="text" placeholder="搜索成员" v-model="searchVal" @input="getDebounceData($event)">
<p class="ellipsis tree_nav" v-if="!searchVal">
<span @click="getDepartmentList(0)" class="ellipsis">天下</span>
<span v-for="(item,index) in departments.titleDepartments" class="ellipsis"
:key="index+'a'" @click="getDepartmentList(item.id)">{{item.departmentName}}</span>
</p>
<selectBox :list="list"/>
</div>
<selectResult :total="total" @del="delList" :list="resList"/>
</div>
<template #footer>
<el-button @click="$emit('update:visible',false)"> </el-button>
<el-button type="primary" @click="saveDialog"> </el-button>
</template>
</el-dialog>
</template>
<script setup>
import selectBox from '../selectBox.vue';
import selectResult from '../selectResult.vue';
import { computed, watch, ref } from 'vue';
import { departments, getDebounceData, getDepartmentList, searchVal } from './common'
import $func from '@/utils/index.js'
let props = defineProps({
visible: {
type: Boolean,
default: false
},
data:{
type: Array,
default: ()=> []
},
isDepartment: {
type: Boolean,
default: false
},
});
let emits = defineEmits(['update:visible', 'change'])
let visibleDialog = computed({
get(){
return props.visible
},
set(){
closeDialog()
}
});
let checkedDepartmentList = ref([])
let checkedEmployessList = ref([])
let list = computed(()=> {
return [{
isDepartment: props.isDepartment,
type: 'department',
data: departments.value.childDepartments,
isActive: (item)=> $func.toggleClass(checkedDepartmentList.value, item),
change: (item)=> $func.toChecked(checkedDepartmentList.value, item),
next: (item)=> getDepartmentList(item.id)
},{
type: 'employee',
data: departments.value.employees,
isActive: (item)=> $func.toggleClass(checkedEmployessList.value, item),
change: (item)=> $func.toChecked(checkedEmployessList.value, item),
}]
})
let resList = computed(()=>{
let data = [{
type: 'employee',
data: checkedEmployessList.value,
cancel: (item)=> $func.removeEle(checkedEmployessList.value, item)
}]
if(props.isDepartment){
data.unshift({
type: 'department',
data: checkedDepartmentList.value,
cancel: (item)=> $func.removeEle(checkedDepartmentList.value, item)
})
}
return data
})
watch(()=> props.visible, (val)=>{
if(val){
getDepartmentList();
searchVal.value = "";
checkedEmployessList.value = props.data.filter(item=>item.type===1).map(({name,targetId})=>({
employeeName: name,
id: targetId
}));
checkedDepartmentList.value = props.data.filter(item=>item.type===3).map(({name,targetId})=>({
departmentName: name,
id: targetId
}));
}
})
const closeDialog = ()=> {
emits('update:visible', false)
}
let total = computed(()=> checkedDepartmentList.value.length + checkedEmployessList.value.length)
let saveDialog = ()=> {
let checkedList = [
...checkedDepartmentList.value,
...checkedEmployessList.value
].map(item=>({
type: item.employeeName ? 1: 3,
targetId: item.id,
name: item.employeeName || item.departmentName
}))
emits('change',checkedList)
}
const delList = ()=> {
checkedDepartmentList.value = [];
checkedEmployessList.value = []
}
</script>
<style>
@import "@/css/dialog.css";
</style>

160
src/components/dialog/employeesRoleDialog.vue

@ -0,0 +1,160 @@
<template>
<el-dialog title="选择成员" v-model="visibleDialog" :width="600" append-to-body class="promoter_person">
<div class="person_body clear">
<div class="person_tree l">
<input type="text" placeholder="搜索成员" v-model="searchVal" @input="getDebounceData($event,activeName)">
<el-tabs v-model="activeName" @tab-change="handleClick">
<el-tab-pane label="组织架构" name="1"></el-tab-pane>
<el-tab-pane label="角色列表" name="2"></el-tab-pane>
</el-tabs>
<p class="ellipsis tree_nav" v-if="activeName === '1' && !searchVal">
<span @click="getDepartmentList(0)" class="ellipsis">天下</span>
<span v-for="(item,index) in departments.titleDepartments" class="ellipsis"
:key="index+'a'" @click="getDepartmentList(item.id)">{{item.departmentName}}</span>
</p>
<selectBox :list="list" style="height: 360px;"/>
</div>
<selectResult :total="total" @del="delList" :list="resList"/>
</div>
<template #footer>
<el-button @click="$emit('update:visible',false)"> </el-button>
<el-button type="primary" @click="saveDialog"> </el-button>
</template>
</el-dialog>
</template>
<script setup>
import selectBox from '../selectBox.vue';
import selectResult from '../selectResult.vue';
import { computed, watch, ref } from 'vue'
import $func from '@/utils/index.js'
import { departments, roles, getDebounceData, getRoleList, getDepartmentList, searchVal } from './common'
let props = defineProps({
visible: {
type: Boolean,
default: false
},
data:{
type: Array,
default: ()=> []
},
isDepartment: {
type: Boolean,
default: false
},
});
let emits = defineEmits(['update:visible', 'change'])
let visibleDialog = computed({
get(){
return props.visible
},
set(){
closeDialog()
}
})
let checkedRoleList = ref([])
let checkedEmployessList = ref([])
let checkedDepartmentList = ref([])
let activeName = ref('1')
let list = computed(()=> {
if(activeName.value === '2'){
return [{
type: 'role',
not: false,
data: roles.value,
isActiveItem: (item)=> $func.toggleClass(checkedRoleList.value, item, 'roleId'),
change: (item)=> $func.toChecked(checkedRoleList.value, item, 'roleId')
}]
}else{
return [{
isDepartment: props.isDepartment,
type: 'department',
data: departments.value.childDepartments,
isActive: (item)=> $func.toggleClass(checkedDepartmentList.value, item),
change: (item)=> $func.toChecked(checkedDepartmentList.value, item),
next: (item)=> getDepartmentList(item.id)
},{
type: 'employee',
data: departments.value.employees,
isActive: (item)=> $func.toggleClass(checkedEmployessList.value, item),
change: (item)=> $func.toChecked(checkedEmployessList.value, item),
}]
}
})
let resList = computed(()=>{
let data = [{
type: 'role',
data: checkedRoleList.value,
cancel: (item)=> $func.removeEle(checkedRoleList.value, item, 'roleId')
},{
type: 'employee',
data: checkedEmployessList.value,
cancel: (item)=> $func.removeEle(checkedEmployessList.value, item)
}]
if(props.isDepartment){
data.splice(1, 0, {
type: 'department',
data: checkedDepartmentList.value,
cancel: (item)=> $func.removeEle(checkedDepartmentList.value, item)
})
}
return data
})
watch(()=> props.visible, (val)=>{
if(val){
activeName.value = "1";
getDepartmentList();
searchVal.value = "";
checkedEmployessList.value = props.data.filter(item=>item.type===1).map(({name,targetId})=>({
employeeName: name,
id: targetId
}));
checkedRoleList.value = props.data.filter(item=>item.type===2).map(({name,targetId})=>({
roleName: name,
roleId: targetId
}));
checkedDepartmentList.value = props.data.filter(item=>item.type===3).map(({name,targetId})=>({
departmentName: name,
id: targetId
}));
}
});
let total = computed(()=> {
return checkedEmployessList.value.length
+ checkedRoleList.value.length
+ checkedDepartmentList.value.length
})
const handleClick = ()=> {
searchVal.value = "";
if (activeName.value === '1') {
getDepartmentList();
} else {
getRoleList();
}
}
const saveDialog = ()=> {
let checkedList = [
...checkedRoleList.value,
...checkedEmployessList.value,
...checkedDepartmentList.value
].map(item=>({
type: item.employeeName?1:(item.roleName?2:3),
targetId: item.id || item.roleId,
name: item.employeeName || item.roleName || item.departmentName
}))
emits('change',checkedList)
}
const delList = ()=> {
checkedEmployessList.value = [];
checkedRoleList.value = [];
checkedDepartmentList.value = [];
}
const closeDialog = ()=> {
emits('update:visible', false)
}
</script>
<style>
@import "@/css/dialog.css";
</style>

77
src/components/dialog/errorDialog.vue

@ -0,0 +1,77 @@
<!--
* @Date: 2022-08-25 14:05:59
* @LastEditors: StavinLi 495727881@qq.com
* @LastEditTime: 2023-03-29 16:05:54
* @FilePath: /Workflow-Vue3/src/components/dialog/errorDialog.vue
-->
<template>
<el-dialog title="提示" v-model="visibleDialog" :width="520">
<div class="ant-confirm-body">
<i class="anticon anticon-close-circle" style="color: #f00;"></i>
<span class="ant-confirm-title">当前无法发布</span>
<div class="ant-confirm-content">
<div>
<p class="error-modal-desc">以下内容不完善需进行修改</p>
<div class="error-modal-list">
<div class="error-modal-item" v-for="(item,index) in list" :key="index">
<div class="error-modal-item-label">流程设计</div>
<div class="error-modal-item-content">{{item.name}} 未选择{{item.type}}</div>
</div>
</div>
</div>
</div>
</div>
<template #footer>
<el-button @click="visibleDialog = false">我知道了</el-button>
<el-button type="primary" @click="visibleDialog = false">前往修改</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { computed } from 'vue'
let props = defineProps({
list: {
type: Array,
default: () => []
},
visible: {
type: Boolean,
default: false
}
})
let emits = defineEmits(['update:visible'])
let visibleDialog = computed({
get() {
return props.visible
},
set(val) {
emits('update:visible', val)
}
})
</script>
<style scoped>
.ant-confirm-body .ant-confirm-title {
color: rgba(0, 0, 0, .85);
font-weight: 500;
font-size: 16px;
line-height: 1.4;
display: block;
overflow: hidden
}
.ant-confirm-body .ant-confirm-content {
margin-left: 38px;
font-size: 14px;
color: rgba(0, 0, 0, .65);
margin-top: 8px
}
.ant-confirm-body>.anticon {
font-size: 22px;
margin-right: 16px;
float: left
}
</style>

96
src/components/dialog/roleDialog.vue

@ -0,0 +1,96 @@
<!--
* @Date: 2022-08-25 14:05:59
* * @LastEditors: StavinLi 495727881@qq.com
* @LastEditTime: 2023-03-15 14:59:19
* @FilePath: /Workflow-Vue3/src/components/dialog/roleDialog.vue
-->
<template>
<el-dialog title="选择角色" v-model="visibleDialog" :width="600" append-to-body class="promoter_person">
<div class="person_body clear">
<div class="person_tree l">
<input type="text" placeholder="搜索角色" v-model="searchVal" @input="getDebounceData($event,2)">
<selectBox :list="list" />
</div>
<selectResult :total="total" @del="delList" :list="resList"/>
</div>
<template #footer>
<el-button @click="closeDialog"> </el-button>
<el-button type="primary" @click="saveDialog"> </el-button>
</template>
</el-dialog>
</template>
<script setup>
import selectBox from '../selectBox.vue';
import selectResult from '../selectResult.vue';
import { computed, watch, ref } from 'vue'
import $func from '@/utils/index.js'
import { roles, getDebounceData, getRoleList, searchVal } from './common'
let props = defineProps({
visible: {
type: Boolean,
default: false
},
data: {
type: Array,
default: () => []
}
});
let checkedRoleList = ref([])
let emits = defineEmits(['update:visible', 'change'])
let list = computed(() => {
return [{
type: 'role',
not: true,
data: roles.value,
isActive: (item) => $func.toggleClass(checkedRoleList.value, item, 'roleId'),
change: (item) => {
checkedRoleList.value = [item]
}
}]
})
let resList = computed(() => {
return [{
type: 'role',
data: checkedRoleList.value,
cancel: (item) => $func.removeEle(checkedRoleList.value, item, 'roleId')
}]
})
let visibleDialog = computed({
get() {
return props.visible
},
set(val) {
closeDialog()
}
})
watch(() => props.visible, (val) => {
if (val) {
getRoleList();
searchVal.value = "";
checkedRoleList.value = props.data.map(({ name, targetId }) => ({
roleName: name,
roleId: targetId
}));
}
})
let total = computed(() => checkedRoleList.value.length)
const saveDialog = () => {
let checkedList = checkedRoleList.value.map(item => ({
type: 2,
targetId: item.roleId,
name: item.roleName
}))
emits('change', checkedList)
}
const delList = () => {
checkedRoleList.value = [];
}
const closeDialog = () => {
emits('update:visible', false)
}
</script>
<style>
@import "@/css/dialog.css";
</style>

231
src/components/drawer/approverDrawer.vue

@ -0,0 +1,231 @@
<template>
<el-drawer :append-to-body="true" title="审批人设置" v-model="visible" custom-class="set_promoter" :show-close="false" :size="550" :before-close="saveApprover">
<div class="demo-drawer__content">
<div class="drawer_content">
<div class="approver_content">
<el-radio-group v-model="approverConfig.settype" class="clear" @change="changeType">
<el-radio v-for="({value, label}) in setTypes" :key="value" :label="value">{{label}}</el-radio>
</el-radio-group>
<el-button type="primary" @click="addApprover" v-if="approverConfig.settype==1">添加/修改成员</el-button>
<p class="selected_list" v-if="approverConfig.settype==1">
<span v-for="(item,index) in approverConfig.nodeUserList" :key="index">{{item.name}}
<img src="@/assets/images/add-close1.png" @click="$func.removeEle(approverConfig.nodeUserList,item,'targetId')">
</span>
<a v-if="approverConfig.nodeUserList.length!=0" @click="approverConfig.nodeUserList=[]">清除</a>
</p>
</div>
<div class="approver_manager" v-if="approverConfig.settype==2">
<p>
<span>发起人的</span>
<select v-model="approverConfig.directorLevel">
<option v-for="item in directorMaxLevel" :value="item" :key="item">{{item==1?'直接':''+item+''}}主管</option>
</select>
</p>
<p class="tip">找不到主管时由上级主管代审批</p>
</div>
<div class="approver_self" v-if="approverConfig.settype==5">
<p>该审批节点设置发起人自己审批人默认为发起人</p>
</div>
<div class="approver_self_select" v-show="approverConfig.settype==4">
<el-radio-group v-model="approverConfig.selectMode" style="width: 100%;">
<el-radio v-for="({value, label}) in selectModes" :label="value" :key="value">{{label}}</el-radio>
</el-radio-group>
<h3>选择范围</h3>
<el-radio-group v-model="approverConfig.selectRange" style="width: 100%;" @change="changeRange">
<el-radio v-for="({value, label}) in selectRanges" :label="value" :key="value">{{label}}</el-radio>
</el-radio-group>
<template v-if="approverConfig.selectRange==2||approverConfig.selectRange==3">
<el-button type="primary" @click="addApprover" v-if="approverConfig.selectRange==2">添加/修改成员</el-button>
<el-button type="primary" @click="addRoleApprover" v-else>添加/修改角色</el-button>
<p class="selected_list">
<span v-for="(item,index) in approverConfig.nodeUserList" :key="index">{{item.name}}
<img src="@/assets/images/add-close1.png" @click="$func.removeEle(approverConfig.nodeUserList,item,'targetId')">
</span>
<a v-if="approverConfig.nodeUserList.length!=0&&approverConfig.selectRange!=1" @click="approverConfig.nodeUserList=[]">清除</a>
</p>
</template>
</div>
<div class="approver_manager" v-if="approverConfig.settype==7">
<p>审批终点</p>
<p style="padding-bottom:20px">
<span>发起人的</span>
<select v-model="approverConfig.examineEndDirectorLevel">
<option v-for="item in directorMaxLevel" :value="item" :key="item">{{item==1?'最高':''+item}}层级主管</option>
</select>
</p>
</div>
<div class="approver_some" v-if="(approverConfig.settype==1&&approverConfig.nodeUserList.length>1)||approverConfig.settype==2||(approverConfig.settype==4&&approverConfig.selectMode==2)">
<p>多人审批时采用的审批方式</p>
<el-radio-group v-model="approverConfig.examineMode" class="clear">
<el-radio :label="1">依次审批</el-radio>
<br/>
<el-radio :label="2" v-if="approverConfig.settype!=2">会签(须所有审批人同意)</el-radio>
</el-radio-group>
</div>
<div class="approver_some" v-if="approverConfig.settype==2||approverConfig.settype==7">
<p>审批人为空时</p>
<el-radio-group v-model="approverConfig.noHanderAction" class="clear">
<el-radio :label="1">自动审批通过/不允许发起</el-radio>
<br/>
<el-radio :label="2">转交给审核管理员</el-radio>
</el-radio-group>
</div>
</div>
<div class="demo-drawer__footer clear">
<el-button type="primary" @click="saveApprover"> </el-button>
<el-button @click="closeDrawer"> </el-button>
</div>
<employees-dialog
v-model:visible="approverVisible"
:data="checkedList"
@change="sureApprover"
/>
<role-dialog
v-model:visible="approverRoleVisible"
:data="checkedRoleList"
@change="sureRoleApprover"
/>
</div>
</el-drawer>
</template>
<script setup>
import {ref, watch, computed} from 'vue'
import $func from '@/utils/index'
import { setTypes, selectModes, selectRanges } from '@/utils/const'
import { mapState, mapMutations } from '@/utils/lib'
import employeesDialog from '../dialog/employeesDialog.vue'
import roleDialog from '../dialog/roleDialog.vue'
let props = defineProps({
directorMaxLevel: {
type: Number,
default: 0
}
});
let approverConfig = ref({})
let approverVisible = ref(false)
let approverRoleVisible = ref(false)
let checkedRoleList = ref([])
let checkedList = ref([])
let { approverConfig1, approverDrawer } = mapState()
let visible = computed({
get(){
return approverDrawer.value
},
set(){
closeDrawer()
}
})
watch(approverConfig1, (val)=>{
approverConfig.value = val.value
})
let { setApproverConfig, setApprover} = mapMutations()
let changeRange = ()=> {
approverConfig.value.nodeUserList = [];
}
const changeType = (val)=> {
approverConfig.value.nodeUserList = [];
approverConfig.value.examineMode = 1;
approverConfig.value.noHanderAction = 2;
if (val == 2) {
approverConfig.value.directorLevel = 1;
} else if (val == 4) {
approverConfig.value.selectMode = 1;
approverConfig.value.selectRange = 1;
} else if (val == 7) {
approverConfig.value.examineEndDirectorLevel = 1
}
}
const addApprover = ()=> {
approverVisible.value = true;
checkedList.value = approverConfig.value.nodeUserList
}
const addRoleApprover = ()=> {
approverRoleVisible.value = true;
checkedRoleList.value = approverConfig.value.nodeUserList
}
const sureApprover = (data)=> {
approverConfig.value.nodeUserList = data;
approverVisible.value = false;
}
const sureRoleApprover = (data)=> {
approverConfig.value.nodeUserList = data;
approverRoleVisible.value = false;
}
const saveApprover = ()=> {
approverConfig.value.error = !$func.setApproverStr(approverConfig.value)
setApproverConfig({
value: approverConfig.value,
flag: true,
id: approverConfig1.value.id
})
closeDrawer()
}
const closeDrawer = ()=> {
setApprover(false)
}
</script>
<style lang="less">
.set_promoter{
.approver_content {
padding-bottom: 10px;
border-bottom: 1px solid #f2f2f2;
}
.approver_self_select,
.approver_content{
.el-button{
margin-bottom: 20px;
}
}
.approver_content,
.approver_some,
.approver_self_select{
.el-radio-group{
display: unset;
}
.el-radio{
width: 27%;
margin-bottom: 20px;
height: 16px;
}
}
.approver_manager p {
line-height: 32px;
}
.approver_manager select {
width: 420px;
height: 32px;
background: rgba(255, 255, 255, 1);
border-radius: 4px;
border: 1px solid rgba(217, 217, 217, 1);
}
.approver_manager p.tip {
margin: 10px 0 22px 0;
font-size: 12px;
line-height: 16px;
color: #f8642d;
}
.approver_self {
padding: 28px 20px;
}
.approver_self_select,
.approver_manager,
.approver_content,
.approver_some {
padding: 20px 20px 0;
}
.approver_manager p:first-of-type,
.approver_some p {
line-height: 19px;
font-size: 14px;
margin-bottom: 14px;
}
.approver_self_select h3 {
margin: 5px 0 20px;
font-size: 14px;
font-weight: bold;
line-height: 19px;
}
}
</style>

363
src/components/drawer/conditionDrawer.vue

@ -0,0 +1,363 @@
<!--
* @Date: 2023-03-15 14:44:17
* @LastEditors: StavinLi 495727881@qq.com
* @LastEditTime: 2023-03-29 15:53:11
* @FilePath: /Workflow-Vue3/src/components/drawer/conditionDrawer.vue
-->
<template>
<el-drawer :append-to-body="true" title="条件设置" v-model="visible" custom-class="condition_copyer" :show-close="false" :size="550" :before-close="saveCondition">
<template #header="{ titleId, titleClass }">
<h3 :id="titleId" :class="titleClass">条件设置</h3>
<select v-model="conditionConfig.priorityLevel" class="priority_level">
<option v-for="item in conditionsConfig.conditionNodes.length" :value="item" :key="item">优先级{{item}}</option>
</select>
</template>
<div class="demo-drawer__content">
<div class="condition_content drawer_content">
<p class="tip">当审批单同时满足以下条件时进入此流程</p>
<ul>
<li v-for="(item,index) in conditionConfig.conditionList" :key="index">
<span class="ellipsis">{{item.type==1 ? '发起人':item.showName}}</span>
<div v-if="item.type==1">
<p :class="conditionConfig.nodeUserList.length > 0?'selected_list':''" @click.self="addConditionRole" style="cursor:text">
<span v-for="(item1,index1) in conditionConfig.nodeUserList" :key="index1">
{{item1.name}}<img src="@/assets/images/add-close1.png" @click="$func.removeEle(conditionConfig.nodeUserList,item1,'targetId')">
</span>
<input type="text" placeholder="请选择具体人员/角色/部门" v-if="conditionConfig.nodeUserList.length == 0" @click="addConditionRole">
</p>
</div>
<div v-else-if="item.columnType == 'String' && item.showType == 3">
<p class="check_box">
<a :class="$func.toggleStrClass(item,item1.key)&&'active'" @click="toStrChecked(item,item1.key)"
v-for="(item1,index1) in JSON.parse(item.fixedDownBoxValue)" :key="index1">{{item1.value}}</a>
</p>
</div>
<div v-else>
<p>
<select v-model="item.optType" :style="'width:'+(item.optType==6?370:100)+'px'" @change="changeOptType(item)">
<option v-for="({value, label}) in optTypes" :value="value" :key="value">{{ label }}</option>
</select>
<input v-if="item.optType!=6" type="text" :placeholder="'请输入'+item.showName" v-enter-number="2" v-model="item.zdy1">
</p>
<p v-if="item.optType==6">
<input type="text" style="width:75px;" class="mr_10" v-enter-number="2" v-model="item.zdy1">
<select style="width:60px;" v-model="item.opt1">
<option v-for="({value, label}) in opt1s" :value="value" :key="value">{{ label }}</option>
</select>
<span class="ellipsis" style="display:inline-block;width:60px;vertical-align: text-bottom;">{{item.showName}}</span>
<select style="width:60px;" class="ml_10" v-model="item.opt2">
<option v-for="({value, label}) in opt1s" :value="value" :key="value">{{ label }}</option>
</select>
<input type="text" style="width:75px;" v-enter-number="2" v-model="item.zdy2">
</p>
</div>
<a v-if="item.type==1" @click="conditionConfig.nodeUserList= [];$func.removeEle(conditionConfig.conditionList,item,'columnId')">删除</a>
<a v-if="item.type==2" @click="$func.removeEle(conditionConfig.conditionList,item,'columnId')">删除</a>
</li>
</ul>
<el-button type="primary" @click="addCondition">添加条件</el-button>
<el-dialog title="选择条件" v-model="conditionVisible" :width="480" append-to-body class="condition_list">
<p>请选择用来区分审批流程的条件字段</p>
<p class="check_box">
<a :class="$func.toggleClass(conditionList,{columnId:0},'columnId')&&'active'" @click="$func.toChecked(conditionList,{columnId:0},'columnId')">发起人</a>
<a v-for="(item,index) in conditions" :key="index" :class="$func.toggleClass(conditionList,item,'columnId')&&'active'"
@click="$func.toChecked(conditionList,item,'columnId')">{{item.showName}}</a>
</p>
<template #footer>
<el-button @click="conditionVisible = false"> </el-button>
<el-button type="primary" @click="sureCondition"> </el-button>
</template>
</el-dialog>
</div>
<employees-role-dialog
v-model:visible="conditionRoleVisible"
:data="checkedList"
@change="sureConditionRole"
:isDepartment="true"
/>
<div class="demo-drawer__footer clear">
<el-button type="primary" @click="saveCondition"> </el-button>
<el-button @click="closeDrawer"> </el-button>
</div>
</div>
</el-drawer>
</template>
<script setup>
import { ref, watch, computed } from 'vue'
import $func from '@/utils/index'
import { mapState, mapMutations } from '@/utils/lib'
import { optTypes, opt1s } from '@/utils/const'
import { getConditions } from '@/api/index'
import employeesRoleDialog from '../dialog/employeesRoleDialog.vue'
let conditionVisible = ref(false)
let conditionsConfig = ref({
conditionNodes: [],
})
let conditionConfig = ref({})
let PriorityLevel = ref('')
let conditions = ref([])
let conditionList = ref([])
let checkedList = ref([])
let conditionRoleVisible = ref(false)
let { tableId, conditionsConfig1, conditionDrawer } = mapState()
let visible = computed({
get() {
return conditionDrawer.value
},
set() {
closeDrawer()
}
})
watch(conditionsConfig1, (val) => {
conditionsConfig.value = val.value;
PriorityLevel.value = val.priorityLevel
conditionConfig.value = val.priorityLevel
? conditionsConfig.value.conditionNodes[val.priorityLevel - 1]
: { nodeUserList: [], conditionList: [] }
})
let { setCondition, setConditionsConfig } = mapMutations()
const changeOptType = (item) => {
if (item.optType == 1) {
item.zdy1 = 2;
} else {
item.zdy1 = 1;
item.zdy2 = 2;
}
}
const toStrChecked = (item, key) => {
let a = item.zdy1 ? item.zdy1.split(",") : []
var isIncludes = $func.toggleStrClass(item, key);
if (!isIncludes) {
a.push(key)
item.zdy1 = a.toString()
} else {
removeStrEle(item, key);
}
}
const removeStrEle = (item, key) => {
let a = item.zdy1 ? item.zdy1.split(",") : []
var includesIndex;
a.map((item, index) => {
if (item == key) {
includesIndex = index
}
});
a.splice(includesIndex, 1);
item.zdy1 = a.toString()
}
const addCondition = async () => {
conditionList.value = [];
conditionVisible.value = true;
let { data } = await getConditions({ tableId: tableId.value })
conditions.value = data;
if (conditionConfig.value.conditionList) {
for (var i = 0; i < conditionConfig.value.conditionList.length; i++) {
var { columnId } = conditionConfig.value.conditionList[i]
if (columnId == 0) {
conditionList.value.push({ columnId: 0 })
} else {
conditionList.value.push(conditions.value.filter(item => { return item.columnId == columnId; })[0])
}
}
}
}
const sureCondition = () => {
//1.+
//2.
for (var i = 0; i < conditionList.value.length; i++) {
var { columnId, showName, columnName, showType, columnType, fixedDownBoxValue } = conditionList.value[i];
if ($func.toggleClass(conditionConfig.value.conditionList, conditionList.value[i], "columnId")) {
continue;
}
if (columnId == 0) {
conditionConfig.value.nodeUserList = [];
conditionConfig.value.conditionList.push({
"type": 1,
"columnId": columnId,
"showName": '发起人'
});
} else {
if (columnType == "Double") {
conditionConfig.value.conditionList.push({
"showType": showType,
"columnId": columnId,
"type": 2,
"showName": showName,
"optType": "1",
"zdy1": "2",
"opt1": "<",
"zdy2": "",
"opt2": "<",
"columnDbname": columnName,
"columnType": columnType,
})
} else if (columnType == "String" && showType == "3") {
conditionConfig.value.conditionList.push({
"showType": showType,
"columnId": columnId,
"type": 2,
"showName": showName,
"zdy1": "",
"columnDbname": columnName,
"columnType": columnType,
"fixedDownBoxValue": fixedDownBoxValue
})
}
}
}
//3.-
for (let i = conditionConfig.value.conditionList.length - 1; i >= 0; i--) {
if (!$func.toggleClass(conditionList.value, conditionConfig.value.conditionList[i], "columnId")) {
conditionConfig.value.conditionList.splice(i, 1);
}
}
conditionConfig.value.conditionList.sort(function (a, b) { return a.columnId - b.columnId; });
conditionVisible.value = false;
}
const saveCondition = () => {
closeDrawer()
var a = conditionsConfig.value.conditionNodes.splice(PriorityLevel.value - 1, 1)//
conditionsConfig.value.conditionNodes.splice(conditionConfig.value.priorityLevel - 1, 0, a[0])//
conditionsConfig.value.conditionNodes.map((item, index) => {
item.priorityLevel = index + 1
});
for (var i = 0; i < conditionsConfig.value.conditionNodes.length; i++) {
conditionsConfig.value.conditionNodes[i].error = $func.conditionStr(conditionsConfig.value, i) == "请设置条件" && i != conditionsConfig.value.conditionNodes.length - 1
}
setConditionsConfig({
value: conditionsConfig.value,
flag: true,
id: conditionsConfig1.value.id
})
}
const addConditionRole = () => {
conditionRoleVisible.value = true;
checkedList.value = conditionConfig.value.nodeUserList
}
const sureConditionRole = (data) => {
conditionConfig.value.nodeUserList = data;
conditionRoleVisible.value = false;
}
const closeDrawer = (val) => {
setCondition(false)
}
</script>
<style lang="less">
.condition_copyer {
.priority_level {
position: absolute;
top: 11px;
right: 30px;
width: 100px;
height: 32px;
background: rgba(255, 255, 255, 1);
border-radius: 4px;
border: 1px solid rgba(217, 217, 217, 1);
font-size: 12px;
}
.condition_content {
padding: 20px 20px 0;
p.tip {
margin: 20px 0;
width: 510px;
text-indent: 17px;
line-height: 45px;
background: rgba(241, 249, 255, 1);
border: 1px solid rgba(64, 163, 247, 1);
color: #46a6fe;
font-size: 14px;
}
ul {
max-height: 500px;
overflow-y: scroll;
margin-bottom: 20px;
li {
&>span {
float: left;
margin-right: 8px;
width: 70px;
line-height: 32px;
text-align: right;
}
&>div {
display: inline-block;
width: 370px;
&>p:not(:last-child) {
margin-bottom: 10px;
}
}
&:not(:last-child)>div>p {
margin-bottom: 20px;
}
&>a {
float: right;
margin-right: 10px;
margin-top: 7px;
}
select,
input {
width: 100%;
height: 32px;
background: rgba(255, 255, 255, 1);
border-radius: 4px;
border: 1px solid rgba(217, 217, 217, 1);
}
select+input {
width: 260px;
}
select {
margin-right: 10px;
width: 100px;
}
p.selected_list {
padding-left: 10px;
border-radius: 4px;
min-height: 32px;
border: 1px solid rgba(217, 217, 217, 1);
word-break: break-word;
}
p.check_box {
line-height: 32px;
}
}
}
.el-button {
margin-bottom: 20px;
}
}
}
.condition_list {
.el-dialog__body {
padding: 16px 26px;
}
p {
color: #666666;
margin-bottom: 10px;
&>.check_box {
margin-bottom: 0;
line-height: 36px;
}
}
}
</style>

95
src/components/drawer/copyerDrawer.vue

@ -0,0 +1,95 @@
<!--
* @Date: 2022-08-25 14:05:59
* @LastEditors: StavinLi 495727881@qq.com
* @LastEditTime: 2023-03-16 16:13:48
* @FilePath: /Workflow-Vue3/src/components/drawer/copyerDrawer.vue
-->
<template>
<el-drawer :append-to-body="true" title="抄送人设置" v-model="visible" custom-class="set_copyer" :show-close="false" :size="550" :before-close="saveCopyer">
<div class="demo-drawer__content">
<div class="copyer_content drawer_content">
<el-button type="primary" @click="addCopyer">添加成员</el-button>
<p class="selected_list">
<span v-for="(item,index) in copyerConfig.nodeUserList" :key="index">{{item.name}}
<img src="@/assets/images/add-close1.png" @click="$func.removeEle(copyerConfig.nodeUserList,item,'targetId')">
</span>
<a v-if="copyerConfig.nodeUserList&&copyerConfig.nodeUserList.length!=0" @click="copyerConfig.nodeUserList=[]">清除</a>
</p>
<el-checkbox-group v-model="ccSelfSelectFlag" class="clear">
<el-checkbox :label="1">允许发起人自选抄送人</el-checkbox>
</el-checkbox-group>
</div>
<div class="demo-drawer__footer clear">
<el-button type="primary" @click="saveCopyer"> </el-button>
<el-button @click="closeDrawer"> </el-button>
</div>
<employees-role-dialog
v-model:visible="copyerVisible"
:data="checkedList"
@change="sureCopyer"
/>
</div>
</el-drawer>
</template>
<script setup>
import employeesRoleDialog from '../dialog/employeesRoleDialog.vue'
import $func from '@/utils/index'
import { mapState, mapMutations } from '@/utils/lib.js'
import { ref, watch, computed } from 'vue'
let copyerConfig = ref({})
let ccSelfSelectFlag = ref([])
let copyerVisible = ref(false)
let checkedList = ref([])
let { copyerDrawer, copyerConfig1 } = mapState()
let visible = computed({
get() {
return copyerDrawer.value
},
set() {
closeDrawer()
}
})
let { setCopyerConfig, setCopyer } = mapMutations()
watch(copyerConfig1, (val) => {
copyerConfig.value = val.value;
ccSelfSelectFlag.value = copyerConfig.value.ccSelfSelectFlag == 0 ? [] : [copyerConfig.value.ccSelfSelectFlag]
})
const addCopyer = () => {
copyerVisible.value = true;
checkedList.value = copyerConfig.value.nodeUserList
}
const sureCopyer = (data) => {
copyerConfig.value.nodeUserList = data;
copyerVisible.value = false;
}
const saveCopyer = () => {
copyerConfig.value.ccSelfSelectFlag = ccSelfSelectFlag.value.length == 0 ? 0 : 1;
copyerConfig.value.error = !$func.copyerStr(copyerConfig.value);
setCopyerConfig({
value: copyerConfig.value,
flag: true,
id: copyerConfig1.value.id
})
closeDrawer();
}
const closeDrawer = () => {
setCopyer(false)
}
</script>
<style lang="less">
.set_copyer {
.copyer_content {
padding: 20px 20px 0;
.el-button {
margin-bottom: 20px;
}
.el-checkbox {
margin-bottom: 20px;
}
}
}
</style>

85
src/components/drawer/promoterDrawer.vue

@ -0,0 +1,85 @@
<!--
* @Date: 2022-08-25 14:05:59
* @LastEditors: StavinLi 495727881@qq.com
* @LastEditTime: 2023-03-17 16:06:24
* @FilePath: /Workflow-Vue3/src/components/drawer/promoterDrawer.vue
-->
<template>
<el-drawer :append-to-body="true" title="发起人" v-model="visible" custom-class="set_promoter" :show-close="false" :size="550" :before-close="savePromoter">
<div class="demo-drawer__content">
<div class="promoter_content drawer_content">
<p>{{ $func.arrToStr(flowPermission) || '所有人' }}</p>
<el-button type="primary" @click="addPromoter">添加/修改发起人</el-button>
</div>
<div class="demo-drawer__footer clear">
<el-button type="primary" @click="savePromoter"> </el-button>
<el-button @click="closeDrawer"> </el-button>
</div>
<employees-dialog
:isDepartment="true"
v-model:visible="promoterVisible"
:data="checkedList"
@change="surePromoter"
/>
</div>
</el-drawer>
</template>
<script setup>
import employeesDialog from '../dialog/employeesDialog.vue'
import $func from '@/utils/index'
import { mapState, mapMutations } from '@/utils/lib'
import { computed, ref, watch } from 'vue'
let flowPermission = ref([])
let promoterVisible = ref(false)
let checkedList = ref([])
let { promoterDrawer, flowPermission1 } = mapState()
let visible = computed({
get() {
return promoterDrawer.value
},
set() {
closeDrawer()
}
})
watch(flowPermission1, (val) => {
flowPermission.value = val.value
})
let { setPromoter, setFlowPermission } = mapMutations()
const addPromoter = () => {
checkedList.value = flowPermission.value
promoterVisible.value = true;
}
const surePromoter = (data) => {
flowPermission.value = data;
promoterVisible.value = false;
}
const savePromoter = () => {
setFlowPermission({
value: flowPermission.value,
flag: true,
id: flowPermission1.value.id
})
closeDrawer()
}
const closeDrawer = () => {
setPromoter(false)
}
</script>
<style lang="less">
.set_promoter {
.promoter_content {
padding: 0 20px;
.el-button {
margin-bottom: 20px;
}
p {
padding: 18px 0;
font-size: 14px;
line-height: 20px;
color: #000000;
}
}
}
</style>

311
src/components/nodeWrap.vue

@ -0,0 +1,311 @@
<!--
* @Date: 2022-09-21 14:41:53
* @LastEditors: StavinLi 495727881@qq.com
* @LastEditTime: 2023-04-12 17:48:26
* @FilePath: /Workflow-Vue3/src/components/nodeWrap.vue
-->
<template>
<div class="node-wrap" v-if="nodeConfig.type < 3">
<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"
type="text"
class="ant-input editable-title-input"
@blur="blurEvent()"
@focus="$event.currentTarget.select()"
v-focus
v-model="nodeConfig.nodeName"
: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 class="branch-wrap" v-if="nodeConfig.type == 4">
<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>
<script setup>
import { onMounted, ref, watch, getCurrentInstance, computed } from "vue";
import $func from "@/utils/index";
import { mapState, mapMutations } from "@/utils/lib";
import { bgColors, placeholderList } from '@/utils/const'
let _uid = getCurrentInstance().uid;
let props = defineProps({
nodeConfig: {
type: Object,
default: () => ({}),
},
flowPermission: {
type: Object,
default: () => [],
},
});
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++) {
props.nodeConfig.conditionNodes[i].error = $func.conditionStr(props.nodeConfig, i) == "请设置条件" && i != props.nodeConfig.conditionNodes.length - 1;
}
}
onMounted(() => {
if (props.nodeConfig.type == 1) {
props.nodeConfig.error = !$func.setApproverStr(props.nodeConfig);
} else if (props.nodeConfig.type == 2) {
props.nodeConfig.error = !$func.copyerStr(props.nodeConfig);
} else if (props.nodeConfig.type == 4) {
resetConditionNodesErr()
}
});
let emits = defineEmits(["update:flowPermission", "update:nodeConfig"]);
let {
isTried,
flowPermission1,
approverConfig1,
copyerConfig1,
conditionsConfig1,
} = mapState();
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);
}
});
let {
setPromoter,
setApprover,
setCopyer,
setCondition,
setFlowPermission,
setApproverConfig,
setCopyerConfig,
setConditionsConfig,
} = mapMutations();
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;
props.nodeConfig.conditionNodes[index].nodeName = props.nodeConfig.conditionNodes[index].nodeName || "条件";
} else {
isInput.value = false;
props.nodeConfig.nodeName = props.nodeConfig.nodeName || defaultText
}
};
const delNode = () => {
emits("update:nodeConfig", props.nodeConfig.childNode);
};
const addTerm = () => {
let len = props.nodeConfig.conditionNodes.length + 1;
props.nodeConfig.conditionNodes.push({
nodeName: "条件" + len,
type: 3,
priorityLevel: len,
conditionList: [],
nodeUserList: [],
childNode: null,
});
resetConditionNodesErr()
emits("update:nodeConfig", props.nodeConfig);
};
const delTerm = (index) => {
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 {
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
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);
};
</script>
<style>
.error_tip {
position: absolute;
top: 0px;
right: 0px;
transform: translate(150%, 0px);
font-size: 24px;
}
.promoter_person .el-dialog__body {
padding: 10px 20px 14px 20px;
}
.selected_list {
margin-bottom: 20px;
line-height: 30px;
}
.selected_list span {
margin-right: 10px;
padding: 3px 6px 3px 9px;
line-height: 12px;
white-space: nowrap;
border-radius: 2px;
border: 1px solid rgba(220, 220, 220, 1);
}
.selected_list img {
margin-left: 5px;
width: 7px;
height: 7px;
cursor: pointer;
}
</style>

82
src/components/selectBox.vue

@ -0,0 +1,82 @@
<!--
* @Date: 2022-08-26 17:18:14
* @LastEditors: StavinLi 495727881@qq.com
* @LastEditTime: 2022-09-21 14:36:25
* @FilePath: /Workflow-Vue3/src/components/selectBox.vue
-->
<template>
<ul class="select-box">
<template v-for="(elem, i) in list" :key="i">
<template v-if="elem.type === 'role'">
<li v-for="item in elem.data" :key="item.roleId"
class="check_box"
:class="{active: elem.isActive && elem.isActive(item), not: elem.not}"
@click="elem.change(item)">
<a :title="item.description" :class="{active: elem.isActiveItem && elem.isActiveItem(item)}">
<img src="@/assets/images/icon_role.png">{{item.roleName}}
</a>
</li>
</template>
<template v-if="elem.type === 'department'">
<li v-for="item in elem.data" :key="item.id" class="check_box" :class="{not: !elem.isDepartment}">
<a v-if="elem.isDepartment"
:class="elem.isActive(item) && 'active'"
@click="elem.change(item)">
<img src="@/assets/images/icon_file.png">{{item.departmentName}}</a>
<a v-else><img src="@/assets/images/icon_file.png">{{item.departmentName}}</a>
<i @click="elem.next(item)">下级</i>
</li>
</template>
<template v-if="elem.type === 'employee'">
<li v-for="item in elem.data" :key="item.id" class="check_box">
<a :class="elem.isActive(item) && 'active'"
@click="elem.change(item)"
:title="item.departmentNames">
<img src="@/assets/images/icon_people.png">{{item.employeeName}}
</a>
</li>
</template>
</template>
</ul>
</template>
<script setup>
defineProps({
list: {
type: Array,
default: () => []
}
})
</script>
<style lang="less">
.select-box {
height: 420px;
overflow-y: auto;
li {
padding: 5px 0;
i {
float: right;
padding-left: 24px;
padding-right: 10px;
color: #3195f8;
font-size: 12px;
cursor: pointer;
background: url(~@/assets/images/next_level_active.png) no-repeat 10px center;
border-left: 1px solid rgb(238, 238, 238);
}
a.active+i {
color: rgb(197, 197, 197);
background-image: url(~@/assets/images/next_level.png);
pointer-events: none;
}
img {
width: 14px;
vertical-align: middle;
margin-right: 5px;
}
}
}
</style>

98
src/components/selectResult.vue

@ -0,0 +1,98 @@
<!--
* @Date: 2022-08-26 16:29:24
* @LastEditors: StavinLi 495727881@qq.com
* @LastEditTime: 2022-09-21 14:36:30
* @FilePath: /Workflow-Vue3/src/components/selectResult.vue
-->
<template>
<div class="select-result l">
<p class="clear">已选{{total}}
<a @click="emits('del')">清空</a>
</p>
<ul>
<template v-for="({type, data, cancel}) in list" :key="type">
<template v-if="type === 'role'">
<li v-for="item in data" :key="item.roleId">
<img src="@/assets/images/icon_role.png">
<span>{{item.roleName}}</span>
<img src="@/assets/images/cancel.png" @click="cancel(item)">
</li>
</template>
<template v-if="type === 'department'">
<li v-for="item in data" :key="item.id">
<img src="@/assets/images/icon_file.png">
<span>{{item.departmentName}}</span>
<img src="@/assets/images/cancel.png" @click="cancel(item)">
</li>
</template>
<template v-if="type === 'employee'">
<li v-for="item in data" :key="item.id">
<img src="@/assets/images/icon_people.png">
<span>{{item.employeeName}}</span>
<img src="@/assets/images/cancel.png" @click="cancel(item)">
</li>
</template>
</template>
</ul>
</div>
</template>
<script setup>
defineProps({
total: {
type: Number,
default: 0
},
list: {
type: Array,
default: () => [{ type: 'role', data, cancel }]
}
})
let emits = defineEmits(['del'])
</script>
<style lang="less">
.select-result {
width: 276px;
height: 100%;
font-size: 12px;
ul {
height: 460px;
overflow-y: auto;
li {
margin: 11px 26px 13px 19px;
line-height: 17px;
span {
vertical-align: middle;
}
img {
&:first-of-type {
width: 14px;
vertical-align: middle;
margin-right: 5px;
}
&:last-of-type {
float: right;
margin-top: 2px;
width: 14px;
}
}
}
}
p {
padding-left: 19px;
padding-right: 20px;
line-height: 37px;
border-bottom: 1px solid #f2f2f2;
a {
float: right;
}
}
}
</style>

2
src/router/index.ts

@ -11,6 +11,7 @@ import nestedRouter from './modules/nested'
import externalLink from './modules/externalLink' import externalLink from './modules/externalLink'
import formRouter from './modules/from' import formRouter from './modules/from'
import functionPageRouter from './modules/functionPage' import functionPageRouter from './modules/functionPage'
import workflowRouter from './modules/workflow'
// 异步组件 // 异步组件
export const asyncRoutes = [ export const asyncRoutes = [
@ -20,6 +21,7 @@ export const asyncRoutes = [
...nestedRouter, ...nestedRouter,
...errorRouter, ...errorRouter,
...externalLink, ...externalLink,
...workflowRouter,
{ {
path: '/:pathMatch(.*)', path: '/:pathMatch(.*)',
redirect: '/404' redirect: '/404'

23
src/router/modules/workflow.ts

@ -0,0 +1,23 @@
import Layout from "@/layout/index.vue";
const workflowRouter = [{
path: '/workflow',
component: Layout,
redirect: '/workflow',
name: 'workflow',
meta: {
title: '工作流',
icon: 'School'
},
children: [
{
path: 'workflow',
component: () => import('@/views/workflow/index.vue'),
name: 'work-flow',
meta: { title: '工作流', keepAlive: true , icon: 'MenuIcon'}
},
]
}]
export default workflowRouter

14
src/views/workflow/index.vue

@ -0,0 +1,14 @@
<!--
@ 作者: 秦东
@ 时间: 2023-05-09 15:22:33
@ 备注:
-->
<template>
</template>
<script lang='ts' setup>
</script>
<style lang='scss' scoped>
</style>

6
tsconfig.json

@ -12,7 +12,11 @@
"esModuleInterop": true, "esModuleInterop": true,
"lib": ["ESNext", "DOM"], "lib": ["ESNext", "DOM"],
// //
"skipLibCheck": true "skipLibCheck": true,
"baseUrl": "./", //
"paths": {
"@/*": ["./src/*"] // baseUrl
}
}, },
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }] "references": [{ "path": "./tsconfig.node.json" }]

6728
yarn.lock

File diff suppressed because it is too large
Loading…
Cancel
Save