123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887 |
- <template lang="">
- <div class="vueFlow">
- <div id="container"></div>
- <div id="stencil"></div>
- <div id="graph-container"></div>
- </div>
- <el-button @click="submitAll" type="primary">保存</el-button>
- <el-dialog
- :title="modalType == 'add' ? '新增' : '编辑'"
- v-model="dialogVisible"
- width="500"
- v-loading="loading"
- >
- <byForm
- :formConfig="formConfig"
- :formOption="formOption"
- v-model="formData.data"
- :rules="rules"
- ref="byform"
- >
- </byForm>
- <template #footer>
- <el-button @click="dialogVisible = false" size="large"
- >取 消</el-button
- >
- <el-button
- type="danger"
- @click="deleteFlowDefinitionNodeObj()"
- size="large"
- :loading="submitLoading"
- >
- 删 除
- </el-button>
- <el-button
- type="primary"
- @click="submitForm('byform')"
- size="large"
- :loading="submitLoading"
- >
- 确 定
- </el-button>
- </template>
- </el-dialog>
- </template>
- <script lang="ts" setup>
- import {
- defineComponent,
- ref,
- onMounted,
- onUnmounted,
- watch,
- reactive,
- toRefs,
- computed,
- nextTick,
- getCurrentInstance,
- } from 'vue'
- import byForm from '@/components/byForm/index'
- import { Graph, Shape } from '@antv/x6'
- import { Stencil } from '@antv/x6-plugin-stencil'
- import { Transform } from '@antv/x6-plugin-transform'
- import { Selection } from '@antv/x6-plugin-selection'
- import { Snapline } from '@antv/x6-plugin-snapline'
- import { Keyboard } from '@antv/x6-plugin-keyboard'
- import { Clipboard } from '@antv/x6-plugin-clipboard'
- import { History } from '@antv/x6-plugin-history'
- import Cookies from 'js-cookie'
- import { ElMessage, ElMessageBox } from "element-plus";
- defineProps({
- title: {
- type: Object,
- default: '',
- },
-
- });
- const { proxy } = getCurrentInstance()
- const internalInstance = getCurrentInstance()
- const dialogVisible = ref(false)
- const modalType = ref('add')
- const loading = ref(false)
- const submitLoading = ref(false)
- const formData = reactive({
- data: {
- userName: '',
- password: '',
- },
- })
- const byform = ref(null)
- const flowDefinitionNodeObj = ref({})
- const rules = reactive({
- nodeName: [
- {
- required: true,
- message: '请输入节点名称',
- trigger: 'blur',
- },
- ],
- handleObjectType: [
- {
- required: true,
- message: '办理人类型不能为空',
- trigger: 'blur',
- },
- ],
- handleObjectId: [
- {
- required: true,
- message: '办理人不能为空',
- trigger: 'blur',
- },
- ],
- })
- const formConfig = computed(() => {
- return [
- {
- type: 'input',
- prop: 'nodeName',
- label: '节点名称',
- required: true,
- itemType: 'text',
- },
- {
- type: 'select',
- prop: 'handleObjectType',
- label: '办理人',
- placeholder: '请选择办理人类型',
- required: true,
- itemWidth: 30,
- fn: (e) => {
- console.log(e)
- gethandleObjectList(e)
- },
- //1用户 2部门负责人 3部门总监 4岗位 5角色
- data: [
- {
- label: '用户',
- value: 1,
- },
- {
- label: '部门负责人',
- value: 2,
- },
- {
- label: '部门总监',
- value: 3,
- },
- {
- label: '岗位',
- value: 4,
- },
- {
- label: '角色',
- value: 5,
- },
- ],
- },
- // {
- // type: "treeSelect",
- // prop: "handleObjectId",
- // label: "请选择办理人",
- // itemWidth: 30,
- // data: [],
- // },
- {
- type: 'select',
- label: ' ',
- itemWidth: 30,
- prop: 'handleObjectId',
- placeholder: '请选择办理人',
- data: [],
- },
- {
- type: 'input',
- prop: 'handlingMethod',
- label: '节点后置执行方法',
- required: true,
- itemType: 'text',
- },
- {
- type: 'input',
- prop: 'jumpCondition',
- label: '条件表达式',
- required: true,
- itemType: 'text',
- },
- {
- type: 'checkbox',
- prop: 'nodeButtonSet',
- label: '节点按钮',
- //1通过 2驳回 3返回上一步 4退回到发起人
- data: [
- {
- label: '通过',
- value: 1,
- },
- {
- label: '驳回',
- value: 2,
- },
- {
- label: '返回上一步',
- value: 3,
- },
- {
- label: '退回到发起人',
- value: 4,
- },
- ],
- },
- {
- type: 'radio',
- prop: 'jobNumber11',
- label: '审批意见必填',
- data: [
- {
- label: '是',
- value: 1,
- },
- {
- label: '否',
- value: 0,
- },
- ],
- },
- ]
- })
- const formOption = reactive({
- inline: true,
- labelWidth: 100,
- itemWidth: 100,
- })
- let graph
- const submitForm = () => {
- byform.value.handleSubmit((valid) => {
- flowDefinitionNodeObj.value[formData.data.id] = formData.data
- console.log(flowDefinitionNodeObj.value)
- })
- }
- const submitFormData = {
- flowInfoId:null,
- titleTemplate:null,
- tenantId:Cookies.get('tenantId'),
- nodeObject:'',
- lineObject:'',
- flowDefinitionNodeList:[],
- }
- const submitAll = () => {
- if(proxy.title == '') {
- ElMessage({
- message: '请输入流程标题',
- type: 'warning',
- })
- return
- }
- submitFormData.titleTemplate = proxy.title
- const nodeList = graph.toJSON().cells
- console.log(nodeList)
- const isStart = false
- for (let i = 0; i < nodeList.length; i++) {
- const element = nodeList[i];
- //是办理节点
- if(element.id != 1 && element.shape != "edge") {
- console.log(element)
- if(!flowDefinitionNodeObj.value[element.id]) {
- ElMessage({
- message: '有节点未配置,请检查节点123123123',
- type: 'warning',
- })
- return
- }
- submitFormData.flowDefinitionNodeList.push({...flowDefinitionNodeObj.value[element.id],nodeType:2})
- }
- if(element.id == "1") {
- submitFormData.flowDefinitionNodeList.push({
- nodeName:'开始',
- nodeType:1,
- id:1,
- nodeButtonSet:'',
- parentId:0,
- })
- }
- //说明是线
- if(element.shape == "edge") {
- console.log(flowDefinitionNodeObj)
- if(!flowDefinitionNodeObj.value[element.target.cell]) {
- ElMessage({
- message: '有节点未配置,请检查节点',
- type: 'warning',
- })
- return
- }
- flowDefinitionNodeObj.value[element.target.cell].id = element.target.cell
- flowDefinitionNodeObj.value[element.target.cell].parentId = element.source.cell
- submitFormData.flowDefinitionNodeList = []
- }
- }
- addVersion()
- console.log(flowDefinitionNodeObj.value)
- }
- //选取一个随机不重复的正整数id
- const randomId = () => {
- const id = Math.floor(Math.random() * 100000000000000000)
- if(flowDefinitionNodeObj.value[id]) {
- randomId()
- } else {
- return id
- }
- }
- const addVersion = () => {
- const idObg = {}
- for (let i = 0; i < submitFormData.flowDefinitionNodeList.length; i++) {
- const element = submitFormData.flowDefinitionNodeList[i];
- if(isNaN(element.id)) {
- if(idObg[element.id]) {
- element.id = idObg[element.id]
- } else {
- const id = randomId()
- idObg[element.id] = id
- element.id = id
- }
- }
- if(isNaN(element.parentId) && element.nodeName != '开始') {
- if(idObg[element.parentId]) {
- element.parentId = idObg[element.parentId]
- } else {
- const id = randomId()
- idObg[element.parentId] = id
- element.parentId = id
- }
- }
- //nodeButtonSet转成字符串类型,用逗号隔开
- if(element.nodeButtonSet) {
- element.nodeButtonSet = element.nodeButtonSet.join(',')
- }
- }
- console.log(submitFormData)
-
- proxy.post('/flowDefinition/addVersion',submitFormData)
- .then((res) => {
- console.log(res)
- ElMessage({
- message: '保存成功',
- type: 'success',
- })
- })
- }
- //将组数里的id和parentId转换成整正整数类型
- const changeId = (arr) => {
- for (let i = 0; i < arr.length; i++) {
- const element = arr[i];
- element.id = parseInt(element.id)
- element.parentId = parseInt(element.parentId)
- }
- }
- const deleteFlowDefinitionNodeObj = (id) => {
- graph.removeNode(formData.data.id)
- delete flowDefinitionNodeObj.value[id]
- dialogVisible.value = false
- }
- const gethandleObjectList = (e) => {
- formData.data.handleObjectId = ''
- if(e === 1) {
- proxy.get('/tenantUser/list?pageNum=1&pageSize=1000&tenantId=' + Cookies.get('tenantId'),{})
- .then((res) => {
- formConfig.value[2].data = res.rows.map((item) => {
- return {
- label: item.nickName,
- value: item.userId,
- }
- })
- })
- }
- if(e === 3 || e === 2) {
- proxy.get('/tenantDept/list?pageNum=1&pageSize=1000&tenantId=' + Cookies.get('tenantId'),{})
- .then((res) => {
- formConfig.value[2].data =res.data.map(item=> {
- return {
- label: item.deptName,
- value: item.deptId,
- }
- })
- })
- }
- if(e === 4) {
-
- }
- if(e === 5) {
- proxy.get('/tenantRole/list?pageNum=1&pageSize=1000&tenantId=' + Cookies.get('tenantId'),{})
- .then((res) => {
- formConfig.value[2].data = res.rows.map((item) => {
- return {
- label: item.roleName,
- value: item.roleId,
- }
- })
- })
- }
-
-
- }
- const getTenantDept = () => {
-
- }
- getTenantDept()
- const recursive = (data) => {
- data.map((item) => {
- item.label = item.deptName;
- item.id = item.deptId;
- if (item.children) {
- recursive(item.children);
- } else {
- item.children = [];
- }
- });
- };
- const pushRoom = (port: any) => {
- console.log(port)
- if(port.node.label == '结束') {
- flowDefinitionNodeObj.value[port.node.id] = {
- nodeName:'结束',
- nodeType:99,
- id:port.id,
- nodeButtonSet:'',
- }
- }
- console.log(flowDefinitionNodeObj.value)
- }
- //用于存储流程定义节点数据
- const antvInit = () => {
- graph = new Graph({
- height: 600,
- container: document.getElementById('graph-container')!,
- grid: true,
- onPortRendered: pushRoom,
- mousewheel: {
- enabled: true,
- zoomAtMousePosition: true,
- modifiers: 'ctrl',
- minScale: 0.5,
- maxScale: 3,
- },
- connecting: {
- router: 'manhattan',
- connector: {
- name: 'rounded',
- args: {
- radius: 8,
- },
- },
- anchor: 'center',
- connectionPoint: 'anchor',
- allowBlank: false,
- snap: {
- radius: 20,
- },
- createEdge() {
- return new Shape.Edge({
- attrs: {
- line: {
- stroke: '#A2B1C3',
- strokeWidth: 2,
- targetMarker: {
- name: 'block',
- width: 12,
- height: 8,
- },
- },
- },
- zIndex: 0,
- })
- },
- validateConnection({ targetMagnet }) {
- return !!targetMagnet
- },
- },
- highlighting: {
- magnetAdsorbed: {
- name: 'stroke',
- args: {
- attrs: {
- fill: '#5F95FF',
- stroke: '#5F95FF',
- },
- },
- },
- },
- })
- const stencil = new Stencil({
- title: '流程图',
- target: graph,
- stencilGraphWidth: 200,
- stencilGraphHeight: 180,
- collapsable: true,
- groups: [
- {
- title: '基础流程图',
- name: 'group1',
- },
- ],
- layoutOptions: {
- columns: 2,
- columnWidth: 80,
- rowHeight: 55,
- },
- })
- document.getElementById('stencil')!.appendChild(stencil.container)
- // #region 使用插件
- graph
- .use(
- new Transform({
- resizing: true,
- rotating: true,
- })
- )
- .use(
- new Selection({
- enabled: true,
- rubberband: true,
- showNodeSelectionBox: true,
- })
- )
- .use(
- new Snapline({
- enabled: true,
- })
- )
- .use(
- new Keyboard({
- enabled: true,
- })
- )
- .use(
- new Clipboard({
- enabled: true,
- })
- )
- .use(
- new History({
- enabled: true,
- })
- )
- // 控制连接桩显示/隐藏
- const showPorts = (ports: NodeListOf<SVGElement>, show: boolean) => {
- for (let i = 0, len = ports.length; i < len; i += 1) {
- ports[i].style.visibility = show ? 'visible' : 'hidden'
- }
- }
- graph.on('node:mouseenter', () => {
- const container = document.getElementById('graph-container')!
- const ports = container.querySelectorAll(
- '.x6-port-body'
- ) as NodeListOf<SVGElement>
- showPorts(ports, true)
- })
- graph.on('node:mouseleave', () => {
- const container = document.getElementById('graph-container')!
- const ports = container.querySelectorAll(
- '.x6-port-body'
- ) as NodeListOf<SVGElement>
- showPorts(ports, false)
- })
- // #endregion
- graph.on('cell:click', ({ e, x, y, cell, view }) => {
- console.log(cell)
- if (cell.label === '开始' || cell.label === '结束' || cell.shape === 'edge') {
- return
- }
- if (flowDefinitionNodeObj.value[cell.id]) {
- formData.data = flowDefinitionNodeObj.value[cell.id]
- } else {
- formData.data = {
- id: cell.id,
- cell: cell,
- }
- }
- dialogVisible.value = true
- })
- // #region 初始化图形
- const ports = {
- groups: {
- top: {
- position: 'top',
- attrs: {
- circle: {
- r: 4,
- magnet: true,
- stroke: '#5F95FF',
- strokeWidth: 1,
- fill: '#fff',
- style: {
- visibility: 'hidden',
- },
- },
- },
- },
- right: {
- position: 'right',
- attrs: {
- circle: {
- r: 4,
- magnet: true,
- stroke: '#5F95FF',
- strokeWidth: 1,
- fill: '#fff',
- style: {
- visibility: 'hidden',
- },
- },
- },
- },
- bottom: {
- position: 'bottom',
- attrs: {
- circle: {
- r: 4,
- magnet: true,
- stroke: '#5F95FF',
- strokeWidth: 1,
- fill: '#fff',
- style: {
- visibility: 'hidden',
- },
- },
- },
- },
- left: {
- position: 'left',
- attrs: {
- circle: {
- r: 4,
- magnet: true,
- stroke: '#5F95FF',
- strokeWidth: 1,
- fill: '#fff',
- style: {
- visibility: 'hidden',
- },
- },
- },
- },
- },
- items: [
- {
- group: 'top',
- },
- {
- group: 'right',
- },
- {
- group: 'bottom',
- },
- {
- group: 'left',
- },
- ],
- }
- Graph.registerNode(
- 'custom-rect',
- {
- inherit: 'rect',
- width: 66,
- height: 36,
- attrs: {
- body: {
- strokeWidth: 1,
- stroke: '#5F95FF',
- fill: '#EFF4FF',
- },
- text: {
- fontSize: 12,
- fill: '#262626',
- },
- },
- ports: { ...ports },
- },
- true
- )
- Graph.registerNode(
- 'custom-polygon',
- {
- inherit: 'polygon',
- width: 66,
- height: 36,
- attrs: {
- body: {
- strokeWidth: 1,
- stroke: '#5F95FF',
- fill: '#EFF4FF',
- },
- text: {
- fontSize: 12,
- fill: '#262626',
- },
- },
- ports: {
- ...ports,
- items: [
- {
- group: 'top',
- },
- {
- group: 'bottom',
- },
- ],
- },
- },
- true
- )
- Graph.registerNode(
- 'custom-circle',
- {
- inherit: 'circle',
- width: 45,
- height: 45,
- attrs: {
- body: {
- strokeWidth: 1,
- stroke: '#5F95FF',
- fill: '#EFF4FF',
- },
- text: {
- fontSize: 12,
- fill: '#262626',
- },
- },
- ports: { ...ports },
- },
- true
- )
- Graph.registerNode(
- 'custom-image',
- {
- inherit: 'rect',
- width: 52,
- height: 52,
- markup: [
- {
- tagName: 'rect',
- selector: 'body',
- },
- {
- tagName: 'image',
- },
- {
- tagName: 'text',
- selector: 'label',
- },
- ],
- attrs: {
- body: {
- stroke: '#5F95FF',
- fill: '#5F95FF',
- },
- image: {
- width: 26,
- height: 26,
- refX: 13,
- refY: 16,
- },
- label: {
- refX: 3,
- refY: 2,
- textAnchor: 'left',
- textVerticalAnchor: 'top',
- fontSize: 12,
- fill: '#fff',
- },
- },
- ports: { ...ports },
- },
- true
- )
- let firstLi = document.createElement('li')
- firstLi.innerText = '指标详情'
- console.log(firstLi)
- const r1 = graph.createNode({
- shape: 'custom-rect',
- label: '开始',
- zIndex: 100,
- attrs: {
- body: {
- rx: 20,
- ry: 26,
- },
- },
- tools: [
- {
- name: 'button',
- args: {
- firstLi,
- },
- },
- ],
- })
- const r2 = graph.createNode({
- shape: 'custom-rect',
- label: '办理',
- })
- const r3 = graph.createNode({
- shape: 'custom-rect',
- attrs: {
- body: {
- rx: 6,
- ry: 6,
- },
- },
- label: '分支',
- })
- const r4 = graph.createNode({
- shape: 'custom-polygon',
- attrs: {
- body: {
- refPoints: '0,10 10,0 20,10 10,20',
- },
- },
- label: '结束',
- })
- stencil.load([ r2, r4], 'group1')
- graph.addNode({
- shape: 'custom-rect',
- label: '开始',
- id: 1,
- x: 500,
- y: 100,
- })
- }
- onMounted(() => {
- antvInit()
- //获取url router参数
- const router = useRouter();
- submitFormData.flowInfoId = router.currentRoute.value.query.id
- })
- </script>
- <style lang="scss">
- .x6-widget-stencil-title {
- display: none;
- }
- .x6-widget-stencil-content {
- top: 0 !important;
- }
- .vueFlow {
- position: relative;
- display: flex;
- justify-content: space-between;
- overflow: hidden;
- height: 600px;
- #stencil {
- position: absolute;
- top: 0;
- left: 0;
- z-index: 100;
- width: 200px;
- height: 500px;
- background: #fff;
- border-right: 1px solid #e8e8e8;
- }
- #container {
- }
- #graph-container {
- width: 100%;
- position: absolute;
- right: 0;
- top: 0;
- }
- }
- </style>
|