|
@@ -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>
|