whj 11 月之前
父节点
当前提交
4e6cf1a109

+ 2 - 1
src/router/generator-platform-routers.js

@@ -451,8 +451,9 @@ const constantRouterComponents = {
   'Test': () => import('@/views/test/Test1.vue'),
   // 自定义
   'CustomForm': () => import('@/views/custom/form/CustomForm.vue'),
+  'CustomForm': () => import('@/views/custom/form/CustomForm.vue'),
   // threeJs
-  'FactoryOne': () => import('@/views/threejs/factory/FactoryOne.vue')
+  'Workflow': () => import('@/views/workflow/workflow/Workflow.vue')
 }
 
 // 前端未找到页面路由(固定不用改)

+ 10 - 1
src/views/test/Test1.vue

@@ -267,7 +267,16 @@ export default {
     edit(record) {
       this.$refs.baseModal.base(record)
     },
-    save() {},
+    save() {
+      if (this.name === '') {
+        this.$message.error('请输入流程名称')
+        return
+      }
+      const params = {
+        name: this.name,
+        details: JSON.stringify(this.details),
+      }
+    },
   },
 }
 </script>

+ 64 - 33
src/views/test/modules/BaseForm.vue

@@ -4,38 +4,43 @@
       <a-form-item label="节点名称">
         <a-input v-decorator="['name', {rules: [{required: true, message: '节点名称不能为空'}]}]" />
       </a-form-item>
-      <a-form-item label="所属部门">
-        <a-tree-select v-decorator="['deptId', {rules: [{required: true, message: '审核人不能为空'}]}]" style="width: 100%" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" :replaceFields="replaceFields" :tree-data="treeData" placeholder="请选择" tree-default-expand-all @change="handleDept">
-        </a-tree-select>
-      </a-form-item>
-      <a-form-item label="审核人">
-        <a-select v-decorator="['verifier', {rules: [{required: true, message: '审核人不能为空'}]}]" placeholder="请选择">
-          <a-select-option v-for="{realName, userId} in verifierList" :key="userId" :label="realName" :value="userId">{{ realName }}
-          </a-select-option>
-        </a-select>
-      </a-form-item>
-      <a-form-item label="配置类型" v-show="false">
-        <a-input v-decorator="['reflect', {initialValue:'reflect'}]">
-        </a-input>
-      </a-form-item>
-      <a-form-item label="条件类">
-        <a-select v-decorator="['titleCode', {rules: [{required: true, message: '条件类不能为空'}]}]" placeholder="请选择" @change="handleTitleCode">
-          <a-select-option v-for="{title, titleCode} in customCodeList" :key="titleCode" :label="title" :value="titleCode">{{ title }}
-          </a-select-option>
-        </a-select>
-      </a-form-item>
-      <a-form-item label="条件名称">
-        <a-select v-decorator="['titleColumnCode', {rules: [{required: true, message: '条件名称不能为空'}]}]" placeholder="请选择" @change="handleTitleColumnCode">
-          <a-select-option v-for="{titleColumnName, titleColumnCode} in customClassNameList" :key="titleColumnCode" :label="titleColumnName" :value="titleColumnCode">{{ titleColumnName }}
-          </a-select-option>
-        </a-select>
-      </a-form-item>
-      <a-form-item label="处理类">
-        <a-select v-decorator="['handleNameId', {rules: [{required: true, message: '条件类不能为空'}]}]" placeholder="请选择">
-          <a-select-option v-for="{handleName, id} in handleNameList" :key="id" :label="handleName" :value="id">{{ handleName }}
-          </a-select-option>
-        </a-select>
-      </a-form-item>
+      <template v-if="record.type===3">
+        <a-form-item label="所属部门">
+          <a-tree-select v-decorator="['deptId', {rules: [{required: true, message: '审核人不能为空'}]}]" style="width: 100%" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" :replaceFields="replaceFields" :tree-data="treeData" placeholder="请选择" tree-default-expand-all @change="handleDept">
+          </a-tree-select>
+        </a-form-item>
+        <a-form-item label="审核人">
+          <a-select v-decorator="['verifier', {rules: [{required: true, message: '审核人不能为空'}]}]" placeholder="请选择">
+            <a-select-option v-for="{realName, userId} in verifierList" :key="userId" :label="realName" :value="userId">{{ realName }}
+            </a-select-option>
+          </a-select>
+        </a-form-item>
+      </template>
+      <template v-if="record.type===2">
+        <a-form-item label="配置类型" v-show="false">
+          <a-input type="hidden" v-decorator="['reflect', {initialValue:'reflect'}]">
+          </a-input>
+        </a-form-item>
+        <a-form-item label="条件类">
+          <a-select v-decorator="['titleCode', {rules: [{required: true, message: '条件类不能为空'}]}]" placeholder="请选择" @change="handleTitleCode">
+            <a-select-option v-for="{title, titleCode} in customCodeList" :key="titleCode" :label="title" :value="titleCode">{{ title }}
+            </a-select-option>
+          </a-select>
+        </a-form-item>
+        <a-form-item label="条件名称">
+          <a-select v-decorator="['titleColumnCode', {rules: [{required: true, message: '条件名称不能为空'}]}]" placeholder="请选择" @change="handleTitleColumnCode">
+            <a-select-option v-for="{titleColumnName, titleColumnCode} in customClassNameList" :key="titleColumnCode" :label="titleColumnName" :value="titleColumnCode">{{ titleColumnName }}
+            </a-select-option>
+          </a-select>
+        </a-form-item>
+        <a-form-item label="处理类">
+          <a-select v-decorator="['handleNameId', {rules: [{required: true, message: '条件类不能为空'}]}]" placeholder="请选择">
+            <a-select-option v-for="{handleName, id} in handleNameList" :key="id" :label="handleName" :value="id">{{ handleName }}
+            </a-select-option>
+          </a-select>
+        </a-form-item>
+      </template>
+
       <!-- <a-form-item label="描述">
         <a-input v-decorator="['seatNumber']" />
       </a-form-item> -->
@@ -85,10 +90,20 @@ export default {
       const {
         form: { setFieldsValue },
       } = this
+
       this.$nextTick(() => {
         setFieldsValue(
           Object.assign(
-            pick(record, ['name', 'verifier', 'reflect', 'titleCode', 'titleColumnCode', 'handleNameId', 'id'])
+            pick(record, [
+              'name',
+              'verifier',
+              'deptId',
+              'reflect',
+              'titleCode',
+              'titleColumnCode',
+              'handleNameId',
+              'id',
+            ])
           )
         )
       })
@@ -124,6 +139,21 @@ export default {
         titleColumnCode: val,
       }).then((res) => {
         this.handleNameList = res.data
+        if (!this.handleNameList.length) {
+          this.$message.warning('该条件名称下没有处理类')
+          return
+        }
+        const {
+          form: { setFieldsValue },
+        } = this
+
+        this.$nextTick(() => {
+          setFieldsValue(
+            Object.assign({
+              handleNameId: res.data[0].id,
+            })
+          )
+        })
       })
     },
 
@@ -144,6 +174,7 @@ export default {
     },
     onClose() {
       this.visible = false
+      this.form.resetFields()
     },
   },
 }

+ 7 - 4
src/views/test/modules/Node.vue

@@ -5,28 +5,31 @@
       <div class="top"></div>
       <div class="bottom"></div>
       <div class="title">
-        {{ detail.name }}
+        发起人
       </div>
       <div class="card-content">
-
+        {{ detail.name }}
       </div>
     </div>
     <div v-else-if="detail.type===2" class="term">
       <div class="top"></div>
       <div class="bottom"></div>
       <div class="title">
-        {{ detail.name }}
+        条件分支
       </div>
       <div class="card-content">
+        {{ detail.name }}
+
       </div>
     </div>
     <div v-else-if="detail.type===3" class="verify">
       <div class="top"></div>
       <div class="bottom"></div>
       <div class="title">
-        {{ detail.name }}
+        审核人
       </div>
       <div class="card-content">
+        {{ detail.name }}
       </div>
 
     </div>

+ 50 - 53
src/views/workflow/workflow/Workflow.vue

@@ -1,62 +1,59 @@
 <template>
-  <a-card :bordered="false">
-    <div v-show="visible">
-      <div class="table-page-search-wrapper" @keyup.enter="handleEnter">
-        <a-form layout="inline">
-          <a-row :gutter="48" v-show="advanced">
-            <a-col :md="6" :sm="24">
-              <a-form-item label="关键字">
-                <a-input v-model="queryParam.keyword" placeholder="请输入名称/类型名称" />
-              </a-form-item>
-            </a-col>
-          </a-row>
-          <a-row :gutter="48">
-            <a-col :md="24 || 24" :sm="24" style="text-align: right">
-              <span class="table-page-search-submitButtons">
-                <a-button type="primary" @click="$refs.table.refresh(true)">查询</a-button>
-                <a-button style="margin-left: 8px" @click="resetSearchForm">重置</a-button>
-                <a @click="()=>{ this.advanced = !this.advanced}" style="margin-left: 8px">
-                  {{ advanced ? '收起' : '展开' }}
-                  <a-icon :type="advanced ? 'up' : 'down'" />
-                </a>
-              </span>
+  <div>
+    <a-card :bordered="false" v-show="visible">
+      <div>
+        <div class="table-page-search-wrapper" @keyup.enter="handleEnter">
+          <a-form layout="inline">
+            <a-row :gutter="48">
+              <a-col :md="6" :sm="24">
+                <a-form-item label="关键字">
+                  <a-input v-model="queryParam.keyword" placeholder="请输入名称/类型名称" />
+                </a-form-item>
+              </a-col>
+              <a-col :md="6 || 24" :sm="24">
+                <span class="table-page-search-submitButtons">
+                  <a-button type="primary" @click="$refs.table.refresh(true)">查询</a-button>
+                  <a-button style="margin-left: 8px" @click="resetSearchForm">重置</a-button>
+                </span>
+              </a-col>
+            </a-row>
+          </a-form>
+        </div>
+
+        <div class="table-operator" style="margin-bottom: 8px;">
+          <a-row>
+            <a-col :md="16">
+              <a-button type="primary" icon="plus" @click="handleAdd()">新增</a-button>
+              <a-button style="margin-left: 8px" type="primary" icon="download" @click="doExport">导出</a-button>
+              <a-dropdown v-action:edit v-if="selectedRowKeys.length > 0">
+                <a-menu slot="overlay">
+                  <a-popconfirm title="是否要删除所选数据?" @confirm="batchDelete()">
+                    <a-menu-item key="1"><a-icon type="delete" /><a>删除</a></a-menu-item>
+                  </a-popconfirm>
+                </a-menu>
+                <a-button style="margin-left: 8px">
+                  批量操作 <a-icon type="down" />
+                </a-button>
+              </a-dropdown>
             </a-col>
           </a-row>
-        </a-form>
-      </div>
+        </div>
 
-      <div class="table-operator" style="margin-bottom: 8px;">
-        <a-row>
-          <a-col :md="16">
-            <a-button v-if="$auth('workflow-workflow-add')" type="primary" icon="plus" @click="handleAdd()">新增</a-button>
-            <a-button style="margin-left: 8px" v-if="$auth('workflow-workflow-export')" type="primary" icon="download" @click="doExport">导出</a-button>
-            <a-dropdown v-action:edit v-if="selectedRowKeys.length > 0 && $auth('workflow-workflow-del')">
-              <a-menu slot="overlay">
-                <a-popconfirm title="是否要删除所选数据?" @confirm="batchDelete()">
-                  <a-menu-item key="1"><a-icon type="delete" /><a>删除</a></a-menu-item>
-                </a-popconfirm>
-              </a-menu>
-              <a-button style="margin-left: 8px">
-                批量操作 <a-icon type="down" />
-              </a-button>
-            </a-dropdown>
-          </a-col>
-        </a-row>
+        <s-table ref="table" size="default" rowKey="id" :columns="columns" :data="loadData" :alert="options.alert" :rowSelection="options.rowSelection" showPagination="auto">
+          <span slot="action" slot-scope="record">
+            <template>
+              <a @click="handleView(record)">查看</a>
+              <operation-button @click="handleEdit(record)">修改</operation-button>
+              <operation-button v-if="$auth('workflow-workflow-del')" :type="2" title="是否要删除该条数据?" @confirm="batchDelete(record.id)">删除</operation-button>
+            </template>
+          </span>
+        </s-table>
       </div>
-
-      <s-table ref="table" size="default" rowKey="id" :columns="columns" :data="loadData" :alert="options.alert" :rowSelection="options.rowSelection" showPagination="auto">
-        <span slot="action" slot-scope="record">
-          <template>
-            <a @click="handleView(record)">查看</a>
-            <operation-button v-if="$auth('workflow-workflow-edit')" @click="handleEdit(record)">修改</operation-button>
-            <operation-button v-if="$auth('workflow-workflow-del')" :type="2" title="是否要删除该条数据?" @confirm="batchDelete(record.id)">删除</operation-button>
-          </template>
-        </span>
-      </s-table>
-    </div>
-    <base-form ref="baseModal" @ok="handleOk" />
+    </a-card>
     <detail ref="detailModal" @ok="handleOk" />
-  </a-card>
+    <base-form ref="baseModal" @ok="handleOk" />
+
+  </div>
 </template>
 
 <script>

+ 368 - 132
src/views/workflow/workflow/modules/BaseForm.vue

@@ -1,140 +1,376 @@
 <template>
-    <a-card :bordered="false" v-show="visible" class="card" :title="modalTitle">
-        <a-row :gutter="48" slot="extra">
-            <a-col :md="48" :sm="48">
-              <span class="table-page-search-submitButtons" style="float: right">
-                <a-button :loading="confirmLoading" type="primary" @click="save()">保存</a-button>
-                <a-button style="margin-left: 8px" type="default" @click="handleCancel()">返回</a-button>
-              </span>
-            </a-col>
-        </a-row>
-        <a-form :form="form">
-
-            <a-form-item v-show="false">
-                <a-input v-decorator="['id']" type="hidden"/>
-                                                                                                                                                                                                                                                                                                                                                            </a-form-item>
-
-            <row-list :col="2">
-                                                                                                                                                                                                                                                                                                                        <row-item>
-
-                            <a-form-item
-                                    label="流程名称"
-                                    :labelCol="BaseTool.Constant.labelCol"
-                                    :wrapperCol="BaseTool.Constant.wrapperCol"
-                            >
-                                                                    <a-input
-                                            v-decorator="['name', {rules: [{required: true, message: '流程名称不能为空'}]}]"/>
-                                                            </a-form-item>
-                        </row-item>
-                                                                                <row-item>
-
-                            <a-form-item
-                                    label="流程总节点数"
-                                    :labelCol="BaseTool.Constant.labelCol"
-                                    :wrapperCol="BaseTool.Constant.wrapperCol"
-                            >
-                                                                    <a-input-number
-                                            style="width: 100%"
-                                            :min="0"
-                                            :formatter="BaseTool.Amount.formatter"
-                                            :parser="BaseTool.Amount.parser"
-                                            v-decorator="['totalNode', {rules: [{required: true, message: '流程总节点数不能为空'}]}]"/>
-                                                            </a-form-item>
-                        </row-item>
-                                                                                <row-item>
-
-                            <a-form-item
-                                    label="层级节点数"
-                                    :labelCol="BaseTool.Constant.labelCol"
-                                    :wrapperCol="BaseTool.Constant.wrapperCol"
-                            >
-                                                                    <a-input-number
-                                            style="width: 100%"
-                                            :min="0"
-                                            :formatter="BaseTool.Amount.formatter"
-                                            :parser="BaseTool.Amount.parser"
-                                            v-decorator="['levelNode', {rules: [{required: true, message: '层级节点数不能为空'}]}]"/>
-                                                            </a-form-item>
-                        </row-item>
-                                                </row-list>
-        </a-form>
-                                                                                                                                                                                                                                                                                                                                                                                                                        </a-card>
+  <div v-show="visible">
+    <div class="title">
+      <h3>{{modalTitle}}</h3>
+      <a-space>
+        <div>
+          流程名称:<a-input style="width:200px" v-model="name" />
+        </div>
+        <a-button type="primary" @click="save">保存</a-button>
+        <a-button @click="handleBack">返回</a-button>
+      </a-space>
+    </div>
+    <div class="main">
+      <div class="scale">
+        <a-space>
+          <a-button shape="circle" icon="minus" @click="minus" />
+          {{ scale }}%
+          <a-button shape="circle" icon="plus" @click="plus" />
+        </a-space>
+      </div>
+      <div ref="container" class="container" :style="{transform: `scale(${scale / 100})`}">
+        <Node v-for="(item, index) in details" :key="index" :detail="item" :ref="item.id" @add="add" @edit="edit" @delete="handleDelete" />
+      </div>
+      <BaseForm ref="baseModal" />
+    </div>
+  </div>
 </template>
 
 <script>
-    import pick from 'lodash.pick'
-    import {addWorkflow, updateWorkflow } from '@/api/workflow/workflow'
-                                                                                                                                                                                                                                                                                                                                                                                                                        export default {
-        name: 'BaseWorkflow',
-        data() {
-            return {
-                confirmLoading: false,
-                modalTitle: null,
-                form: this.$form.createForm(this),
-                visible: false,
-            // 下拉框map
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        }
+// import jsPlumb from 'jsplumb'
+import Node from './modules/Node.vue'
+import { newInstance, EVENT_CONNECTION, EVENT_CONNECTION_DBL_CLICK, EVENT_DRAG_STOP } from '@jsplumb/browser-ui'
+import BaseForm from './modules/BaseForm.vue'
+import { addWorkflow, updateWorkflow } from '@/api/workflow/workflow'
+export default {
+  components: {
+    Node,
+    BaseForm,
+  },
+  data() {
+    return {
+      visible: false,
+      jsPlumb: null,
+      instance: null,
+      scale: 100,
+      name: '',
+      modalTitle: '',
+      record: {},
+      details: [
+        {
+          name: '发起人',
+          id: '1',
+          type: 1,
+          y: 100,
+          x: 500,
+          children: [],
         },
-        props: {},
-        created() {
-            // 下拉框map
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        },
-        methods: {
-            base(record) {
-                this.visible = true
-                // 如果是空标识添加
-                if (this.BaseTool.Object.isBlank(record)) {
-                    this.modalTitle = '添加'
-                    return
-                }
-                this.modalTitle = '编辑'
-                const {form: {setFieldsValue}} = this
-                // 日期处理
-                                this.$nextTick(() => {
-                    setFieldsValue(Object.assign(pick(record, [
-                                                                                    'id',
-                                                                                                                                                                                                                                                                                                                                                                                                                                        'name',
-                                                                                                                'totalNode',
-                                                                                                                'levelNode',
-                                                    ])))
-                })
-            },
-            save() {
-                const {form: {validateFieldsAndScroll}} = this
-                this.confirmLoading = true
-                validateFieldsAndScroll((errors, values) => {
-                    if (errors) {
-                        this.confirmLoading = false
-                        return
-                    }
-                    // 日期处理
-                                        if (this.BaseTool.String.isBlank(values.id)) {
-                        addWorkflow(values)
-                                .then(() => {
-                                    this.handleCancel(values)
-                                }).catch(() => {
-                            this.confirmLoading = false
-                        })
-                    } else {
-                        updateWorkflow(values)
-                                .then(() => {
-                                    this.handleCancel(values)
-                                }).catch(() => {
-                            this.confirmLoading = false
-                        })
-                    }
-                })
+        // {
+        //   y: 350,
+        //   x: 500,
+        //   id: '2',
+        //   type: 2,
+        //   name: 'node2',
+        //   children: ['3'],
+        // },
+        // {
+        //   y: 600,
+        //   x: 500,
+        //   id: '3',
+        //   type: 3,
+        //   name: 'node3',
+        //   children: [],
+        // },
+      ],
+    }
+  },
+  mounted() {},
+  created() {},
+  methods: {
+    base(record) {
+      this.visible = true
+      // 如果是空标识添加
+      if (this.BaseTool.Object.isBlank(record)) {
+        this.modalTitle = '添加'
+        this.init()
+        return
+      }
+      this.record = record
+      this.name = record.name
+      this.modalTitle = '编辑'
+      this.details = JSON.parse(record.json)
+      this.init()
+    },
+    init() {
+      const that = this
+      // 初始化节点
+      this.instance = newInstance({
+        container: this.$refs.container,
+        dragOptions: {
+          containmentPadding: 10,
+          grid: { w: 20, h: 20 },
+        },
+      })
+      this.instance.importDefaults({
+        anchor: 'Continuous',
+        connectionsDetachable: false,
+        // 连接器类型,这里设置为Flowchart
+        connector: {
+          type: 'Flowchart',
+        },
+        paintStyle: { stroke: '#666', strokeWidth: 1 },
+        hoverPaintStyle: { stroke: '#1890ff', strokeWidth: 2 },
+        connectionOverlays: [
+          {
+            type: 'Arrow',
+            options: {
+              width: 13,
+              length: 13,
+              location: 1,
             },
-            handleCancel(values) {
-                this.visible = false
-                this.confirmLoading = false
-                this.form.resetFields()
-                if (this.BaseTool.Object.isNotBlank(values)) {
-                    this.$emit('ok', values)
-                } else {
-                    this.$emit('ok')
-                }
+          },
+          // {
+          //   type: 'Custom',
+          //   options: {
+          //     create: (component) => {
+          //       const d = document.createElement('button')
+          //       d.innerHTML = '+'
+          //       d.className = 'plus_btn'
+          //       console.log(d)
+          //       return d
+          //     },
+          //     location: [5, 0],
+          //     events: {
+          //       tap: (e, o) => {
+          //         console.log('tap', e, o)
+          //       }
+          //     }
+          //   }
+          // }
+        ],
+        // 添加两个标签和箭头
+      })
+      this.instance.addSourceSelector('.bottom')
+      this.instance.addTargetSelector('.top')
+      this.details.forEach((item) => {
+        if (item.children.length) {
+          item.children.forEach((children) => {
+            that.instance.connect({
+              // 获取节点1和节点2的引用
+              source: this.$refs[item.id][0].$el,
+              target: this.$refs[children][0].$el,
+              // 连接方式,这里设置为连续
+              // paintStyle: { stroke: children.label == '同意' ? '#345' : 'red', strokeWidth: 3 },
+              anchor: 'AutoDefault',
+              // 连接器类型,这里设置为Flowchart
+              connector: 'Flowchart',
+              // 添加两个标签和箭头
+            })
+          })
+        } else {
+          // instance.addEndpoint(this.$refs[item.name][0].$el, { target: false, source: false })
+        }
+      })
+      // this.$refs.node.forEach((item) => {
+      //   console.log(item)
+      // })
+
+      // 连接三个端点
+      // instance.connect({
+      //   // 获取节点1和节点2的引用
+      //   source: this.$refs.node1,
+      //   target: this.$refs.node2,
+      //   // 连接方式,这里设置为连续
+      //   anchor: 'AutoDefault',
+      //   // 连接器类型,这里设置为Flowchart
+      //   connector: 'Flowchart',
+      //   // 添加两个标签和箭头
+      //   overlays: [
+      //     { type: 'Label', options: { label: 'Connection 1', location: 0.5 } },
+      //     { type: 'Arrow', options: { location: 1 } },
+      //   ],
+      // })
+      // instance.connect({
+      //   source: this.$refs.node2,
+      //   target: this.$refs.node3,
+      //   connector: 'Flowchart',
+      //   anchor: 'AutoDefault',
+      //   overlays: [
+      //     { type: 'Label', options: { label: 'Connection 2', location: 0.5 } },
+      //     { type: 'Arrow', options: { location: 1 } },
+      //   ],
+      // })
+      //拖拽
+      this.instance.bind(EVENT_DRAG_STOP, (val) => {
+        console.log(val.el.__vue__)
+        console.log(3)
+        val.el.__vue__.setPosition(val.elements[0].pos)
+      })
+      // 建立链接
+      this.instance.bind(EVENT_CONNECTION, (val) => {
+        console.log(val)
+        console.log(2)
+      })
+      // 删除连接
+      this.instance.bind(EVENT_CONNECTION_DBL_CLICK, (conn) => {
+        this.$confirm({
+          title: '确定删除所点击的链接吗?',
+          onOk() {
+            that.instance.deleteConnection(conn)
+          },
+        })
+      })
+      this.$forceUpdate()
+    },
+    minus() {
+      if (this.scale > 50) {
+        this.scale -= 10
+      }
+      this.instance.setZoom(this.scale / 100)
+    },
+    plus() {
+      if (this.scale < 150) {
+        this.scale += 10
+      }
+      this.instance.setZoom(this.scale / 100)
+    },
+    add(record, type) {
+      const newVal = {
+        name: type === 2 ? '条件分支' : '审核人',
+        id: +new Date(),
+        verifier: '',
+        reflect: '',
+        titleCode: '',
+        titleColumnCode: '',
+        handleNameId: '',
+      }
+      if (record.children.length > 0) {
+        const children = this.details
+          .filter((detail) => {
+            return record.children.includes(detail.id)
+          })
+          .reduce((pre, item) => {
+            if (item.x > pre.x) {
+              pre = item
             }
-                                                                                                                                                                                                                                                                                                            }
-    }
+            return pre
+          })
+        record.children.push(newVal.id)
+        this.details.push({
+          x: children.x + 240,
+          y: children.y,
+          type,
+          children: [],
+          ...newVal,
+        })
+      } else {
+        record.children.push(newVal.id)
+        this.details.push({
+          x: record.x,
+          y: record.y + 250,
+          type,
+          children: [],
+          ...newVal,
+        })
+      }
+      this.$nextTick(() => {
+        this.instance.connect({
+          // 获取节点1和节点2的引用
+          source: this.$refs[record.id][0].$el,
+          target: this.$refs[newVal.id][0].$el,
+          // 连接方式,这里设置为连续
+          // paintStyle: { stroke: children.label == '同意' ? '#345' : 'red', strokeWidth: 3 },
+          anchor: 'AutoDefault',
+          // 连接器类型,这里设置为Flowchart
+          connector: 'Flowchart',
+          // 添加两个标签和箭头
+        })
+      })
+      // this.details.push()
+    },
+    //删除节点
+    handleDelete(record) {
+      this.instance.unmanage(this.$refs[record.id][0].$el, true)
+      this.details = this.details.filter((item) => {
+        return item.id !== record.id
+      })
+    },
+    edit(record) {
+      this.$refs.baseModal.base(record)
+    },
+    save() {
+      if (this.name === '') {
+        this.$message.error('请输入流程名称')
+        return
+      }
+      const params = {
+        name: this.name,
+        id: this.record.id,
+        json: JSON.stringify(this.details),
+      }
+      if (params.id) {
+        updateWorkflow(params).then((res) => {
+          this.$message.success('修改成功')
+          this.handleBack()
+        })
+      } else {
+        addWorkflow(params).then((res) => {
+          this.$message.success('添加成功')
+          this.handleBack()
+        })
+      }
+    },
+    handleBack() {
+      this.visible = false
+      this.$emit('ok')
+    },
+  },
+}
 </script>
+
+<style lang="less" scoped>
+.container {
+  position: relative;
+  flex: 1;
+  width: 100%;
+  height: 100%;
+  transform-origin: 0 0;
+  // transform: scale(0.5);
+}
+.title {
+  width: 100%;
+  padding: 20px;
+  background: #fff;
+  border-radius: 5px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  h3 {
+    padding: 0;
+    margin: 0;
+  }
+}
+/deep/ .plus_btn {
+  padding: 0;
+  margin: 0;
+  background: #1890ff !important;
+  color: #fff !important;
+  border-radius: 50%;
+  width: 40px;
+  height: 40px;
+  border: #1890ff 1px solid;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  font-size: 24px;
+  cursor: pointer;
+}
+/deep/.jtk-overlay {
+  color: #1890ff;
+  font-size: 18px;
+  z-index: 9;
+}
+.main {
+  position: relative;
+  display: flex;
+  flex-direction: column;
+  min-height: calc(100vh - 100px);
+  width: 100%;
+}
+.scale {
+  position: absolute;
+  bottom: 20px;
+  right: 30px;
+  z-index: 9999;
+}
+</style>

+ 184 - 0
src/views/workflow/workflow/modules/modules/BaseForm.vue

@@ -0,0 +1,184 @@
+<template>
+  <a-drawer title="编辑" placement="right" :closable="false" :visible="visible" @close="onClose">
+    <a-form :form="form">
+      <a-form-item label="节点名称">
+        <a-input v-decorator="['name', {rules: [{required: true, message: '节点名称不能为空'}]}]" />
+      </a-form-item>
+      <template v-if="record.type===3">
+        <a-form-item label="所属部门">
+          <a-tree-select v-decorator="['deptId', {rules: [{required: true, message: '审核人不能为空'}]}]" style="width: 100%" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" :replaceFields="replaceFields" :tree-data="treeData" placeholder="请选择" tree-default-expand-all @change="handleDept">
+          </a-tree-select>
+        </a-form-item>
+        <a-form-item label="审核人">
+          <a-select v-decorator="['verifier', {rules: [{required: true, message: '审核人不能为空'}]}]" placeholder="请选择">
+            <a-select-option v-for="{realName, userId} in verifierList" :key="userId" :label="realName" :value="userId">{{ realName }}
+            </a-select-option>
+          </a-select>
+        </a-form-item>
+      </template>
+      <template v-if="record.type===2">
+        <a-form-item label="配置类型" v-show="false">
+          <a-input type="hidden" v-decorator="['reflect', {initialValue:'reflect'}]">
+          </a-input>
+        </a-form-item>
+        <a-form-item label="条件类">
+          <a-select v-decorator="['titleCode', {rules: [{required: true, message: '条件类不能为空'}]}]" placeholder="请选择" @change="handleTitleCode">
+            <a-select-option v-for="{title, titleCode} in customCodeList" :key="titleCode" :label="title" :value="titleCode">{{ title }}
+            </a-select-option>
+          </a-select>
+        </a-form-item>
+        <a-form-item label="条件名称">
+          <a-select v-decorator="['titleColumnCode', {rules: [{required: true, message: '条件名称不能为空'}]}]" placeholder="请选择" @change="handleTitleColumnCode">
+            <a-select-option v-for="{titleColumnName, titleColumnCode} in customClassNameList" :key="titleColumnCode" :label="titleColumnName" :value="titleColumnCode">{{ titleColumnName }}
+            </a-select-option>
+          </a-select>
+        </a-form-item>
+        <a-form-item label="处理类">
+          <a-select v-decorator="['handleNameId', {rules: [{required: true, message: '条件类不能为空'}]}]" placeholder="请选择">
+            <a-select-option v-for="{handleName, id} in handleNameList" :key="id" :label="handleName" :value="id">{{ handleName }}
+            </a-select-option>
+          </a-select>
+        </a-form-item>
+      </template>
+
+      <!-- <a-form-item label="描述">
+        <a-input v-decorator="['seatNumber']" />
+      </a-form-item> -->
+
+    </a-form>
+    <div class="btn">
+      <a-button :loading="confirmLoading" type="primary" @click="save">保存</a-button>
+    </div>
+  </a-drawer>
+</template>
+
+<script>
+import pick from 'lodash.pick'
+import { getDeptTree } from '@/api/upms/dept'
+import { queryUserByDept } from '@/api/upms/user'
+import { getCustomClassNameList, getCustomCodeList } from '@/api/custom/className'
+export default {
+  data() {
+    return {
+      visible: false,
+      confirmLoading: false,
+      form: this.$form.createForm(this),
+      record: {},
+      replaceFields: {
+        key: 'id',
+      },
+      verifierList: [],
+      treeData: [],
+      classNameCodeMap: {},
+      customCodeList: [],
+      customClassNameList: [],
+      handleNameList: [],
+    }
+  },
+  created() {
+    getDeptTree().then((res) => {
+      this.treeData = this.setTree(res.data)
+    })
+    getCustomCodeList({ code: 'reflect' }).then((res) => {
+      this.customCodeList = res.data
+    })
+  },
+  methods: {
+    base(record) {
+      this.visible = true
+      this.record = record
+      const {
+        form: { setFieldsValue },
+      } = this
+
+      this.$nextTick(() => {
+        setFieldsValue(
+          Object.assign(
+            pick(record, ['name', 'verifier', 'reflect', 'titleCode', 'titleColumnCode', 'handleNameId', 'id'])
+          )
+        )
+      })
+    },
+    setTree(list) {
+      return list.map((item) => {
+        return {
+          title: item.title,
+          key: item.id,
+          value: item.id,
+          children: item.children ? this.setTree(item.children) : [],
+        }
+      })
+    },
+    handleDept(deptId) {
+      queryUserByDept({ deptId }).then((res) => {
+        this.verifierList = res.data
+      })
+    },
+    handleTitleCode(val) {
+      this._titleCode = val
+      getCustomClassNameList({
+        code: 'reflect',
+        titleCode: val,
+      }).then((res) => {
+        this.customClassNameList = res.data
+      })
+    },
+    handleTitleColumnCode(val) {
+      getCustomClassNameList({
+        code: 'reflect',
+        titleCode: this._titleCode,
+        titleColumnCode: val,
+      }).then((res) => {
+        this.handleNameList = res.data
+        if (!this.handleNameList.length) {
+          this.$message.warning('该条件名称下没有处理类')
+          return
+        }
+        const {
+          form: { setFieldsValue },
+        } = this
+
+        this.$nextTick(() => {
+          setFieldsValue(
+            Object.assign({
+              handleNameId: res.data[0].id,
+            })
+          )
+        })
+      })
+    },
+
+    save() {
+      const {
+        form: { validateFieldsAndScroll },
+      } = this
+      this.confirmLoading = true
+      validateFieldsAndScroll((errors, values) => {
+        if (errors) {
+          this.confirmLoading = false
+          return
+        }
+        this.record.name = values.name
+        this.record.verifier = values.verifier
+        this.record.reflect = values.reflect
+        this.record.titleCode = values.titleCode
+        this.record.titleColumnCode = values.titleColumnCode
+        this.record.handleNameId = values.handleNameId
+        this.record.deptId = values.deptId
+        this.confirmLoading = false
+        this.onClose()
+      })
+    },
+    onClose() {
+      this.visible = false
+      this.form.resetFields()
+    },
+  },
+}
+</script>
+
+<style lang="less" scoped>
+.btn {
+  text-align: center;
+}
+</style>

+ 189 - 0
src/views/workflow/workflow/modules/modules/Node.vue

@@ -0,0 +1,189 @@
+<template>
+  <div class="node" :style="{left:detail.x+'px',top:detail.y+'px'}" @mouseover="show = true" @mouseout="show=false">
+
+    <div v-if="detail.type===1" class="start">
+      <div class="top"></div>
+      <div class="bottom"></div>
+      <div class="title">
+        发起人
+      </div>
+      <div class="card-content">
+        {{ detail.name }}
+      </div>
+    </div>
+    <div v-else-if="detail.type===2" class="term">
+      <div class="top"></div>
+      <div class="bottom"></div>
+      <div class="title">
+        条件分支
+      </div>
+      <div class="card-content">
+        {{ detail.name }}
+
+      </div>
+    </div>
+    <div v-else-if="detail.type===3" class="verify">
+      <div class="top"></div>
+      <div class="bottom"></div>
+      <div class="title">
+        审核人
+      </div>
+      <div class="card-content">
+        {{ detail.name }}
+      </div>
+
+    </div>
+    <div class="action">
+      <a-row type="flex" justify="space-around" align="middle">
+
+        <a-col :span="6">
+          <div class="btn">
+            <a-tooltip>
+              <template slot="title">
+                条件分支
+              </template>
+              <a-button size="small" shape="circle" @click="add(2)" icon="apartment" />
+            </a-tooltip>
+          </div>
+        </a-col>
+        <a-col :span="6">
+          <div class="btn">
+            <a-tooltip>
+              <template slot="title">
+                审核人
+              </template>
+              <a-button size="small" shape="circle" icon="audit" @click="add(3)" type="primary" class="audit" />
+            </a-tooltip>
+          </div>
+        </a-col>
+        <a-col :span="6">
+          <div class="btn">
+            <a-tooltip>
+              <template slot="title">
+                编辑
+              </template>
+              <a-button size="small" @click="edit()" shape="circle" icon="edit" type="primary" />
+            </a-tooltip>
+          </div>
+        </a-col>
+        <a-col :span="6">
+          <div class="btn">
+            <a-tooltip>
+              <template slot="title">
+                删除
+              </template>
+              <a-popconfirm title="确定删除该节点?" ok-text="是" cancel-text="否" @confirm="handleDelete">
+                <a-button size="small" shape="circle" icon="delete" type="danger" />
+              </a-popconfirm>
+            </a-tooltip>
+          </div>
+        </a-col>
+      </a-row>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    detail: {
+      type: Object,
+      default: () => {},
+    },
+  },
+  data() {
+    return {
+      show: false,
+    }
+  },
+  methods: {
+    setPosition(position) {
+      console.log(position)
+      this.detail.x = position.x
+      this.detail.y = position.y
+    },
+    add(type) {
+      this.$emit('add', this.detail, type)
+    },
+    edit(type) {
+      this.$emit('edit', this.detail)
+    },
+    handleDelete() {
+      this.$emit('delete', this.detail)
+    },
+  },
+}
+</script>
+
+<style lang="less" scoped>
+.node {
+  width: 200px;
+  position: absolute;
+  cursor: pointer;
+  border-radius: 0 0 10px 10px;
+  .top {
+    position: absolute;
+    top: 0;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    background: #456;
+    border-radius: 50%;
+    width: 10px;
+    height: 10px;
+    z-index: 9;
+  }
+  .bottom {
+    position: absolute;
+    bottom: 0;
+    background: #456;
+    border-radius: 50%;
+    left: 50%;
+    transform: translate(-50%, 50%);
+    width: 10px;
+    z-index: 9;
+    height: 10px;
+  }
+  .title {
+    padding: 2px 5px;
+    overflow: hidden;
+    background: #9e9ebc;
+    color: #fff;
+    border-radius: 10px 10px 0 0;
+  }
+  .card-content {
+    background: #fff;
+    min-height: 50px;
+  }
+  .term {
+    .title {
+      color: #0ab74c;
+      border-bottom: 1px solid #ccc;
+      background: #fff;
+    }
+  }
+  .verify {
+    .title {
+      background: #e99e09;
+    }
+  }
+}
+.action {
+  border-top: 1px solid #ccc;
+  font-size: 12px;
+  border-radius: 0 0 10px 10px;
+  background: #fff;
+  .btn {
+    padding: 5px;
+    text-align: center;
+  }
+}
+
+.audit {
+  background: #e99e09;
+  border: #e99e09 solid 1px;
+  &:hover {
+    background: #f7b737;
+    border: #f7b737 solid 1px;
+  }
+}
+</style>