Merge branch 'dev' of http://highdatas.com:9000/r/foundation/designer.approve.2 into dev
38个文件已删除
31个文件已修改
18个文件已添加
1 文件已重命名
| | |
| | | ### 项目结构 |
| | | |
| | | ``` |
| | | ├─api 接口 |
| | | ├─assets |
| | | |doc 系统介绍 数据结构介绍等 |
| | | |public 浏览器上面设置 图标等 |
| | | |src |
| | | └─├─assets 资源 css等 |
| | | │ └─image |
| | | ├─components 通用组件 |
| | | ├─components 通用组件 弹窗 |
| | | │ └─common |
| | | | └─ ellipsis.vue 文本超出多少自动转为省略 |
| | | | └─orgPicker 树形架构图 人员/岗位/辖区等 |
| | | | └─flowDialog 弹窗 |
| | | |-config 配置文件 |
| | | | └─application 应用环境的配置文件 通过index.js切换 |
| | | ├─router 路由 |
| | | ├─store vuex,设计器数据存储 |
| | | ├─utils |
| | | ├─utils 工具方法 |
| | | └─views 主要页面及视图 |
| | | ├─admin |
| | | │ └─layout |
| | | │ ├─form 表单设计 |
| | | │ └─process 流程设计 |
| | | │ └─ProcessDesign.vue 流程设计入口-组件 |
| | | │ └─ProcessDiagramViewer.vue 查看流程-组件 |
| | | ├─common |
| | | │ ├─form 表单 |
| | | │ │ ├─components 表单组件 |
| | | │ │ ├─config 表单组件配置 |
| | | │ │ ├─expand 扩展组件 |
| | | │ │ └─settings 设置 |
| | | │ └─process 流程 |
| | | │ ├─config 流程节点设置 |
| | | │ └─nodes 流程节点 |
| | | │ └─viewNodes 查看流程图 横向 |
| | | | └─InsertButton.vue 点击插入节点的按钮,可以选择后续节点类型, |
| | | 例如审批/条件等等 |
| | | └─workspace 工作区 |
| | | │ └─process 查看审批流的页面入口 引用上面查看流程的组件 |
| | | |
| | | ``` |
| | | |
| | |
| | | <meta charset="utf-8"> |
| | | <meta http-equiv="X-UA-Compatible" content="IE=edge"> |
| | | <meta name="viewport" content="width=device-width,initial-scale=1.0"> |
| | | <link rel="icon" href="<%= BASE_URL %>favicon.ico"> |
| | | <link rel="icon" href="<%= BASE_URL %>img.png"> |
| | | <title><%= htmlWebpackPlugin.options.title %></title> |
| | | </head> |
| | | <body> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | //import layout from './components/layout' |
| | | export default { |
| | | components: {}, |
| | | data() { |
| | | return {} |
| | | }, |
| | | mounted() { |
| | | let beforeUrl = sessionStorage.getItem('router-path') |
| | | if(beforeUrl === undefined || beforeUrl === ''){ |
| | | //this.$router.push("/workPanel") |
| | | }else { |
| | | //this.$router.push(beforeUrl) |
| | | } |
| | | |
| | | |
| | | }, |
| | | methods: {} |
| | |
| | | body { |
| | | margin: 0; |
| | | min-width: 500px; |
| | | background-color: #f5f6f6; |
| | | //background-color: #f5f6f6; |
| | | } |
| | | body,html {margin:0; height:100%;} |
| | | ul { |
| | |
| | | import request from '@/api/request.js'; |
| | | |
| | | // 查询表单组 |
| | | export function getFormGroups(param) { |
| | | return request({ |
| | | url: 'admin/form/group', |
| | | method: 'get', |
| | | params: param, |
| | | }); |
| | | } |
| | | |
| | | export function getEntitySet(param) { |
| | | param.token="admin"; |
| | | return request({ |
| | |
| | | data: param, |
| | | }); |
| | | } |
| | | //字典 |
| | | export function getDict(param) { |
| | | param.token="admin"; |
| | | return request({ |
| | |
| | | data: param, |
| | | }); |
| | | } |
| | | // 表单排序 |
| | | export function groupItemsSort(param) { |
| | | return request({ |
| | | url: 'admin/form/group/sort', |
| | | method: 'put', |
| | | data: param, |
| | | }); |
| | | } |
| | | |
| | | // 更新表单组 |
| | | export function updateGroup(param, method) { |
| | | return request({ |
| | | url: 'admin/form/group', |
| | | method: method, |
| | | params: param, |
| | | }); |
| | | } |
| | | |
| | | // 获取表单分组 |
| | | export function getGroup() { |
| | | return request({ |
| | | url: 'admin/form/group/list', |
| | | method: 'get', |
| | | }); |
| | | } |
| | | |
| | | // 更新表单 |
| | | export function updateForm(param) { |
| | | return request({ |
| | | url: 'admin/form', |
| | | method: 'put', |
| | | params: param, |
| | | }); |
| | | } |
| | | |
| | | export function createForm(param) { |
| | | return request({ |
| | | url: 'admin/form', |
| | | method: 'post', |
| | | data: param, |
| | | }); |
| | | } |
| | | export function createFlow(param) { |
| | | param.token="admin"; |
| | | return request({ |
| | |
| | | data: param, |
| | | }); |
| | | } |
| | | // 查询表单详情 |
| | | export function getFormDetail(id) { |
| | | return request({ |
| | | url: 'admin/form/detail/' + id, |
| | | method: 'get', |
| | | }); |
| | | } |
| | | |
| | | // 查询审批流详情 |
| | | export function getFlowDetail(param) { |
| | | param.token="admin" |
| | |
| | | data:param |
| | | }); |
| | | } |
| | | export function getFormDetailV2(templateId) { |
| | | // 查询审批流详情 不可编辑 横向 |
| | | export function getWorkSetpsByBusinessId(param) { |
| | | param.token="admin" |
| | | param.dataname="md_position" |
| | | return request({ |
| | | url: 'workspace/process/detail', |
| | | method: 'get', |
| | | params: { |
| | | templateId, |
| | | }, |
| | | }); |
| | | } |
| | | |
| | | // 更新表单详情 |
| | | export function updateFormDetail(param) { |
| | | return request({ |
| | | url: 'admin/form/detail', |
| | | method: 'put', |
| | | data: param, |
| | | }); |
| | | } |
| | | |
| | | // 发起流程 |
| | | export function startProcess(param) { |
| | | return request({ |
| | | url: 'workspace/process/start', |
| | | method: 'POST', |
| | | data: param, |
| | | }); |
| | | } |
| | | |
| | | // 查询我发起的 |
| | | export function applyList(data) { |
| | | return request({ |
| | | url: 'workspace/process/applyList', |
| | | method: 'POST', |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | // 查看我的待办 |
| | | export function todoList(data) { |
| | | return request({ |
| | | url: 'workspace/process/toDoList', |
| | | method: 'POST', |
| | | data, |
| | | }); |
| | | } |
| | | export function ccList(data) { |
| | | return request({ |
| | | url: 'workspace/process/ccList', |
| | | method: 'POST', |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | export function submitedTaskList(data) { |
| | | return request({ |
| | | url: 'workspace/process/submitedTaskList', |
| | | method: 'POST', |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | export function deleteProcessInstance(data) { |
| | | return request({ |
| | | url: 'workspace/process/deleteProcessInstance', |
| | | method: 'POST', |
| | | data : { data} |
| | | }); |
| | | } |
| | | |
| | | // 查看我的已办 |
| | | export function doneList(data) { |
| | | return request({ |
| | | url: 'workspace/process/doneList', |
| | | method: 'POST', |
| | | data, |
| | | }); |
| | | } |
| | | // 查询流程详情 |
| | | export function getProcessInstanceInfo(processInstanceId, taskId) { |
| | | return request({ |
| | | url: 'workspace/process/instanceInfo', |
| | | method: 'POST', |
| | | data: { processInstanceId, taskId }, |
| | | }); |
| | | } |
| | | |
| | | // 同意 |
| | | export function agree(data) { |
| | | return request({ |
| | | url: 'workspace/agree', |
| | | method: 'POST', |
| | | data: data, |
| | | }); |
| | | } |
| | | // 委派人 |
| | | export function delegateTask(data) { |
| | | return request({ |
| | | url: 'workspace/delegateTask', |
| | | method: 'POST', |
| | | data: data, |
| | | }); |
| | | } |
| | | // 委派人完成的按钮 |
| | | export function resolveTask(data) { |
| | | return request({ |
| | | url: 'workspace/resolveTask', |
| | | method: 'POST', |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // 拒绝,驳回 |
| | | export function refuse(data) { |
| | | return request({ |
| | | url: 'workspace/refuse', |
| | | method: 'POST', |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // 撤回 |
| | | export function revoke(data) { |
| | | return request({ |
| | | url: 'workspace/revoke', |
| | | method: 'POST', |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // 转办 |
| | | export function assignee(data) { |
| | | return request({ |
| | | url: 'workspace/assignee', |
| | | method: 'POST', |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // 回退 |
| | | export function rollback(data) { |
| | | return request({ |
| | | url: 'workspace/rollback', |
| | | method: 'POST', |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // 加签 |
| | | export function addMulti(data) { |
| | | return request({ |
| | | url: 'workspace/addMulti', |
| | | method: 'POST', |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // 查询加签人信息 |
| | | export function queryMultiUsersInfo(data) { |
| | | return request({ |
| | | url: 'workspace/queryMultiUsersInfo', |
| | | method: 'POST', |
| | | data: data, |
| | | }); |
| | | } |
| | | // 减签 |
| | | export function deleteMulti(data) { |
| | | return request({ |
| | | url: 'workspace/deleteMulti', |
| | | method: 'POST', |
| | | data: data, |
| | | }); |
| | | } |
| | | // 评论 |
| | | export function comments(data) { |
| | | return request({ |
| | | url: 'workspace/comments', |
| | | method: 'POST', |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // 获取历史任务信息列表 |
| | | export function historyTaskList(param) { |
| | | return request({ |
| | | url: 'workspace/process/historyTaskList', |
| | | method: 'GET', |
| | | params: param, |
| | | }); |
| | | } |
| | | |
| | | // 上传文件 |
| | | export function upLoadFileApi(data) { |
| | | return request({ |
| | | url: 'workspace/upLoadFile', |
| | | method: 'POST', |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // 下载文件 |
| | | export function downLoadFileApi(data) { |
| | | return request({ |
| | | url: 'workspace/downLoadFile', |
| | | method: 'POST', |
| | | data: data, |
| | | responseType: 'blob', //必须加,否则可能出现乱码或者文件错误,导致文件无法打开 |
| | | }); |
| | | } |
| | | |
| | | // 查询可退回的节点 |
| | | export function getRollbackNodes(data) { |
| | | return request({ |
| | | url: 'workspace/rollbackNodes', |
| | | method: 'POST', |
| | | data, |
| | | url: 'root/approve/getWorkSetps', |
| | | method: 'post', |
| | | data:param |
| | | }); |
| | | } |
| | |
| | | import Vue from "vue"; |
| | | import axios from "axios"; |
| | | import application from '@/config/application'; |
| | | |
| | | import { Notification, MessageBox, Message } from "element-ui"; |
| | | |
| | |
| | | // 字体图标 |
| | | |
| | | const service = axios.create({ |
| | | baseURL: Vue.prototype.BASE_URL+":88/api" , |
| | | baseURL:`${application.baseURL}` , |
| | | //baseURL: Vue.prototype.BASE_URL + ":8090/admin", |
| | | timeout: 50000 |
| | | }); |
| | |
| | | |
| | | service.interceptors.response.use( |
| | | rsp => { |
| | | // console.log("aaaaaaa》》》rps",rsp.data.data) |
| | | // var a =this.$Utils.decode(rsp.data.data) |
| | | // console.log("解码后的rsp》》》rps",a) |
| | | return rsp; |
| | | }, |
| | | // 拦截异常的响应 |
| | |
| | | <template> |
| | | <w-dialog :border="false" closeFree width="600px" @ok="selectOk" :title="title" v-model="visible"> |
| | | <flow-dialog :border="false" closeFree width="600px" @ok="selectOk" :title="title" v-model="visible"> |
| | | <div class="picker"> |
| | | <div class="candidate" v-loading="loading"> |
| | | <div class="role-header" > |
| | |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </w-dialog> |
| | | </flow-dialog> |
| | | </template> |
| | | |
| | | <script> |
| | | import {getOrgTree, getUserByName} from '@/api/org' |
| | | import {getEntitySet} from "@/api/design"; |
| | | |
| | | export default { |
| | |
| | | } |
| | | return '**' |
| | | }, |
| | | searchUser() { |
| | | let userName = this.search.trim() |
| | | this.searchUsers = [] |
| | | this.loading = true |
| | | getUserByName({userName: userName}).then(rsp => { |
| | | this.loading = false |
| | | this.searchUsers = rsp.data |
| | | this.selectToLeft() |
| | | }).catch(err => { |
| | | this.loading = false |
| | | this.$message.error("接口异常") |
| | | }) |
| | | }, |
| | | |
| | | selectToLeft() { |
| | | let nodes = this.search.trim() === '' ? this.nodes : this.searchUsers; |
| | | nodes.forEach(node => { |
File was renamed from src/components/common/WDialog.vue |
| | |
| | | |
| | | <script> |
| | | export default { |
| | | name: "WDialog", |
| | | name: "flowDialog", |
| | | install(Vue) { |
| | | Vue.component("WDialog", this); |
| | | Vue.component("flowDialog", this); |
| | | }, |
| | | components: {}, |
| | | props: { |
New file |
| | |
| | | export default { |
| | | baseURL: 'http://grand-dev.highdatas.com', |
| | | |
| | | } |
New file |
| | |
| | | export default { |
| | | baseURL: 'http://localhost:88/api', |
| | | |
| | | } |
New file |
| | |
| | | export default { |
| | | baseURL: '', |
| | | /* |
| | | 钉钉配置 |
| | | */ |
| | | dd: { |
| | | corpid: 'ding6b6a824032ecd975bc961a6cb783455b' |
| | | } |
| | | } |
New file |
| | |
| | | export default { |
| | | baseURL: 'https://csec.jemincare.com', |
| | | |
| | | } |
New file |
| | |
| | | import local from './application-local'; |
| | | import prod from './application-prod'; |
| | | import dev from './application-dev'; |
| | | import uat from './application-uat'; |
| | | |
| | | export default { |
| | | ...local, |
| | | }; |
| | |
| | | import "@/assets/iconfont/iconfont.css" |
| | | |
| | | import Ellipsis from '@/components/common/Ellipsis' |
| | | import WDialog from '@/components/common/WDialog' |
| | | import Tip from '@/components/common/Tip' |
| | | import flowDialog from '@/components/common/flowDialog.vue' |
| | | import Utils from '@/utils/utils.js' |
| | | |
| | | Vue.use(ElementUI); |
| | | Vue.use(Ellipsis); |
| | | Vue.use(WDialog); |
| | | Vue.use(Tip); |
| | | Vue.use(flowDialog); |
| | | |
| | | Vue.use(vueEsign) |
| | | Vue.prototype.$cssSrc=require('@/assets/flowDesignVertical.scss'); |
| | | Vue.prototype.$isVertical=true; |
| | | Vue.config.productionTip = false |
| | | Vue.prototype.$Utils = Utils |
| | | |
| | |
| | | redirect: "/formsPanel", |
| | | }, |
| | | { |
| | | path: "/index", |
| | | name: "index", |
| | | component: () => import("@/views/Index.vue"), |
| | | meta: { title: "OA工作流", viewport: viewport }, |
| | | }, |
| | | |
| | | |
| | | { |
| | | path: "/formsPanel", |
| | | name: "formsPanel", |
| | | component: () => import("@/views/admin/FormsPanel.vue"), |
| | |
| | | |
| | | return data; |
| | | }, |
| | | convertToTreeData(data, parent,index,parentId) { |
| | | const tempJson = data.find(f => |
| | | f.index_no === index |
| | | ) |
| | | parent.children = { |
| | | "id": tempJson.id, |
| | | "parentId": parentId, |
| | | "name": "审批人", |
| | | "type": "APPROVAL", |
| | | "children":{},//必须要 不然选中的值无法传递 |
| | | "props": |
| | | { |
| | | "assignedType": "ASSIGN_USER", |
| | | "nobody": { |
| | | "handler": "TO_PASS", |
| | | "assignedUser": [] |
| | | }, |
| | | "refuse": { |
| | | "type": "TO_END", |
| | | "target": "" |
| | | }, |
| | | "assignedUser": [{"id": tempJson.board_id||tempJson.rule_code, "name": tempJson.name,"type":tempJson.board_id!=null?"group":"staff"}], |
| | | "approvalGroup":tempJson.board_id!=null?{"id":tempJson.board_id,"name":tempJson.name}:"", |
| | | "staffGroup":tempJson.board_id!=null?"":{"id":tempJson.rule_code,"name":tempJson.name}, |
| | | } |
| | | } |
| | | //节点数组的大小 大于当前循环的 说明还有子项 继续循环 |
| | | if (data.length >index) { |
| | | let getChildren = this.convertToTreeData(data, parent.children, index+1,parent.children.id) |
| | | parent.children=getChildren |
| | | } |
| | | return parent; |
| | | }, |
| | | //审批流树形结构转换为json |
| | | dataTree(data, index, parentId) { |
| | | let result = [];//存放结果 |
| | | let names = [];//存放审批人 |
| | | let ruleCode = [];//架构组 |
| | | data.props.assignedUser.forEach(org => names.push(org.name)); |
| | | let ids = [] |
| | | data.props.assignedUser.forEach(org => ids.push(org.id)); |
| | | // 修改的时候 根据选中类型是架构还是审批组 渲染数据 |
| | | if(data.props.assignedUser[0].type==='staff'){ |
| | | ids = []; |
| | | data.props.assignedUser.forEach(org => ruleCode.push(org.id)); |
| | | }else{ |
| | | //判断选中的数据类型是架构还是审批组 如果是架构 将审批组清空 board_id置为空 |
| | | if (data.props.staffGroup!=undefined&& Object.keys(data.props.staffGroup).length!==0) { |
| | | ids = []; |
| | | data.props.assignedUser.forEach(org => ruleCode.push(org.id)); |
| | | } |
| | | } |
| | | |
| | | //插入流程数组项 |
| | | result.push( |
| | | { |
| | | name: String(names).replaceAll(',', '、'), |
| | | id: data.id||'', |
| | | parent_id: parentId||'', |
| | | index_no: index, |
| | | board_id: ids.length > 0 ? String(ids).replaceAll(',', '、') : null, |
| | | rule_code: ruleCode.length > 0 ? String(ruleCode).replaceAll(',', '、') : null |
| | | } |
| | | ) // 只取当前节点的信息,不包括 children |
| | | //如果下面还有子项 继续往下读数据 |
| | | if (data.children!==undefined&&Object.keys(data.children).length !== 0) { |
| | | let getChildren = this.dataTree(data.children, index + 1, parentId) |
| | | result = result.concat(getChildren) |
| | | } |
| | | |
| | | return result |
| | | }, |
| | | |
| | | }; |
| | |
| | | <div class="layout-body"> |
| | | <process-design ref="processDesign" v-show="activeSelect === 'processDesign'"/> |
| | | </div> |
| | | <w-dialog :showFooter="false" v-model="validVisible" title="设置项检查"> |
| | | <flow-dialog :showFooter="false" v-model="validVisible" title="设置项检查"> |
| | | <el-result :icon="validIcon" :title="errTitle" :subTitle="validResult.desc"> |
| | | <i slot="icon" style="font-size: 30px" v-if="!validResult.finished" class="el-icon-loading"></i> |
| | | <div slot="subTitle" class="err-info" v-if="validResult.errs.length > 0"> |
| | |
| | | </el-form> |
| | | </template> |
| | | </el-result> |
| | | </w-dialog> |
| | | </flow-dialog> |
| | | </el-container> |
| | | |
| | | </template> |
| | | |
| | | <script> |
| | | import LayoutHeader from './LayoutHeader' |
| | | import {getFormDetail, createForm, updateFormDetail, createFlow, getFlowDetail} from '@/api/design' |
| | | import {createFlow, getFlowDetail} from '@/api/design' |
| | | |
| | | import ProcessDesign from '@/views/admin/layout/ProcessDesign' |
| | | |
| | |
| | | |
| | | }, |
| | | methods: { |
| | | convertToTreeData(data, parent,index,parentId) { |
| | | //index从1开始 从index_no=1的节点开始往下一个个找 |
| | | const tempJson = data.find(f => |
| | | f.index_no === index |
| | | ) |
| | | console.log("tempJson",tempJson); |
| | | //解析子审批节点 |
| | | parent.children = { |
| | | "id": tempJson.id, |
| | | "parentId": parentId, |
| | | "name": "审批人", |
| | | "type": "APPROVAL", |
| | | "props": |
| | | { |
| | | "assignedType": "ASSIGN_USER", |
| | | "nobody": { |
| | | "handler": "TO_PASS", |
| | | "assignedUser": [] |
| | | }, |
| | | "refuse": { |
| | | "type": "TO_END", |
| | | "target": "" |
| | | }, |
| | | "assignedUser": [{"id": tempJson.board_id||tempJson.rule_code, "name": tempJson.name,"type":tempJson.board_id!=null?"group":"staff"}], |
| | | "approvalGroup":tempJson.board_id!=null?{"id":tempJson.board_id,"name":tempJson.name}:"", |
| | | "staffGroup":tempJson.board_id!=null?"":{"id":tempJson.rule_code,"name":tempJson.name}, |
| | | } |
| | | } |
| | | //如果传过来的审批节点数组大于当前索引 说明下面还有 |
| | | if (data.length >index) { |
| | | let getChildren = this.convertToTreeData(data, parent.children, index+1,parent.children.id) |
| | | parent.children=getChildren |
| | | } |
| | | return parent; |
| | | }, |
| | | |
| | | loadFormInfo(formId) { |
| | | let param = {"id": formId} |
| | | |
| | | //获取流程详情 |
| | | getFlowDetail(param).then(rsp => { |
| | | let form = rsp.data.data; |
| | | console.log("getFlowDetail-form", form) |
| | | form.logo = "" |
| | | form.formItems = [] |
| | | form.process =this.convertToTreeData(form.steps, { |
| | | form.process =this.$Utils.convertToTreeData(form.steps, { |
| | | "id": form.id, "parentId": null, |
| | | "type": "ROOT", |
| | | "name": "发起人", |
| | |
| | | form.templateName = form.name |
| | | form.groupId = null; |
| | | |
| | | console.log("输出转换后的form,",form) |
| | | |
| | | this.$store.commit('loadForm', form) |
| | | }).catch(err => { |
| | | this.$message.error(err) |
| | |
| | | }) |
| | | }, |
| | | validateDesign() { |
| | | console.log('000') |
| | | this.validVisible = true |
| | | this.validStep = 0 |
| | | this.showValiding() |
| | |
| | | publishProcess() { |
| | | this.validateDesign() |
| | | }, |
| | | //审批流树形结构转换为json |
| | | dataTree(data, index, parentId) { |
| | | let result = []; |
| | | let names = []; |
| | | let ruleCode = []; |
| | | console.log("data》》》",data) |
| | | data.props.assignedUser.forEach(org => names.push(org.name)); |
| | | let ids = [] |
| | | data.props.assignedUser.forEach(org => ids.push(org.id)); |
| | | // 修改的时候 根据选中类型是架构还是审批组 渲染数据 |
| | | if(data.props.assignedUser[0].type==='staff'){ |
| | | ids = []; |
| | | data.props.assignedUser.forEach(org => ruleCode.push(org.id)); |
| | | }else{ |
| | | //判断选中的数据类型是架构还是审批组 如果是架构 将审批组清空 board_id置为空 |
| | | if (data.props.staffGroup!=undefined&& Object.keys(data.props.staffGroup).length!==0) { |
| | | ids = []; |
| | | data.props.assignedUser.forEach(org => ruleCode.push(org.id)); |
| | | } |
| | | } |
| | | |
| | | //插入流程数组项 |
| | | result.push( |
| | | { |
| | | name: String(names).replaceAll(',', '、'), |
| | | id: data.id||'', |
| | | parent_id: parentId||'', |
| | | index_no: index, |
| | | board_id: ids.length > 0 ? String(ids).replaceAll(',', '、') : null, |
| | | rule_code: ruleCode.length > 0 ? String(ruleCode).replaceAll(',', '、') : null |
| | | } |
| | | ) // 只取当前节点的信息,不包括 children |
| | | console.log("result>>>",result) |
| | | //如果下面还有子项 继续往下读数据 |
| | | if (data.children!==undefined&&Object.keys(data.children).length !== 0) { |
| | | let getChildren = this.dataTree(data.children, index + 1, parentId) |
| | | result = result.concat(getChildren) |
| | | } |
| | | |
| | | return result |
| | | }, |
| | | |
| | | doPublish() { |
| | | this.$confirm('确认发布后流程立即生效,是否继续?', '提示', { |
| | |
| | | type: 'warning' |
| | | }).then(() => { |
| | | let processNew = JSON.parse(JSON.stringify(this.setup.process)); |
| | | console.log("processNew", processNew) |
| | | //判断条件分支 |
| | | this.conditionRecursion(processNew); |
| | | let data = {}; |
| | | data.name = this.form.name; |
| | | data.id = processNew.id||'' |
| | | var i = 1; |
| | | let i = 1; |
| | | //转数据结构 |
| | | data.steps = this.dataTree(processNew.children, i, processNew.id); |
| | | data.steps = this.$Utils.dataTree(processNew.children, i, processNew.id); |
| | | let template = {data} |
| | | console.log("新数组结构-template", template); |
| | | createFlow(template).then(rsp => { |
| | | this.$message.success("创建流程成功") |
| | | this.$router.push("/formsPanel") |
| | |
| | | <div style="float: right"> |
| | | <el-button type="text" icon="el-icon-edit-outline" size="mini" @click="editFrom(item, groups)">编辑 |
| | | </el-button> |
| | | <el-button type="text" :icon="item.isStop ? 'el-icon-check':'el-icon-close'" size="mini" |
| | | @click="stopFrom(item)"> |
| | | {{ item.isStop ? '启用' : '停用' }} |
| | | </el-button> |
| | | <el-button type="text" size="mini" @click="viewGroup(item,groups)">查看流程</el-button> |
| | | <el-button type="text" icon="el-icon-delete" size="mini" @click="moveFrom(item)" v-if="item.isStop">删除 |
| | | </el-button> |
| | | |
| | | <el-popover placement="left" trigger="click" width="400" style="margin-left: 10px" |
| | | @show="moveSelect === null" v-else> |
| | | @show="moveSelect === null" > |
| | | <el-radio-group v-model="moveSelect" size="mini"> |
| | | <el-radio :label="g.id" border v-for="g in groups" :key="g.id" v-show="g.id > 1" |
| | | :disabled="g.id === groups.id" style="margin: 10px;">{{ g.name }} |
| | |
| | | <script> |
| | | import draggable from "vuedraggable"; |
| | | import { |
| | | groupItemsSort, updateForm, getEntitySet |
| | | groupItemsSort, getEntitySet |
| | | } from '@/api/design' |
| | | |
| | | export default { |
| | |
| | | getGroups() { |
| | | let template = {"dataname": "sys_state_approve"} |
| | | getEntitySet(template).then(rsp => { |
| | | console.log("getEntitySet", rsp.data.data) |
| | | this.groups = rsp.data.data.entityset |
| | | console.log("this.groups", this.groups) |
| | | //this.groups = rsp.data |
| | | }).catch(err => this.$message.error('获取审批流程异常')) |
| | | }, |
| | | newProcess(groupId) { |
| | | this.$store.commit("setTemplate", this.getTemplateData()); |
| | | this.$store.commit("setIsEdit", false); |
| | | this.$router.push("/admin/design?groupId=" + groupId); |
| | | }, |
| | | groupSort() { |
| | | this.groupsSort = false |
| | | groupItemsSort(this.groups).then(rsp => { |
| | | this.$message.success("排序成功") |
| | | this.getGroups() |
| | | }).catch(err => { |
| | | this.getGroups() |
| | | this.$message.error(err.response.data) |
| | | }) |
| | | |
| | | }, |
| | | |
| | | |
| | | viewGroup(item, group) { |
| | | console.log("viewGroup",item) |
| | | this.$router.push( |
| | | { |
| | | path: "/workspace/process/instance/tabs", |
| | |
| | | ); |
| | | }, |
| | | |
| | | updateForm(item, type) { |
| | | updateForm({templateId: item.templateId, type: type}).then(rsp => { |
| | | this.$message.success(rsp.data) |
| | | this.getGroups() |
| | | }).catch(err => this.$message.error(err.response.data)) |
| | | }, |
| | | getTemplateData(data, group) { |
| | | return data |
| | | }, |
| | | |
| | | editFrom(item, group) { |
| | | console.log("item",item) |
| | | this.$router.push("/admin/design?code=" + item.id); |
| | | }, |
| | | stopFrom(item) { |
| | | console.log(item) |
| | | let tip = '是否删除此流程?'; |
| | | this.$confirm(`<span style="font-weight: bold">${item.name}</span>` + tip, '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning', |
| | | dangerouslyUseHTMLString: true, |
| | | }).then(() => { |
| | | this.updateForm(item, (item.isStop ? 'using' : 'stop')); |
| | | }) |
| | | }, |
| | | moveFrom(item) { |
| | | if (item.isStop) { |
| | | this.$confirm(`您确定要删除表单 <span style="font-weight: bold">${item.name}</span>> 吗,删除后无法恢复,是否继续?`, '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning', |
| | | dangerouslyUseHTMLString: true, |
| | | }).then(() => { |
| | | this.updateForm(item, 'delete'); |
| | | }) |
| | | } else { |
| | | if (this.moveSelect === null || this.moveSelect === '') { |
| | | this.$message.error('请选择分组') |
| | | return; |
| | | } |
| | | updateForm({templateId: item.templateId, type: 'move', groupId: this.moveSelect}).then(rsp => { |
| | | this.$message.success(rsp.data) |
| | | this.getGroups() |
| | | this.moveSelect = null |
| | | }).catch(err => this.$message.error(err.response.data)) |
| | | } |
| | | }, |
| | | |
| | | |
| | | } |
| | | } |
| | | </script> |
| | |
| | | @select="handleSelect"> |
| | | <el-menu-item index="processDesign" @click="to('processDesign')">审批流程 |
| | | </el-menu-item> |
| | | <!-- <el-menu-item index="proSetting" @click="to('proSetting')">扩展设置</el-menu-item>--> |
| | | </el-menu> |
| | | <div class="publish"> |
| | | |
| | |
| | | </div> |
| | | </div> |
| | | |
| | | <el-dialog title="请使用手机扫码预览" :visible.sync="viewCode" width="300px" :close-on-click-modal="false" center> |
| | | <img src="../../assets/image/code.png" width="250" height="250"> |
| | | </el-dialog> |
| | | |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | this.$emit('input', path) |
| | | }, |
| | | handleSelect(key, keyPath) { |
| | | console.log(key, keyPath); |
| | | }, |
| | | listener() { |
| | | window.onunload = this.closeBefore() |
| | |
| | | <template> |
| | | <el-main> |
| | | <div class="switchStyle"> |
| | | <el-button size="small" @click="switchCss" >切换</el-button> |
| | | |
| | | </div> |
| | | <div class="scale"> |
| | | <el-button icon="el-icon-plus" size="small" @click="scale += 10" :disabled="scale >= 150" circle></el-button> |
| | | <span>{{ scale }}%</span> |
| | | <el-button icon="el-icon-minus" size="small" @click="scale -= 10" :disabled="scale <= 40" circle></el-button> |
| | | <!-- <el-button @click="validate">校验流程</el-button>--> |
| | | </div> |
| | | <div class="design" :style="'transform: scale('+ scale / 100 +');'"> |
| | | <process-tree ref="process-tree" @selectedNode="nodeSelected"/> |
| | |
| | | }, |
| | | computed:{ |
| | | selectedNode(){ |
| | | console.log("ProcessDesign-selectedNode") |
| | | return this.$store.state.selectedNode |
| | | } |
| | | }, |
| | |
| | | |
| | | }, |
| | | methods: { |
| | | switchCss(){ |
| | | |
| | | console.log(this.$cssSrc) |
| | | console.log(this.$isVertical) |
| | | |
| | | if(this.$isVertical){ |
| | | this.$cssSrc=require('@/assets/flowDesign.scss') |
| | | this.$isVertical=false; |
| | | }else{ |
| | | this.$cssSrc=require('@/assets/flowDesignVertical.scss') |
| | | this.$isVertical=true; |
| | | } |
| | | this.$forceUpdate() |
| | | |
| | | }, |
| | | validate(){ |
| | | return this.$refs["process-tree"].validateProcess() |
| | | }, |
| | | nodeSelected(node){ |
| | | console.log('配置节点aaa', node) |
| | | this.showConfig = true |
| | | } |
| | | }, |
| | |
| | | <template> |
| | | <el-main> |
| | | <el-main style="overflow:auto;padding: 0px;height: 90vh"> |
| | | <div class="scale"> |
| | | <el-button icon="el-icon-plus" size="small" @click="scale += 10" :disabled="scale >= 150" circle></el-button> |
| | | <span>{{ scale }}%</span> |
| | | <el-button icon="el-icon-minus" size="small" @click="scale -= 10" :disabled="scale <= 40" circle></el-button> |
| | | </div> |
| | | <div class="design" :style="'transform: scale('+ scale / 100 +');'"> |
| | | <div class="design" :style="'transform: scale('+ scale / 100 +');transform-origin:left top'"> |
| | | <process-tree-viewer ref="process-tree" @selectedNode="nodeSelected"/> |
| | | </div> |
| | | <el-drawer :title="selectedNode.name" :visible.sync="showConfig" |
| | |
| | | components: { ProcessTreeViewer,NodeConfig }, |
| | | data() { |
| | | return { |
| | | scale: 100, |
| | | scale: 90, |
| | | selected: {}, |
| | | showInput: false, |
| | | showConfig: false |
| | |
| | | }, |
| | | computed:{ |
| | | selectedNode(){ |
| | | console.log("ProcessDiagramViewer-selectedNode",this.$store.state) |
| | | return this.$store.state.selectedNode |
| | | } |
| | | }, |
| | |
| | | }, |
| | | methods: { |
| | | test(){ |
| | | console.log("test") |
| | | }, |
| | | validate(){ |
| | | return this.$refs["process-tree"].validateProcess() |
| | | }, |
| | | nodeSelected(node){ |
| | | console.log('配置节点bbb', node) |
| | | this.showConfig = true |
| | | } |
| | | }, |
| | |
| | | import Subprocess from '@/views/common/process/nodes/SubprocessNode.vue' |
| | | |
| | | import DefaultProps from "./DefaultNodeProps" |
| | | |
| | | export default { |
| | | name: "ProcessTree", |
| | | components: {Node, Root, Approval, Task, Cc, Trigger, Concurrent, Condition, Inclusive, Delay, Empty, Subprocess}, |
| | |
| | | ])) |
| | | return h('div', {class:{'_root': true}, ref:'_root'}, processTrees) |
| | | }, |
| | | |
| | | methods: { |
| | | getDomTree(h, node) { |
| | | this.toMapping(node); |
| | |
| | | //解码渲染的时候插入dom到同级 |
| | | decodeAppendDom(h, node, dom, props = {}){ |
| | | props.config = node |
| | | console.log("decodeAppendDom",props) |
| | | dom.unshift(h(node.type.toLowerCase(), { |
| | | props: props, |
| | | ref: node.id, |
| | |
| | | //id映射到map,用来向上遍历 |
| | | toMapping(node){ |
| | | if (node && node.id){ |
| | | //console.log("node=> " + node.id + " name:" + node.name + " type:" + node.type) |
| | | this.nodeMap.set(node.id, node) |
| | | } |
| | | }, |
| | |
| | | return node.type === 'CONCURRENTS' |
| | | }, |
| | | getRandomId(){ |
| | | console.log("tree生成节点id") |
| | | return ''; |
| | | //return `HighDatas_${new Date().getTime().toString().substring(5)}${Math.round(Math.random()*9000+1000)}` |
| | | }, |
| | | //选中一个节点 |
| | | selectNode(node){ |
| | | this.$store.commit('selectedNode', node) |
| | | this.$store.commit('selectedNode', node); |
| | | this.$emit('selectedNode', node) |
| | | }, |
| | | //处理节点插入逻辑 |
| | | insertNode(type, parentNode){ |
| | | |
| | | this.$refs['_root'].click() |
| | | //缓存一下后面的节点 |
| | | let afterNode = parentNode.children |
| | | //插入新节点 |
| | | parentNode.children = { |
| | | |
| | | id: this.getRandomId(), |
| | | parentId: parentNode.id, |
| | | props: {}, |
| | | type: type, |
| | | type: type |
| | | |
| | | } |
| | | switch (type){ |
| | | |
| | | case 'APPROVAL': this.insertApprovalNode(parentNode, afterNode); break; |
| | | case 'SUBPROCESS' : this.insertApprovalNode(parentNode, afterNode); break; |
| | | case 'TASK': this.insertTaskNode(parentNode); break; |
| | |
| | | if (afterNode && afterNode.id){ |
| | | afterNode.parentId = parentNode.children.id |
| | | } |
| | | this.$set(parentNode.children, 'children', afterNode) |
| | | this.$set(parentNode.children, 'children', Object) |
| | | |
| | | } |
| | | this.$forceUpdate() |
| | | }, |
| | | insertApprovalNode(parentNode){ |
| | | console.log("tree 添加通过节点",parentNode.children) |
| | | this.$set(parentNode.children, "name", "审批人") |
| | | console.log("tree-DefaultProps.APPROVAL_PROPS)",DefaultProps.APPROVAL_PROPS) |
| | | |
| | | this.$set(parentNode.children, "props", this.$deepCopy(DefaultProps.APPROVAL_PROPS)) |
| | | |
| | | |
| | | }, |
| | | insertTaskNode(parentNode){ |
| | | this.$set(parentNode.children, "name", "办理人") |
| | |
| | | name: "条件1", |
| | | children:{} |
| | | },{ |
| | | |
| | | id: this.getRandomId(), |
| | | parentId: parentNode.children.id, |
| | | type: "CONDITION", |
| | |
| | | }, |
| | | //删除当前节点 |
| | | delNode(node){ |
| | | console.log("ProcessTree删除节点", node) |
| | | |
| | | //获取该节点的父节点 |
| | | let parentNode = this.nodeMap.get(node.parentId) |
| | | if (parentNode){ |
| | |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss" :src="$cssSrc" > |
| | | |
| | | <style lang="less" scoped> |
| | | ._root{ |
| | | margin: 0 auto; |
| | | } |
| | | .process-end{ |
| | | width: 60px; |
| | | margin: 0 auto; |
| | | margin-bottom: 20px; |
| | | border-radius: 15px; |
| | | padding: 5px 10px; |
| | | font-size: small; |
| | | color: #747474; |
| | | background-color: #f2f2f2; |
| | | box-shadow: 0 0 10px 0 #bcbcbc; |
| | | } |
| | | .primary-node{ |
| | | display: flex; |
| | | align-items: center; |
| | | flex-direction: column; |
| | | } |
| | | .branch-node{ |
| | | display: flex; |
| | | justify-content: center; |
| | | /*border-top: 2px solid #cccccc; |
| | | border-bottom: 2px solid #cccccc;*/ |
| | | } |
| | | .branch-node-item{ |
| | | position: relative; |
| | | display: flex; |
| | | background: #f5f6f6; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | border-top: 2px solid #cccccc; |
| | | border-bottom: 2px solid #cccccc; |
| | | &:before{ |
| | | content: ""; |
| | | position: absolute; |
| | | top: 0; |
| | | left: calc(50% - 1px); |
| | | margin: auto; |
| | | width: 2px; |
| | | height: 100%; |
| | | background-color: #CACACA; |
| | | } |
| | | .line-top-left, .line-top-right, .line-bot-left, .line-bot-right{ |
| | | position: absolute; |
| | | width: 50%; |
| | | height: 4px; |
| | | background-color: #f5f6f6; |
| | | } |
| | | .line-top-left{ |
| | | top: -2px; |
| | | left: -1px; |
| | | } |
| | | .line-top-right{ |
| | | top: -2px; |
| | | right: -1px; |
| | | } |
| | | .line-bot-left{ |
| | | bottom: -2px; |
| | | left: -1px; |
| | | } |
| | | .line-bot-right{ |
| | | bottom: -2px; |
| | | right: -1px; |
| | | } |
| | | } |
| | | .add-branch-btn{ |
| | | position: absolute; |
| | | width: 80px; |
| | | .add-branch-btn-el{ |
| | | z-index: 999; |
| | | position: absolute; |
| | | top: -15px; |
| | | } |
| | | } |
| | | |
| | | .empty-node{ |
| | | display: flex; |
| | | justify-content: center; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | } |
| | | </style> |
| | | |
| | |
| | | <script> |
| | | //导入所有节点组件 |
| | | import Approval from '@/views/common/process/nodes/ApprovalNode.vue' |
| | | import Task from '@/views/common/process/nodes/TaskNode.vue' |
| | | import Cc from '@/views/common/process/nodes/CcNode.vue' |
| | | import Concurrent from '@/views/common/process/nodes/ConcurrentNode.vue' |
| | | import Condition from '@/views/common/process/nodes/ConditionNode.vue' |
| | | import Inclusive from '@/views/common/process/nodes/InclusiveNode.vue' |
| | | import Trigger from '@/views/common/process/nodes/TriggerNode.vue' |
| | | import Delay from '@/views/common/process/nodes/DelayNode.vue' |
| | | import Empty from '@/views/common/process/nodes/EmptyNode.vue' |
| | | import Root from '@/views/common/process/nodes/RootNode.vue' |
| | | import Node from '@/views/common/process/nodes/Node.vue' |
| | | import Approval from '@/views/common/process/viewNodes/ApprovalNode.vue' |
| | | import Task from '@/views/common/process/viewNodes/TaskNode.vue' |
| | | import Cc from '@/views/common/process/viewNodes/CcNode.vue' |
| | | import Concurrent from '@/views/common/process/viewNodes/ConcurrentNode.vue' |
| | | import Condition from '@/views/common/process/viewNodes/ConditionNode.vue' |
| | | import Inclusive from '@/views/common/process/viewNodes/InclusiveNode.vue' |
| | | import Trigger from '@/views/common/process/viewNodes/TriggerNode.vue' |
| | | import Delay from '@/views/common/process/viewNodes/DelayNode.vue' |
| | | import Empty from '@/views/common/process/viewNodes/EmptyNode.vue' |
| | | import Root from '@/views/common/process/viewNodes/RootNode.vue' |
| | | import Node from '@/views/common/process/viewNodes/Node.vue' |
| | | |
| | | import DefaultProps from "./DefaultNodeProps" |
| | | |
| | |
| | | this.nodeMap.clear() |
| | | let processTrees = this.getDomTree(h, this.dom) |
| | | //插入末端节点 |
| | | processTrees.push(h('div', {style:{'text-align': 'center'}}, [ |
| | | processTrees.push(h('div', {class:{'end-class': true}}, [ |
| | | h('div', {class:{'process-end': true}, domProps: {innerHTML:'流程结束'}}) |
| | | ])) |
| | | return h('div', {class:{'_root': true}, ref:'_root'}, processTrees) |
| | |
| | | |
| | | //普通业务节点 |
| | | let childDoms = this.getDomTree(h, node.children) |
| | | |
| | | let headerBgc = '#ff943e' |
| | | let headerBgc = '#909399' |
| | | if (this.$store.state.runningList.includes(node.id)) { |
| | | headerBgc = '#1e90ff' |
| | | } |
| | |
| | | }, |
| | | //选中一个节点 |
| | | selectNode(node){ |
| | | console.log("ProcessTreeViewer-emit-selectNode") |
| | | this.$store.commit('selectedNode', node) |
| | | this.$emit('selectedNode', node) |
| | | }, |
| | |
| | | }, |
| | | //删除当前节点 |
| | | delNode(node){ |
| | | console.log("删除节点", node) |
| | | //获取该节点的父节点 |
| | | let parentNode = this.nodeMap.get(node.parentId) |
| | | if (parentNode){ |
| | |
| | | |
| | | <style lang="less" scoped> |
| | | ._root{ |
| | | display: flex; |
| | | align-items:center; |
| | | margin: 0 auto; |
| | | |
| | | } |
| | | .end-class { |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | &:before { |
| | | content: ''; |
| | | top: 50%; |
| | | left: 100%; |
| | | display: block; |
| | | width: 0; |
| | | height: 0; |
| | | |
| | | border-style: solid; |
| | | border-color: #CACACA transparent transparent; |
| | | background: #F5F5F7; |
| | | border-top: 5px solid transparent; |
| | | border-bottom: 5px solid transparent; |
| | | border-left: 10px solid #CACACA; /* 左边界 */ |
| | | } |
| | | } |
| | | .process-end{ |
| | | width: 60px; |
| | | width: 100px; |
| | | height: 40px; |
| | | margin: 0 auto; |
| | | margin-bottom: 20px; |
| | | // margin-bottom: 20px; |
| | | border-radius: 15px; |
| | | padding: 5px 10px; |
| | | font-size: small; |
| | | //font-size: small; |
| | | color: #747474; |
| | | background-color: #f2f2f2; |
| | | box-shadow: 0 0 10px 0 #bcbcbc; |
| | | display: flex; |
| | | justify-content:center; |
| | | align-items: center; |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | .primary-node{ |
| | | display: flex; |
| | | align-items: center; |
| | | flex-direction: column; |
| | | flex-direction: row |
| | | } |
| | | .branch-node{ |
| | | display: flex; |
| | | justify-content: center; |
| | | /*border-top: 2px solid #cccccc; |
| | | border-bottom: 2px solid #cccccc;*/ |
| | | } |
| | | .branch-node-item{ |
| | | position: relative; |
| | |
| | | flex-direction: column; |
| | | align-items: center; |
| | | } |
| | | |
| | | </style> |
| | |
| | | <div> |
| | | <el-form label-position="top" label-width="90px"> |
| | | <el-form-item label="⚙ 选择审批组或审批架构" prop="text" class="user-type"> |
| | | <el-select @change="selected(this,'group')" value-key="id" style="width: 80%;" size="small" v-model="nodeProps.approvalGroup" placeholder="请选择审批组"> |
| | | <el-option v-for="approvals in approvalGroups" :label="approvals.name" :value="approvals" :key="approvals.id"></el-option> |
| | | <el-select @change="selected(this,'group')" value-key="id" style="width: 80%;" size="small" |
| | | v-model="nodeProps.approvalGroup" placeholder="请选择审批组"> |
| | | <el-option v-for="approvals in approvalGroups" :label="approvals.name" :value="approvals" |
| | | :key="approvals.id"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="⚙ 选择审批组或审批架构" prop="text" class="user-type"> |
| | | <el-select @change="selected(this,'staff')" value-key="id" style="width: 80%;" size="small" v-model="nodeProps.staffGroup" placeholder="请选择审批架构"> |
| | | <el-option v-for="staffApprovals in staffGroups" :label="staffApprovals.name" :value="staffApprovals" :key="staffApprovals.id"></el-option> |
| | | <el-select @change="selected(this,'staff')" value-key="id" style="width: 80%;" size="small" |
| | | v-model="nodeProps.staffGroup" placeholder="请选择审批架构"> |
| | | <el-option v-for="staff in staffGroups" :label="staff.name" :value="staff" |
| | | :key="staff.id"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-divider></el-divider> |
| | | <el-form-item label="参数名"> |
| | | <el-input style="width: 80%;" placeholder="参数名" v-model="nodeProps.params" size="small" clearable /> |
| | | </el-form-item> |
| | | |
| | | <el-divider></el-divider> |
| | | <el-form-item label="触发事件"> |
| | | <div> |
| | | <el-button type="primary" size="mini" icon="el-icon-plus" style="margin: 0 15px 15px 0" round @click="addConditionGroup"> |
| | | <el-button type="primary" size="mini" icon="el-icon-plus" style="margin: 0 15px 15px 0" round |
| | | @click="addConditionGroup"> |
| | | 添加审批触发事件 |
| | | </el-button> |
| | | </div> |
| | | |
| | | <div style="width: 100%" v-for="(group, index) in selectedNode.props.groups" :key="index + '_g'" class="group"> |
| | | <div class="group-header"> |
| | | <span class="group-name">触发事件{{index+1}}</span> |
| | | <i class="el-icon-delete" @click="delGroup(index)"></i> |
| | | |
| | | </div> |
| | | <el-row :gutter="10" > |
| | | <el-col :span="12"><el-select @change="selected(this)" size="small" v-model="group.action" placeholder="请选择审批组"> |
| | | <el-option v-for="actionItem in actions" :label="actionItem.label" :value="actionItem" :key="actionItem.value"></el-option> |
| | | <el-col :span="12"> |
| | | <el-select @change="selected(this)" size="small" v-model="group.action" placeholder="请选择审批组"> |
| | | <el-option v-for="actionItem in actions" :label="actionItem.label" :value="actionItem" |
| | | :key="actionItem.value"></el-option> |
| | | </el-select> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | |
| | | <el-col :span="20"> |
| | | <el-input placeholder="java方法" v-model="group.method" size="small" clearable></el-input> |
| | | </el-col> |
| | | |
| | | |
| | | </el-row> |
| | | </div> |
| | | |
| | | </el-form-item> |
| | | <el-form-item label="🙅 如果办理被驳回 👇"> |
| | | <el-radio-group @input="setValue" v-model="nodeProps.refuse.type"> |
| | |
| | | </el-radio-group> |
| | | <div v-if="nodeProps.refuse.type === 'TO_NODE'"> |
| | | <span>指定节点:</span> |
| | | <el-select style="margin-left: 10px; width: 150px;" placeholder="选择跳转节点" size="small" v-model="nodeProps.refuse.target"> |
| | | <el-select style="margin-left: 10px; width: 150px;" placeholder="选择跳转节点" size="small" |
| | | v-model="nodeProps.refuse.target"> |
| | | <el-option v-for="(node, i) in nodeOptions" :key="i" :label="node.name" :value="node.id"></el-option> |
| | | </el-select> |
| | | </div> |
| | | |
| | | </el-form-item> |
| | | </el-form> |
| | | <org-picker :title="pickerTitle" multiple :type="orgPickerType" ref="orgPicker" :selected="orgPickerSelected" |
| | | @ok="selected"/> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import OrgPicker from "@/components/common/OrgPicker"; |
| | | import {getDict, getEntitySet} from "@/api/design"; |
| | | |
| | | |
| | | export default { |
| | | name: "ApprovalNodeConfig", |
| | | components: {OrgPicker}, |
| | | props: { |
| | | config: { |
| | | type: Object, |
| | |
| | | return { |
| | | showOrgSelect: false, |
| | | orgPickerSelected: [], |
| | | orgPickerType: 'user', |
| | | groupNames: ['1', '2', '3', '4', '6', 'F', 'G', 'H', 'I', 'J'], |
| | | approvalGroups:[ |
| | | // {"value":'first',"label":'地区经理审批'}, |
| | | // {"value":'secound',"label":'大区经理审批'}, |
| | | // {"value":'third',"label":'商务经理审批'}, |
| | | // {"value":'four',"label":'财务经理审批'}, |
| | | // {"value":'five',"label":'总经理审批'}, |
| | | ], |
| | | staffGroups:[], |
| | | actions:[ |
| | |
| | | return this.$store.state.selectedNode |
| | | }, |
| | | nodeProps() { |
| | | |
| | | // this.$store.state.selectedNode.props.staffGroup=this.$store.state.selectedNode.props.assignedUser[0] |
| | | // //this.$store.state.selectedNode.props.staffGroup.code="SalesDirector" |
| | | // //this.$store.state.selectedNode.props.staffGroup.id="position_sales_1" |
| | | // console.log("this.$store.state.selectedNode.props",this.$store.state.selectedNode.props) |
| | | return this.$store.state.selectedNode.props |
| | | }, |
| | | select() { |
| | | console.log("this.config--select",this.config) |
| | | return this.config.assignedUser |
| | | }, |
| | | |
| | | pickerTitle() { |
| | | switch (this.orgPickerType) { |
| | | case 'user': |
| | | return '请选择人员'; |
| | | case 'role': |
| | | return '请选择系统角色'; |
| | | default: |
| | | return null; |
| | | } |
| | | }, |
| | | |
| | | }, |
| | | mounted() { |
| | | this.getApprovalGroup(); |
| | | this.getStaffGroup(); |
| | | console.log("this.$store.state.selectedNode.props.staffGroup",this.$store.state.selectedNode.props.staffGroup) |
| | | }, |
| | | methods: { |
| | | getApprovalGroup(){ |
| | | let template = {"dataname": "sys_state_board","attachMeta":true} |
| | | getEntitySet(template).then(rsp => { |
| | | console.log("getEntitySet", rsp.data.data) |
| | | this.approvalGroups = rsp.data.data.entityset |
| | | |
| | | console.log("this.approvalGroups", this.approvalGroups) |
| | | }).catch(err => this.$message.error('获取审批流程异常')) |
| | | }, |
| | | getStaffGroup(){ |
| | | let template = {"code":"position_sales"} |
| | | getDict(template).then(rsp => { |
| | | console.log("getDict", rsp.data.data.dictionary) |
| | | this.staffGroups=this.$Utils.decode(rsp.data.data.dictionary.items) |
| | | this.staffGroups.forEach(item=>item.name=item.value); |
| | | this.staffGroups.forEach(item=>item.id=item.code); |
| | | console.log("getDict", this.staffGroups) |
| | | this.staffGroups.forEach(item => { |
| | | item.name = item.value |
| | | item.id = item.code |
| | | }); |
| | | // this.staffGroups.forEach(item => ); |
| | | }).catch(err => this.$message.error('获取审批流程异常')) |
| | | }, |
| | | //如果切换选箱不是指定节点 那就把之前选择的指定节点信息 给清除掉 避免提交上去 |
| | | setValue(){ |
| | | if(this.nodeProps.refuse.type!=='TO_NODE'){ |
| | | this.nodeProps.refuse.target=''; |
| | | |
| | | } |
| | | }, |
| | | delGroup(index) { |
| | | this.selectedNode.props.groups.splice(index, 1) |
| | | }, |
| | | addConditionGroup() { |
| | | console.log("this.config",this.config) |
| | | this.config.groups.push({ |
| | | // cids:[], |
| | | // groupType: "OR", |
| | | //conditions:[] |
| | | }) |
| | | }, |
| | | selected(select,type) { |
| | | console.log("输出选中select",this.nodeProps) |
| | | this.nodeProps.assignedUser=[] |
| | | |
| | | if(type==='group'){ |
| | | this.nodeProps.staffGroup={} |
| | | this.nodeProps.assignedUser.push({ |
| | |
| | | } |
| | | ) |
| | | } |
| | | console.log("assignedUser",this.config) |
| | | this.orgPickerSelected.length = 0 |
| | | |
| | | }, |
| | | removeOrgItem(index) { |
| | | this.select.splice(index, 1) |
| | |
| | | <style lang="less" scoped> |
| | | .el-row { |
| | | margin-bottom: 20px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .el-col { |
| | | border-radius: 4px; |
| | | } |
| | | |
| | | .user-type { |
| | | /deep/ .el-radio { |
| | | width: 110px; |
| | |
| | | } |
| | | }, |
| | | selected(select) { |
| | | console.log(select) |
| | | this.users.length = 0 |
| | | select.forEach(u => this.users.push(u)) |
| | | }, |
| | |
| | | group.conditions.splice(index, 1) |
| | | }, |
| | | conditionChange(index, group) { |
| | | console.log("index",index); |
| | | console.log("group",group); |
| | | //判断新增的 |
| | | group.cids.forEach(cid => { |
| | | if (0 > group.conditions.findIndex(cd => cd.id === cid)){ |
| | |
| | | //条件节点 |
| | | prioritySortList() { |
| | | let node = this.$store.state.nodeMap.get(this.selectedNode.parentId) |
| | | console.log(this.selectedNode.id, node) |
| | | if (node) { |
| | | return node.branchs || [] |
| | | } |
| | |
| | | this.showOrgSelect = true |
| | | }, |
| | | selected(select) { |
| | | console.log(select) |
| | | this.showOrgSelect = false |
| | | select.forEach(val => this.select.push(val)) |
| | | }, |
| | |
| | | } |
| | | }, |
| | | selected(select) { |
| | | console.log(select) |
| | | this.users.length = 0 |
| | | select.forEach(u => this.users.push(u)) |
| | | }, |
| | |
| | | if (0 > group.conditions.findIndex(cd => cd.id === cid)){ |
| | | //新增条件 |
| | | let condition = {...this.conditionList[index]} |
| | | console.log(condition, this.conditionList, index) |
| | | condition.compare = ''; |
| | | condition.value = [] |
| | | group.conditions.push(condition) |
| | |
| | | //条件节点 |
| | | prioritySortList() { |
| | | let node = this.$store.state.nodeMap.get(this.selectedNode.parentId) |
| | | console.log(this.selectedNode.id, node) |
| | | if (node) { |
| | | return node.branchs || [] |
| | | } |
| | |
| | | <template> |
| | | <div> |
| | | <el-tabs v-model="active" v-if="name && formConfig.length > 0"> |
| | | <el-tab-pane :label="name" name="properties"> |
| | | <component :is="(selectNode.type||'').toLowerCase()" :config="selectNode.props"/> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="表单权限设置" name="permissions"> |
| | | <form-authority-config/> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | <component :is="(selectNode.type||'').toLowerCase()" v-else :config="selectNode.props"/> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | }, |
| | | computed: { |
| | | selectNode() { |
| | | console.log("selectNode",this.$store.state) |
| | | return this.$store.state.selectedNode |
| | | }, |
| | | formConfig() { |
| | |
| | | }, |
| | | computed:{ |
| | | select(){ |
| | | console.log("this.config.assignedUser-select",this.config.assignedUser) |
| | | return this.config.assignedUser |
| | | } |
| | | }, |
| | |
| | | } |
| | | }, |
| | | mounted(){ |
| | | this.getGroups() |
| | | |
| | | }, |
| | | methods: { |
| | | selectUser() { |
| | |
| | | removeOrgItem(index) { |
| | | this.select.splice(index, 1) |
| | | }, |
| | | getGroups(){ |
| | | // 简便 不使用迭代方法处理 |
| | | getFormGroups().then(rsp => { |
| | | var data = rsp.data |
| | | this.fromGroup = data.map(group => { |
| | | return { |
| | | value: group.id, |
| | | label: group.name, |
| | | children: group.items.map(item => { |
| | | return { |
| | | value: item.formId, |
| | | label: item.formName, |
| | | }; |
| | | }) |
| | | }; |
| | | }); |
| | | }).catch(err => this.$message.error('获取分组异常')) |
| | | }, |
| | | |
| | | handleChange(key){ |
| | | // 对值进行处理 |
| | | } |
| | |
| | | this.$refs.orgPicker.show() |
| | | }, |
| | | selected(select) { |
| | | console.log(select) |
| | | this.orgPickerSelected.length = 0 |
| | | select.forEach(val => this.orgPickerSelected.push(val)) |
| | | }, |
| | |
| | | }, |
| | | content(){ |
| | | const config = this.config.props |
| | | console.log("content:config.assignedUser",config) |
| | | let texts = [] |
| | | config.assignedUser.forEach(org => texts.push(org.name)) |
| | | return String(texts).replaceAll(',', '、') |
| | | }, |
| | | |
| | | }, |
| | | // flowText(){ |
| | | // const config = this.config |
| | | // console.log("flowText-config",config); |
| | | // |
| | | // // return config.approvalArr.filter(ite=>ite.node_id===config.id)[0].approval_time; |
| | | // if(config.approvalArr!==undefined){ |
| | | // return "发起时间:"+config.approvalArr.filter(ite=>ite.node_id===config.id)[0].approval_time; |
| | | // } |
| | | // |
| | | // return '' |
| | | // } |
| | | }, |
| | | created() { |
| | | console.log("加载ApprovalNode.vue") |
| | | }, |
| | | methods: { |
| | | getFormItemById(id){ |
| | |
| | | }, |
| | | //校验数据配置的合法性 |
| | | validate(err) { |
| | | console.log('condition children', this.config.children) |
| | | console.log('this.level', this.level) |
| | | console.log('this.size', this.size) |
| | | if (!(this.level == this.size && this.size != 0) && !this.config.children?.id) { |
| | | this.showError = true |
| | | this.errorInfo = '条件分支后不能为空' |
| | |
| | | }, |
| | | //校验数据配置的合法性 |
| | | validate(err) { |
| | | console.log('inclusive children', this.config.children) |
| | | if (!(this.level == this.size && this.size != 0) && !this.config.children?.id) { |
| | | this.showError = true |
| | | this.errorInfo = '条件分支后不能为空' |
| | |
| | | //节点内容区域文字 |
| | | content: { |
| | | type: String, |
| | | default: "" |
| | | default: "111" |
| | | }, |
| | | title:{ |
| | | type: String, |
| | |
| | | }, |
| | | data() { |
| | | return { |
| | | isV:this.$isVertical |
| | | } |
| | | }, |
| | | |
| | | |
| | | created() { |
| | | console.log("this.isV",this.flowText) |
| | | }, |
| | | methods: {} |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss" :src="$cssSrc" scoped > |
| | | <style lang="less" scoped> |
| | | |
| | | .root { |
| | | &:before { |
| | | display: none !important; |
| | | } |
| | | } |
| | | |
| | | .node-error-state { |
| | | .node-body { |
| | | box-shadow: 0px 0px 5px 0px #F56C6C !important; |
| | | } |
| | | } |
| | | |
| | | .node { |
| | | padding: 0 50px; |
| | | width: 220px; |
| | | position: relative; |
| | | |
| | | &:before { |
| | | content: ''; |
| | | position: absolute; |
| | | top: -12px; |
| | | left: 50%; |
| | | -webkit-transform: translateX(-50%); |
| | | transform: translateX(-50%); |
| | | width: 0; |
| | | border-style: solid; |
| | | border-width: 8px 6px 4px; |
| | | border-color: #CACACA transparent transparent; |
| | | background: #F5F5F7; |
| | | } |
| | | |
| | | .node-body { |
| | | cursor: pointer; |
| | | max-height: 120px; |
| | | position: relative; |
| | | border-radius: 5px; |
| | | background-color: white; |
| | | box-shadow: 0px 0px 5px 0px #d8d8d8; |
| | | |
| | | &:hover { |
| | | box-shadow: 0px 0px 3px 0px @theme-primary; |
| | | |
| | | .node-body-header { |
| | | .el-icon-close { |
| | | display: inline; |
| | | font-size: medium; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .node-body-header { |
| | | border-top-left-radius: 5px; |
| | | border-top-right-radius: 5px; |
| | | padding: 5px 15px; |
| | | color: white; |
| | | font-size: xx-small; |
| | | |
| | | .el-icon-close { |
| | | display: none; |
| | | } |
| | | |
| | | .name { |
| | | height: 14px; |
| | | width: 150px; |
| | | display: inline-block |
| | | } |
| | | } |
| | | |
| | | .node-body-content { |
| | | padding: 18px; |
| | | color: #656363; |
| | | font-size: 14px; |
| | | |
| | | i { |
| | | position: absolute; |
| | | top: 55%; |
| | | right: 5px; |
| | | font-size: medium; |
| | | } |
| | | |
| | | .placeholder { |
| | | color: #8c8c8c; |
| | | } |
| | | } |
| | | |
| | | .node-error { |
| | | position: absolute; |
| | | right: -40px; |
| | | top: 20px; |
| | | font-size: 25px; |
| | | color: #F56C6C; |
| | | } |
| | | } |
| | | |
| | | .node-footer { |
| | | position: relative; |
| | | |
| | | .btn { |
| | | width: 100%; |
| | | display: flex; |
| | | padding: 20px 0 32px; |
| | | justify-content: center; |
| | | } |
| | | |
| | | /deep/ .el-button { |
| | | height: 32px; |
| | | } |
| | | |
| | | &::before { |
| | | content: ""; |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | z-index: -1; |
| | | margin: auto; |
| | | width: 2px; |
| | | height: 100%; |
| | | background-color: #CACACA; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | | |
| | |
| | | }, |
| | | content(){ |
| | | const config = this.config.props |
| | | console.log("role,config.assignedUser",config.assignedUser) |
| | | switch (config.assignedType){ |
| | | case "ASSIGN_USER": |
| | | if (config.assignedUser.length > 0){ |
New file |
| | |
| | | <template> |
| | | <node :title="config.name" :show-error="showError" :content="content" :error-info="errorInfo" |
| | | @selected="$emit('selected')" @delNode="$emit('delNode')" @insertNode="type => $emit('insertNode', type)" |
| | | placeholder="请设置审批人" :header-bgc="headerBgc" header-icon="el-icon-s-check"/> |
| | | </template> |
| | | |
| | | <script> |
| | | import Node from './Node.vue' |
| | | |
| | | export default { |
| | | name: "ApprovalNode", |
| | | props:{ |
| | | config:{ |
| | | type: Object, |
| | | default: () => { |
| | | return {} |
| | | } |
| | | } |
| | | }, |
| | | components: {Node}, |
| | | data() { |
| | | return { |
| | | showError: false, |
| | | errorInfo: '', |
| | | } |
| | | }, |
| | | computed:{ |
| | | headerBgc() { |
| | | if (this.$store.state.diagramMode === 'viewer') { |
| | | return this.config.props.headerBgc |
| | | } else { |
| | | return '#ff943e' |
| | | } |
| | | }, |
| | | content(){ |
| | | const config = this.config.props |
| | | let texts = [] |
| | | config.assignedUser.forEach(org => texts.push(org.name)) |
| | | return String(texts).replaceAll(',', '、') |
| | | |
| | | }, |
| | | // flowText(){ |
| | | // const config = this.config |
| | | // console.log("flowText-config",config); |
| | | // |
| | | // // return config.approvalArr.filter(ite=>ite.node_id===config.id)[0].approval_time; |
| | | // if(config.approvalArr!==undefined){ |
| | | // return "发起时间:"+config.approvalArr.filter(ite=>ite.node_id===config.id)[0].approval_time; |
| | | // } |
| | | // |
| | | // return '' |
| | | // } |
| | | }, |
| | | created() { |
| | | }, |
| | | methods: { |
| | | getFormItemById(id){ |
| | | return this.$store.state.design.formItems.find(item => item.id === id) |
| | | }, |
| | | //校验数据配置的合法性 |
| | | validate(err){ |
| | | try { |
| | | this.showError = !this[`validate_${this.config.props.assignedType}`](err) |
| | | |
| | | if (this.config.props.nobody.handler === 'TO_USER' && this.config.props.nobody.assignedUser.length === 0) { |
| | | this.errorInfo = '审批人为空时, 转交给指定人员:【请指定一个具体的人】' |
| | | err.push('审批人为空时, 转交给指定人员:【请指定一个具体的人】') |
| | | this.showError = true |
| | | } |
| | | |
| | | return this.showError |
| | | } catch (e) { |
| | | return true; |
| | | } |
| | | }, |
| | | validate_ASSIGN_USER(err){ |
| | | if(this.config.props.assignedUser.length > 0){ |
| | | return true; |
| | | }else { |
| | | this.errorInfo = '请指定审批人员' |
| | | err.push(`${this.config.name} 未指定审批人员`) |
| | | return false |
| | | } |
| | | }, |
| | | validate_SELF_SELECT(err){ |
| | | return true; |
| | | }, |
| | | validate_LEADER_TOP(err){ |
| | | return true; |
| | | }, |
| | | validate_LEADER(err){ |
| | | return true; |
| | | }, |
| | | validate_ROLE(err){ |
| | | if (this.config.props.assignedUser.length <= 0){ |
| | | this.errorInfo = '请指定负责审批的系统角色' |
| | | err.push(`${this.config.name} 未指定审批角色`) |
| | | return false |
| | | } |
| | | return true; |
| | | }, |
| | | validate_SELF(err){ |
| | | return true; |
| | | }, |
| | | validate_FORM_USER(err){ |
| | | if (this.config.props.formUser === ''){ |
| | | this.errorInfo = '请指定表单中的人员组件' |
| | | err.push(`${this.config.name} 审批人为表单中人员,但未指定`) |
| | | return false |
| | | } |
| | | return true; |
| | | }, |
| | | validate_REFUSE(err){ |
| | | return true; |
| | | }, |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <node :title="config.name" :show-error="showError" :content="content" :error-info="errorInfo" |
| | | @selected="$emit('selected')" @delNode="$emit('delNode')" @insertNode="type => $emit('insertNode', type)" |
| | | placeholder="请设置抄送人" header-bgc="#3296fa" header-icon="el-icon-s-promotion"/> |
| | | </template> |
| | | |
| | | <script> |
| | | import Node from './Node.vue' |
| | | |
| | | export default { |
| | | name: "CcNode", |
| | | props:{ |
| | | config:{ |
| | | type: Object, |
| | | default: () => { |
| | | return {} |
| | | } |
| | | } |
| | | }, |
| | | components: {Node}, |
| | | data() { |
| | | return { |
| | | showError: false, |
| | | errorInfo: '', |
| | | } |
| | | }, |
| | | computed:{ |
| | | content() { |
| | | if (this.config.props.shouldAdd){ |
| | | return '由发起人指定' |
| | | }else if (this.config.props.assignedUser.length > 0) { |
| | | let texts = [] |
| | | this.config.props.assignedUser.forEach(org => texts.push(org.name)) |
| | | return String(texts).replaceAll(',', '、') |
| | | } else { |
| | | return null |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | //校验数据配置的合法性 |
| | | validate(err){ |
| | | this.showError = false |
| | | if(this.config.props.shouldAdd){ |
| | | this.showError = false |
| | | }else if(this.config.props.assignedUser.length === 0){ |
| | | this.showError = true |
| | | this.errorInfo = '请选择需要抄送的人员' |
| | | } |
| | | if (this.showError){ |
| | | err.push(`抄送节点 ${this.config.name} 未设置抄送人`) |
| | | } |
| | | return !this.showError |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="node"> |
| | | <div class="node-body" @click="$emit('selected')"> |
| | | <div class="node-body-left" @click.stop="$emit('leftMove')" v-if="level > 1" v-show="$store.state.diagramMode !== 'viewer'"> |
| | | <i class="el-icon-arrow-left"></i> |
| | | </div> |
| | | <div class="node-body-main"> |
| | | <div class="node-body-main-header"> |
| | | <span class="title"> |
| | | <i class="el-icon-s-operation"></i> |
| | | <ellipsis class="name" hover-tip :content="config.name ? config.name:('并行任务' + level)"/> |
| | | </span> |
| | | <span class="option" v-show="$store.state.diagramMode !== 'viewer'"> |
| | | <el-tooltip effect="dark" content="复制分支" placement="top"> |
| | | <i class="el-icon-copy-document" @click="$emit('copy')"></i> |
| | | </el-tooltip> |
| | | <i class="el-icon-close" @click.stop="$emit('delNode')"></i> |
| | | </span> |
| | | </div> |
| | | <div class="node-body-main-content"> |
| | | <span>并行任务(同时进行)</span> |
| | | </div> |
| | | </div> |
| | | <div class="node-body-right" @click.stop="$emit('rightMove')" v-if="level < size" v-show="$store.state.diagramMode !== 'viewer'"> |
| | | <i class="el-icon-arrow-right"></i> |
| | | </div> |
| | | </div> |
| | | <div class="node-footer"> |
| | | <div class="btn"> |
| | | <insert-button v-show="$store.state.diagramMode !== 'viewer'" @insertNode="type => $emit('insertNode', type)"></insert-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import InsertButton from '@/views/common/InsertButton.vue' |
| | | |
| | | export default { |
| | | name: "ConcurrentNode", |
| | | components: {InsertButton}, |
| | | props:{ |
| | | config:{ |
| | | type: Object, |
| | | default: () => { |
| | | return {} |
| | | } |
| | | }, |
| | | level:{ |
| | | type: Number, |
| | | default: 1 |
| | | }, |
| | | //条件数 |
| | | size:{ |
| | | type: Number, |
| | | default: 0 |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | |
| | | } |
| | | }, |
| | | methods: {} |
| | | } |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | |
| | | |
| | | .node{ |
| | | padding: 30px 55px 0; |
| | | width: 220px; |
| | | .node-body{ |
| | | overflow: hidden; |
| | | cursor: pointer; |
| | | min-height: 80px; |
| | | max-height: 120px; |
| | | position: relative; |
| | | border-radius: 5px; |
| | | background-color: white; |
| | | box-shadow: 0px 0px 5px 0px #d8d8d8; |
| | | &:hover{ |
| | | .node-body-left, .node-body-right{ |
| | | i{ |
| | | display: block !important; |
| | | } |
| | | } |
| | | .node-body-main { |
| | | .option{ |
| | | display: inline-block !important; |
| | | } |
| | | } |
| | | box-shadow: 0px 0px 3px 0px @theme-primary; |
| | | } |
| | | .node-body-left, .node-body-right{ |
| | | display: flex; |
| | | align-items: center; |
| | | position: absolute; |
| | | height: 100%; |
| | | i{ |
| | | display: none; |
| | | } |
| | | &:hover{ |
| | | background-color: #ececec; |
| | | } |
| | | } |
| | | .node-body-left{ |
| | | left: 0; |
| | | } |
| | | .node-body-right{ |
| | | right: 0; |
| | | } |
| | | .node-body-main { |
| | | position: absolute; |
| | | width: 188px; |
| | | left: 17px; |
| | | display: inline-block; |
| | | |
| | | .node-body-main-header{ |
| | | padding: 10px 0px 5px; |
| | | font-size: xx-small; |
| | | position: relative; |
| | | .title{ |
| | | color: #718dff; |
| | | .name{ |
| | | display: inline-block; |
| | | height: 14px; |
| | | width: 130px; |
| | | margin-left: 2px; |
| | | } |
| | | } |
| | | .option{ |
| | | position: absolute; |
| | | right: 0; |
| | | display: none; |
| | | font-size: medium; |
| | | i{ |
| | | color: #888888; |
| | | padding: 0 3px; |
| | | } |
| | | } |
| | | } |
| | | .node-body-main-content { |
| | | padding: 6px; |
| | | color: #656363; |
| | | font-size: 14px; |
| | | |
| | | i { |
| | | position: absolute; |
| | | top: 55%; |
| | | right: 10px; |
| | | font-size: medium; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .node-footer{ |
| | | position: relative; |
| | | .btn{ |
| | | width: 100%; |
| | | display: flex; |
| | | height: 70px; |
| | | padding: 20px 0 32px; |
| | | justify-content: center; |
| | | } |
| | | /deep/ .el-button{ |
| | | height: 32px; |
| | | } |
| | | &::before{ |
| | | content: ""; |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | z-index: -1; |
| | | margin: auto; |
| | | width: 2px; |
| | | height: 100%; |
| | | background-color: #CACACA; |
| | | } |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div :class="{'node': true, 'node-error-state': showError}"> |
| | | <div :class="{'node-body': true, 'error': showError}"> |
| | | <div class="node-body-left" @click="$emit('leftMove')" v-if="level > 1 && $store.state.diagramMode !== 'viewer'"> |
| | | <i class="el-icon-arrow-left"></i> |
| | | </div> |
| | | <div class="node-body-main" @click="$emit('selected')"> |
| | | <div class="node-body-main-header"> |
| | | <ellipsis class="title" hover-tip :content="config.name ? config.name : ('条件' + level)"/> |
| | | <span class="level">优先级{{ level }}</span> |
| | | <span class="option" v-if="$store.state.diagramMode !== 'viewer'"> |
| | | <el-tooltip effect="dark" content="复制条件" placement="top"> |
| | | <i class="el-icon-copy-document" @click.stop="$emit('copy')"></i> |
| | | </el-tooltip> |
| | | <i class="el-icon-close" @click.stop="$emit('delNode')"></i> |
| | | </span> |
| | | </div> |
| | | <div class="node-body-main-content"> |
| | | <span class="placeholder" v-if="(content || '').trim() === ''">{{ |
| | | level == size && size != 0 ? "其他条件进入此流程" : placeholder |
| | | }}</span> |
| | | <ellipsis hoverTip :row="4" :content="content" v-else/> |
| | | </div> |
| | | </div> |
| | | <div class="node-body-right" @click="$emit('rightMove')" |
| | | v-if="level < size && $store.state.diagramMode !== 'viewer'"> |
| | | <i class="el-icon-arrow-right"></i> |
| | | </div> |
| | | <div class="node-error" v-if="showError"> |
| | | <el-tooltip effect="dark" :content="errorInfo" placement="top-start"> |
| | | <i class="el-icon-warning-outline"></i> |
| | | </el-tooltip> |
| | | </div> |
| | | </div> |
| | | <div class="node-footer"> |
| | | <div class="btn"> |
| | | <insert-button v-if="$store.state.diagramMode !== 'viewer'" |
| | | @insertNode="type => $emit('insertNode', type)"></insert-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import InsertButton from '@/views/common/InsertButton.vue' |
| | | import {ValueType} from '@/views/common/ComponentsConfigExport' |
| | | const groupNames = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']; |
| | | export default { |
| | | name: "ConditionNode", |
| | | components: {InsertButton}, |
| | | props: { |
| | | config: { |
| | | type: Object, |
| | | default: () => { |
| | | return {} |
| | | } |
| | | }, |
| | | //索引位置 |
| | | level: { |
| | | type: Number, |
| | | default: 1 |
| | | }, |
| | | //条件数 |
| | | size: { |
| | | type: Number, |
| | | default: 0 |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | ValueType, |
| | | groupNames, |
| | | placeholder: '请设置条件', |
| | | errorInfo: '', |
| | | showError: false |
| | | } |
| | | }, |
| | | computed: { |
| | | content() { |
| | | const groups = this.config.props.groups |
| | | let confitions = [] |
| | | groups.forEach(group => { |
| | | let subConditions = [] |
| | | group.conditions.forEach(subCondition => { |
| | | let subConditionStr = '' |
| | | switch (subCondition.valueType) { |
| | | case ValueType.dept: |
| | | case ValueType.user: |
| | | subConditionStr = `${subCondition.title}属于[${String(subCondition.value.map(u => u.name)).replaceAll(',', '. ')}]之一` |
| | | break; |
| | | case ValueType.number: |
| | | case ValueType.string: |
| | | subConditionStr = this.getOrdinaryConditionContent(subCondition) |
| | | break; |
| | | } |
| | | subConditions.push(subConditionStr) |
| | | }) |
| | | //根据子条件关系构建描述 |
| | | let subConditionsStr = String(subConditions) |
| | | .replaceAll(',', subConditions.length > 1 ? |
| | | (group.groupType === 'AND' ? ') 且 (' : ') 或 (') : |
| | | (group.groupType === 'AND' ? ' 且 ' : ' 或 ')) |
| | | confitions.push(subConditions.length > 1 ? `(${subConditionsStr})` : subConditionsStr) |
| | | }) |
| | | //构建最终描述 |
| | | return String(confitions).replaceAll(',', (this.config.props.groupsType === 'AND' ? ' 且 ' : ' 或 ')) |
| | | } |
| | | }, |
| | | methods: { |
| | | getDefault(val, df) { |
| | | return val && val !== '' ? val : df; |
| | | }, |
| | | getOrdinaryConditionContent(subCondition) { |
| | | |
| | | switch (subCondition.compare) { |
| | | case 'IN': |
| | | let items = subCondition.value.map(function (item) { |
| | | return item.label |
| | | }) |
| | | return `${subCondition.title}为[${String(items).replaceAll(',', '、')}]中之一` |
| | | case 'B': |
| | | return `${subCondition.value[0]} < ${subCondition.title} < ${subCondition.value[1]}` |
| | | case 'AB': |
| | | return `${subCondition.value[0]} ≤ ${subCondition.title} < ${subCondition.value[1]}` |
| | | case 'BA': |
| | | return `${subCondition.value[0]} < ${subCondition.title} ≤ ${subCondition.value[1]}` |
| | | case 'ABA': |
| | | return `${subCondition.value[0]} ≤ ${subCondition.title} ≤ ${subCondition.value[1]}` |
| | | case '<=': |
| | | return `${subCondition.title} ≤ ${this.getDefault(subCondition.value[0], ' ?')}` |
| | | case '>=': |
| | | return `${subCondition.title} ≥ ${this.getDefault(subCondition.value[0], ' ?')}` |
| | | default: |
| | | return `${subCondition.title}${subCondition.compare}${this.getDefault(subCondition.value[0], ' ?')}` |
| | | } |
| | | }, |
| | | //校验数据配置的合法性 |
| | | validate(err) { |
| | | |
| | | if (!(this.level == this.size && this.size != 0) && !this.config.children?.id) { |
| | | this.showError = true |
| | | this.errorInfo = '条件分支后不能为空' |
| | | err.push(`条件分支后不能为空`) |
| | | return !this.showError |
| | | } |
| | | |
| | | const props = this.config.props |
| | | if (props.groups.length <= 0){ |
| | | this.showError = true |
| | | this.errorInfo = '请设置分支条件' |
| | | err.push(`${this.config.name} 未设置条件`) |
| | | }else { |
| | | if (!(this.level == this.size && this.size != 0)) { |
| | | for (let i = 0; i < props.groups.length; i++) { |
| | | if (props.groups[i].cids.length === 0){ |
| | | this.showError = true |
| | | this.errorInfo = `请设置条件组${this.groupNames[i]}内的条件` |
| | | err.push(`条件 ${this.config.name} 条件组${this.groupNames[i]}内未设置条件`) |
| | | break |
| | | }else { |
| | | let conditions = props.groups[i].conditions |
| | | for (let ci = 0; ci < conditions.length; ci++) { |
| | | let subc = conditions[ci] |
| | | if (subc.value.length === 0){ |
| | | this.showError = true |
| | | }else { |
| | | this.showError = false |
| | | } |
| | | if (this.showError){ |
| | | this.errorInfo = `请完善条件组${this.groupNames[i]}内的${subc.title}条件` |
| | | err.push(`条件 ${this.config.name} 条件组${this.groupNames[i]}内${subc.title}条件未完善`) |
| | | return false |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return !this.showError; |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | |
| | | |
| | | .node-error-state { |
| | | .node-body { |
| | | box-shadow: 0px 0px 5px 0px #F56C6C !important; |
| | | } |
| | | } |
| | | |
| | | .node { |
| | | padding: 30px 55px 0; |
| | | width: 220px; |
| | | |
| | | .node-body { |
| | | cursor: pointer; |
| | | min-height: 80px; |
| | | max-height: 120px; |
| | | position: relative; |
| | | border-radius: 5px; |
| | | background-color: white; |
| | | box-shadow: 0px 0px 5px 0px #d8d8d8; |
| | | |
| | | &:hover { |
| | | .node-body-left, .node-body-right { |
| | | i { |
| | | display: block !important; |
| | | } |
| | | } |
| | | |
| | | .node-body-main { |
| | | .level { |
| | | display: none !important; |
| | | } |
| | | |
| | | .option { |
| | | display: inline-block !important; |
| | | } |
| | | } |
| | | |
| | | box-shadow: 0px 0px 3px 0px @theme-primary; |
| | | } |
| | | |
| | | .node-body-left, .node-body-right { |
| | | display: flex; |
| | | align-items: center; |
| | | position: absolute; |
| | | height: 100%; |
| | | |
| | | i { |
| | | display: none; |
| | | } |
| | | |
| | | &:hover { |
| | | background-color: #ececec; |
| | | } |
| | | } |
| | | |
| | | .node-body-left { |
| | | left: 0; |
| | | } |
| | | |
| | | .node-body-right { |
| | | right: 0; |
| | | top: 0; |
| | | } |
| | | |
| | | .node-body-main { |
| | | //position: absolute; |
| | | width: 188px; |
| | | margin-left: 17px; |
| | | display: inline-block; |
| | | |
| | | .node-body-main-header { |
| | | padding: 10px 0px 5px; |
| | | font-size: xx-small; |
| | | position: relative; |
| | | |
| | | .title { |
| | | color: #15bca3; |
| | | display: inline-block; |
| | | height: 14px; |
| | | width: 125px; |
| | | } |
| | | |
| | | .level { |
| | | position: absolute; |
| | | right: 15px; |
| | | color: #888888; |
| | | } |
| | | |
| | | .option { |
| | | position: absolute; |
| | | right: 0; |
| | | display: none; |
| | | font-size: medium; |
| | | |
| | | i { |
| | | color: #888888; |
| | | padding: 0 3px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .node-body-main-content { |
| | | padding: 6px; |
| | | color: #656363; |
| | | font-size: 14px; |
| | | |
| | | i { |
| | | position: absolute; |
| | | top: 55%; |
| | | right: 10px; |
| | | font-size: medium; |
| | | } |
| | | |
| | | .placeholder { |
| | | color: #8c8c8c; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .node-error { |
| | | position: absolute; |
| | | right: -40px; |
| | | top: 20px; |
| | | font-size: 25px; |
| | | color: #F56C6C; |
| | | } |
| | | } |
| | | |
| | | .node-footer { |
| | | position: relative; |
| | | |
| | | .btn { |
| | | width: 100%; |
| | | display: flex; |
| | | height: 70px; |
| | | padding: 20px 0 32px; |
| | | justify-content: center; |
| | | } |
| | | |
| | | /deep/ .el-button { |
| | | height: 32px; |
| | | } |
| | | |
| | | &::before { |
| | | content: ""; |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | z-index: -1; |
| | | margin: auto; |
| | | width: 2px; |
| | | height: 100%; |
| | | background-color: #CACACA; |
| | | } |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <node :title="config.name" :show-error="showError" :content="content" :error-info="errorInfo" |
| | | @selected="$emit('selected')" @delNode="$emit('delNode')" @insertNode="type => $emit('insertNode', type)" |
| | | placeholder="请设置延时时间" header-bgc="#f25643" header-icon="el-icon-time"/> |
| | | </template> |
| | | |
| | | <script> |
| | | import Node from './Node.vue' |
| | | |
| | | export default { |
| | | name: "DelayNode", |
| | | props:{ |
| | | config:{ |
| | | type: Object, |
| | | default: () => { |
| | | return {} |
| | | } |
| | | } |
| | | }, |
| | | components: {Node}, |
| | | data() { |
| | | return { |
| | | showError: false, |
| | | errorInfo: '', |
| | | } |
| | | }, |
| | | computed:{ |
| | | content(){ |
| | | if (this.config.props.type === 'FIXED'){ |
| | | return `等待 ${this.config.props.time} ${this.getName(this.config.props.unit)}` |
| | | }else if(this.config.props.type === 'AUTO'){ |
| | | return `至当天 ${this.config.props.dateTime}` |
| | | }else { |
| | | return null |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | //校验数据配置的合法性 |
| | | validate(err){ |
| | | this.showError = false |
| | | try { |
| | | if (this.config.props.type === "AUTO") { |
| | | if ((this.config.props.dateTime || "") === ""){ |
| | | this.showError = true |
| | | this.errorInfo = "请选择时间点" |
| | | } |
| | | } else { |
| | | if (this.config.props.time <= 0) { |
| | | this.showError = true |
| | | this.errorInfo = "请设置延时时长" |
| | | } |
| | | } |
| | | } catch (e) { |
| | | this.showError = true |
| | | this.errorInfo = "配置出现问题" |
| | | } |
| | | if (this.showError){ |
| | | err.push(`${this.config.name} 未设置延时规则`) |
| | | } |
| | | return !this.showError |
| | | }, |
| | | getName(unit){ |
| | | switch (unit){ |
| | | case 'D': return '天'; |
| | | case 'H': return '小时'; |
| | | case 'M': return '分钟'; |
| | | default: return '未知'; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <node :show="false" @insertNode="type => $emit('insertNode', type)"/> |
| | | </template> |
| | | |
| | | <script> |
| | | import Node from './Node.vue' |
| | | |
| | | export default { |
| | | name: "EmptyNode", |
| | | components: {Node}, |
| | | data() { |
| | | return {} |
| | | }, |
| | | methods: {} |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div :class="{'node': true, 'node-error-state': showError}"> |
| | | <div :class="{'node-body': true, 'error': showError}"> |
| | | <div class="node-body-left" @click="$emit('leftMove')" v-if="level > 1 && $store.state.diagramMode !== 'viewer'"> |
| | | <i class="el-icon-arrow-left"></i> |
| | | </div> |
| | | <div class="node-body-main" @click="$emit('selected')"> |
| | | <div class="node-body-main-header"> |
| | | <ellipsis class="title" hover-tip :content="config.name ? config.name : ('条件' + level)"/> |
| | | <span class="level">优先级{{ level }}</span> |
| | | <span class="option" v-if="$store.state.diagramMode !== 'viewer'"> |
| | | <el-tooltip effect="dark" content="复制条件" placement="top"> |
| | | <i class="el-icon-copy-document" @click.stop="$emit('copy')"></i> |
| | | </el-tooltip> |
| | | <i class="el-icon-close" @click.stop="$emit('delNode')"></i> |
| | | </span> |
| | | </div> |
| | | <div class="node-body-main-content"> |
| | | <span class="placeholder" v-if="(content || '').trim() === ''">{{ |
| | | level == size && size != 0 ? "其他条件进入此流程" : placeholder |
| | | }}</span> |
| | | <ellipsis hoverTip :row="4" :content="content" v-else/> |
| | | </div> |
| | | </div> |
| | | <div class="node-body-right" @click="$emit('rightMove')" |
| | | v-if="level < size && $store.state.diagramMode !== 'viewer'"> |
| | | <i class="el-icon-arrow-right"></i> |
| | | </div> |
| | | <div class="node-error" v-if="showError"> |
| | | <el-tooltip effect="dark" :content="errorInfo" placement="top-start"> |
| | | <i class="el-icon-warning-outline"></i> |
| | | </el-tooltip> |
| | | </div> |
| | | </div> |
| | | <div class="node-footer"> |
| | | <div class="btn"> |
| | | <insert-button v-if="$store.state.diagramMode !== 'viewer'" |
| | | @insertNode="type => $emit('insertNode', type)"></insert-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import InsertButton from '@/views/common/InsertButton.vue' |
| | | import {ValueType} from '@/views/common/ComponentsConfigExport' |
| | | const groupNames = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']; |
| | | export default { |
| | | name: "InclusiveNode", |
| | | components: {InsertButton}, |
| | | props: { |
| | | config: { |
| | | type: Object, |
| | | default: () => { |
| | | return {} |
| | | } |
| | | }, |
| | | //索引位置 |
| | | level: { |
| | | type: Number, |
| | | default: 1 |
| | | }, |
| | | //条件数 |
| | | size: { |
| | | type: Number, |
| | | default: 0 |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | ValueType, |
| | | groupNames, |
| | | placeholder: '请设置条件', |
| | | errorInfo: '', |
| | | showError: false |
| | | } |
| | | }, |
| | | computed: { |
| | | content() { |
| | | const groups = this.config.props.groups |
| | | let confitions = [] |
| | | groups.forEach(group => { |
| | | let subConditions = [] |
| | | group.conditions.forEach(subCondition => { |
| | | let subConditionStr = '' |
| | | switch (subCondition.valueType) { |
| | | case ValueType.dept: |
| | | case ValueType.user: |
| | | subConditionStr = `${subCondition.title}属于[${String(subCondition.value.map(u => u.name)).replaceAll(',', '. ')}]之一` |
| | | break; |
| | | case ValueType.number: |
| | | case ValueType.string: |
| | | subConditionStr = this.getOrdinaryConditionContent(subCondition) |
| | | break; |
| | | } |
| | | subConditions.push(subConditionStr) |
| | | }) |
| | | //根据子条件关系构建描述 |
| | | let subConditionsStr = String(subConditions) |
| | | .replaceAll(',', subConditions.length > 1 ? |
| | | (group.groupType === 'AND' ? ') 且 (' : ') 或 (') : |
| | | (group.groupType === 'AND' ? ' 且 ' : ' 或 ')) |
| | | confitions.push(subConditions.length > 1 ? `(${subConditionsStr})` : subConditionsStr) |
| | | }) |
| | | //构建最终描述 |
| | | return String(confitions).replaceAll(',', (this.config.props.groupsType === 'AND' ? ' 且 ' : ' 或 ')) |
| | | } |
| | | }, |
| | | methods: { |
| | | getDefault(val, df) { |
| | | return val && val !== '' ? val : df; |
| | | }, |
| | | getOrdinaryConditionContent(subCondition) { |
| | | switch (subCondition.compare) { |
| | | case 'IN': |
| | | return `${subCondition.title}为[${String(subCondition.value).replaceAll(',', '、')}]中之一` |
| | | case 'B': |
| | | return `${subCondition.value[0]} < ${subCondition.title} < ${subCondition.value[1]}` |
| | | case 'AB': |
| | | return `${subCondition.value[0]} ≤ ${subCondition.title} < ${subCondition.value[1]}` |
| | | case 'BA': |
| | | return `${subCondition.value[0]} < ${subCondition.title} ≤ ${subCondition.value[1]}` |
| | | case 'ABA': |
| | | return `${subCondition.value[0]} ≤ ${subCondition.title} ≤ ${subCondition.value[1]}` |
| | | case '<=': |
| | | return `${subCondition.title} ≤ ${this.getDefault(subCondition.value[0], ' ?')}` |
| | | case '>=': |
| | | return `${subCondition.title} ≥ ${this.getDefault(subCondition.value[0], ' ?')}` |
| | | default: |
| | | return `${subCondition.title}${subCondition.compare}${this.getDefault(subCondition.value[0], ' ?')}` |
| | | } |
| | | }, |
| | | //校验数据配置的合法性 |
| | | validate(err) { |
| | | if (!(this.level == this.size && this.size != 0) && !this.config.children?.id) { |
| | | this.showError = true |
| | | this.errorInfo = '条件分支后不能为空' |
| | | err.push(`条件分支后不能为空`) |
| | | return !this.showError |
| | | } |
| | | |
| | | const props = this.config.props |
| | | if (props.groups.length <= 0){ |
| | | this.showError = true |
| | | this.errorInfo = '请设置分支条件' |
| | | err.push(`${this.config.name} 未设置条件`) |
| | | }else { |
| | | if (!(this.level == this.size && this.size != 0)) { |
| | | for (let i = 0; i < props.groups.length; i++) { |
| | | if (props.groups[i].cids.length === 0){ |
| | | this.showError = true |
| | | this.errorInfo = `请设置条件组${this.groupNames[i]}内的条件` |
| | | err.push(`条件 ${this.config.name} 条件组${this.groupNames[i]}内未设置条件`) |
| | | break |
| | | }else { |
| | | let conditions = props.groups[i].conditions |
| | | for (let ci = 0; ci < conditions.length; ci++) { |
| | | let subc = conditions[ci] |
| | | if (subc.value.length === 0){ |
| | | this.showError = true |
| | | }else { |
| | | this.showError = false |
| | | } |
| | | if (this.showError){ |
| | | this.errorInfo = `请完善条件组${this.groupNames[i]}内的${subc.title}条件` |
| | | err.push(`条件 ${this.config.name} 条件组${this.groupNames[i]}内${subc.title}条件未完善`) |
| | | return false |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return !this.showError; |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | |
| | | |
| | | .node-error-state { |
| | | .node-body { |
| | | box-shadow: 0px 0px 5px 0px #F56C6C !important; |
| | | } |
| | | } |
| | | |
| | | .node { |
| | | padding: 30px 55px 0; |
| | | width: 220px; |
| | | |
| | | .node-body { |
| | | cursor: pointer; |
| | | min-height: 80px; |
| | | max-height: 120px; |
| | | position: relative; |
| | | border-radius: 5px; |
| | | background-color: white; |
| | | box-shadow: 0px 0px 5px 0px #d8d8d8; |
| | | |
| | | &:hover { |
| | | .node-body-left, .node-body-right { |
| | | i { |
| | | display: block !important; |
| | | } |
| | | } |
| | | |
| | | .node-body-main { |
| | | .level { |
| | | display: none !important; |
| | | } |
| | | |
| | | .option { |
| | | display: inline-block !important; |
| | | } |
| | | } |
| | | |
| | | box-shadow: 0px 0px 3px 0px @theme-primary; |
| | | } |
| | | |
| | | .node-body-left, .node-body-right { |
| | | display: flex; |
| | | align-items: center; |
| | | position: absolute; |
| | | height: 100%; |
| | | |
| | | i { |
| | | display: none; |
| | | } |
| | | |
| | | &:hover { |
| | | background-color: #ececec; |
| | | } |
| | | } |
| | | |
| | | .node-body-left { |
| | | left: 0; |
| | | } |
| | | |
| | | .node-body-right { |
| | | right: 0; |
| | | top: 0; |
| | | } |
| | | |
| | | .node-body-main { |
| | | //position: absolute; |
| | | width: 188px; |
| | | margin-left: 17px; |
| | | display: inline-block; |
| | | |
| | | .node-body-main-header { |
| | | padding: 10px 0px 5px; |
| | | font-size: xx-small; |
| | | position: relative; |
| | | |
| | | .title { |
| | | color: #425c9d; |
| | | display: inline-block; |
| | | height: 14px; |
| | | width: 125px; |
| | | } |
| | | |
| | | .level { |
| | | position: absolute; |
| | | right: 15px; |
| | | color: #888888; |
| | | } |
| | | |
| | | .option { |
| | | position: absolute; |
| | | right: 0; |
| | | display: none; |
| | | font-size: medium; |
| | | |
| | | i { |
| | | color: #888888; |
| | | padding: 0 3px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .node-body-main-content { |
| | | padding: 6px; |
| | | color: #656363; |
| | | font-size: 14px; |
| | | |
| | | i { |
| | | position: absolute; |
| | | top: 55%; |
| | | right: 10px; |
| | | font-size: medium; |
| | | } |
| | | |
| | | .placeholder { |
| | | color: #8c8c8c; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .node-error { |
| | | position: absolute; |
| | | right: -40px; |
| | | top: 20px; |
| | | font-size: 25px; |
| | | color: #F56C6C; |
| | | } |
| | | } |
| | | |
| | | .node-footer { |
| | | position: relative; |
| | | |
| | | .btn { |
| | | width: 100%; |
| | | display: flex; |
| | | height: 70px; |
| | | padding: 20px 0 32px; |
| | | justify-content: center; |
| | | } |
| | | |
| | | /deep/ .el-button { |
| | | height: 32px; |
| | | } |
| | | |
| | | &::before { |
| | | content: ""; |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | z-index: -1; |
| | | margin: auto; |
| | | width: 2px; |
| | | height: 100%; |
| | | background-color: #CACACA; |
| | | } |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div :class="{ 'nodeView':true, 'root': isRoot || !show, 'node-error-state': showError}"> |
| | | <div v-if="show" @click="$emit('selected')" :class="{'node-body': true, 'error': showError}" > |
| | | <div> |
| | | <div class="node-body-header" :style="{'background-color': headerBgc}"> |
| | | <i :class="headerIcon" style="margin-right: 5px" v-if="(headerIcon || '') !== ''"></i> |
| | | <ellipsis class="name" hover-tip :content="title"/> |
| | | <i class="el-icon-close" v-if="!isRoot && $store.state.diagramMode !== 'viewer'" style="float:right;" @click="$emit('delNode')"></i> |
| | | </div> |
| | | <div class="node-body-content"> |
| | | <i :class="leftIcon" v-if="leftIcon"></i> |
| | | <span class="placeholder" v-if="(content || '').trim() === ''">{{placeholder}}</span> |
| | | <ellipsis :row="3" :content="content" v-else/> |
| | | <i class="el-icon-arrow-right" v-if="$store.state.diagramMode !== 'viewer'" ></i> |
| | | </div> |
| | | <div class="node-error" v-if="showError"> |
| | | |
| | | <el-tooltip effect="dark" :content="errorInfo" placement="top-start"> |
| | | <i class="el-icon-warning-outline"></i> |
| | | </el-tooltip> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="node-footer"> |
| | | <div class="btn"> |
| | | <insert-button v-show="$store.state.diagramMode !== 'viewer'" @insertNode="type => $emit('insertNode', type)"></insert-button> |
| | | |
| | | </div> |
| | | |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <script> |
| | | import InsertButton from '@/views/common/InsertButton.vue' |
| | | |
| | | |
| | | export default { |
| | | name: "NodeView", |
| | | components: {InsertButton}, |
| | | props:{ |
| | | //是否为根节点 |
| | | isRoot: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | //是否显示节点体 |
| | | show: { |
| | | type: Boolean, |
| | | default: true |
| | | }, |
| | | //节点内容区域文字 |
| | | content: { |
| | | type: String, |
| | | default: "" |
| | | }, |
| | | title:{ |
| | | type: String, |
| | | default: "标题" |
| | | }, |
| | | placeholder:{ |
| | | type: String, |
| | | default: "请设置" |
| | | }, |
| | | flowText:{ |
| | | type: String, |
| | | default: "" |
| | | }, |
| | | //节点体左侧图标 |
| | | leftIcon: { |
| | | type: String, |
| | | default: undefined |
| | | }, |
| | | //头部图标 |
| | | headerIcon:{ |
| | | type: String, |
| | | default: '' |
| | | }, |
| | | //头部背景色 |
| | | headerBgc:{ |
| | | type: String, |
| | | default: '#576a95' |
| | | }, |
| | | //是否显示错误状态 |
| | | showError:{ |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | errorInfo:{ |
| | | type: String, |
| | | default: '无信息' |
| | | }, |
| | | }, |
| | | data() { |
| | | return { |
| | | } |
| | | }, |
| | | |
| | | |
| | | created() { |
| | | }, |
| | | methods: {} |
| | | } |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .root{ |
| | | &:before{ |
| | | display: none !important; |
| | | } |
| | | } |
| | | .node-error-state{ |
| | | &.node-body{ |
| | | box-shadow: 0px 0px 5px 0px #F56C6C !important; |
| | | } |
| | | } |
| | | .nodeView{ |
| | | display: flex; |
| | | align-items:center; |
| | | width: auto; |
| | | position: relative; |
| | | &:before{ |
| | | content: ''; |
| | | top: 50%; |
| | | left: 100%; |
| | | display: block; |
| | | width: 0; |
| | | height: 0; |
| | | |
| | | border-style: solid; |
| | | border-color: #CACACA transparent transparent; |
| | | background: #F5F5F7; |
| | | border-top: 5px solid transparent; |
| | | border-bottom: 5px solid transparent; |
| | | border-left: 10px solid #CACACA; /* 左边界 */ |
| | | |
| | | } |
| | | .node-body{ |
| | | width: 220px; |
| | | cursor: pointer; |
| | | max-height: 120px; |
| | | position: relative; |
| | | border-radius: 5px; |
| | | background-color: white; |
| | | box-shadow: 0px 0px 5px 0px #d8d8d8; |
| | | &:hover{ |
| | | box-shadow: 0px 0px 3px 0px #1890FF; |
| | | .node-body-header { |
| | | .el-icon-close { |
| | | display: inline; |
| | | font-size: medium; |
| | | } |
| | | } |
| | | } |
| | | .node-body-header{ |
| | | border-top-left-radius: 5px; |
| | | border-top-right-radius: 5px; |
| | | padding: 5px 15px; |
| | | color: white; |
| | | font-size: xx-small; |
| | | .el-icon-close{ |
| | | display: none; |
| | | } |
| | | .name{ |
| | | height: 14px; |
| | | width: 150px; |
| | | display: inline-block |
| | | } |
| | | } |
| | | .node-body-content{ |
| | | padding: 18px; |
| | | color: #656363; |
| | | font-size: 14px; |
| | | i{ |
| | | position: absolute; |
| | | top: 55%; |
| | | right: 5px; |
| | | font-size: medium; |
| | | } |
| | | .placeholder{ |
| | | color: #8c8c8c; |
| | | } |
| | | } |
| | | .node-error{ |
| | | position: absolute; |
| | | right: -40px; |
| | | top: 20px; |
| | | font-size: 25px; |
| | | color: #F56C6C; |
| | | } |
| | | } |
| | | |
| | | .node-footer{ |
| | | position: relative; |
| | | .btn{ |
| | | width: 80px; |
| | | display: flex; |
| | | // padding: 20px 0 32px; |
| | | justify-content: center; |
| | | } |
| | | /deep/ .el-button{ |
| | | height: 32px; |
| | | } |
| | | &::before{ |
| | | content: ""; |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | z-index: -1; |
| | | margin: auto; |
| | | width: 100%; |
| | | height: 2px; |
| | | background-color: #CACACA; |
| | | } |
| | | } |
| | | } |
| | | |
| | | </style> |
| | | |
New file |
| | |
| | | <template> |
| | | <node title="发起人" :is-root="true" :content="content" |
| | | @selected="$emit('selected')" @insertNode="type => $emit('insertNode', type)" |
| | | placeholder="所有人" :header-bgc="headerBgc" header-icon="el-icon-user-solid"/> |
| | | </template> |
| | | |
| | | <script> |
| | | import Node from './Node.vue' |
| | | |
| | | export default { |
| | | name: "RootNode", |
| | | components: {Node}, |
| | | props:{ |
| | | config:{ |
| | | type: Object, |
| | | default: () => { |
| | | return {} |
| | | } |
| | | } |
| | | }, |
| | | computed:{ |
| | | content(){ |
| | | if (this.config.props.assignedUser.length > 0){ |
| | | let texts = [] |
| | | this.config.props.assignedUser.forEach(org => texts.push(org.writer_name)) |
| | | return String(texts).replaceAll(',', '、') |
| | | } else { |
| | | return '所有人' |
| | | } |
| | | }, |
| | | // flowText(){ |
| | | // const config = this.config |
| | | // console.log("flowText-config",config); |
| | | // if(config.approvalArr!==undefined){ |
| | | // return "发起时间:"+config.approvalArr.filter(ite=>ite.node_id===config.id)[0].approval_time; |
| | | // } |
| | | // return '' |
| | | // }, |
| | | headerBgc() { |
| | | if (this.$store.state.diagramMode === 'viewer') { |
| | | return this.config.props.headerBgc |
| | | } else { |
| | | return '#576a95' |
| | | } |
| | | }, |
| | | }, |
| | | data() { |
| | | return { |
| | | } |
| | | }, |
| | | methods: {} |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <node :title="config.name" :show-error="showError" :content="content" :error-info="errorInfo" |
| | | @selected="$emit('selected')" @delNode="$emit('delNode')" @insertNode="type => $emit('insertNode', type)" |
| | | placeholder="请设置审批人" :header-bgc="headerBgc" header-icon="el-icon-s-check"/> |
| | | </template> |
| | | <script> |
| | | import Node from './Node.vue' |
| | | |
| | | export default { |
| | | name: "SubprocessNode", |
| | | props:{ |
| | | config:{ |
| | | type: Object, |
| | | default: () => { |
| | | return {} |
| | | } |
| | | } |
| | | }, |
| | | components: {Node}, |
| | | data() { |
| | | return { |
| | | showError: false, |
| | | errorInfo: '', |
| | | } |
| | | }, |
| | | computed:{ |
| | | headerBgc() { |
| | | if (this.$store.state.diagramMode === 'viewer') { |
| | | return this.config.props.headerBgc |
| | | } else { |
| | | return '#ff943e' |
| | | } |
| | | }, |
| | | content(){ |
| | | const config = this.config.props |
| | | switch (config.assignedType){ |
| | | case "ASSIGN_USER": |
| | | if (config.assignedUser.length > 0){ |
| | | let texts = [] |
| | | config.assignedUser.forEach(org => texts.push(org.name)) |
| | | return String(texts).replaceAll(',', '、') |
| | | }else { |
| | | return '请指定审批人' |
| | | } |
| | | case "SELF": |
| | | return '发起人自己' |
| | | case "SELF_SELECT": |
| | | return config.selfSelect.multiple ? '发起人自选多人':'发起人自选一人' |
| | | case "LEADER_TOP": |
| | | return '多级主管依次审批' |
| | | case "LEADER": |
| | | return config.leader.level > 1 ? '发起人的第 ' + config.leader.level + ' 级主管' : '发起人的直接主管' |
| | | case "FORM_USER": |
| | | if (!config.formUser || config.formUser === ''){ |
| | | return '表单内联系人(未选择)' |
| | | }else { |
| | | let text = this.getFormItemById(config.formUser) |
| | | if (text && text.title){ |
| | | return `表单(${text.title})内的人员` |
| | | }else { |
| | | return '该表单已被移除😥' |
| | | } |
| | | } |
| | | case "ROLE": |
| | | |
| | | if (config.assignedUser.length > 0){ |
| | | let texts = [] |
| | | config.assignedUser.forEach(org => texts.push(org.name)) |
| | | return String(texts).replaceAll(',', '、') |
| | | }else { |
| | | return '指定角色(未设置)' |
| | | } |
| | | default: return '未知设置项😥' |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | getFormItemById(id){ |
| | | return this.$store.state.design.formItems.find(item => item.id === id) |
| | | }, |
| | | //校验数据配置的合法性 |
| | | validate(err){ |
| | | try { |
| | | this.showError = !this[`validate_${this.config.props.assignedType}`](err) |
| | | |
| | | if (this.config.props.nobody.handler === 'TO_USER' && this.config.props.nobody.assignedUser.length === 0) { |
| | | this.errorInfo = '审批人为空时, 转交给指定人员:【请指定一个具体的人】' |
| | | err.push('审批人为空时, 转交给指定人员:【请指定一个具体的人】') |
| | | this.showError = true |
| | | } |
| | | |
| | | return this.showError |
| | | } catch (e) { |
| | | return true; |
| | | } |
| | | }, |
| | | validate_ASSIGN_USER(err){ |
| | | if(this.config.props.assignedUser.length > 0){ |
| | | return true; |
| | | }else { |
| | | this.errorInfo = '请指定审批人员' |
| | | err.push(`${this.config.name} 未指定审批人员`) |
| | | return false |
| | | } |
| | | }, |
| | | validate_SELF_SELECT(err){ |
| | | return true; |
| | | }, |
| | | validate_LEADER_TOP(err){ |
| | | return true; |
| | | }, |
| | | validate_LEADER(err){ |
| | | return true; |
| | | }, |
| | | validate_ROLE(err){ |
| | | if (this.config.props.role.length <= 0){ |
| | | this.errorInfo = '请指定负责审批的系统角色' |
| | | err.push(`${this.config.name} 未指定审批角色`) |
| | | return false |
| | | } |
| | | return true; |
| | | }, |
| | | validate_SELF(err){ |
| | | return true; |
| | | }, |
| | | validate_FORM_USER(err){ |
| | | if (this.config.props.formUser === ''){ |
| | | this.errorInfo = '请指定表单中的人员组件' |
| | | err.push(`${this.config.name} 审批人为表单中人员,但未指定`) |
| | | return false |
| | | } |
| | | return true; |
| | | }, |
| | | validate_REFUSE(err){ |
| | | return true; |
| | | }, |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <node :title="config.name" :show-error="showError" :content="content" :error-info="errorInfo" |
| | | @selected="$emit('selected')" @delNode="$emit('delNode')" @insertNode="type => $emit('insertNode', type)" |
| | | placeholder="请设置办理人" :header-bgc="headerBgc" header-icon="el-icon-s-check"/> |
| | | </template> |
| | | |
| | | <script> |
| | | import Node from './Node.vue' |
| | | |
| | | export default { |
| | | name: "TaskNode", |
| | | props:{ |
| | | config:{ |
| | | type: Object, |
| | | default: () => { |
| | | return {} |
| | | } |
| | | } |
| | | }, |
| | | components: {Node}, |
| | | data() { |
| | | return { |
| | | showError: false, |
| | | errorInfo: '', |
| | | } |
| | | }, |
| | | computed:{ |
| | | headerBgc() { |
| | | if (this.$store.state.diagramMode === 'viewer') { |
| | | return this.config.props.headerBgc |
| | | } else { |
| | | return '#e6b039' |
| | | } |
| | | }, |
| | | content(){ |
| | | const config = this.config.props |
| | | switch (config.assignedType){ |
| | | case "ASSIGN_USER": |
| | | if (config.assignedUser.length > 0){ |
| | | let texts = [] |
| | | config.assignedUser.forEach(org => texts.push(org.name)) |
| | | return String(texts).replaceAll(',', '、') |
| | | }else { |
| | | return '请指定办理人' |
| | | } |
| | | case "SELF": |
| | | return '发起人自己' |
| | | case "SELF_SELECT": |
| | | return config.selfSelect.multiple ? '发起人自选多人':'发起人自选一人' |
| | | case "LEADER_TOP": |
| | | return '多级主管依次办理' |
| | | case "LEADER": |
| | | return config.leader.level > 1 ? '发起人的第 ' + config.leader.level + ' 级主管' : '发起人的直接主管' |
| | | case "FORM_USER": |
| | | if (!config.formUser || config.formUser === ''){ |
| | | return '表单内联系人(未选择)' |
| | | }else { |
| | | let text = this.getFormItemById(config.formUser) |
| | | if (text && text.title){ |
| | | return `表单(${text.title})内的人员` |
| | | }else { |
| | | return '该表单已被移除😥' |
| | | } |
| | | } |
| | | case "ROLE": |
| | | if (config.assignedUser.length > 0){ |
| | | let texts = [] |
| | | config.assignedUser.forEach(org => texts.push(org.name)) |
| | | return String(texts).replaceAll(',', '、') |
| | | }else { |
| | | return '指定角色(未设置)' |
| | | } |
| | | default: return '未知设置项😥' |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | getFormItemById(id){ |
| | | return this.$store.state.design.formItems.find(item => item.id === id) |
| | | }, |
| | | //校验数据配置的合法性 |
| | | validate(err){ |
| | | try { |
| | | this.showError = !this[`validate_${this.config.props.assignedType}`](err) |
| | | |
| | | if (this.config.props.nobody.handler === 'TO_USER' && this.config.props.nobody.assignedUser.length === 0) { |
| | | this.errorInfo = '办理人为空时, 转交给指定人员:【请指定一个具体的人】' |
| | | err.push('办理人为空时, 转交给指定人员:【请指定一个具体的人】') |
| | | this.showError = true |
| | | } |
| | | |
| | | return this.showError |
| | | } catch (e) { |
| | | return true; |
| | | } |
| | | }, |
| | | validate_ASSIGN_USER(err){ |
| | | if(this.config.props.assignedUser.length > 0){ |
| | | return true; |
| | | }else { |
| | | this.errorInfo = '请指定办理人员' |
| | | err.push(`${this.config.name} 未指定办理人员`) |
| | | return false |
| | | } |
| | | }, |
| | | validate_SELF_SELECT(err){ |
| | | return true; |
| | | }, |
| | | validate_LEADER_TOP(err){ |
| | | return true; |
| | | }, |
| | | validate_LEADER(err){ |
| | | return true; |
| | | }, |
| | | validate_ROLE(err){ |
| | | if (this.config.props.role.length <= 0){ |
| | | this.errorInfo = '请指定负责办理的系统角色' |
| | | err.push(`${this.config.name} 未指定办理角色`) |
| | | return false |
| | | } |
| | | return true; |
| | | }, |
| | | validate_SELF(err){ |
| | | return true; |
| | | }, |
| | | validate_FORM_USER(err){ |
| | | if (this.config.props.formUser === ''){ |
| | | this.errorInfo = '请指定表单中的人员组件' |
| | | err.push(`${this.config.name} 办理人为表单中人员,但未指定`) |
| | | return false |
| | | } |
| | | return true; |
| | | }, |
| | | validate_REFUSE(err){ |
| | | return true; |
| | | }, |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <node :title="config.name" :show-error="showError" :content="content" :error-info="errorInfo" |
| | | @selected="$emit('selected')" @delNode="$emit('delNode')" @insertNode="type => $emit('insertNode', type)" |
| | | placeholder="请设置触发器" header-bgc="#47bc82" header-icon="el-icon-set-up"/> |
| | | </template> |
| | | |
| | | <script> |
| | | import Node from './Node.vue' |
| | | |
| | | export default { |
| | | name: "TriggerNode", |
| | | props:{ |
| | | config:{ |
| | | type: Object, |
| | | default: () => { |
| | | return {} |
| | | } |
| | | } |
| | | }, |
| | | components: {Node}, |
| | | data() { |
| | | return { |
| | | showError: false, |
| | | errorInfo: '', |
| | | } |
| | | }, |
| | | computed:{ |
| | | content(){ |
| | | this.config |
| | | } |
| | | }, |
| | | methods: { |
| | | //校验数据配置的合法性 |
| | | validate(err){ |
| | | this.showError = false |
| | | if (this.config.props.type === 'WEBHOOK'){ |
| | | if(this.$isNotEmpty(this.config.props.http.url)){ |
| | | this.showError = false |
| | | }else { |
| | | this.showError = true |
| | | this.errorInfo = '请设置WEBHOOK的URL地址' |
| | | } |
| | | }else if(this.config.props.type === 'EMAIL'){ |
| | | if(!this.$isNotEmpty(this.config.props.email.subject) |
| | | || this.config.props.email.to.length === 0 |
| | | || !this.$isNotEmpty(this.config.props.email.content)){ |
| | | this.showError = true |
| | | this.errorInfo = '请设置邮件发送配置' |
| | | }else { |
| | | this.showError = false |
| | | } |
| | | } |
| | | if (this.showError){ |
| | | err.push(`${this.config.name} 触发动作未设置完善`) |
| | | } |
| | | return !this.showError |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | |
| | | </style> |
| | |
| | | <template> |
| | | <div class="process-view"> |
| | | |
| | | <div class="process-view__tabs" v-loading="loading"> |
| | | <el-tabs type="border-card"> |
| | | <el-tab-pane label="流程图"> |
| | | <process-diagram-viewer /> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { getProcessInstanceInfo,getFlowDetail } from "@/api/design"; |
| | | import {getFlowDetail, getWorkSetpsByBusinessId} from "@/api/design"; |
| | | import ProcessDiagramViewer from "@/views/admin/layout/ProcessDiagramViewer"; |
| | | |
| | | export default { |
| | |
| | | return { |
| | | loading: false, |
| | | processInstanceId: "", |
| | | taskId: "", |
| | | formData: {}, |
| | | currentNode: {}, |
| | | processInfo: "", |
| | | }; |
| | | }, |
| | | |
| | | methods: { |
| | | convertToTreeData(data, parent,index,parentId) { |
| | | const tempJson = data.find(f => |
| | | f.index_no === index |
| | | ) |
| | | console.log("tempJson",tempJson); |
| | | this.$store.state.noTakeList .push(tempJson.id) |
| | | parent.children = { |
| | | "id": tempJson.id, |
| | | "parentId": parentId, |
| | | "name": "审批人", |
| | | "type": "APPROVAL", |
| | | "props": |
| | | { |
| | | "assignedType": "ASSIGN_USER", |
| | | "nobody": { |
| | | "handler": "TO_PASS", |
| | | "assignedUser": [] |
| | | }, |
| | | "refuse": { |
| | | "type": "TO_END", |
| | | "target": "" |
| | | }, |
| | | "assignedUser": [{"id": tempJson.board_id||tempJson.rule_code, "name": tempJson.name,"type":tempJson.board_id!=null?"group":"staff"}], |
| | | "approvalGroup":tempJson.board_id!=null?{"id":tempJson.board_id,"name":tempJson.name}:"", |
| | | "staffGroup":tempJson.board_id!=null?"":{"id":tempJson.rule_code,"name":tempJson.name}, |
| | | } |
| | | } |
| | | if (data.length >index) { |
| | | let getChildren = this.convertToTreeData(data, parent.children, index+1,parent.children.id) |
| | | parent.children=getChildren |
| | | } |
| | | return parent; |
| | | }, |
| | | |
| | | getProcessInfo() { |
| | | this.loading = true; |
| | | let param = {"id": this.processInstanceId} |
| | | getWorkSetpsByBusinessId(param).then(rsp => { |
| | | let workSetps=rsp.data.data |
| | | if(workSetps.length>0){ |
| | | let index=-1; |
| | | let resultProcess; |
| | | let noApprovalArr=workSetps.filter(item=>item.end_time===null); |
| | | ////如果所有节点都没审批 那么就取index_no=1的id为当前运行的节点 |
| | | if(noApprovalArr.length===workSetps.length){ |
| | | resultProcess=workSetps.find(item=>item.index_no===1) |
| | | }else{ |
| | | //否则就取遍历查询 审批节点不为空 index_no最大的 |
| | | workSetps.forEach(item => { |
| | | if (item.index_no > index && item.end_time!==null) { |
| | | index = item.index_no; |
| | | resultProcess = item; |
| | | } |
| | | }) |
| | | } |
| | | this.$store.state.runningList .push(resultProcess.approve_step_id) |
| | | param.id=resultProcess.approve_id |
| | | this.getFlowDetail(param) |
| | | }else{ |
| | | this.$message.error("未查询到审批流数据!") |
| | | } |
| | | }).catch(err => { |
| | | this.$message.error(err) |
| | | }) |
| | | |
| | | |
| | | }, |
| | | getFlowDetail(param){ |
| | | getFlowDetail(param).then(rsp => { |
| | | |
| | | let form = rsp.data.data; |
| | | console.log("getFlowDetail-form", form) |
| | | form.logo = "" |
| | | form.settings = { |
| | | "commiter": [], |
| | | "admin": [], |
| | | "sign": false, |
| | | "notify": { |
| | | "types": [ |
| | | "APP" |
| | | ], |
| | | " title": "消息通知标题" |
| | | } |
| | | } |
| | | form.formItems = [] |
| | | |
| | | form.process =this.convertToTreeData(form.steps, { |
| | | form.process =this.$Utils.convertToTreeData(form.steps, { |
| | | "id": form.id, "parentId": null, |
| | | "type": "ROOT", |
| | | "name": "发起人", |
| | |
| | | "formPerms": [] |
| | | }, |
| | | },1,form.id) |
| | | this.$store.state.runningList .push(form.id) |
| | | |
| | | |
| | | form.name=this.$Utils.decode(form.name); |
| | | form.templateName = form.name |
| | | form.groupId = null; |
| | | form.icon = "{\"icon\":\"el-icon-eleme\",\"background\":\"#1e90ff\"}"; |
| | | form.notify = ""; |
| | | form.remark = "备注说明"; |
| | | form.isStop = false |
| | | form.whoCommit = "[]" |
| | | form.whoEdit = "[]" |
| | | form.whoExport = "[]" |
| | | form.templateId = "Steps-B-Director" |
| | | form.formId = "Steps-B-Director" |
| | | form.processDefinitionId = null |
| | | this.$store.state.design = form; |
| | | console.log("this.$store.state.design",this.$store.state.design) |
| | | console.log("输出转换后的form,",form) |
| | | this.$store.commit('loadForm', form) |
| | | }).catch(err => { |
| | | this.$message.error(err) |
| | | }) .finally(() => { |
| | | this.loading = false; |
| | | }); |
| | | // getProcessInstanceInfo(this.processInstanceId, this.taskId) |
| | | // .then((rsp) => { |
| | | // console.log("流程详情", rsp.data); |
| | | // const form = { ...rsp.data.result.processTemplates }; |
| | | // const currentNode = { ...rsp.data.result?.currentNode }; |
| | | // |
| | | // form.logo = JSON.parse(form.logo); |
| | | // form.settings = JSON.parse(form.settings); |
| | | // form.process = JSON.parse(form.process); |
| | | // this.$store.state.design = form; |
| | | // this.$store.state.endList = rsp.data.result.endList; |
| | | // this.$store.state.runningList = rsp.data.result.runningList; |
| | | // this.$store.state.noTakeList = rsp.data.result.noTakeList; |
| | | // this.$store.state.detailVOList = rsp.data.result.detailVOList; |
| | | // |
| | | // this.currentNode = currentNode; |
| | | // this.form = form; |
| | | // }) |
| | | // .finally(() => { |
| | | // this.loading = false; |
| | | // }); |
| | | }, |
| | | } |
| | | }, |
| | | beforeMount() { |
| | | this.processInstanceId = this.$route.query.processInstanceId; |
| | | this.taskId = this.$route.query.taskId; |
| | | }, |
| | | mounted() { |
| | | this.getProcessInfo(); |
| | |
| | | .process-view { |
| | | padding: 20px; |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | //display: flex; |
| | | //flex-direction: column; |
| | | box-sizing: border-box; |
| | | |
| | | &__header { |