Эх сурвалжийг харах

feat: 添加流程模型、表单和节点相关接口及组件

kagg886 3 сар өмнө
parent
commit
3d844e66a7
49 өөрчлөгдсөн 6829 нэмэгдсэн , 0 устгасан
  1. 45 0
      src/api/flow/flowDemo.ts
  2. 98 0
      src/api/flow/flowForm.ts
  3. 143 0
      src/api/flow/flowModel.ts
  4. 83 0
      src/components/gFlow/Control.vue
  5. 20 0
      src/components/gFlow/DataDialog.vue
  6. 347 0
      src/components/gFlow/checkFlow.vue
  7. 95 0
      src/components/gFlow/config.ts
  8. 58 0
      src/components/gFlow/consts.ts
  9. 85 0
      src/components/gFlow/flowLog.vue
  10. 74 0
      src/components/gFlow/model.ts
  11. 308 0
      src/components/gFlow/propertySetting/CommonProperty.vue
  12. 41 0
      src/components/gFlow/propertySetting/PropertyDialog.vue
  13. 237 0
      src/components/gFlow/propertySetting/branch.vue
  14. 7 0
      src/components/gFlow/propertySetting/model.ts
  15. 16 0
      src/components/gFlow/registerNode/index.ts
  16. 100 0
      src/components/gFlow/registerNode/registerConcurrent.ts
  17. 107 0
      src/components/gFlow/registerNode/registerConcurrentDone.ts
  18. 100 0
      src/components/gFlow/registerNode/registerCondition.ts
  19. 111 0
      src/components/gFlow/registerNode/registerConditionDone.ts
  20. 51 0
      src/components/gFlow/registerNode/registerEdgeDone.ts
  21. 119 0
      src/components/gFlow/registerNode/registerEnd.ts
  22. 130 0
      src/components/gFlow/registerNode/registerEndDone.ts
  23. 86 0
      src/components/gFlow/registerNode/registerPush.ts
  24. 93 0
      src/components/gFlow/registerNode/registerPushDone.ts
  25. 70 0
      src/components/gFlow/registerNode/registerStart.ts
  26. 71 0
      src/components/gFlow/registerNode/registerStartDone.ts
  27. 120 0
      src/components/gFlow/registerNode/registerUserTask.ts
  28. 121 0
      src/components/gFlow/registerNode/registerUserTaskDone.ts
  29. 223 0
      src/components/gFlow/showDesign.vue
  30. 52 0
      src/utils/formCreate.ts
  31. 181 0
      src/views/flow/flowDemo/list/component/detail.vue
  32. 140 0
      src/views/flow/flowDemo/list/component/edit.vue
  33. 44 0
      src/views/flow/flowDemo/list/component/model.ts
  34. 294 0
      src/views/flow/flowDemo/list/index.vue
  35. 302 0
      src/views/flow/flowForm/center/index.vue
  36. 170 0
      src/views/flow/flowForm/list/component/addFormData.vue
  37. 177 0
      src/views/flow/flowForm/list/component/dataDetail.vue
  38. 147 0
      src/views/flow/flowForm/list/component/detail.vue
  39. 179 0
      src/views/flow/flowForm/list/component/edit.vue
  40. 80 0
      src/views/flow/flowForm/list/component/formDesign.vue
  41. 61 0
      src/views/flow/flowForm/list/component/model.ts
  42. 355 0
      src/views/flow/flowForm/list/index.vue
  43. 280 0
      src/views/flow/flowModel/list/component/design.vue
  44. 221 0
      src/views/flow/flowModel/list/component/detail.vue
  45. 233 0
      src/views/flow/flowModel/list/component/edit.vue
  46. 67 0
      src/views/flow/flowModel/list/component/model.ts
  47. 448 0
      src/views/flow/flowModel/list/index.vue
  48. 29 0
      src/views/flow/flowModel/monitor/component/model.ts
  49. 210 0
      src/views/flow/flowModel/monitor/index.vue

+ 45 - 0
src/api/flow/flowDemo.ts

@@ -0,0 +1,45 @@
+import request from '/@/utils/request'
+// 查询流程审批测试列表
+export function listFlowDemo(query:object) {
+  return request({
+    url: '/api/v1/flow/flowDemo/list',
+    method: 'get',
+    params: query
+  })
+}
+// 查询流程审批测试详细
+export function getFlowDemo(id:number) {
+  return request({
+    url: '/api/v1/flow/flowDemo/get',
+    method: 'get',
+    params: {
+      id: id.toString()
+    }
+  })
+}
+// 新增流程审批测试
+export function addFlowDemo(data:object) {
+  return request({
+    url: '/api/v1/flow/flowDemo/add',
+    method: 'post',
+    data: data
+  })
+}
+// 修改流程审批测试
+export function updateFlowDemo(data:object) {
+  return request({
+    url: '/api/v1/flow/flowDemo/edit',
+    method: 'put',
+    data: data
+  })
+}
+// 删除流程审批测试
+export function delFlowDemo(ids:number[]) {
+  return request({
+    url: '/api/v1/flow/flowDemo/delete',
+    method: 'delete',
+    data:{
+      ids:ids
+    }
+  })
+}

+ 98 - 0
src/api/flow/flowForm.ts

@@ -0,0 +1,98 @@
+import request from '/@/utils/request'
+// 查询流程表单列表
+export function listFlowForm(query:object) {
+  return request({
+    url: '/api/v1/flow/flowForm/list',
+    method: 'get',
+    params: query
+  })
+}
+// 查询流程表单详细
+export function getFlowForm(id:number) {
+  return request({
+    url: '/api/v1/flow/flowForm/get',
+    method: 'get',
+    params: {
+      id: id.toString()
+    }
+  })
+}
+// 新增流程表单
+export function addFlowForm(data:object) {
+  return request({
+    url: '/api/v1/flow/flowForm/add',
+    method: 'post',
+    data: data
+  })
+}
+// 修改流程表单
+export function updateFlowForm(data:object) {
+  return request({
+    url: '/api/v1/flow/flowForm/edit',
+    method: 'put',
+    data: data
+  })
+}
+// 删除流程表单
+export function delFlowForm(ids:number[]) {
+  return request({
+    url: '/api/v1/flow/flowForm/delete',
+    method: 'delete',
+    data:{
+      ids:ids
+    }
+  })
+}
+//部署表单
+export function genFlowForm(id:number) {
+  return request({
+    url: '/api/v1/flow/flowForm/gen',
+    method: 'post',
+    data:{id}
+  })
+}
+
+// 新增流程表单数据
+export function addFlowFormData(data:object) {
+  return request({
+    url: '/api/v1/flow/flowForm/addFormData',
+    method: 'post',
+    data: data
+  })
+}
+
+// 新增流程表单数据
+export function editFlowFormData(data:object) {
+  return request({
+    url: '/api/v1/flow/flowForm/editFormData',
+    method: 'put',
+    data: data
+  })
+}
+
+// 获取流程表单列表数据
+export function ListFlowFormData(data:object) {
+  return request({
+    url: '/api/v1/flow/flowForm/dataList',
+    method: 'get',
+    params: data
+  })
+}
+
+// 获取流程表单数据
+export function getFlowFormData(data:object) {
+  return request({
+    url: '/api/v1/flow/flowForm/getFormData',
+    method: 'get',
+    params: data
+  })
+}
+
+// 删除流程表单数据
+export function delFlowFormData(data:object) {
+  return request({
+    url: '/api/v1/flow/flowForm/delFormData',
+    method: 'delete',
+    data: data
+  })
+}

+ 143 - 0
src/api/flow/flowModel.ts

@@ -0,0 +1,143 @@
+import request from '/@/utils/request'
+// 查询流程模型列表
+export function listFlowModel(query:object) {
+  return request({
+    url: '/api/v1/flow/flowModel/list',
+    method: 'get',
+    params: query
+  })
+}
+// 查询流程模型详细
+export function getFlowModel(id:number) {
+  return request({
+    url: '/api/v1/flow/flowModel/get',
+    method: 'get',
+    params: {
+      id: id.toString()
+    }
+  })
+}
+// 新增流程模型
+export function addFlowModel(data:object) {
+  return request({
+    url: '/api/v1/flow/flowModel/add',
+    method: 'post',
+    data: data
+  })
+}
+// 修改流程模型
+export function updateFlowModel(data:object) {
+  return request({
+    url: '/api/v1/flow/flowModel/edit',
+    method: 'put',
+    data: data
+  })
+}
+// 删除流程模型
+export function delFlowModel(ids:number[]) {
+  return request({
+    url: '/api/v1/flow/flowModel/delete',
+    method: 'delete',
+    data:{
+      ids:ids
+    }
+  })
+}
+//相关连表查询数据
+export function linkedDataSearch(){
+  return request({
+    url: '/api/v1/flow/flowModel/linkedData',
+    method: 'get'
+  })
+}
+
+export function saveModeNode(data:object){
+  return request({
+    url: '/api/v1/flow/flowModel/saveModelNode',
+    method: 'post',
+    data: data
+  })
+}
+
+export function getNodeData(modelId:number){
+  return request({
+    url: '/api/v1/flow/flowModel/getModelNode',
+    method: 'get',
+    params:{modelId:modelId}
+  })
+}
+
+//发起流程
+export function wfStart(query:Object){
+  return request({
+    url: '/api/v1/flow/flowModel/wfStart',
+    method: 'get',
+    params:query
+  })
+}
+
+//保存发起流程信息
+export function saveStartWf(data:Object){
+  return request({
+    url: '/api/v1/flow/flowModel/wfSaveStart',
+    method: 'post',
+    data:data
+  })
+}
+
+
+export function getCheckData(query:Object){
+  return request({
+    url: '/api/v1/flow/flowModel/checkData',
+    method: 'get',
+    params:query
+  })
+}
+
+//保存审批信息
+export function saveCheckWf(data:any){
+  if (data.isProxy){
+    return request({
+      url: '/api/v1/flow/flowModel/proxy',
+      method: 'post',
+      data:data
+    })
+  }
+  return request({
+    url: '/api/v1/flow/flowModel/checkSave',
+    method: 'post',
+    data:data
+  })
+}
+
+// 获取审批日志列表
+export function checkLog(params:Object){
+  return request({
+    url: '/api/v1/flow/flowModel/log',
+    method: 'get',
+    params:params
+  })
+}
+
+export function getRunStep(params:Object){
+  return request({
+    url: '/api/v1/flow/flowModel/runStep',
+    method: 'get',
+    params:params
+  })
+}
+//获取流程监控信息
+export function getMonitor(params:Object){
+  return request({
+    url: '/api/v1/flow/flowModel/monitor',
+    method: 'get',
+    params:params
+  })
+}
+export function stopRun(ids:number[]){
+  return request({
+    url: '/api/v1/flow/flowModel/stopRun',
+    method: 'put',
+    data:{ids:ids}
+  })
+}

+ 83 - 0
src/components/gFlow/Control.vue

@@ -0,0 +1,83 @@
+<template>
+  <div>
+     <el-button-group>
+      <el-button  size="small" @click="$_zoomIn">放大</el-button>
+      <el-button  size="small" @click="$_zoomOut">缩小</el-button>
+      <el-button  size="small" @click="$_zoomReset">大小适应</el-button>
+      <el-button  size="small" @click="$_translateRest">定位还原</el-button>
+      <el-button  size="small" @click="$_reset">还原(大小&定位)</el-button>
+      <el-button  size="small" @click="$_undo" :disabled="undoDisable">上一步(ctrl+z)</el-button>
+      <el-button  size="small" @click="$_redo" :disabled="redoDisable">下一步(ctrl+y)</el-button>
+      <el-button  size="small" @click="$_download">下载图片</el-button>
+      <el-button  size="small" @click="$_catData">查看数据</el-button>
+      <el-button v-if="catTurboData"  size="small" @click="$_catTurboData">查看turbo数据</el-button>
+      <el-button  size="small" @click="$_showMiniMap">查看缩略图</el-button>
+      <el-button  size="small" @click="$_saveModel" type="success">保存模型</el-button>
+    </el-button-group>
+  </div>
+</template>
+<script setup lang="ts">
+import LogicFlow from "@logicflow/core";
+import {onMounted, ref} from "vue";
+import {MiniMap} from "@logicflow/extension";
+
+defineOptions({ name: "Control"})
+const props = defineProps({
+  lf:{
+    type:LogicFlow,
+    default:()=>{return {} as LogicFlow}
+  },
+  catTurboData: Boolean
+})
+const emit = defineEmits(['catData','catTurboData','saveModel'])
+const undoDisable = ref(true)
+const redoDisable = ref(true)
+const graphData = ref()
+const dataVisible = ref(false)
+
+onMounted(()=>{
+  props.lf.on('history:change', ({ data: { undoAble, redoAble } }) => {
+    undoDisable.value = !undoAble
+    redoDisable.value = !redoAble
+  });
+})
+const $_zoomIn = () => {
+  props.lf.zoom(true);
+}
+const $_zoomOut = () => {
+  props.lf.zoom(false);
+}
+const $_zoomReset = () => {
+  props.lf.resetZoom();
+}
+const $_translateRest = () => {
+  props.lf.resetTranslate()
+}
+const $_reset = () => {
+  props.lf.resetZoom();
+  props.lf.resetTranslate();
+}
+const $_undo = () => {
+  props.lf.undo();
+}
+const $_redo = () => {
+  props.lf.redo();
+}
+const $_download = () => {
+  props.lf.getSnapshot();
+}
+const $_catData = () => {
+  emit('catData');
+}
+const $_catTurboData = () => {
+  emit('catTurboData');
+}
+const $_showMiniMap = () => {
+  (props.lf.extension.miniMap as MiniMap).show(props.lf.graphModel.width - 170, 40)
+}
+const $_saveModel = ()=>{
+  emit('saveModel');
+}
+</script>
+<style scoped>
+</style>

+ 20 - 0
src/components/gFlow/DataDialog.vue

@@ -0,0 +1,20 @@
+<template>
+  <div>
+    <vue-json-pretty :path="'res'" :data="graphData"> </vue-json-pretty>
+  </div>
+</template>
+<script setup lang="ts">
+import VueJsonPretty from 'vue-json-pretty';
+import 'vue-json-pretty/lib/styles.css';
+defineOptions({ name: "DataDialog"})
+defineProps({
+  graphData:{
+    type: Object,
+    default: () => {
+      return {}
+    }
+  }
+})
+</script>
+<style scoped>
+</style>

+ 347 - 0
src/components/gFlow/checkFlow.vue

@@ -0,0 +1,347 @@
+<template>
+  <div class="check-flow-container">
+    <!--发起工作流-->
+    <el-dialog title="发起审批" v-model="startWfOpen" width="500px" append-to-body :close-on-click-modal="false" destroy-on-close>
+      <el-form ref="wfStartFormRef" :model="wfStartForm" :rules="wfStartRules" label-width="120px">
+        <el-form-item label="项目名称" prop="title">
+          <el-input v-model="startWfTitle" disabled />
+        </el-form-item>
+        <el-form-item label="选择工作流" prop="wfId">
+          <el-select v-model="wfStartForm.wfId" @change="setSelectedFlow" clearable>
+            <el-option
+                v-for="item in wfOptions"
+                :key="item.id"
+                :label="item.name"
+                :value="item.id"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="流程图" v-if="wfStartForm.wfId && wfStartForm.wfId!=='0'">
+          <el-link type="primary" :underline="false" @click="showFlowDesign(wfStartForm.wfId,0,'start')">点击查看 {{ selectedFlow }} 的流程图</el-link>
+        </el-form-item>
+        <el-form-item label="紧急程度" prop="newType">
+          <el-select v-model="wfStartForm.newType" >
+            <el-option
+                v-for="item in flow_level"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="审核意见" prop="checkCon">
+          <el-input v-model="wfStartForm.checkCon" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitWfStart">确 定</el-button>
+        <el-button @click="cancelWfStart">取 消</el-button>
+      </div>
+      <el-dialog title="流程图" v-model="isShowFlowDesignStart" @opened="showFlowDesignOpen" width="90%" append-to-body destroy-on-close>
+        <ShowFlowDesign ref="showFlowDesignRef" />
+      </el-dialog>
+    </el-dialog>
+    <!--流程审批-->
+    <el-dialog title="流程审批" v-model="checkWfOpen" width="900px" append-to-body :close-on-click-modal="false" destroy-on-close>
+      <el-form ref="wfCheckFormRef" :model="wfCheckForm" :rules="wfCheckRules" label-width="120px">
+        <el-form-item label="项目名称" prop="title">
+          <el-input v-model="checkWfTitle" disabled />
+        </el-form-item>
+        <el-form-item label="审批意见" prop="checkCon">
+          <el-input v-model="wfCheckForm.checkCon"  type="textarea" :rows="3"/>
+        </el-form-item>
+        <el-form-item label="流程图" >
+          <el-button @click="showFlowDesign(flowId,processId,'check')" type="success" plain>点击查看流程图</el-button>
+        </el-form-item>
+        <el-form-item label="下一步骤" prop="nextStep" v-show="nextProcess&&!backProcess">
+          <template v-if="checkFlowInfo.nodeInfo && checkFlowInfo.nodeInfo.nextNode.length>0">
+            <el-tag v-for="(item,index) in checkFlowInfo.nodeInfo.nextNode" :key="'nextStep_'+index">{{item.nodeText.value}}【{{item.todo.join(',')}}】</el-tag>
+          </template>
+          <template v-else>
+            <el-tag>审批完成</el-tag>
+          </template>
+        </el-form-item>
+        <el-form-item label="回退步骤" v-if="backProcess" prop="wfBackFlow">
+          <el-select placeholder="请选择回退步骤" v-model="wfCheckForm.wfBackFlow">
+            <template v-if="checkFlowInfo">
+              <el-option v-for="(item) of checkFlowInfo.preprocess"
+                         :key="''+item.nodeId"
+                         :label="item.nodeText.value"
+                         :value="''+item.nodeId"
+              ></el-option>
+            </template>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="附件">
+          <upload-file :action="baseURL+'api/v1/system/upload/singleFile'" v-model="upFileInfo" @upFileData="upFile" :limit="1"></upload-file>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button v-show="doCheck && !doBack" type="primary" @click="submitWfCheck('ok')">提交审批</el-button>
+        <el-button type="danger" v-if="checkFlowInfo?.nodeInfo?.rollback===1" @click="submitWfCheck('back')">回  退</el-button>
+        <el-button type="info" @click="checkLogs">审批记录</el-button>
+      </div>
+      <el-dialog title="流程图" v-model="isShowFlowDesignCheck" @opened="showFlowCheckingOpen" width="90%" append-to-body destroy-on-close>
+        <ShowFlowDesign ref="showFlowCheckRef" />
+      </el-dialog>
+    </el-dialog>
+    <el-drawer
+        v-model="showLog"
+        title="审批记录"
+        direction="rtl"
+        @opened="showLogs"
+        destroy-on-close
+    >
+      <FlowLog ref="flowLogRef" :form-id="runInfo?.formId" :form-table="runInfo?.formTable"/>
+    </el-drawer>
+  </div>
+</template>
+<script setup lang="ts">
+
+import {getCurrentInstance, ref} from "vue";
+import {
+  checkFlowInfoData,
+  FlowRunInfo,
+  WfCheckFormData,
+  WfOptionsData,
+  wfStartFormData
+} from "/@/components/gFlow/model";
+import {FlowDemoTableColumns} from "/@/views/flow/flowDemo/list/component/model";
+import {ElMessage, FormInstance} from "element-plus";
+import {getCheckData, saveCheckWf, saveStartWf, wfStart} from "/@/api/flow/flowModel";
+import ShowFlowDesign from "/@/components/gFlow/showDesign.vue"
+import UploadFile from "/@/components/uploadFile/index.vue";
+import FlowLog from "/@/components/gFlow/flowLog.vue";
+const props = defineProps({
+  saveCheckWfAttr:{
+    type:Function,
+    default:saveCheckWf
+  }
+})
+defineOptions({ name: "checkFlow"})
+const baseURL:string|undefined|boolean = import.meta.env.VITE_API_URL
+const startWfOpen = ref(false)
+const startWfTitle =ref('')
+const wfStartForm = ref<wfStartFormData>({} as wfStartFormData)
+const showFlowDesignRef = ref()
+const showFlowCheckRef = ref()
+const wfStartRules = ref({
+  wfId: [
+    { required: true, message: "请选择工作流", trigger: "change" }
+  ],
+  newType: [
+    { required: true, message: "请选择紧急程度", trigger: "change" }
+  ]
+})
+const wfStartFormRef = ref<FormInstance>()
+const wfOptions = ref<Array<WfOptionsData>>([])
+const isShowFlowDesignStart = ref(false)
+const isShowFlowDesignCheck = ref(false)
+const wfCheckForm = ref<WfCheckFormData>({} as WfCheckFormData)
+const checkWfOpen = ref(false)
+const wfCheckRules = ref({
+  checkCon: [
+    { required: true, message: "请填写审批意见", trigger: "input" }
+  ],
+  wfBackFlow: [
+    { required: true, message: "请选择回退步骤", trigger: "change" }
+  ],
+})
+const wfCheckFormRef = ref()
+const designInfo = ref({})
+const selectedFlow = ref('')
+const {proxy} = <any>getCurrentInstance()
+const checkWfTitle = ref('')
+const checkFlowInfo = ref<checkFlowInfoData>({} as checkFlowInfoData)
+const flowId = ref(0)
+const processId = ref(0)
+const nextProcess = ref(true)
+const backProcess = ref(false)
+const doCheck = ref(true)
+const doBack = ref(false)
+const upFileInfo = ref<any[]>([])
+const runInfo = ref<FlowRunInfo>()
+const showLog = ref(false)
+const flowLogRef = ref()
+// 字典选项数据
+const {
+  flow_level
+} = proxy.useDict(
+    'flow_level',
+)
+const emit = defineEmits(['getList'])
+const showFlowDesignOpen = ()=>{
+  showFlowDesignRef.value.showDesign(designInfo.value)
+}
+const showFlowCheckingOpen = ()=>{
+  showFlowCheckRef.value.showDesign(designInfo.value)
+}
+const setSelectedFlow = ()=>{
+  wfOptions.value.some(item => {
+    if (item.id === parseInt(wfStartForm.value.wfId as string)) {
+      selectedFlow.value = item.name
+      return false
+    }
+  })
+}
+const showFlowDesign =  (flowId:string|number, processId = 0,tp='') => {
+  if(tp=='start'){
+    isShowFlowDesignStart.value = true
+  }else{
+    isShowFlowDesignCheck.value = true
+  }
+  designInfo.value = {flowId:flowId,processId:processId,runId: wfCheckForm.value.runId};
+}
+const submitWfStart = ()=>{
+  wfStartFormRef.value?.validate((valid: boolean) => {
+    if (valid) {
+      console.log(wfStartForm.value)
+      saveStartWf(wfStartForm.value).then((res:any)=>{
+        ElMessage.success("发起成功")
+        startWfOpen.value = false
+        emit("getList")
+      })
+    }
+  })
+}
+const cancelWfStart = ()=>{
+  startWfOpen.value = false
+}
+const handleStartFlow = (row: FlowDemoTableColumns|null)=>{
+  const btn = row?.actionBtn
+  if(btn.title.indexOf('无审批权限')>-1){
+    ElMessage.error("您没有审批权限")
+    return
+  }
+  switch(btn.type){
+    case 'link':
+      if(btn.api=='wfStart'){
+        resetWfForm()
+        //获取流程数据
+        wfStart({wfType:btn.wfType,wfModelType:btn.wfModelType,wfTitle:btn.wfTitle,wfStatusField:btn.wfStatusField,wfFid:btn.wfFid}).then((response:any)=>{
+          wfOptions.value =response.data.flow?response.data.flow:[]
+          startWfTitle.value = row?(row as any)[btn.wfTitle]:''
+          wfStartForm.value.wfType = response.data.info.wfType
+          wfStartForm.value.wfTitle = response.data.info.wfTitle
+          wfStartForm.value.wfStatusField = response.data.info.wfStatusField
+          wfStartForm.value.wfFid = response.data.info.wfFid
+        })
+        startWfOpen.value = true
+      }else if(btn.api=='wfCheck'){
+        resetCheckForm()
+        getCheckData({wfType:btn.wfType,wfModelType:btn.wfModelType,wfTitle:btn.wfTitle,wfStatusField:btn.wfStatusField,wfFid:btn.wfFid,isProxy:btn?.isProxy}).then((response:any)=>{
+          checkWfTitle.value = response.data.data.runInfo.runName
+          flowId.value = response.data.data.runInfo.flowId
+          processId.value = response.data.data.nodeInfo.nodeId
+          wfCheckForm.value.runId = response.data.data.runInfo.id
+          wfCheckForm.value.nodeId = response.data.data.nodeInfo.nodeId
+          checkFlowInfo.value.nodeInfo = response.data.data.nodeInfo
+          checkFlowInfo.value.preprocess = response.data.data.preProcess
+          runInfo.value = response.data.data.runInfo
+          wfCheckForm.value.isProxy = btn?.isProxy
+        })
+        checkWfOpen.value = true
+      }
+      break;
+  }
+}
+const resetWfForm = ()=>{
+  wfOptions.value = []
+  startWfTitle.value = ''
+  wfStartForm.value = {
+    wfType:'',
+    wfTitle:'',
+    wfStatusField:'',
+    wfFid:'',
+    wfId:undefined,
+    newType:undefined,
+    checkCon:'',
+  };
+  wfStartFormRef.value?.resetFields()
+}
+const resetCheckForm = ()=>{
+  checkWfTitle.value = ""
+  checkFlowInfo.value = {
+    nodeInfo:{
+      nextNode:[],
+      nodeId:'',
+      nodeText:'',
+      todo:[],
+      rollback:0
+    },
+    preprocess:[],
+  }
+  wfCheckForm.value = {
+    art:null,
+    checkCon:'',
+    flowId:'',
+    flowProcess:'',
+    nodeId:'',
+    npid:'',
+    runId:'',
+    runProcess:'',
+    submitToSave:'',
+    sup:'',
+    wfBackFlow:'',
+    wfFid:'',
+    wfMode:'',
+    wfStatusField:'',
+    wfTitle:'',
+    wfType:'',
+    isProxy:false
+  }
+  doBack.value =false
+  backProcess.value = false
+  wfCheckFormRef.value?.resetFields()
+}
+const upFile = (data:any)=>{
+  if(data&&data.length>0) {
+    wfCheckForm.value.art = JSON.stringify(data)
+    upFileInfo.value = data
+  }else{
+    wfCheckForm.value.art = ""
+  }
+}
+const submitWfCheck = (type:string)=>{
+  wfCheckForm.value.submitToSave = type
+  switch(type){
+    case 'ok':
+      props.saveCheckWfAttr(wfCheckForm.value).then((response:any)=>{
+        if (response.code === 0) {
+          ElMessage.success("审批成功")
+          checkWfOpen.value = false
+          emit("getList")
+        }
+      })
+      break
+    case 'back':
+      doBack.value = true
+      backProcess.value=true
+      if(!wfCheckForm.value.wfBackFlow){
+        ElMessage.error('请选择回退步骤')
+        return
+      }
+      props.saveCheckWfAttr(wfCheckForm.value).then((response:any)=>{
+        if (response.code === 0) {
+          ElMessage.success("回退成功")
+          checkWfOpen.value = false
+          emit("getList")
+        }
+      })
+      break
+  }
+}
+const checkLogs = ()=>{
+  showLog.value = true
+}
+const showLogs = ()=>{
+  flowLogRef.value.getLogList()
+}
+defineExpose({handleStartFlow})
+</script>
+<style scoped lang="scss">
+.dialog-footer{
+  display: flex;
+  justify-content: flex-end;
+}
+</style>

+ 95 - 0
src/components/gFlow/config.ts

@@ -0,0 +1,95 @@
+import LogicFlow from "@logicflow/core";
+import {DndPanel, SelectionSelect} from "@logicflow/extension";
+const setPatternItems = (lf:LogicFlow)=>{
+    (lf.extension.dndPanel as DndPanel).setPatternItems([
+        {
+            label: '选区',
+            icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAAOVJREFUOBGtVMENwzAIjKP++2026ETdpv10iy7WFbqFyyW6GBywLCv5gI+Dw2Bluj1znuSjhb99Gkn6QILDY2imo60p8nsnc9bEo3+QJ+AKHfMdZHnl78wyTnyHZD53Zzx73MRSgYvnqgCUHj6gwdck7Zsp1VOrz0Uz8NbKunzAW+Gu4fYW28bUYutYlzSa7B84Fh7d1kjLwhcSdYAYrdkMQVpsBr5XgDGuXwQfQr0y9zwLda+DUYXLaGKdd2ZTtvbolaO87pdo24hP7ov16N0zArH1ur3iwJpXxm+v7oAJNR4JEP8DoAuSFEkYH7cAAAAASUVORK5CYII=',
+            callback: () => {
+                (lf.extension.selectionSelect as SelectionSelect).openSelectionSelect();
+                lf.once('selection:selected', () => {
+                    (lf.extension.selectionSelect as SelectionSelect).closeSelectionSelect();
+                });
+            }
+        },
+        {
+            type: "start",
+            text: "开始",
+            label: "开始",
+            icon:
+                "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAAnBJREFUOBGdVL1rU1EcPfdGBddmaZLiEhdx1MHZQXApraCzQ7GKLgoRBxMfcRELuihWKcXFRcEWF8HBf0DdDCKYRZpnl7p0svLe9Zzbd29eQhTbC8nv+9zf130AT63jvooOGS8Vf9Nt5zxba7sXQwODfkWpkbjTQfCGUd9gIp3uuPP8bZ946g56dYQvnBg+b1HB8VIQmMFrazKcKSvFW2dQTxJnJdQ77urmXWOMBCmXM2Rke4S7UAW+/8ywwFoewmBps2tu7mbTdp8VMOkIRAkKfrVawalJTtIliclFbaOBqa0M2xImHeVIfd/nKAfVq/LGnPss5Kh00VEdSzfwnBXPUpmykNss4lUI9C1ga+8PNrBD5YeqRY2Zz8PhjooIbfJXjowvQJBqkmEkVnktWhwu2SM7SMx7Cj0N9IC0oQXRo8xwAGzQms+xrB/nNSUWVveI48ayrFGyC2+E2C+aWrZHXvOuz+CiV6iycWe1Rd1Q6+QUG07nb5SbPrL4426d+9E1axKjY3AoRrlEeSQo2Eu0T6BWAAr6COhTcWjRaYfKG5csnvytvUr/WY4rrPMB53Uo7jZRjXaG6/CFfNMaXEu75nG47X+oepU7PKJvvzGDY1YLSKHJrK7vFUwXKkaxwhCW3u+sDFMVrIju54RYYbFKpALZAo7sB6wcKyyrd+aBMryMT2gPyD6GsQoRFkGHr14TthZni9ck0z+Pnmee460mHXbRAypKNy3nuMdrWgVKj8YVV8E7PSzp1BZ9SJnJAsXdryw/h5ctboUVi4AFiCd+lQaYMw5z3LGTBKjLQOeUF35k89f58Vv/tGh+l+PE/wG0rgfIUbZK5AAAAABJRU5ErkJggg=="
+        },
+        {
+            type: "userTask",
+            label: "任务",
+            text: "任务",
+            icon:
+                "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAEFVwZaAAAABGdBTUEAALGPC/xhBQAAAqlJREFUOBF9VM9rE0EUfrMJNUKLihGbpLGtaCOIR8VjQMGDePCgCCIiCNqzCAp2MyYUCXhUtF5E0D+g1t48qAd7CCLqQUQKEWkStcEfVGlLdp/fm3aW2QQdyLzf33zz5m2IsAZ9XhDpyaaIZkTS4ASzK41TFao88GuJ3hsr2pAbipHxuSYyKRugagICGANkfFnNh3HeE2N0b3nN2cgnpcictw5veJIzxmDamSlxxQZicq/mflxhbaH8BLRbuRwNtZp0JAhoplVRUdzmCe/vO27wFuuA3S5qXruGdboy5/PRGFsbFGKo/haRtQHIrM83bVeTrOgNhZReWaYGnE4aUQgTJNvijJFF4jQ8BxJE5xfKatZWmZcTQ+BVgh7s8SgPlCkcec4mGTmieTP4xd7PcpIEg1TX6gdeLW8rTVMVLVvb7ctXoH0Cydl2QOPJBG21STE5OsnbweVYzAnD3A7PVILuY0yiiyDwSm2g441r6rMSgp6iK42yqroI2QoXeJVeA+YeZSa47gZdXaZWQKTrG93rukk/l2Al6Kzh5AZEl7dDQy+JjgFahQjRopSxPbrbvK7GRe9ePWBo1wcU7sYrFZtavXALwGw/7Dnc50urrHJuTPSoO2IMV3gUQGNg87IbSOIY9BpiT9HV7FCZ94nPXb3MSnwHn/FFFE1vG6DTby+r31KAkUktB3Qf6ikUPWxW1BkXSPQeMHHiW0+HAd2GelJsZz1OJegCxqzl+CLVHa/IibuHeJ1HAKzhuDR+ymNaRFM+4jU6UWKXorRmbyqkq/D76FffevwdCp+jN3UAN/C9JRVTDuOxC/oh+EdMnqIOrlYteKSfadVRGLJFJPSB/ti/6K8f0CNymg/iH2gO/f0DwE0yjAFO6l8JaR5j0VPwPwfaYHqOqrCI319WzwhwzNW/aQAAAABJRU5ErkJggg==",
+            className: "important-node",
+            properties: {
+                disabled: true
+            }
+        },
+        {
+            type: "concurrent",
+            label: "并行网关",
+            icon:
+                "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsTAAALEwEAmpwYAAADAElEQVRIidWWvYtdVRTFf2uf995EY4RggjxCEEkaiYjYJMiks0mho4hEbOIHYrAKBLFIY6Ex4F+QIpNqIE1MZyManIyQwgQbPyKx0SKiOI7Gj5l33znL4t43c2fee6ZK4YED955z9l57rX32vle2uZsj7qp3oAOwr78bobFNCWwYDDPdTkIg8AXQHPAPULb4+g1YA4rxu9/f+mWhc4cAnrJ5yPY5YUA7Qc8BN4CPgJ3NuRngG+AQMAcg9CSwDrAXeIJasgoQsGzzosRrnRQPAqeBv4EusACc2aDazMLlVnBr6xLJOor4YBqNTor3DEuYxVbEje/6kticc4mDwEsKzwP3rgOA50FXge3AoFn/wXBccALzJvIi6J7Gb+tyCOxDzvFqb/va8Wq194WLtimcWwAsA0sjEwPJIPtSSboC+rAJdFPOioUNKfS+oqzmSmclHm/DT0+yQGYx50LE5NscMrm4j3WYlM7nSkjsQBu1tWHpWk9hon4hp9QfDvPe0gBuwhf0UjDTjVnjVGCBpLFzUwvNNnY+2ut2rwr2bK54Y4KBOgwVBySIXL7ShK4wkuhlxGmjGeAvIAG3wfcr1Me+CcwC19b1c8HDCvAuoRXQHzANwNxG3AQysNoIMgDts923+dHWz+OpKCD1KPxJKUNiXKIRg4vN3DpeEbzgujorYEd7U0U46QFUfhc5m8RWhOk5KODCAmJOopp4kULIfkzWdxEdpPF+VpuNrxOCBANMxQRDDEYPA/uFP9cE/f+TQdNfnja8NWm3dBIKHQNTwp+UmJTijRw8ChwBetRNKgy/luCIzPPY+8FvgNaa8ytIuOSTYS1G0Zdl1PAmAkiHqbtjm1HVKsjXQWeB6wCGr1UNnxG+rxSdihHjaQyM54U+BbZRN7sAfpI4WQpvGz+bpOuum+GyzDvAAYITEkt5s88yBtDIcmMcXxfBH9u+TAhMDzDiYBP0HtfMd9XEWAEeaYyjDTBtXBs9NGqtgD8DzQK3bB2j/jaMSEQzvzW+AqD//V/FvxL3LMIFg3D4AAAAAElFTkSuQmCC",
+            className: "import_icon"
+        },
+        {
+            type: "push",
+            label: "互斥网关",
+            icon:
+                "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsTAAALEwEAmpwYAAACYklEQVRIie2VT4iOURTGf899v4+RlIWUjRpGDaLURNmQhdjZWE1JWbGWZGdtZ2ErMVPKwkpJKcoQlkP+ZEooVsP8MYz33sfivu837zczUcxYOXXq7Zxzz3POc+65r2yznBKWNfu/AGgB9Pb2NkwmppVACzsdA44AknzT0hUn4VhgQ6sF7TaAiDFSxthV8vu3LzKAcBcAsCGZO4LtHat1BHwWtB/0qR6dlDMIVgM7gYfNDgJAcqhUJAds3QNvBz8HzoDPCcYx/YIHUlxRFCUQKcusyT4vaUTo8gKKYmo3TDoK2hJgzGgXeDZ3wDWkUfBmhfIoxCG7oCwLwChoY0XAcUkzxqc6HYjQUB2oiLqBNQvKJFrvgKe5iGIbrAAVSKDM01SD5ZNClzoAdkPhRxUVwNTjUTB0fEQWSj3euzVI09iU+nBrEV9tS4v4ciHotAiD81GXTGxvAw8DfXMAWlKMVdXz82YOoKuEvwZIzTwdAEl5XaC9yKE/llCBXQW/RlqL9GQpAVoAQe5LVp9II6CXv4gv5j7FPD69MKYCKAKHYqn7kneCt87PKtVMupUH6KlMtWjckOkqugu1XrQvwG7gWcO3qj4cy6+kOE2Ks4/yw6b+TnKJEEAwkJsoR6Eka/MWme8WexFjuWomQhASzMxMMzU1ycy3rxclYXQCwuF83Ng+brEHwqtE+3GiRap2cv62ThgGJA4K3S5kHMSaNeuIMSLpnZ0GgSHgFvgD0DZaj9NHu2cfqSc1F717DzJ744LrwGdn+kgpYifsBDAs2AFcI2eaBF8Q3oT5mJO4k0z/f/q/k590kAk0S7XKDgAAAABJRU5ErkJggg=="
+        },
+        {
+            type: "condition",
+            label: "条件网关",
+            icon:
+                "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsTAAALEwEAmpwYAAABlUlEQVRIibXWv2oUURQG8N9KCATRFEFNEf9AEixSBDVBsLDIC6QTUqSxSSXYCSGpQh7AykIfIFZ2CnaJYCOIWNgohJAUFoLNSohkvRZ7huwOs7MzYffAcOac+93vmzvnnjvTSCkZpl0YKjuklFRYxRR+InVcDyrxVhT4FKR3cANHaOLioAQSXnfEK5G7NyiBH2jhFq7iSwhcGpTAorN3fxJ+uWxCXQHx9H+CfLEf+DwC8Bl/qwAz3rp9MIpGnQl1BU5r4o0U5MawoV3E8dzYVPjDXP4Ye3iq3R+lAqtYj/uj3NgH7RrczuWnMYsDbPUTmAw/h28F470sYT6fLKpBtkuOa5Bn1qoi8Ct8s2Csn/2uIpCdkvdrEF8Pf1d+G+ca7b3u42CzAvmjwP4L/x2Xizp5OwCruIZ3EU+XkI8F5jBW8TDiN0UCJ7qLNBLgtRKB2cCsdOT20SoSeBngJUzgRcRzJQLjgfmIK5iJeLfXYfdV92fxeQl5Zk9yc5q42UtgEq+0i/2sAnlmj/EWO1jgjLcx7N+W/0Nx+IW0B+PQAAAAAElFTkSuQmCC"
+        },
+        {
+            type: "end",
+            text: "结束",
+            label: "结束",
+            icon:
+                "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAAH6ji2bAAAABGdBTUEAALGPC/xhBQAAA1BJREFUOBFtVE1IVUEYPXOf+tq40Y3vPcmFIdSjIorWoRG0ERWUgnb5FwVhYQSl72oUoZAboxKNFtWiwKRN0M+jpfSzqJAQclHo001tKkjl3emc8V69igP3znzfnO/M9zcDcKT67azmjYWTwl9Vn7Vumeqzj1DVb6cleQY4oAVnIOPb+mKAGxQmKI5CWNJ2aLPatxWa3aB9K7/fB+/Z0jUF6TmMlFLQqrkECWQzOZxYGjTlOl8eeKaIY5yHnFn486xBustDjWT6dG7pmjHOJd+33t0iitTPkK6tEvjxq4h2MozQ6WFSX/LkDUGfFwfhEZj1Auz/U4pyAi5Sznd7uKzznXeVHlI/Aywmk6j7fsUsEuCGADrWARXXwjxWQsUbIupDHJI7kF5dRktg0eN81IbiZXiTESic50iwS+t1oJgL83jAiBupLDCQqwziaWSoAFSeIR3P5Xv5az00wyIn35QRYTwdSYbz8pH8fxUUAtxnFvYmEmgI0wYXUXcCCSpeEVpXlsRhBnCEATxWylL9+EKCAYhe1NGstUa6356kS9NVvt3DU2fd+Wtbm/+lSbylJqsqkSm9CRhvoJVlvKPvF1RKY/FcPn5j4UfIMLn8D4UYb54BNsilTDXKnF4CfTobA0FpoW/LSp306wkXM+XaOJhZaFkcNM82ASNAWMrhrUbRfmyeI1FvRBTpN06WKxa9BK0o2E4Pd3zfBBEwPsv9sQBnmLVbLEIZ/Xe9LYwJu/Er17W6HYVBc7vmuk0xUQ+pqxdom5Fnp55SiytXLPYoMXNM4u4SNSCFWnrVIzKG3EGyMXo6n/BQOe+bX3FClY4PwydVhthOZ9NnS+ntiLh0fxtlUJHAuGaFoVmttpVMeum0p3WEXbcll94l1wM/gZ0Ccczop77VvN2I7TlsZCsuXf1WHvWEhjO8DPtyOVg2/mvK9QqboEth+7pD6NUQC1HN/TwvydGBARi9MZSzLE4b8Ru3XhX2PBxf8E1er2A6516o0w4sIA+lwURhAON82Kwe2iDAC1Watq4XHaGQ7skLcFOtI5lDxuM2gZe6WFIotPAhbaeYlU4to5cuarF1QrcZ/lwrLaCJl66JBocYZnrNlvm2+MBCTmUymPrYZVbjdlr/BxlMjmNmNI3SAAAAAElFTkSuQmCC"
+        }
+    ]);
+}
+
+const setTheme = (lf:LogicFlow) => {
+    lf.setTheme({
+        circle: {
+            stroke: '#000000',
+            strokeWidth: 1,
+            outlineColor: '#88f',
+        },
+        rect: {
+            outlineColor: '#88f',
+            strokeWidth: 1,
+        },
+        polygon: {
+            strokeWidth: 1,
+        },
+        polyline: {
+            stroke: '#000000',
+            hoverStroke: '#000000',
+            selectedStroke: '#000000',
+            outlineColor: '#88f',
+            strokeWidth: 1,
+        },
+        nodeText: {
+            color: '#000000',
+        },
+        edgeText: {
+            color: '#000000',
+            background: {
+                fill: '#f7f9ff',
+            },
+        },
+    });
+}
+
+export {setPatternItems,setTheme}

+ 58 - 0
src/components/gFlow/consts.ts

@@ -0,0 +1,58 @@
+// 流程审批规则-所有人
+const FlowCheckRuleAll = 0
+// 流程审批规则-角色
+const FlowCheckRuleRole = 1
+// 流程审批规则-部门
+const FlowCheckRuleDept = 2
+// 流程审批规则-部门负责人
+const FlowCheckRuleDeptLeader = 3
+// 流程审批规则-用户
+const FlowCheckRuleUser = 4
+// 流程审批规则-岗位
+const FlowCheckRulePost = 5
+// 流程审批规则-表单业务创建人
+const FlowCheckRuleFormCreator = 6
+// 流程审批规则-表单业务创建人所属部门
+const FlowCheckRuleFormCreatorDept = 7
+// 流程审批规则-表单业务创建人所属部门负责人
+const FlowCheckRuleFormCreatorDeptLeader = 8
+
+const FlowCheckRuleFormCreatorDeptPrev = 9
+
+const FlowCheckRuleFormCreatorDeptLeaderPrev = 10
+
+
+
+//节点类型-开始节点
+const NodeTypeStart = "start"
+//节点类型-结束节点
+const NodeTypeEnd = "end"
+//节点类型-任务节点
+const NodeTypeUserTask = "userTask"
+//节点类型-并行网关
+const NodeTypeConcurrent = "concurrent"
+//节点类型-互斥网关
+const NodeTypePush = "push"
+//节点类型-条件网关
+const NodeTypeCondition = "condition"
+export {
+    FlowCheckRuleAll,
+    FlowCheckRuleRole,
+    FlowCheckRuleDept,
+    FlowCheckRuleDeptLeader,
+    FlowCheckRuleUser,
+    FlowCheckRulePost,
+    FlowCheckRuleFormCreator,
+    FlowCheckRuleFormCreatorDept,
+    FlowCheckRuleFormCreatorDeptLeader,
+		FlowCheckRuleFormCreatorDeptPrev,
+	FlowCheckRuleFormCreatorDeptLeaderPrev,
+    NodeTypeStart,
+    NodeTypeEnd,
+    NodeTypeUserTask,
+    NodeTypeConcurrent,
+    NodeTypePush,
+    NodeTypeCondition
+}
+
+

+ 85 - 0
src/components/gFlow/flowLog.vue

@@ -0,0 +1,85 @@
+<template>
+  <template v-if="activities && activities.length>0">
+    <el-timeline style="width:100%;margin: 12px auto;padding: 8px;">
+      <el-timeline-item
+          v-for="(activity, index) in activities"
+          :key="index"
+          :type="activity.btn=='流程回退'||activity.btn=='退回修改'?'danger':'success'"
+          size="large"
+          hide-timestamp
+      >
+        <el-card>
+          <h4>{{activity.nodeName}}:{{activity.createdAt}}</h4>
+          <div style="margin-top: 5px;">
+            <div>
+              <span style="color: #999;">审批意见:</span>
+              <span>{{activity.content}}</span>
+            </div>
+            <div>
+              <span style="color: #999;">审批人:</span>
+              <span>{{activity.approvalUser?.userNickname}}</span>
+            </div>
+            <div>
+              <span style="color: #999;">审批操作:</span>
+              <span>{{activity.btn}}</span>
+            </div>
+            <div v-if="activity.art && activity.art.length>0">
+              <span style="color: #999;">附件:</span>
+              <el-link v-for="(file,fi) in activity.art" :key="fi" :href="proxy.getUpFileUrl(file.url)" target="_blank" type="primary">{{file.name}}</el-link>
+            </div>
+          </div>
+        </el-card>
+      </el-timeline-item>
+    </el-timeline>
+    <pagination
+        v-show="tableData.total>0"
+        :total="tableData.total"
+        v-model:page="tableData.param.pageNum"
+        v-model:limit="tableData.param.pageSize"
+        @pagination="getLogList"
+        layout="prev, pager, next"
+    />
+  </template>
+  <template v-else>
+    <el-empty description="没有数据" />
+  </template>
+</template>
+
+<script setup lang="ts">
+  import {FlowLogData} from "/@/components/gFlow/model";
+  import {checkLog} from "/@/api/flow/flowModel";
+  import {getCurrentInstance, ref} from "vue";
+  defineOptions({ name: "flowLog"})
+  const {proxy} = <any>getCurrentInstance();
+  const props = defineProps({
+    formId:{
+      type:Number,
+      default:0
+    },
+    formTable:{
+      type:String,
+      default:''
+    }
+  })
+  const tableData = ref({
+    total:0,
+    param:{
+      formId:props.formId,
+      formTable:props.formTable,
+      pageNum: 1,
+      pageSize: 10,
+    }
+  })
+  const activities = ref<FlowLogData[]>()
+
+  const getLogList = ()=>{
+    checkLog(tableData.value.param).then((response:any)=>{
+      activities.value = response.data.list
+      tableData.value.total = response.data.total
+    })
+  }
+  defineExpose({getLogList})
+</script>
+<style scoped lang="scss">
+
+</style>

+ 74 - 0
src/components/gFlow/model.ts

@@ -0,0 +1,74 @@
+export interface WfCheckFormData {
+    sup:string|undefined;
+    wfTitle:string|undefined;
+    wfFid:string|undefined;
+    wfType:string|undefined;
+    wfStatusField:string|undefined;
+    flowId:string|undefined;
+    flowProcess:string|undefined;
+    runId:string|undefined;
+    runProcess:string|undefined;
+    npid:string|undefined;
+    wfMode:string|undefined;
+    checkCon:string|undefined;
+    wfBackFlow:string|undefined;
+    art:any;
+    submitToSave:string|undefined;
+    nodeId:string|undefined;
+    isProxy:boolean;
+}
+
+export interface WfOptionsData{
+    id:number;
+    name:string;
+}
+
+export interface wfStartFormData{
+    wfType:string|undefined;
+    wfTitle:string|undefined;
+    wfStatusField:string|undefined;
+    wfFid:string|undefined;
+    wfId:string|undefined;
+    newType:string|undefined;
+    checkCon:string|undefined;
+}
+
+export interface nodeOption{
+    nodeId:string;
+    nodeText:any;
+}
+
+export interface checkFlowInfoData{
+    preprocess:nodeOption[];
+    nodeInfo:NodeInfoData
+}
+
+export interface NodeInfoData{
+    nodeId:string;
+    nextNode:NodeInfoData[]
+    nodeText:any,
+    todo:string[],
+    rollback:number;
+}
+
+export interface FlowRunInfo{
+    runId:number|undefined;
+    formId:number|undefined;
+    formTable:string|undefined;
+}
+
+export interface User{
+    id:number;
+    userNickname:string;
+}
+
+export interface FlowLogData{
+    approvalUser:User;
+    art:any[];
+    btn:string;
+    content:string;
+    createdAt:string;
+    id:number;
+    uid:number;
+    nodeName:string;
+}

+ 308 - 0
src/components/gFlow/propertySetting/CommonProperty.vue

@@ -0,0 +1,308 @@
+<template>
+  <div>
+    <el-form label-width="130px" :model="formData">
+      <el-form-item label="节点名称">
+        <el-input v-model="formData.text" :disabled="readonly"></el-input>
+      </el-form-item>
+      <el-form-item label="审核方式" v-if="nodeType===NodeTypeStart">
+        <el-select v-model="formData.actionRule" placeholder="请选择审核方式" clearable :disabled="readonly">
+          <el-option v-for="item in actionRuleOption"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="接收方式" v-else>
+        <el-select v-model="formData.actionRule" placeholder="请选择接收方式" clearable :disabled="readonly">
+          <el-option v-for="item in actionRuleOption"
+                     :key="item.value"
+                     :label="item.label"
+                     :value="item.value"
+          />
+        </el-select>
+      </el-form-item>
+			<el-form-item label="指定上级部门" v-show="formData.actionRule===FlowCheckRuleFormCreatorDeptPrev || formData.actionRule===FlowCheckRuleFormCreatorDeptLeaderPrev">
+				<el-input-number
+					v-model="formData.deptProv"
+					style="width: 200px"
+					placeholder="Please input"
+				>
+					<template #prefix><span>上</span></template>
+					<template #suffix><span>级部门</span></template>
+				</el-input-number>
+			</el-form-item>
+      <el-form-item label="指定角色" v-show="formData.actionRule===FlowCheckRuleRole">
+        <el-cascader
+            :options="roleList"
+            :props="{ checkStrictly: true,emitPath: false, value: 'id', label: 'name',multiple: true }"
+            placeholder="请选择角色"
+            clearable
+            class="w100"
+            v-model="formData.roleIds"
+            :disabled="readonly"
+        >
+          <template #default="{ node, data }">
+            <span>{{ data.name }}</span>
+            <span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
+          </template>
+        </el-cascader>
+      </el-form-item>
+      <el-form-item label="指定部门" prop="deptId" v-show="formData.actionRule===FlowCheckRuleDept ||formData.actionRule===FlowCheckRuleDeptLeader">
+        <el-cascader
+            :options="deptData"
+            :props="{ checkStrictly: true,emitPath: false, value: 'deptId', label: 'deptName',multiple: true }"
+            placeholder="请选择部门"
+            clearable
+            class="w100"
+            v-model="formData.deptIds"
+            :disabled="readonly"
+        >
+          <template #default="{ node, data }">
+            <span>{{ data.deptName }}</span>
+            <span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
+          </template>
+        </el-cascader>
+      </el-form-item>
+      <el-form-item label="指定岗位" prop="postIds" v-show="formData.actionRule===FlowCheckRulePost">
+        <el-select v-model="formData.postIds" placeholder="请选择" clearable class="w100" multiple :disabled="readonly">
+          <el-option
+              v-for="post in postList"
+              :key="'post-'+post.postId"
+              :label="post.postName"
+              :value="post.postId">
+          </el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="指定人员"  v-show="formData.actionRule===FlowCheckRuleUser">
+        <select-user v-model="formData.userIds"></select-user>
+      </el-form-item>
+      <el-form-item label="多人审批处理规则"  >
+        <el-select v-model="formData.approveRule" placeholder="请选择多人审批处理规则" style="width: 100%" :disabled="readonly">
+          <el-option v-for="item in approveRuleOption"
+                     :key="item.value"
+                     :label="item.label"
+                     :value="item.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="网关审批处理规则" v-show="nodeType===NodeTypeConcurrent||nodeType===NodeTypePush||nodeType===NodeTypeCondition">
+        <el-select v-model="nodeType" placeholder="请选择多人审批处理规则" :disabled="true" style="width: 100%">
+          <el-option v-for="item in conditionRuleOption"
+                     :key="item.value"
+                     :label="item.label"
+                     :value="item.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="发送通知" >
+        <el-checkbox-group v-model="formData.notice" :disabled="readonly">
+          <el-checkbox value="sms" >短信</el-checkbox>
+          <el-checkbox value="email" >邮件</el-checkbox>
+          <el-checkbox value="innerNotice" >站内通知</el-checkbox>
+        </el-checkbox-group>
+      </el-form-item>
+      <el-form-item label="允许退回" v-show="nodeType!==NodeTypeStart">
+        <el-radio-group v-model="formData.rollback" :disabled="readonly">
+          <el-radio :value="1">是</el-radio>
+          <el-radio :value="0">否</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="分支条件" v-show="nodeType===NodeTypeCondition">
+        <Branch ref="branchRef" :modelValue="formData.nodeExt" @setNodeExt="setNodeExt"></Branch>
+      </el-form-item>
+       <el-form-item>
+        <el-button type="primary" @click="onSubmit" v-if="!readonly">保存</el-button>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+<script setup lang="ts">
+import {NodeConditionData} from "/@/components/gFlow/propertySetting/model";
+
+interface UserInfo  {
+  userNickname:string;
+  userId:number;
+}
+interface PostInfo{
+  postId:number;
+  postName:string;
+}
+import {getDeptTree, getParams, getUserByIds} from "/@/api/system/user";
+import selectUser from "/@/components/selectUser/index.vue";
+import LogicFlow from "@logicflow/core";
+import {computed, getCurrentInstance, onMounted, reactive, ref, toRefs} from "vue";
+import Branch from "/@/components/gFlow/propertySetting/branch.vue"
+import {
+  FlowCheckRuleAll,
+  FlowCheckRuleDept,
+  FlowCheckRuleDeptLeader,
+  FlowCheckRuleFormCreator,
+  FlowCheckRuleFormCreatorDept,
+  FlowCheckRuleFormCreatorDeptLeader,
+	FlowCheckRuleFormCreatorDeptPrev,
+	FlowCheckRuleFormCreatorDeptLeaderPrev,
+  FlowCheckRulePost,
+  FlowCheckRuleRole,
+  FlowCheckRuleUser, NodeTypeConcurrent, NodeTypeCondition, NodeTypePush, NodeTypeStart
+} from "/@/components/gFlow/consts";
+defineOptions({ name: "CommonProperty"})
+const branchRef = ref()
+const { proxy } = <any>getCurrentInstance();
+const props = defineProps({
+  nodeData: {
+    type: Object,
+    default: () => {
+      return null
+    }
+  },
+  lf:{
+    type:LogicFlow,
+    default: () => {
+      return {} as LogicFlow
+    }
+  },
+  readonly:{
+    type:Boolean,
+    default:false
+  }
+})
+const nodeType = computed(()=>{
+  return props.nodeData.type.replace('Done','')
+})
+const emit = defineEmits(['onClose'])
+const selectUserRef =ref()
+const state = reactive({
+  text: '',
+  roleList:[],//角色选项列表
+  postList:[] as PostInfo[],//岗位选项列表
+  deptData:[],//部门选项列表
+  actionRuleOption:[
+    {
+      label:'任何人',
+      value:FlowCheckRuleAll
+    },
+    {
+      label:'指定角色',
+      value:FlowCheckRuleRole
+    },
+    {
+      label:'指定部门',
+      value:FlowCheckRuleDept
+    },
+    {
+      label:'指定部门负责人',
+      value:FlowCheckRuleDeptLeader
+    },
+    {
+      label:'指定人员',
+      value:FlowCheckRuleUser
+    },
+    {
+      label:'指定岗位',
+      value:FlowCheckRulePost
+    },
+    {
+      label:'表单业务创建人',
+      value:FlowCheckRuleFormCreator
+    },
+    {
+      label:'表单业务创建人所属部门',
+      value:FlowCheckRuleFormCreatorDept
+    },
+    {
+      label:'表单业务创建人所属部门负责人',
+      value:FlowCheckRuleFormCreatorDeptLeader
+    },
+		{
+			label:'表单业务创建人所属上级部门',
+			value:FlowCheckRuleFormCreatorDeptPrev
+		},
+		{
+			label:'表单业务创建人所属上级部门负责人',
+			value:FlowCheckRuleFormCreatorDeptLeaderPrev
+		}
+  ],
+  approveRuleOption:[
+    {
+      label:'抢办模式(任何人第一个处理则通过)',
+      value:1
+    },
+    {
+      label:'顺序执行(所有人按顺序执行完才通过)',
+      value:2
+    },
+    {
+      label:'并行执行(所有人执行完才通过)',
+      value:3
+    },
+  ],
+  //分支条件审核规则
+  conditionRuleOption:[
+    {label:"并行网关-所有分支都必须完成审核",value:NodeTypeConcurrent},
+    {label:"互斥网关-所有分支中只能有其中一条审核",value:NodeTypePush},
+    {label:"条件网关-符合条件的某条分或多条支进行审核",value:NodeTypeCondition},
+  ],
+  formData: {
+    text: '',
+    actionRule: undefined,
+    roleIds:[],
+    deptIds:[],
+    userIds:[],
+    postIds:[],
+    approveRule:'',
+    notice:[],
+    rollback:undefined,
+    nodeExt:[] as Array<NodeConditionData[]>,
+		deptProv:1
+  }
+})
+const { formData, deptData, roleList, postList, actionRuleOption, approveRuleOption, conditionRuleOption} = toRefs(state)
+onMounted(()=>{
+  const { properties, text } = props.nodeData
+  if (properties) {
+    state.formData = Object.assign({}, state.formData, properties)
+    //设置条件
+    branchRef.value.initNodeData(state.formData.nodeExt)
+  }
+  if (text && text.value) {
+    state.formData.text = text.value
+  }
+  if (text && text.value) {
+    state.text = text.value
+  }
+  getSelector()
+})
+const getSelector = () =>{
+  //获取角色岗位选项
+  getParams().then((res)=>{
+    const roles = res.data.roleList??[];
+    const roleAccess = res.data.roleAccess??[];
+    roles.map((item:any)=>{
+      if(!roleAccess.includes(item.id)){
+        item.disabled = true
+      }
+    })
+    state.roleList = proxy.handleTree(roles??[], "id","pid","children",true);
+    state.postList = res.data.posts??[];
+  });
+  getDeptTree().then((res)=>{
+    state.deptData = res.data.deps
+  })
+}
+const onSubmit = () =>{
+  branchRef.value.setNodeExt()
+  const { id } = props.nodeData
+  props.lf.setProperties(id, {
+    ...state.formData
+  });
+  props.lf.updateText(id, state.formData.text);
+  emit('onClose')
+}
+const setNodeExt = (data:Array<NodeConditionData[]>) =>{
+  state.formData.nodeExt = data
+}
+</script>
+<style scoped>
+
+</style>

+ 41 - 0
src/components/gFlow/propertySetting/PropertyDialog.vue

@@ -0,0 +1,41 @@
+<template>
+  <div class="property-dialog">
+    <CommonProperty
+      :nodeData="nodeData"
+      :lf="lf"
+      @onClose="handleClose"
+      :readonly="readonly"/>
+  </div>
+</template>
+<script setup lang="ts">
+import CommonProperty from './CommonProperty.vue'
+import LogicFlow from "@logicflow/core";
+defineOptions({ name: "PropertyDialog"})
+defineProps({
+  nodeData: {
+    type: Object,
+    default: () => {
+      return null
+    }
+  },
+  lf: {
+    type:LogicFlow,
+    default: () => {
+      return {} as LogicFlow
+    }
+  },
+  readonly:{
+    type:Boolean,
+    default:false
+  }
+})
+const emit = defineEmits(['setPropertiesFinish'])
+const handleClose = () => {
+  emit('setPropertiesFinish')
+}
+</script>
+<style>
+.property-dialog{
+  padding: 20px;
+}
+</style>

+ 237 - 0
src/components/gFlow/propertySetting/branch.vue

@@ -0,0 +1,237 @@
+<template>
+  <el-container>
+    <el-main style="padding: 0 20px 20px 20px">
+      <div class="top-tips">满足以下条件时进入当前分支</div>
+      <template v-for="(conditionGroup, conditionGroupIdx) in conditionList">
+        <div
+            class="or-branch-link-tip"
+            v-if="conditionGroupIdx != 0">
+          或满足
+        </div>
+        <div class="condition-group-editor">
+          <div class="header">
+            <span>条件组 {{ conditionGroupIdx + 1 }}</span>
+            <div @click="deleteConditionGroup(conditionGroupIdx)">
+              <el-icon class="branch-delete-icon"><ele-Delete /></el-icon>
+            </div>
+          </div>
+
+          <div class="main-content">
+            <!-- 单个条件 -->
+            <div class="condition-content-box cell-box">
+              <div>描述</div>
+              <div>条件字段</div>
+              <div>运算符</div>
+              <div>值</div>
+            </div>
+            <div
+                class="condition-content"
+                v-for="(condition, idx) in conditionGroup">
+              <div class="condition-relation">
+                <span>{{ idx == 0 ? '当' : '且' }}</span>
+                <div @click="deleteConditionList(conditionGroup, idx)">
+                  <el-icon class="branch-delete-icon"><ele-Delete /></el-icon>
+                </div>
+              </div>
+              <div class="condition-content">
+                <div class="condition-content-box">
+                  <el-input
+                      v-model="condition.label"
+                      placeholder="描述" />
+                  <el-input
+                      v-model="condition.field"
+                      placeholder="条件字段" />
+                  <el-select
+                      v-model="condition.operator"
+                      placeholder="请选择">
+                    <el-option
+                        label="等于"
+                        value="=="></el-option>
+                    <el-option
+                        label="不等于"
+                        value="!="></el-option>
+                    <el-option
+                        label="大于"
+                        value=">"></el-option>
+                    <el-option
+                        label="大于等于"
+                        value=">="></el-option>
+                    <el-option
+                        label="小于"
+                        value="<"></el-option>
+                    <el-option
+                        label="小于等于"
+                        value="<="></el-option>
+                    <el-option
+                        label="包含"
+                        value="include"></el-option>
+                    <el-option
+                        label="不包含"
+                        value="notInclude"></el-option>
+                  </el-select>
+                  <el-input
+                      v-model="condition.value"
+                      placeholder="值" />
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class="sub-content">
+            <el-button
+                link
+                type="primary"
+                @click="addConditionList(conditionGroup)">
+              <el-icon><ele-Plus /></el-icon>
+              添加条件
+            </el-button>
+          </div>
+        </div>
+      </template>
+      <el-button
+          style="width: 100%"
+          type="info"
+          text
+          bg
+          @click="addConditionGroup">
+        <el-icon><ele-Plus /></el-icon>
+        添加条件组
+      </el-button>
+    </el-main>
+  </el-container>
+</template>
+<script lang="ts" setup>
+import {NodeConditionData} from "/@/components/gFlow/propertySetting/model";
+import {onMounted, ref, watch} from "vue";
+defineOptions({ name: "Branch"})
+const emit = defineEmits(['setNodeExt'])
+const conditionList = ref<Array<NodeConditionData[]>>([])
+const initNodeData = (data:Array<NodeConditionData[]>)=>{
+  conditionList.value = data
+}
+const addConditionGroup = () => {
+  addConditionList(conditionList.value[conditionList.value.push([] as never) - 1])
+}
+const addConditionList = (conditionList:NodeConditionData[]) => {
+  conditionList.push({
+    label: '',
+    field: '',
+    operator: '',
+    value: '',
+  })
+}
+const deleteConditionGroup = (idx:number) => {
+  conditionList.value.splice(idx, 1)
+}
+const deleteConditionList = (conditionList:NodeConditionData[],idx:number) => {
+  conditionList.splice(idx,1)
+}
+const setNodeExt = ()=>{
+  emit('setNodeExt',conditionList.value)
+}
+defineExpose({initNodeData,setNodeExt})
+</script>
+
+<style scoped lang="scss">
+.top-tips {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 12px;
+  color: #646a73;
+}
+
+.or-branch-link-tip {
+  margin: 10px 0;
+  color: #646a73;
+}
+
+.condition-group-editor {
+  user-select: none;
+  border-radius: 4px;
+  border: 1px solid #e4e5e7;
+  position: relative;
+  margin-bottom: 16px;
+
+  .branch-delete-icon {
+    font-size: 18px;
+  }
+
+  .header {
+    background-color: #f4f6f8;
+    padding: 0 12px;
+    font-size: 14px;
+    color: #171e31;
+    height: 36px;
+    display: flex;
+    align-items: center;
+
+    span {
+      flex: 1;
+    }
+  }
+
+  .main-content {
+    padding: 0 12px;
+
+    .condition-relation {
+      color: #9ca2a9;
+      display: flex;
+      align-items: center;
+      height: 36px;
+      display: flex;
+      justify-content: space-between;
+      padding: 0 2px;
+    }
+
+    .condition-content-box {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+
+      div {
+        width: 100%;
+        min-width: 120px;
+      }
+
+      div:not(:first-child) {
+        margin-left: 16px;
+      }
+    }
+
+    .cell-box {
+      div {
+        padding: 16px 0;
+        width: 100%;
+        min-width: 120px;
+        color: #909399;
+        font-size: 14px;
+        font-weight: 600;
+        text-align: center;
+      }
+    }
+
+    .condition-content {
+      display: flex;
+      flex-direction: column;
+
+      :deep(.el-input__wrapper) {
+        border-top-left-radius: 0;
+        border-bottom-left-radius: 0;
+      }
+
+      .content {
+        flex: 1;
+        padding: 0 0 4px 0;
+        display: flex;
+        align-items: center;
+        min-height: 31.6px;
+        flex-wrap: wrap;
+      }
+    }
+  }
+
+  .sub-content {
+    padding: 12px;
+  }
+}
+</style>

+ 7 - 0
src/components/gFlow/propertySetting/model.ts

@@ -0,0 +1,7 @@
+export interface NodeConditionData{
+    label:string|undefined;
+    field:string|undefined;
+    value:string|undefined;
+    operator:string|undefined;
+}
+

+ 16 - 0
src/components/gFlow/registerNode/index.ts

@@ -0,0 +1,16 @@
+import registerEnd from '/@/components/gFlow/registerNode/registerEnd'
+import registerEndDone from '/@/components/gFlow/registerNode/registerEndDone'
+import registerStart  from "/@/components/gFlow/registerNode/registerStart";
+import registerStartDone  from "/@/components/gFlow/registerNode/registerStartDone";
+import registerConcurrent from "/@/components/gFlow/registerNode/registerConcurrent"
+import registerConcurrentDone from "/@/components/gFlow/registerNode/registerConcurrentDone"
+import registerPush from "/@/components/gFlow/registerNode/registerPush"
+import registerPushDone from "/@/components/gFlow/registerNode/registerPushDone"
+import registerCondition from "/@/components/gFlow/registerNode/registerCondition"
+import registerConditionDone from "/@/components/gFlow/registerNode/registerConditionDone"
+import registerUserTask from "/@/components/gFlow/registerNode/registerUserTask"
+import registerUserTaskDone from "/@/components/gFlow/registerNode/registerUserTaskDone"
+import registerEdgeDone from "/@/components/gFlow/registerNode/registerEdgeDone"
+export {registerEnd,registerEndDone,registerStart,registerStartDone,registerConcurrent,registerConcurrentDone,
+    registerPush,registerPushDone,registerCondition,registerConditionDone,registerUserTask,registerUserTaskDone,
+    registerEdgeDone}

+ 100 - 0
src/components/gFlow/registerNode/registerConcurrent.ts

@@ -0,0 +1,100 @@
+import LogicFlow, {PolygonNode, PolygonNodeModel,h} from "@logicflow/core";
+
+export default function registerConcurrent (lf:LogicFlow) {
+  lf.register('concurrent', () => {
+    class Node extends PolygonNode {
+      getIconShape () {
+        const {model} = this.props
+        const {stroke} = model.getNodeStyle()
+        return h(
+          'svg',
+          {
+            x: 20,
+            y: 18,
+            width: 30,
+            height: 30,
+            viewBox: '0 0 1126 1024'
+          },
+          h(
+            'path',
+            {
+              fill: stroke,
+              d: 'M918.7328 90.112h-374.784c-16.7936 0-30.72 13.9264-30.72 30.72v782.336c0 16.7936 13.9264 30.72 30.72 30.72h374.784c16.7936 0 30.72-13.9264 30.72-30.72v-782.336c0-16.7936-13.9264-30.72-30.72-30.72z m-74.1376 61.44c-72.0896 84.7872-142.9504 206.848-142.9504 357.9904 0 130.2528-47.104 253.5424-126.976 336.6912V151.552h269.9264z m-210.944 720.896c81.5104-93.7984 129.024-224.8704 129.024-362.9056 0-130.6624 61.44-237.9776 124.928-314.1632V872.448h-253.952zM348.5696 146.2272c-7.7824-6.5536-19.6608-1.2288-19.6608 9.0112v47.5136H105.6768c-16.7936 0-30.72 13.9264-30.72 30.72s13.9264 30.72 30.72 30.72h223.232v47.5136c0 10.24 11.8784 15.5648 19.6608 9.0112l90.5216-78.2336c5.3248-4.9152 5.3248-13.1072 0-18.0224L348.5696 146.2272zM348.5696 420.6592c-7.7824-6.5536-19.6608-1.2288-19.6608 9.0112v47.5136H105.6768c-16.7936 0-30.72 13.9264-30.72 30.72s13.9264 30.72 30.72 30.72h223.232v47.5136c0 10.24 11.8784 15.5648 19.6608 9.0112l90.5216-78.2336c5.3248-4.9152 5.3248-13.1072 0-18.0224l-90.5216-78.2336zM348.5696 695.0912c-7.7824-6.5536-19.6608-1.2288-19.6608 9.0112v47.5136H105.6768c-16.7936 0-30.72 13.9264-30.72 30.72s13.9264 30.72 30.72 30.72h223.232v47.5136c0 10.24 11.8784 15.5648 19.6608 9.0112l90.5216-78.2336c5.3248-4.9152 5.3248-13.1072 0-18.0224l-90.5216-78.2336z'
+            }
+          )
+        )
+      }
+      getShape () {
+        const {model} = this.props
+        const {width, height, x, y, points} = model
+        const {fill, fillOpacity, strokeWidth, stroke, strokeOpacity,} = model.getNodeStyle()
+        const transform = `matrix(1 0 0 1 ${x - width / 2} ${y - height / 2})`
+        const pointsPath = points.map((point:any[]) => point.join(',')).join(' ')
+        return h(
+          'g',
+          {
+            transform
+          },
+          [
+            h(
+              'polygon',
+              {
+                points: pointsPath,
+                fill,
+                stroke,
+                strokeWidth,
+                strokeOpacity,
+                fillOpacity
+              }
+            ),
+            this.getIconShape()
+          ]
+        )
+      }
+    }
+    class Model extends PolygonNodeModel {
+      constructor (data:any, graphModel:any) {
+        data.text = {
+          value: (data.text && data.text.value) || '',
+          x: data.x,
+          y: data.y + 50
+        }
+        super(data, graphModel)
+        const lenght = 35
+        this.points = [
+          [lenght, 0],
+          [lenght * 2, lenght],
+          [lenght, lenght * 2],
+          [0, lenght]
+        ]
+      }
+      initNodeData(data:any) {
+        super.initNodeData(data)
+        const lenght = 35
+        this.points = [
+          [lenght, 0],
+          [lenght * 2, lenght],
+          [lenght, lenght * 2],
+          [0, lenght]
+        ]
+      }
+      // 自定义锚点样式
+      getAnchorStyle() {
+        const style = super.getAnchorStyle();
+        return Object.assign({}, style, {
+          stroke: 'rgb(24, 125, 255)',
+          r: 3,
+          hover: {
+            r: 8,
+            fill: 'rgb(24, 125, 255)',
+            stroke: 'rgb(24, 125, 255)',
+          },
+        });
+      }
+    }
+    return {
+      view: Node,
+      model: Model
+    }
+  })
+}

+ 107 - 0
src/components/gFlow/registerNode/registerConcurrentDone.ts

@@ -0,0 +1,107 @@
+import LogicFlow, {PolygonNode, PolygonNodeModel,h} from "@logicflow/core";
+
+export default function registerConcurrentDone (lf:LogicFlow) {
+  lf.register('concurrentDone', () => {
+    class Node extends PolygonNode {
+      getIconShape () {
+        const {model} = this.props
+        const {stroke} = model.getNodeStyle()
+        return h(
+          'svg',
+          {
+            x: 20,
+            y: 18,
+            width: 30,
+            height: 30,
+            viewBox: '0 0 1126 1024'
+          },
+          h(
+            'path',
+            {
+              fill: stroke,
+              d: 'M918.7328 90.112h-374.784c-16.7936 0-30.72 13.9264-30.72 30.72v782.336c0 16.7936 13.9264 30.72 30.72 30.72h374.784c16.7936 0 30.72-13.9264 30.72-30.72v-782.336c0-16.7936-13.9264-30.72-30.72-30.72z m-74.1376 61.44c-72.0896 84.7872-142.9504 206.848-142.9504 357.9904 0 130.2528-47.104 253.5424-126.976 336.6912V151.552h269.9264z m-210.944 720.896c81.5104-93.7984 129.024-224.8704 129.024-362.9056 0-130.6624 61.44-237.9776 124.928-314.1632V872.448h-253.952zM348.5696 146.2272c-7.7824-6.5536-19.6608-1.2288-19.6608 9.0112v47.5136H105.6768c-16.7936 0-30.72 13.9264-30.72 30.72s13.9264 30.72 30.72 30.72h223.232v47.5136c0 10.24 11.8784 15.5648 19.6608 9.0112l90.5216-78.2336c5.3248-4.9152 5.3248-13.1072 0-18.0224L348.5696 146.2272zM348.5696 420.6592c-7.7824-6.5536-19.6608-1.2288-19.6608 9.0112v47.5136H105.6768c-16.7936 0-30.72 13.9264-30.72 30.72s13.9264 30.72 30.72 30.72h223.232v47.5136c0 10.24 11.8784 15.5648 19.6608 9.0112l90.5216-78.2336c5.3248-4.9152 5.3248-13.1072 0-18.0224l-90.5216-78.2336zM348.5696 695.0912c-7.7824-6.5536-19.6608-1.2288-19.6608 9.0112v47.5136H105.6768c-16.7936 0-30.72 13.9264-30.72 30.72s13.9264 30.72 30.72 30.72h223.232v47.5136c0 10.24 11.8784 15.5648 19.6608 9.0112l90.5216-78.2336c5.3248-4.9152 5.3248-13.1072 0-18.0224l-90.5216-78.2336z'
+            }
+          )
+        )
+      }
+      getShape () {
+        const {model} = this.props
+        const {width, height, x, y, points} = model
+        const {fill, fillOpacity, strokeWidth, stroke, strokeOpacity,} = model.getNodeStyle()
+        const transform = `matrix(1 0 0 1 ${x - width / 2} ${y - height / 2})`
+        const pointsPath = points.map((point:any[]) => point.join(',')).join(' ')
+        return h(
+          'g',
+          {
+            transform
+          },
+          [
+            h(
+              'polygon',
+              {
+                points: pointsPath,
+                fill,
+                stroke,
+                strokeWidth,
+                strokeOpacity,
+                fillOpacity
+              }
+            ),
+            this.getIconShape()
+          ]
+        )
+      }
+    }
+    class Model extends PolygonNodeModel {
+      constructor (data:any, graphModel:any) {
+        data.text = {
+          value: (data.text && data.text.value) || '',
+          x: data.x,
+          y: data.y + 50
+        }
+        super(data, graphModel)
+        const lenght = 35
+        this.points = [
+          [lenght, 0],
+          [lenght * 2, lenght],
+          [lenght, lenght * 2],
+          [0, lenght]
+        ]
+      }
+      initNodeData(data:any) {
+        super.initNodeData(data)
+        const lenght = 35
+        this.points = [
+          [lenght, 0],
+          [lenght * 2, lenght],
+          [lenght, lenght * 2],
+          [0, lenght]
+        ]
+      }
+      // 自定义锚点样式
+      getAnchorStyle() {
+        const style = super.getAnchorStyle();
+        return Object.assign({}, style, {
+          stroke: 'rgb(24, 125, 255)',
+          r: 3,
+          hover: {
+            r: 8,
+            fill: 'rgb(24, 125, 255)',
+            stroke: 'rgb(24, 125, 255)',
+          },
+        });
+      }
+      getNodeStyle() {
+        const style = super.getNodeStyle();
+        style.stroke = "#1296db";
+        style.strokeWidth = 2;
+        style.fill = '#d5e8d4';
+        return style;
+      }
+    }
+    return {
+      view: Node,
+      model: Model
+    }
+  })
+}

+ 100 - 0
src/components/gFlow/registerNode/registerCondition.ts

@@ -0,0 +1,100 @@
+import LogicFlow, {PolygonNode, PolygonNodeModel,h} from "@logicflow/core";
+
+export default function registerCondition (lf:LogicFlow) {
+  lf.register('condition', () => {
+    class Node extends PolygonNode {
+      getIconShape () {
+        const {model} = this.props
+        const {stroke} = model.getNodeStyle()
+        return h(
+            'svg',
+            {
+              x: 20,
+              y: 18,
+              width: 30,
+              height: 30,
+              viewBox: '0 0 1126 1024'
+            },
+            h(
+                'path',
+                {
+                  fill: stroke,
+                  d: 'M832 708.032A128.064 128.064 0 0 1 800 960a128 128 0 0 1-32-251.968V576a32 32 0 0 0-32-32H288a32 32 0 0 0-32 32v132.032A128.064 128.064 0 0 1 224 960a128 128 0 0 1-32-251.968V544a64 64 0 0 1 64-64h224V315.968A128.064 128.064 0 0 1 512 64a128 128 0 0 1 32 251.968V480h224a64 64 0 0 1 64 64v164.032zM512 256a64 64 0 1 0 0-128 64 64 0 0 0 0 128zM224 896a64 64 0 1 0 0-128 64 64 0 0 0 0 128z m576 0a64 64 0 1 0 0-128 64 64 0 0 0 0 128z'
+                }
+            )
+        )
+      }
+      getShape () {
+        const {model} = this.props
+        const {width, height, x, y, points} = model
+        const {fill, fillOpacity, strokeWidth, stroke, strokeOpacity,} = model.getNodeStyle()
+        const transform = `matrix(1 0 0 1 ${x - width / 2} ${y - height / 2})`
+        const pointsPath = points.map((point:any[]) => point.join(',')).join(' ')
+        return h(
+            'g',
+            {
+              transform
+            },
+            [
+              h(
+                  'polygon',
+                  {
+                    points: pointsPath,
+                    fill,
+                    stroke,
+                    strokeWidth,
+                    strokeOpacity,
+                    fillOpacity
+                  }
+              ),
+              this.getIconShape()
+            ]
+        )
+      }
+    }
+    class Model extends PolygonNodeModel {
+      constructor (data:any, graphModel:any) {
+        data.text = {
+          value: (data.text && data.text.value) || '',
+          x: data.x,
+          y: data.y + 50
+        }
+        super(data, graphModel)
+        const lenght = 35
+        this.points = [
+          [lenght, 0],
+          [lenght * 2, lenght],
+          [lenght, lenght * 2],
+          [0, lenght]
+        ]
+      }
+      initNodeData(data:any) {
+        super.initNodeData(data)
+        const lenght = 35
+        this.points = [
+          [lenght, 0],
+          [lenght * 2, lenght],
+          [lenght, lenght * 2],
+          [0, lenght]
+        ]
+      }
+      // 自定义锚点样式
+      getAnchorStyle() {
+        const style = super.getAnchorStyle();
+        return Object.assign({}, style, {
+            stroke: 'rgb(24, 125, 255)',
+            r: 3,
+            hover: {
+              r: 8,
+              fill: 'rgb(24, 125, 255)',
+              stroke: 'rgb(24, 125, 255)',
+            },
+        });
+      }
+    }
+    return {
+      view: Node,
+      model: Model
+    }
+  })
+}

+ 111 - 0
src/components/gFlow/registerNode/registerConditionDone.ts

@@ -0,0 +1,111 @@
+import LogicFlow, {PolygonNode, PolygonNodeModel,h} from "@logicflow/core";
+
+export default function registerConditionDone (lf:LogicFlow) {
+  lf.register('conditionDone', () => {
+    class Node extends PolygonNode {
+      getIconShape () {
+        const {model} = this.props
+        const {stroke} = model.getNodeStyle()
+        return h(
+            'svg',
+            {
+              x: 20,
+              y: 18,
+              width: 30,
+              height: 30,
+              viewBox: '0 0 1126 1024'
+            },
+            h(
+                'path',
+                {
+                  fill: stroke,
+                  d: 'M832 708.032A128.064 128.064 0 0 1 800 960a128 128 0 0 1-32-251.968V576a32 32 0 0 0-32-32H288a32 32 0 0 0-32 32v132.032A128.064 128.064 0 0 1 224 960a128 128 0 0 1-32-251.968V544a64 64 0 0 1 64-64h224V315.968A128.064 128.064 0 0 1 512 64a128 128 0 0 1 32 251.968V480h224a64 64 0 0 1 64 64v164.032zM512 256a64 64 0 1 0 0-128 64 64 0 0 0 0 128zM224 896a64 64 0 1 0 0-128 64 64 0 0 0 0 128z m576 0a64 64 0 1 0 0-128 64 64 0 0 0 0 128z'
+                }
+            )
+        )
+      }
+      getShape () {
+        const {model} = this.props
+        const {width, height, x, y, points} = model
+        const {fill, fillOpacity, strokeWidth, stroke, strokeOpacity,} = model.getNodeStyle()
+        const transform = `matrix(1 0 0 1 ${x - width / 2} ${y - height / 2})`
+        const pointsPath = points.map((point:any[]) => point.join(',')).join(' ')
+        return h(
+            'g',
+            {
+              transform
+            },
+            [
+              h(
+                  'polygon',
+                  {
+                    points: pointsPath,
+                    fill,
+                    stroke,
+                    strokeWidth,
+                    strokeOpacity,
+                    fillOpacity
+                  }
+              ),
+              this.getIconShape()
+            ]
+        )
+      }
+    }
+    class Model extends PolygonNodeModel {
+      constructor (data:any, graphModel:any) {
+        data.text = {
+          value: (data.text && data.text.value) || '',
+          x: data.x,
+          y: data.y + 50
+        }
+        super(data, graphModel)
+        const lenght = 35
+        this.points = [
+          [lenght, 0],
+          [lenght * 2, lenght],
+          [lenght, lenght * 2],
+          [0, lenght]
+        ]
+      }
+      initNodeData(data:any) {
+        super.initNodeData(data)
+        const lenght = 35
+        this.points = [
+          [lenght, 0],
+          [lenght * 2, lenght],
+          [lenght, lenght * 2],
+          [0, lenght]
+        ]
+      }
+      // 自定义锚点样式
+      getAnchorStyle() {
+        const style = super.getAnchorStyle();
+        return Object.assign({}, style, {
+            stroke: 'rgb(24, 125, 255)',
+            r: 3,
+            hover: {
+              r: 8,
+              fill: 'rgb(24, 125, 255)',
+              stroke: 'rgb(24, 125, 255)',
+            },
+        });
+      }
+      getNodeStyle() {
+          const style = super.getNodeStyle();
+          const properties = this.properties;
+          if (properties.disabled) {
+              style.stroke = "#1B7FFF";
+          } else {
+              style.stroke = "rgb(24, 125, 255)";
+          }
+          style.fill = '#d5e8d4';
+          return style;
+      }
+    }
+    return {
+      view: Node,
+      model: Model
+    }
+  })
+}

+ 51 - 0
src/components/gFlow/registerNode/registerEdgeDone.ts

@@ -0,0 +1,51 @@
+import { PolylineEdge, PolylineEdgeModel, LogicFlow } from '@logicflow/core';
+import EdgeTextTheme = LogicFlow.EdgeTextTheme;
+
+class SequenceModel extends PolylineEdgeModel {
+    // 设置边样式
+    getEdgeStyle() {
+        const style = super.getEdgeStyle();
+        const { properties } = this;
+        if (properties.isstrokeDashed) {
+            style.strokeDasharray = '4, 4';
+        }
+        style.stroke = 'orange';
+        return style;
+    }
+
+    // 设置边文本样式
+    getTextStyle() {
+        const style: EdgeTextTheme = super.getTextStyle();
+        style.color = '#3451F1';
+        style.fontSize = 20;
+        style.background = Object.assign({}, style.background, {
+            fill: '#F2F131',
+        });
+        return style;
+    }
+
+    // 设置 hover 轮廓样式
+    getOutlineStyle() {
+        const style = super.getOutlineStyle();
+        style.stroke = 'blue';
+        return style;
+    }
+    setAttributes() {
+        this.isAnimation = true
+    }
+
+    getEdgeAnimationStyle() {
+        const style = super.getEdgeAnimationStyle()
+        style.strokeDasharray = '5 5'
+        style.animationDuration = '10s'
+        style.stroke  = '#7ebf7a'
+        return style
+    }
+}
+export default function registerEdgeDone(lf:LogicFlow) {
+    lf.register({
+        type: 'edgeDone',
+        view: PolylineEdge,
+        model: SequenceModel,
+    })
+}

+ 119 - 0
src/components/gFlow/registerNode/registerEnd.ts

@@ -0,0 +1,119 @@
+import LogicFlow, {CircleNode, CircleNodeModel,h} from "@logicflow/core";
+
+export default function registerEnd (lf:LogicFlow) {
+  lf.register('end', () => {
+    class EndNode extends CircleNode {
+      getIconShape () {
+        const {model} = this.props
+        const {
+          x,
+          y,
+          width,
+          height
+        } = model
+        const stroke = '#404040'
+        return h(
+          'svg',
+          {
+            x: x - width / 2,
+            y: y - height / 2,
+            width: 40,
+            height: 40,
+            viewBox: '0 0 1024 1024'
+          },
+          h(
+            'path',
+            {
+              fill: stroke,
+              d: 'M212.992 526.336 212.992 526.336 212.992 526.336 215.04 526.336 212.992 526.336Z'
+            }
+          ),
+          // 圆形外框隐藏
+          // h(
+          //   'path',
+          //   {
+          //     fill: stroke,
+          //     d: 'M817.152 202.752 817.152 202.752C737.28 122.88 628.736 75.776 509.952 75.776c-118.784 0-229.376 49.152-307.2 126.976l0 0c-77.824 77.824-126.976 186.368-126.976 307.2 0 118.784 49.152 229.376 126.976 307.2 77.824 79.872 188.416 126.976 307.2 126.976 120.832 0 229.376-49.152 307.2-126.976 79.872-77.824 126.976-186.368 126.976-307.2C946.176 389.12 897.024 280.576 817.152 202.752zM770.048 770.048c-65.536 65.536-157.696 108.544-260.096 108.544-102.4 0-194.56-40.96-260.096-108.544C184.32 704.512 141.312 612.352 141.312 509.952s40.96-194.56 108.544-260.096C317.44 184.32 409.6 141.312 509.952 141.312c100.352 0 192.512 40.96 258.048 106.496l2.048 2.048c65.536 65.536 108.544 157.696 108.544 260.096S837.632 704.512 770.048 770.048z'
+          //   }
+          // ),
+          h(
+            'path',
+            {
+              fill: stroke,
+              d: 'M724.992 296.96 724.992 296.96 296.96 296.96 296.96 724.992 724.992 724.992 724.992 296.96Z'
+            }
+          )
+        )
+      }
+      getShape () {
+        const {model} = this.props
+        const {x, y, r} = model
+        const {fill, stroke, strokeWidth} = model.getNodeStyle()
+        return h(
+          'g',
+          {
+          },
+          [
+            h(
+              'circle',
+              {
+                cx: x,
+                cy: y,
+                r,
+                fill,
+                stroke,
+                strokeWidth
+              }
+            ),
+            this.getIconShape()
+          ]
+        )
+      }
+    }
+    class EndModel extends CircleNodeModel {
+      initNodeData(data:any) {
+        data.text = {
+          value: (data.text && data.text.value) || '',
+          x: data.x,
+          y: data.y + 35
+        }
+        super.initNodeData(data)
+        this.setProperties({
+          r: 20,
+        })
+      }
+      // 自定义锚点样式
+      getAnchorStyle() {
+        const style = super.getAnchorStyle();
+        return Object.assign({}, style, {
+          stroke: 'rgb(24, 125, 255)',
+          r: 3,
+          hover: {
+            r: 8,
+            fill: 'rgb(24, 125, 255)',
+            stroke: 'rgb(24, 125, 255)',
+          },
+        });
+      }
+      // 自定义节点outline
+      getOutlineStyle() {
+        const style = super.getOutlineStyle();
+        style.stroke = '#88f'
+        return style
+      }
+      getConnectedSourceRules () {
+        const rules = super.getConnectedSourceRules()
+        const notAsTarget = {
+          message: '终止节点不能作为连线的起点',
+          validate: () => false
+        }
+        rules.push(notAsTarget)
+        return rules
+      }
+    }
+    return {
+      view: EndNode,
+      model: EndModel
+    }
+  })
+}

+ 130 - 0
src/components/gFlow/registerNode/registerEndDone.ts

@@ -0,0 +1,130 @@
+import LogicFlow, {CircleNode, CircleNodeModel,h} from "@logicflow/core";
+
+export default function registerEndDone (lf:LogicFlow) {
+  lf.register('endDone', () => {
+    class EndNode extends CircleNode {
+      getIconShape () {
+        const {model} = this.props
+        const {
+          x,
+          y,
+          width,
+          height
+        } = model
+        const stroke = '#1B7FFF'
+        return h(
+          'svg',
+          {
+            x: x - width / 2,
+            y: y - height / 2,
+            width: 40,
+            height: 40,
+            viewBox: '0 0 1024 1024'
+          },
+          h(
+            'path',
+            {
+              fill: stroke,
+              d: 'M212.992 526.336 212.992 526.336 212.992 526.336 215.04 526.336 212.992 526.336Z'
+            }
+          ),
+          // 圆形外框隐藏
+          // h(
+          //   'path',
+          //   {
+          //     fill: stroke,
+          //     d: 'M817.152 202.752 817.152 202.752C737.28 122.88 628.736 75.776 509.952 75.776c-118.784 0-229.376 49.152-307.2 126.976l0 0c-77.824 77.824-126.976 186.368-126.976 307.2 0 118.784 49.152 229.376 126.976 307.2 77.824 79.872 188.416 126.976 307.2 126.976 120.832 0 229.376-49.152 307.2-126.976 79.872-77.824 126.976-186.368 126.976-307.2C946.176 389.12 897.024 280.576 817.152 202.752zM770.048 770.048c-65.536 65.536-157.696 108.544-260.096 108.544-102.4 0-194.56-40.96-260.096-108.544C184.32 704.512 141.312 612.352 141.312 509.952s40.96-194.56 108.544-260.096C317.44 184.32 409.6 141.312 509.952 141.312c100.352 0 192.512 40.96 258.048 106.496l2.048 2.048c65.536 65.536 108.544 157.696 108.544 260.096S837.632 704.512 770.048 770.048z'
+          //   }
+          // ),
+          h(
+            'path',
+            {
+              fill: stroke,
+              d: 'M724.992 296.96 724.992 296.96 296.96 296.96 296.96 724.992 724.992 724.992 724.992 296.96Z'
+            }
+          )
+        )
+      }
+      getShape () {
+        const {model} = this.props
+        const {x, y, r} = model
+        const {fill, stroke, strokeWidth} = model.getNodeStyle()
+        return h(
+          'g',
+          {
+          },
+          [
+            h(
+              'circle',
+              {
+                cx: x,
+                cy: y,
+                r,
+                fill,
+                stroke,
+                strokeWidth
+              }
+            ),
+            this.getIconShape()
+          ]
+        )
+      }
+    }
+    class EndModel extends CircleNodeModel {
+      initNodeData(data:any) {
+        data.text = {
+          value: (data.text && data.text.value) || '',
+          x: data.x,
+          y: data.y + 35
+        }
+        super.initNodeData(data)
+        this.setProperties({
+          r: 20,
+        })
+      }
+      // 自定义锚点样式
+      getAnchorStyle() {
+        const style = super.getAnchorStyle();
+        return Object.assign({}, style, {
+          stroke: 'rgb(24, 125, 255)',
+          r: 3,
+          hover: {
+            r: 8,
+            fill: 'rgb(24, 125, 255)',
+            stroke: 'rgb(24, 125, 255)',
+          },
+        });
+      }
+      // 自定义节点outline
+      getOutlineStyle() {
+        const style = super.getOutlineStyle();
+        style.stroke = '#88f'
+        return style
+      }
+      getConnectedSourceRules () {
+        const rules = super.getConnectedSourceRules()
+        const notAsTarget = {
+          message: '终止节点不能作为连线的起点',
+          validate: () => false
+        }
+        rules.push(notAsTarget)
+        return rules
+      }
+      getNodeStyle() {
+        const style = super.getNodeStyle();
+        const properties = this.properties;
+        if (properties.disabled) {
+          style.stroke = "#1B7FFF";
+        } else {
+          style.stroke = "rgb(24, 125, 255)";
+        }
+        style.fill = '#d5e8d4';
+        return style;
+      }
+    }
+    return {
+      view: EndNode,
+      model: EndModel
+    }
+  })
+}

+ 86 - 0
src/components/gFlow/registerNode/registerPush.ts

@@ -0,0 +1,86 @@
+import LogicFlow, {PolygonNode, PolygonNodeModel,h} from "@logicflow/core";
+
+export default function registerPush (lf:LogicFlow) {
+  lf.register('push', () => {
+    class Node extends PolygonNode {
+      getIconShape () {
+        const {model} = this.props
+        const {
+          stroke
+        } = model.getNodeStyle()
+        return h(
+          'svg',
+          {
+            x: 18,
+            y: 18,
+            width: 30,
+            height: 30,
+            viewBox: '0 0 1024 1024'
+          },
+          h(
+            'path',
+            {
+              fill: stroke,
+              d: 'M982.357333 352.028444L841.955556 211.399111a45.511111 45.511111 0 0 0-32.540445-13.425778 45.511111 45.511111 0 0 0-45.511111 45.511111V705.422222a102.855111 102.855111 0 1 1-204.8 0V318.577778a193.877333 193.877333 0 0 0-386.844444 0v352.711111l-63.715556-63.715556a45.511111 45.511111 0 0 0-64.398222 64.398223L182.044444 812.600889a45.511111 45.511111 0 0 0 32.085334 13.425778 45.511111 45.511111 0 0 0 45.511111-45.511111V318.577778a102.855111 102.855111 0 0 1 204.8 0v386.844444a193.877333 193.877333 0 0 0 386.844444 0V352.711111l63.715556 63.715556a45.511111 45.511111 0 0 0 32.085333 13.198222 45.511111 45.511111 0 0 0 32.312889-77.596445z'
+            }
+          )
+        )
+      }
+      getShape () {
+        const {model} = this.props
+        const {width, height, x, y, points} = model
+        const {
+          fill,
+          fillOpacity,
+          strokeWidth,
+          stroke,
+          strokeOpacity,
+        } = model.getNodeStyle()
+        const transform = `matrix(1 0 0 1 ${x - width / 2} ${y - height / 2})`
+        const pointsPath = points.map((point:any[]) => point.join(',')).join(' ')
+        return h(
+          'g',
+          {
+            transform
+          },
+          [
+            h(
+              'polygon',
+              {
+                points: pointsPath,
+                fill,
+                stroke,
+                strokeWidth,
+                strokeOpacity,
+                fillOpacity
+              }
+            ),
+            this.getIconShape(),
+            //this.getPulsShape()
+          ]
+        )
+      }
+    }
+    class Model extends PolygonNodeModel {
+      constructor (data:any, graphModel:any) {
+        data.text = {
+          value: (data.text && data.text.value) || '',
+          x: data.x,
+          y: data.y + 50
+        }
+        super(data, graphModel)
+        const lenght = 35
+        this.points = [
+          [lenght, 0],
+          [lenght * 2, lenght],
+          [lenght, lenght * 2],
+          [0, lenght]
+        ]
+      }
+    }
+    return {
+      view: Node,
+      model: Model
+    }
+  })
+}

+ 93 - 0
src/components/gFlow/registerNode/registerPushDone.ts

@@ -0,0 +1,93 @@
+import LogicFlow, {PolygonNode, PolygonNodeModel,h} from "@logicflow/core";
+
+export default function registerPushDone (lf:LogicFlow) {
+  lf.register('pushDone', () => {
+    class Node extends PolygonNode {
+      getIconShape () {
+        const {model} = this.props
+        const {
+          stroke
+        } = model.getNodeStyle()
+        return h(
+          'svg',
+          {
+            x: 18,
+            y: 18,
+            width: 30,
+            height: 30,
+            viewBox: '0 0 1024 1024'
+          },
+          h(
+            'path',
+            {
+              fill: stroke,
+              d: 'M982.357333 352.028444L841.955556 211.399111a45.511111 45.511111 0 0 0-32.540445-13.425778 45.511111 45.511111 0 0 0-45.511111 45.511111V705.422222a102.855111 102.855111 0 1 1-204.8 0V318.577778a193.877333 193.877333 0 0 0-386.844444 0v352.711111l-63.715556-63.715556a45.511111 45.511111 0 0 0-64.398222 64.398223L182.044444 812.600889a45.511111 45.511111 0 0 0 32.085334 13.425778 45.511111 45.511111 0 0 0 45.511111-45.511111V318.577778a102.855111 102.855111 0 0 1 204.8 0v386.844444a193.877333 193.877333 0 0 0 386.844444 0V352.711111l63.715556 63.715556a45.511111 45.511111 0 0 0 32.085333 13.198222 45.511111 45.511111 0 0 0 32.312889-77.596445z'
+            }
+          )
+        )
+      }
+      getShape () {
+        const {model} = this.props
+        const {width, height, x, y, points} = model
+        const {
+          fill,
+          fillOpacity,
+          strokeWidth,
+          stroke,
+          strokeOpacity,
+        } = model.getNodeStyle()
+        const transform = `matrix(1 0 0 1 ${x - width / 2} ${y - height / 2})`
+        const pointsPath = points.map((point:any[]) => point.join(',')).join(' ')
+        return h(
+          'g',
+          {
+            transform
+          },
+          [
+            h(
+              'polygon',
+              {
+                points: pointsPath,
+                fill,
+                stroke,
+                strokeWidth,
+                strokeOpacity,
+                fillOpacity
+              }
+            ),
+            this.getIconShape(),
+            //this.getPulsShape()
+          ]
+        )
+      }
+    }
+    class Model extends PolygonNodeModel {
+      constructor (data:any, graphModel:any) {
+        data.text = {
+          value: (data.text && data.text.value) || '',
+          x: data.x,
+          y: data.y + 50
+        }
+        super(data, graphModel)
+        const lenght = 35
+        this.points = [
+          [lenght, 0],
+          [lenght * 2, lenght],
+          [lenght, lenght * 2],
+          [0, lenght]
+        ]
+      }
+      getNodeStyle() {
+        const style = super.getNodeStyle();
+        style.stroke = "#1296db";
+        style.strokeWidth = 2;
+        style.fill = '#d5e8d4';
+        return style;
+      }
+    }
+    return {
+      view: Node,
+      model: Model
+    }
+  })
+}

+ 70 - 0
src/components/gFlow/registerNode/registerStart.ts

@@ -0,0 +1,70 @@
+import LogicFlow, { h, CircleNode, CircleNodeModel } from "@logicflow/core";
+
+class RegisterStart extends CircleNode {
+    // 从iconfont下载的svg
+    getIcon() {
+        const { x, y, width, height } = this.props.model;
+        const style = this.props.model.getNodeStyle();
+        return h(
+            "svg",
+            {
+                // model中x,y表示中心坐标,而svg x,y表示左上角
+                x: x - width / 2,
+                y: y - height / 2,
+                viewBox: "0 0 1024 1024",
+                width,
+                height
+            },
+            [
+                h("path", {
+                    d:
+                        "M696 480H544V328c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v152H328c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h152v152c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V544h152c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8z",
+                    fill: style.stroke
+                })
+            ]
+        );
+    }
+    getShape() {
+        const { x, y, r } = this.props.model;
+        const style = this.props.model.getNodeStyle();
+        return h("g", {}, [
+            h("circle", {
+                ...style,
+                cx: x,
+                cy: y,
+                r
+            }),
+            this.getIcon()
+        ]);
+    }
+}
+
+class StartModel extends CircleNodeModel {
+    initNodeData(data:any) {
+        if (data.text && typeof data.text === "string") {
+            data.text = {
+                value: data.text,
+                x: data.x,
+                y: data.y + 40
+            };
+        }
+        super.initNodeData(data);
+        this.setProperties({
+            r: 20,
+        })
+    }
+    getNodeStyle() {
+        const style = super.getNodeStyle();
+        style.stroke = "#1296db";
+        style.strokeWidth = 4;
+        return style;
+    }
+}
+
+export default function registerStart(lf:LogicFlow){
+    lf.register({
+        type: "start",
+        model: StartModel,
+        view: RegisterStart
+    })
+}

+ 71 - 0
src/components/gFlow/registerNode/registerStartDone.ts

@@ -0,0 +1,71 @@
+import LogicFlow, { h, CircleNode, CircleNodeModel } from "@logicflow/core";
+
+class RegisterStartDone extends CircleNode {
+    // 从iconfont下载的svg
+    getIcon() {
+        const { x, y, width, height } = this.props.model;
+        const style = this.props.model.getNodeStyle();
+        return h(
+            "svg",
+            {
+                // model中x,y表示中心坐标,而svg x,y表示左上角
+                x: x - width / 2,
+                y: y - height / 2,
+                viewBox: "0 0 1024 1024",
+                width,
+                height
+            },
+            [
+                h("path", {
+                    d:
+                        "M696 480H544V328c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v152H328c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h152v152c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V544h152c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8z",
+                    fill: style.stroke
+                })
+            ]
+        );
+    }
+    getShape() {
+        const { x, y, r } = this.props.model;
+        const style = this.props.model.getNodeStyle();
+        return h("g", {}, [
+            h("circle", {
+                ...style,
+                cx: x,
+                cy: y,
+                r
+            }),
+            this.getIcon()
+        ]);
+    }
+}
+
+class StartDoneModel extends CircleNodeModel {
+    initNodeData(data:any) {
+        if (data.text && typeof data.text === "string") {
+            data.text = {
+                value: data.text,
+                x: data.x,
+                y: data.y + 40
+            };
+        }
+        super.initNodeData(data);
+        this.setProperties({
+            r: 20,
+        })
+    }
+    getNodeStyle() {
+        const style = super.getNodeStyle();
+        style.stroke = "#1296db";
+        style.strokeWidth = 2;
+        style.fill = '#d5e8d4';
+        return style;
+    }
+}
+
+export default function registerStartDone(lf:LogicFlow){
+    lf.register({
+        type: "startDone",
+        model: StartDoneModel,
+        view: RegisterStartDone
+    })
+}

+ 120 - 0
src/components/gFlow/registerNode/registerUserTask.ts

@@ -0,0 +1,120 @@
+import LogicFlow, { RectNode, RectNodeModel, h } from "@logicflow/core";
+
+class UserTaskView extends RectNode {
+    getLabelShape() {
+        const { model } = this.props;
+        const { x, y, width, height } = model;
+        const style = model.getNodeStyle();
+        return h(
+            "svg",
+            {
+                x: x - width / 2 + 5,
+                y: y - height / 2 + 5,
+                width: 25,
+                height: 25,
+                viewBox: "0 0 1274 1024"
+            },
+            [
+                h("path", {
+                    fill: style.stroke,
+                    d:
+                        "M690.366075 350.568358c0-98.876614-79.937349-179.048571-178.558027-179.048571-98.59935 0-178.515371 80.150629-178.515371 179.048571 0 98.833958 79.916021 178.963259 178.515371 178.963259C610.428726 529.531617 690.366075 449.380988 690.366075 350.568358M376.140632 350.568358c0-75.159877 60.72082-136.072649 135.667416-136.072649 74.989253 0 135.667416 60.912772 135.667416 136.072649 0 75.117221-60.678164 136.029993-135.667416 136.029993C436.861451 486.577022 376.140632 425.664251 376.140632 350.568358M197.284012 762.923936 197.284012 778.472049l15.526785 0 291.255186 0.127968L819.784387 778.472049l15.569441 0 0-15.548113c0-139.783721-136.413897-285.581938-311.026243-273.275681-10.002833 0.703824-24.740482 9.128385-34.658002 9.938849-8.573857 0.74648 13.692577 8.232609 14.396401 16.827793 9.021745-0.789136 6.313088 13.095393 15.505457 13.095393 150.597017 0 263.14488 103.07823 263.14488 224.62651l15.441473-15.590769-285.816546-0.042656-278.991585 1.81288 15.526785 15.612097c0-82.752645 75.095893-152.70849 136.861785-191.824044 7.25152-4.58552 8.659169-17.659585 4.862784-22.906273-6.846288-9.426977-19.877697-8.701825-28.046322-6.014496C285.262018 560.521203 197.284012 667.758394 197.284012 762.923936"
+                }),
+                h("path", {
+                    fill: style.stroke,
+                    d:
+                        "M512.31992 1.535616c-282.766642 0-512.021328 228.89211-512.021328 511.210864 0 282.46805 229.254686 511.25352 512.021328 511.25352 117.431975 0 228.828126-39.606098 318.810964-111.204199 10.791969-8.488545 12.540865-24.22861 3.988336-34.99925-8.616513-10.770641-24.356578-12.540865-35.127218-3.94568-81.174373 64.538532-181.586603 100.241606-287.650754 100.241606-255.210864 0-462.028493-206.561693-462.028493-461.367325 0-254.762976 206.817629-461.303341 462.028493-461.303341 255.210864 0 462.092477 206.561693 462.092477 461.303341 0 87.380821-24.33525 171.093227-69.614596 243.651087-7.272848 11.645089-3.668416 27.086562 8.040657 34.35941 11.709073 7.272848 27.10789 3.62576 34.402066-7.976672 50.184787-80.406565 77.143381-173.247355 77.143381-270.055153C1024.383904 230.427726 795.10789 1.535616 512.31992 1.535616z"
+                })
+            ]
+        );
+    }
+    getShape() {
+        const { model } = this.props;
+        const { x, y, width, height, radius, properties } = model;
+        const style = model.getNodeStyle();
+        //console.log(properties);
+        return h("g", {}, [
+            h("rect", {
+                ...style,
+                x: x - width / 2,
+                y: y - height / 2,
+                rx: radius,
+                ry: radius,
+                width,
+                height
+            }),
+            this.getLabelShape()
+        ]);
+    }
+}
+
+class UserTaskModel extends RectNodeModel {
+    constructor (data:any, graphModel:any) {
+        data.text = {
+            value: (data.text && data.text.value) || '',
+            x: data.x,
+            y: data.y + 40
+        }
+        super(data, graphModel)
+        const length = 35
+        this.points = [
+            [length, 0],
+            [length * 2, length],
+            [length, length * 2],
+            [0, length]
+        ]
+    }
+    setAttributes() {
+        const { scale = 1, width = 100, height = 40 } = this.properties;
+        this.width = width * (scale as number);
+        this.height = height * (scale as number);
+    }
+    getTextStyle() {
+        const style = super.getTextStyle();
+        style.fontSize = 12;
+        const properties = this.properties;
+        style.color =  "#404040";
+        return style;
+    }
+    getNodeStyle() {
+        const style = super.getNodeStyle();
+        const properties = this.properties;
+        if (properties.disabled) {
+            style.stroke = "#1B7FFF";
+        } else {
+            style.stroke = "rgb(24, 125, 255)";
+        }
+        return style;
+    }
+    getAnchorStyle() {
+        const style = super.getAnchorStyle();
+        return Object.assign({}, style, {
+            stroke: 'rgb(24, 125, 255)',
+            r: 3,
+            hover: {
+                r: 8,
+                fill: 'rgb(24, 125, 255)',
+                stroke: 'rgb(24, 125, 255)',
+            },
+        });
+    }
+    getAnchorLineStyle() {
+        const style = super.getAnchorLineStyle();
+        style.stroke = "rgb(24, 125, 255)";
+        return style;
+    }
+    getOutlineStyle() {
+        const style = super.getOutlineStyle();
+        style.stroke = "#1B7FFF";
+        style.hover!.stroke = "#1B7FFF";
+        return style;
+    }
+}
+
+export default function registerUserTask(lf:LogicFlow){
+    lf.register({
+        type: "userTask",
+        view: UserTaskView,
+        model: UserTaskModel
+    })
+}

+ 121 - 0
src/components/gFlow/registerNode/registerUserTaskDone.ts

@@ -0,0 +1,121 @@
+import LogicFlow, { RectNode, RectNodeModel, h } from "@logicflow/core";
+
+class UserTaskDoneView extends RectNode {
+    getLabelShape() {
+        const { model } = this.props;
+        const { x, y, width, height } = model;
+        const style = model.getNodeStyle();
+        return h(
+            "svg",
+            {
+                x: x - width / 2 + 5,
+                y: y - height / 2 + 5,
+                width: 25,
+                height: 25,
+                viewBox: "0 0 1274 1024"
+            },
+            [
+                h("path", {
+                    fill: style.stroke,
+                    d:
+                        "M690.366075 350.568358c0-98.876614-79.937349-179.048571-178.558027-179.048571-98.59935 0-178.515371 80.150629-178.515371 179.048571 0 98.833958 79.916021 178.963259 178.515371 178.963259C610.428726 529.531617 690.366075 449.380988 690.366075 350.568358M376.140632 350.568358c0-75.159877 60.72082-136.072649 135.667416-136.072649 74.989253 0 135.667416 60.912772 135.667416 136.072649 0 75.117221-60.678164 136.029993-135.667416 136.029993C436.861451 486.577022 376.140632 425.664251 376.140632 350.568358M197.284012 762.923936 197.284012 778.472049l15.526785 0 291.255186 0.127968L819.784387 778.472049l15.569441 0 0-15.548113c0-139.783721-136.413897-285.581938-311.026243-273.275681-10.002833 0.703824-24.740482 9.128385-34.658002 9.938849-8.573857 0.74648 13.692577 8.232609 14.396401 16.827793 9.021745-0.789136 6.313088 13.095393 15.505457 13.095393 150.597017 0 263.14488 103.07823 263.14488 224.62651l15.441473-15.590769-285.816546-0.042656-278.991585 1.81288 15.526785 15.612097c0-82.752645 75.095893-152.70849 136.861785-191.824044 7.25152-4.58552 8.659169-17.659585 4.862784-22.906273-6.846288-9.426977-19.877697-8.701825-28.046322-6.014496C285.262018 560.521203 197.284012 667.758394 197.284012 762.923936"
+                }),
+                h("path", {
+                    fill: style.stroke,
+                    d:
+                        "M512.31992 1.535616c-282.766642 0-512.021328 228.89211-512.021328 511.210864 0 282.46805 229.254686 511.25352 512.021328 511.25352 117.431975 0 228.828126-39.606098 318.810964-111.204199 10.791969-8.488545 12.540865-24.22861 3.988336-34.99925-8.616513-10.770641-24.356578-12.540865-35.127218-3.94568-81.174373 64.538532-181.586603 100.241606-287.650754 100.241606-255.210864 0-462.028493-206.561693-462.028493-461.367325 0-254.762976 206.817629-461.303341 462.028493-461.303341 255.210864 0 462.092477 206.561693 462.092477 461.303341 0 87.380821-24.33525 171.093227-69.614596 243.651087-7.272848 11.645089-3.668416 27.086562 8.040657 34.35941 11.709073 7.272848 27.10789 3.62576 34.402066-7.976672 50.184787-80.406565 77.143381-173.247355 77.143381-270.055153C1024.383904 230.427726 795.10789 1.535616 512.31992 1.535616z"
+                })
+            ]
+        );
+    }
+    getShape() {
+        const { model } = this.props;
+        const { x, y, width, height, radius, properties } = model;
+        const style = model.getNodeStyle();
+        //console.log(properties);
+        return h("g", {}, [
+            h("rect", {
+                ...style,
+                x: x - width / 2,
+                y: y - height / 2,
+                rx: radius,
+                ry: radius,
+                width,
+                height
+            }),
+            this.getLabelShape()
+        ]);
+    }
+}
+
+class UserTaskDoneModel extends RectNodeModel {
+    constructor (data:any, graphModel:any) {
+        data.text = {
+            value: (data.text && data.text.value) || '',
+            x: data.x,
+            y: data.y + 40
+        }
+        super(data, graphModel)
+        const length = 35
+        this.points = [
+            [length, 0],
+            [length * 2, length],
+            [length, length * 2],
+            [0, length]
+        ]
+    }
+    setAttributes() {
+        const { scale = 1, width = 100, height = 40 } = this.properties;
+        this.width = width * (scale as number);
+        this.height = height * (scale as number);
+    }
+    getTextStyle() {
+        const style = super.getTextStyle();
+        style.fontSize = 12;
+        const properties = this.properties;
+        style.color =  "#404040";
+        return style;
+    }
+    getNodeStyle() {
+        const style = super.getNodeStyle();
+        const properties = this.properties;
+        if (properties.disabled) {
+            style.stroke = "#1B7FFF";
+        } else {
+            style.stroke = "rgb(24, 125, 255)";
+        }
+        style.fill = '#d5e8d4';
+        return style;
+    }
+    getAnchorStyle() {
+        const style = super.getAnchorStyle();
+        return Object.assign({}, style, {
+            stroke: 'rgb(24, 125, 255)',
+            r: 3,
+            hover: {
+                r: 8,
+                fill: 'rgb(24, 125, 255)',
+                stroke: 'rgb(24, 125, 255)',
+            },
+        });
+    }
+    getAnchorLineStyle() {
+        const style = super.getAnchorLineStyle();
+        style.stroke = "rgb(24, 125, 255)";
+        return style;
+    }
+    getOutlineStyle() {
+        const style = super.getOutlineStyle();
+        style.stroke = "#1B7FFF";
+        style.hover!.stroke = "#1B7FFF";
+        return style;
+    }
+}
+
+export default function registerUserTaskDone(lf:LogicFlow){
+    lf.register({
+        type: "userTaskDone",
+        view: UserTaskDoneView,
+        model: UserTaskDoneModel
+    })
+}

+ 223 - 0
src/components/gFlow/showDesign.vue

@@ -0,0 +1,223 @@
+<template>
+  <div class="FL-container getting-started">
+    <!-- 画布 -->
+    <div class="app-content" ref="logicFlowContainerRef"></div>
+    <!-- 属性面板 -->
+    <el-drawer title="设置节点属性" v-model="dialogVisible" direction="rtl" size="900px" :before-close="closeDialog">
+      <PropertyDialog v-if="dialogVisible" :nodeData="clickNode" :lf="lf as LogicFlow" @setPropertiesFinish="closeDialog" :readonly="true"></PropertyDialog>
+    </el-drawer>
+  </div>
+</template>
+
+<script setup lang="ts">
+import LogicFlow, {BaseEdgeModel, BaseNodeModel} from "@logicflow/core";
+import "@logicflow/core/lib/style/index.css";
+import '@logicflow/extension/lib/style/index.css';
+import {ref} from "vue";
+import {setTheme} from "/@/components/gFlow/config";
+
+import {
+  registerEnd,
+  registerStart,
+  registerStartDone,
+  registerConcurrent,
+  registerPush,
+  registerCondition,
+  registerUserTask, registerEdgeDone, registerConditionDone, registerEndDone, registerConcurrentDone, registerPushDone
+} from "/@/components/gFlow/registerNode";
+import PropertyDialog from "/@/components/gFlow/propertySetting/PropertyDialog.vue";
+import {getNodeData} from "/@/api/flow/flowModel";
+import {
+  FlowCheckRuleDept,
+  FlowCheckRuleDeptLeader, FlowCheckRulePost,
+  FlowCheckRuleRole,
+  FlowCheckRuleUser
+} from "/@/components/gFlow/consts";
+import registerUserTaskDone from "./registerNode/registerUserTaskDone";
+
+defineOptions({ name: "ShowFlowDesign"})
+const modelId = ref(0)
+const nodeId = ref('')
+const logicFlowContainerRef = ref()
+const lf = ref<LogicFlow>({} as LogicFlow)
+const addPanelStyle = ref({
+  top: '0',
+  left: '0',
+})
+const showAddPanel = ref(false)
+const addClickNode = ref<any>()
+const clickNode = ref({})
+const dialogVisible = ref(false)
+const moveData = ref({})
+
+const showDesign = (params:any)=>{
+  modelId.value = params.flowId
+  nodeId.value = params.processId
+  lf.value = new LogicFlow({
+    container: logicFlowContainerRef.value,
+    grid: false,
+  })
+  registerNode()
+  initLF()
+}
+//注册节点信息
+const registerNode = ()=>{
+  const logicFlow = lf.value as LogicFlow
+  registerStart(logicFlow)
+  registerStartDone(logicFlow)
+  registerEnd(logicFlow)
+  registerEndDone(logicFlow)
+  registerConcurrent(logicFlow)
+  registerConcurrentDone(logicFlow)
+  registerPush(logicFlow)
+  registerPushDone(logicFlow)
+  registerCondition(logicFlow)
+  registerConditionDone(logicFlow)
+  registerUserTask(logicFlow)
+  registerUserTaskDone(logicFlow)
+  registerEdgeDone(logicFlow)
+}
+const initLF= async ()=>{
+  const logicFlow = lf.value as LogicFlow;
+  setTheme(logicFlow)
+  await $_render()
+  $_LfEvent()
+  //nodeId.value = 'f4330b11-25ff-4ced-b011-9730bf1be122' //测试用
+  //设置已经处理过的节点状态
+  if(nodeId.value!='') {
+    /*lf.value.getNodeOutgoingEdge(nodeId.value).map((edge: BaseEdgeModel) => {
+      lf.value.changeEdgeType(edge.id, "edgeDone")
+    })
+    const data = lf.value.getNodeDataById(nodeId.value)
+    lf.value.changeNodeType(nodeId.value,data?.type+"Done")*/
+    setDonePrevNode(nodeId.value)
+  }
+}
+const setDonePrevNode = (nodeId:string)=>{
+  lf.value.getNodeIncomingNode(nodeId).map((node:BaseNodeModel)=>{
+    if(node.type.indexOf("Done")>=0){
+      return
+    }
+    lf.value.changeNodeType(node.id,node.type+"Done")
+    lf.value.getNodeOutgoingEdge(node.id).map((edge: BaseEdgeModel) => {
+      lf.value.changeEdgeType(edge.id, "edgeDone")
+    })
+    setDonePrevNode(node.id)
+  })
+}
+const $_render = async ()=>{
+  //获取节点数据
+  return getNodeData(modelId.value).then((res:any)=>{
+    const nodes = (res.data.nodes??[]).map((item:any)=>{
+      const node = {
+        id: item.nodeId,
+        type: item.nodeType,
+        x: item.nodePosition.x,
+        y: item.nodePosition.y,
+        text: item.nodeText??{},
+        properties: {
+          text: item.nodeText?.value,
+          actionRule: item.nodeActionRule,
+          approveRule: item.nodeRule,
+          notice: item.notice ?? [],
+          rollback: item.rollback,
+          nodeExt: item.nodeExt??[],
+					deptProv: item.deptProv??1
+        }
+      }
+      setReceiver(node,item.nodeReceiver)
+      return node
+    })
+    const edges = (res.data.edges??[]).map((item:any)=>{
+      return {
+        id: item.id,
+        type: item.lineType,
+        sourceNodeId: item.sourceNodeId,
+        targetNodeId: item.targetNodeId,
+        startPoint:item.startPoint,
+        endPoint:item.endPoint,
+        properties: item.properties,
+        pointsList: item.pointsList,
+        text:item.text
+      }
+    })
+    lf.value.render({nodes,edges});
+    $_LfEvent();
+  })
+}
+const setReceiver = (node:any,receivers:Array<string>)=>{
+  switch(node.properties.actionRule){
+    case FlowCheckRuleRole://角色
+      node.properties.roleIds = receivers
+      break
+    case FlowCheckRuleDept://部门
+    case FlowCheckRuleDeptLeader://部门负责人
+      node.properties.deptIds = receivers
+      break
+    case FlowCheckRuleUser://指定人员
+      node.properties.userIds = receivers
+      break
+    case FlowCheckRulePost://岗位
+      node.properties.postIds = receivers
+  }
+}
+
+const $_LfEvent=()=>{
+  const logicFlow = lf.value as LogicFlow;
+  logicFlow.on('node:click', (data) => {
+    console.log('node:click', data);
+    clickNode.value = data.data;
+    dialogVisible.value = true;
+  })
+  logicFlow.on('edge:click', ({ data }) => {
+    console.log('edge:click', data);
+    //this.$data.clickNode = data;
+    //this.$data.dialogVisible = true;
+  });
+  logicFlow.on('element:click', () => {
+    hideAddPanel();
+  });
+  logicFlow.on('edge:add', ({ data }) => {
+    console.log('edge:add', data);
+  });
+  logicFlow.on('node:mousemove', ({ data }) => {
+    console.log('node:mousemove');
+    moveData.value = data;
+  });
+  logicFlow.on('blank:click', () => {
+    hideAddPanel();
+  });
+  logicFlow.on('connection:not-allowed', (data) => {
+    console.log('connection:not-allowed',data)
+  });
+  logicFlow.on('node:mousemove', () => {
+    console.log('on mousemove');
+  });
+}
+const hideAddPanel = () => {
+  showAddPanel.value = false;
+  addPanelStyle.value.top = '0';
+  addPanelStyle.value.left = '0';
+  addClickNode.value = null;
+}
+const closeDialog = () => {
+  dialogVisible.value = false;
+}
+defineExpose({showDesign})
+</script>
+
+<style scoped lang="scss">
+.FL-container {
+  width: 100%;
+  overflow: hidden;
+  .app-content {
+    height: calc(100vh - 120px);
+  }
+}
+.demo-control{
+  position: absolute;
+  top: 20px;
+  right: 50px;
+  z-index: 2;
+}
+</style>

+ 52 - 0
src/utils/formCreate.ts

@@ -0,0 +1,52 @@
+/**
+ * 针对 https://github.com/xaboy/form-create-designer 封装的工具类
+ */
+import formCreate from "@form-create/element-ui";
+
+// 编码表单 Conf
+export const encodeConf = (designerRef: object) => {
+  // @ts-ignore
+  return JSON.stringify(designerRef.value.getOption())
+}
+
+// 编码表单 Fields
+export const encodeFields = (designerRef: object) => {
+  // @ts-ignore
+  const rule = designerRef.value.getRule()
+  return formCreate.toJson(rule)
+}
+
+// 解码表单 Fields
+export const decodeFields = (fields: string[]) => {
+  const rule: object[] = []
+  fields.forEach((item) => {
+    rule.push(formCreate.parseJson(item))
+  })
+  return rule
+}
+
+// 设置表单的 Conf 和 Fields
+export const setConfAndFields = (designerRef: object, conf: string, fields: string) => {
+  // @ts-ignore
+  designerRef.value.setOption(JSON.parse(conf))
+  // @ts-ignore
+  designerRef.value.setRule(decodeFields(fields))
+}
+
+// 设置表单的 Conf 和 Fields
+export const setConfAndFields2 = (
+  detailPreview: object,
+  conf: string,
+  fields: string,
+  value?: object
+) => {
+  // @ts-ignore
+  detailPreview.value.option = formCreate.parseJson(conf)
+  // @ts-ignore
+  detailPreview.value.rule = decodeFields(fields)
+  if (value) {
+    // @ts-ignore
+    detailPreview.value.value = value
+  }
+}
+

+ 181 - 0
src/views/flow/flowDemo/list/component/detail.vue

@@ -0,0 +1,181 @@
+<template>
+  <!-- 流程审批测试详情抽屉 -->
+  <div class="flow-flowDemo-detail">
+    <el-drawer v-model="isShowDialog" size="80%" direction="ltr">
+      <template #header>
+        <h4>流程审批测试详情</h4>
+      </template>
+      <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick" style="margin: 8px;">
+        <el-tab-pane label="表单详情" name="0">
+          <el-descriptions
+              class="margin-top"
+              :column="3"
+              border
+              style="margin: 8px;"
+          >
+            <el-descriptions-item :span="1">
+              <template #label>
+                <div class="cell-item">
+                  主键
+                </div>
+              </template>
+              {{ formData.id }}
+            </el-descriptions-item>
+            <el-descriptions-item :span="1">
+              <template #label>
+                <div class="cell-item">
+                  标题
+                </div>
+              </template>
+              {{ formData.title }}
+            </el-descriptions-item>
+            <el-descriptions-item :span="1">
+              <template #label>
+                <div class="cell-item">
+                  审核状态
+                </div>
+              </template>
+              {{ proxy.getOptionValue(formData.status, statusOptions,'value','label') }}
+            </el-descriptions-item>
+            <el-descriptions-item :span="1">
+              <template #label>
+                <div class="cell-item">
+                  用户id
+                </div>
+              </template>
+              {{ formData.createdBy }}
+            </el-descriptions-item>
+            <el-descriptions-item :span="1">
+              <template #label>
+                <div class="cell-item">
+                  年龄
+                </div>
+              </template>
+              {{ formData.age }}
+            </el-descriptions-item>
+          </el-descriptions>
+        </el-tab-pane>
+        <el-tab-pane label="审批记录" name="1">
+            <FlowLog ref="flowLogRef" :form-id="formId" :form-table="formTable" :key="formId"/>
+        </el-tab-pane>
+        <el-tab-pane label="流程图" name="2">
+          <ShowFlowDesign ref="showFlowCheckRef" />
+        </el-tab-pane>
+      </el-tabs>
+    </el-drawer>
+  </div>
+</template>
+<script setup lang="ts">
+  import { reactive, toRefs, ref,getCurrentInstance } from 'vue';
+  import {
+    getFlowDemo,
+  } from "/@/api/flow/flowDemo";
+  import {
+    FlowDemoInfoData,
+    FlowDemoEditState
+  } from "/@/views/flow/flowDemo/list/component/model"
+  import {TabsPaneContext} from "element-plus";
+  import FlowLog from "/@/components/gFlow/flowLog.vue";
+  import ShowFlowDesign from "/@/components/gFlow/showDesign.vue";
+  import {getRunStep} from "/@/api/flow/flowModel";
+  defineOptions({ name: "ApiV1FlowFlowDemoDetail"})
+  const props = defineProps({
+    statusOptions:{
+      type:Array,
+      default:()=>[]
+    },
+  })
+  const flowLogRef = ref()
+  const showFlowCheckRef = ref()
+  const formId = ref(0)
+  const formTable = ref('')
+  const activeName = ref('0')
+  const handleClick = (tab: TabsPaneContext) => {
+    if(tab.index=="1"){
+      flowLogRef.value.getLogList()
+    }else if(tab.index=="2"){
+      getRunStep({formTable:formTable.value,formId:formId.value}).then((res:any)=>{
+        showFlowCheckRef.value.showDesign({flowId:res.data.data?.runFlow||'0',processId:res.data.data?.runFlowNode||''})
+      })
+    }
+  }
+  const {proxy} = <any>getCurrentInstance()
+  const state = reactive<FlowDemoEditState>({
+    loading:false,
+    isShowDialog: false,
+    formData: {
+      id: undefined,
+      title: undefined,
+      status: false ,
+      updatedAt: undefined,
+      createdBy: undefined,
+      age: undefined,
+    },
+    // 表单校验
+    rules: {
+      id : [
+          { required: true, message: "主键不能为空", trigger: "blur" }
+      ],
+      status : [
+          { required: true, message: "审核状态不能为空", trigger: "blur" }
+      ],
+    }
+  });
+  const { isShowDialog,formData } = toRefs(state);
+  // 打开弹窗
+  const openDialog = (row?: FlowDemoInfoData) => {
+    resetForm();
+    if(row) {
+      formId.value = row.actionBtn.wfFid
+      formTable.value = row.actionBtn.wfType
+      getFlowDemo(row.id!).then((res:any)=>{
+        const data = res.data;
+        data.createdBy = data.createdUser?.userNickname
+        state.formData = data;
+      })
+    }
+    state.isShowDialog = true;
+  };
+  // 关闭弹窗
+  const closeDialog = () => {
+    state.isShowDialog = false;
+  };
+  defineExpose({
+    openDialog,
+  });
+  // 取消
+  const onCancel = () => {
+    closeDialog();
+  };
+  const resetForm = ()=>{
+    state.formData = {
+      id: undefined,
+      title: undefined,
+      status: false ,
+      updatedAt: undefined,
+      createdBy: undefined,
+      age: undefined,
+    }
+    activeName.value = '0'
+  };
+</script>
+<style scoped>
+  .flow-flowDemo-detail :deep(.el-form-item--large .el-form-item__label){
+    font-weight: bolder;
+  }
+  .pic-block{
+    margin-right: 8px;
+  }
+  .file-block{
+    width: 100%;
+    border: 1px solid var(--el-border-color);
+    border-radius: 6px;
+    cursor: pointer;
+    position: relative;
+    overflow: hidden;
+    transition: var(--el-transition-duration-fast);
+    margin-bottom: 5px;
+    padding: 3px 6px;
+  }
+  .ml-2{margin-right: 5px;}
+</style>

+ 140 - 0
src/views/flow/flowDemo/list/component/edit.vue

@@ -0,0 +1,140 @@
+<template>  
+  <div class="flow-flowDemo-edit">
+    <!-- 添加或修改流程审批测试对话框 -->
+    <el-dialog v-model="isShowDialog" width="800px" :close-on-click-modal="false" :destroy-on-close="true">
+      <template #header>
+        <div v-drag="['.flow-flowDemo-edit .el-dialog', '.flow-flowDemo-edit .el-dialog__header']">{{(!formData.id || formData.id==0?'添加':'修改')+'流程审批测试'}}</div>
+      </template>
+      <el-form ref="formRef" :model="formData" :rules="rules" label-width="120px">        
+        <el-form-item label="标题" prop="title">
+          <el-input v-model="formData.title" placeholder="请输入标题" />
+        </el-form-item>        
+        <el-form-item label="年龄" prop="age">
+          <el-input v-model="formData.age" placeholder="请输入年龄" />
+        </el-form-item>       
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
+          <el-button @click="onCancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+<script setup lang="ts">
+import { reactive, toRefs, ref,unref,getCurrentInstance } from 'vue';
+import {ElMessageBox, ElMessage, FormInstance,UploadProps} from 'element-plus';
+import {
+  listFlowDemo,
+  getFlowDemo,
+  delFlowDemo,
+  addFlowDemo,
+  updateFlowDemo,  
+} from "/@/api/flow/flowDemo";
+import {
+  FlowDemoTableColumns,
+  FlowDemoInfoData,
+  FlowDemoTableDataState,
+  FlowDemoEditState
+} from "/@/views/flow/flowDemo/list/component/model"
+defineOptions({ name: "ApiV1FlowFlowDemoEdit"})
+const emit = defineEmits(['flowDemoList'])
+  const props = defineProps({    
+    statusOptions:{
+      type:Array,
+      default:()=>[]
+    },    
+  })
+const {proxy} = <any>getCurrentInstance()
+const formRef = ref<HTMLElement | null>(null);
+const menuRef = ref();
+const state = reactive<FlowDemoEditState>({
+  loading:false,
+  isShowDialog: false,
+  formData: {    
+    id: undefined,    
+    title: undefined,    
+    status: false ,    
+    updatedAt: undefined,    
+    createdBy: undefined,    
+    age: undefined,    
+  },
+  // 表单校验
+  rules: {    
+    id : [
+        { required: true, message: "主键不能为空", trigger: "blur" }
+    ],    
+    status : [
+        { required: true, message: "审核状态不能为空", trigger: "blur" }
+    ],    
+  }
+});
+const { loading,isShowDialog,formData,rules } = toRefs(state);
+// 打开弹窗
+const openDialog = (row?: FlowDemoInfoData) => {
+  resetForm();
+  if(row) {
+    getFlowDemo(row.id!).then((res:any)=>{
+      const data = res.data;      
+      state.formData = data;
+  })
+}
+  state.isShowDialog = true;
+};
+// 关闭弹窗
+const closeDialog = () => {
+  state.isShowDialog = false;
+};
+defineExpose({
+  openDialog,
+});
+// 取消
+const onCancel = () => {
+  closeDialog();
+};
+// 提交
+const onSubmit = () => {
+  const formWrap = unref(formRef) as any;
+  if (!formWrap) return;
+  formWrap.validate((valid: boolean) => {
+    if (valid) {
+      state.loading = true;
+      if(!state.formData.id || state.formData.id===0){
+        //添加
+      addFlowDemo(state.formData).then(()=>{
+          ElMessage.success('添加成功');
+          closeDialog(); // 关闭弹窗
+          emit('flowDemoList')
+        }).finally(()=>{
+          state.loading = false;
+        })
+      }else{
+        //修改
+      updateFlowDemo(state.formData).then(()=>{
+          ElMessage.success('修改成功');
+          closeDialog(); // 关闭弹窗
+          emit('flowDemoList')
+        }).finally(()=>{
+          state.loading = false;
+        })
+      }
+    }
+  });
+};
+const resetForm = ()=>{
+  state.formData = {    
+    id: undefined,    
+    title: undefined,    
+    status: false ,    
+    updatedAt: undefined,    
+    createdBy: undefined,    
+    age: undefined,    
+  }  
+};
+</script>
+<style scoped>  
+  .kv-label{margin-bottom: 15px;font-size: 14px;}
+  .mini-btn i.el-icon{margin: unset;}
+  .kv-row{margin-bottom: 12px;}
+</style>

+ 44 - 0
src/views/flow/flowDemo/list/component/model.ts

@@ -0,0 +1,44 @@
+export interface FlowDemoTableColumns {
+    id:number;  // 主键
+    title:string;  // 标题
+    status:number;  // 审核状态
+    createdBy:string;  // 用户id
+    age:number;  // 年龄
+    actionBtn:any
+}
+
+
+export interface FlowDemoInfoData {
+    id:number|undefined;        // 主键
+    title:string|undefined; // 标题
+    status:boolean; // 审核状态
+    updatedAt:string|undefined; // 更新日期
+    createdBy:number|undefined; // 用户id
+    age:number|undefined; // 年龄
+    actionBtn?:any
+}
+
+
+export interface FlowDemoTableDataState {
+    ids:any[];
+    tableData: {
+        data: Array<FlowDemoTableColumns>;
+        total: number;
+        loading: boolean;
+        param: {
+            pageNum: number;
+            pageSize: number;
+            title: string|undefined;
+            status: number|undefined;
+            dateRange: string[];
+        };
+    };
+}
+
+
+export interface FlowDemoEditState{
+    loading:boolean;
+    isShowDialog: boolean;
+    formData:FlowDemoInfoData;
+    rules: object;
+}

+ 294 - 0
src/views/flow/flowDemo/list/index.vue

@@ -0,0 +1,294 @@
+<template>
+  <div class="flow-flowDemo-container">
+    <el-card shadow="hover">
+        <div class="flow-flowDemo-search mb15">
+            <el-form :model="tableData.param" ref="queryRef" :inline="true" label-width="100px">
+            <el-row>
+                <el-col :span="8" class="colBlock">
+                  <el-form-item label="标题" prop="title">
+                    <el-input
+                        v-model="tableData.param.title"
+                        placeholder="请输入标题"
+                        clearable
+                        @keyup.enter.native="flowDemoList"
+                    />
+                  </el-form-item>
+                </el-col>
+                <el-col :span="8" class="colBlock">
+                  <el-form-item label="审核状态" prop="status">
+                    <el-select v-model="tableData.param.status" placeholder="请选择审核状态" clearable style="width:200px;">
+                        <el-option
+                            v-for="dict in flow_status"
+                            :key="dict.value"
+                            :label="dict.label"
+                            :value="dict.value"
+                        />
+                    </el-select>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="8" class="colBlock">
+                  <el-form-item>
+                    <el-button type="primary"   @click="flowDemoList"><el-icon><ele-Search /></el-icon>搜索</el-button>
+                    <el-button  @click="resetQuery(queryRef)"><el-icon><ele-Refresh /></el-icon>重置</el-button>
+                  </el-form-item>
+                </el-col>
+              </el-row>
+            </el-form>
+            <el-row :gutter="10" class="mb8">
+              <el-col :span="1.5">
+                <el-button
+                  type="primary"
+                  @click="handleAdd"
+                  v-auth="'api/v1/flow/flowDemo/add'"
+                ><el-icon><ele-Plus /></el-icon>新增</el-button>
+              </el-col>
+              <el-col :span="1.5">
+                <el-button
+                  type="success"
+                  :disabled="single"
+                  @click="handleUpdate(null)"
+                  v-auth="'api/v1/flow/flowDemo/edit'"
+                ><el-icon><ele-Edit /></el-icon>修改</el-button>
+              </el-col>
+              <el-col :span="1.5">
+                <el-button
+                  type="danger"
+                  :disabled="multiple"
+                  @click="handleDelete(null)"
+                  v-auth="'api/v1/flow/flowDemo/delete'"
+                ><el-icon><ele-Delete /></el-icon>删除</el-button>
+              </el-col>
+            </el-row>
+        </div>
+        <el-table v-loading="loading" :data="tableData.data" @selection-change="handleSelectionChange">
+          <el-table-column type="selection" width="55" align="center" />
+          <el-table-column label="主键" align="center" prop="id"
+            min-width="150px"
+             />
+          <el-table-column label="标题" align="center" prop="title"
+            min-width="150px"
+             />
+          <el-table-column label="审核状态" align="center" prop="status" min-width="150px">
+            <template #default="scope">
+              <el-tag :type="columnColor(scope.row)">{{ statusFormat(scope.row) }}</el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column label="用户id" align="center" prop="createdBy"
+            min-width="150px"
+             />
+          <el-table-column label="年龄" align="center" prop="age"
+            min-width="150px"
+             />
+          <el-table-column label="操作" align="center" class-name="small-padding" min-width="200px" fixed="right">
+            <template #default="scope">
+              <el-button
+                type="primary"
+                link
+                @click="handleView(scope.row)"
+                v-auth="'api/v1/flow/flowDemo/get'"
+              ><el-icon><ele-View /></el-icon>详情</el-button>
+              <el-button
+                type="primary"
+                link
+                @click="handleUpdate(scope.row)"
+                v-auth="'api/v1/flow/flowDemo/edit'"
+              ><el-icon><ele-EditPen /></el-icon>修改</el-button>
+              <el-button
+                  v-if="scope.row.actionBtn && scope.row.actionBtn.type!='disabled'"
+                  type="primary"
+                  link
+                  @click="handleStartFlow(scope.row)"
+              ><el-icon><ele-Coordinate/></el-icon>{{scope.row.actionBtn.title}}</el-button>
+              <el-button
+                type="primary"
+                link
+                @click="handleDelete(scope.row)"
+                v-auth="'api/v1/flow/flowDemo/delete'"
+              ><el-icon><ele-DeleteFilled /></el-icon>删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <pagination
+            v-show="tableData.total>0"
+            :total="tableData.total"
+            v-model:page="tableData.param.pageNum"
+            v-model:limit="tableData.param.pageSize"
+            @pagination="flowDemoList"
+        />
+    </el-card>
+    <ApiV1FlowFlowDemoEdit
+       ref="editRef"
+       :statusOptions="flow_status"
+       @flowDemoList="flowDemoList"
+    ></ApiV1FlowFlowDemoEdit>
+    <ApiV1FlowFlowDemoDetail
+      ref="detailRef"
+      :statusOptions="flow_status"
+      @flowDemoList="flowDemoList"
+    ></ApiV1FlowFlowDemoDetail>
+  <checkFlow ref="ckFlowRef" @getList="flowDemoList"></checkFlow>
+  </div>
+</template>
+<script setup lang="ts">
+import checkFlow from "/@/components/gFlow/checkFlow.vue"
+import {toRefs, reactive, onMounted, ref,  computed,getCurrentInstance,toRaw} from 'vue';
+import {ElMessageBox, ElMessage, FormInstance} from 'element-plus';
+import {
+    listFlowDemo,
+    delFlowDemo,
+} from "/@/api/flow/flowDemo";
+import {
+    FlowDemoTableColumns,
+    FlowDemoInfoData,
+    FlowDemoTableDataState,
+} from "/@/views/flow/flowDemo/list/component/model"
+import ApiV1FlowFlowDemoEdit from "/@/views/flow/flowDemo/list/component/edit.vue"
+import ApiV1FlowFlowDemoDetail from "/@/views/flow/flowDemo/list/component/detail.vue"
+defineOptions({ name: "apiV1FlowFlowDemoList"})
+const {proxy} = <any>getCurrentInstance()
+const loading = ref(false)
+const queryRef = ref()
+const editRef = ref();
+const detailRef = ref();
+// 是否显示所有搜索选项
+const showAll =  ref(false)
+// 非单个禁用
+const single = ref(true)
+// 非多个禁用
+const multiple =ref(true)
+const ckFlowRef = ref()
+const word = computed(()=>{
+    if(showAll.value === false) {
+        //对文字进行处理
+        return "展开搜索";
+    } else {
+        return "收起搜索";
+    }
+})
+// 字典选项数据
+const {
+    flow_status,
+} = proxy.useDict(
+    'flow_status',
+)
+const state = reactive<FlowDemoTableDataState>({
+    ids:[],
+    tableData: {
+        data: [],
+        total: 0,
+        loading: false,
+        param: {
+            pageNum: 1,
+            pageSize: 10,
+            title: undefined,
+            status: undefined,
+            dateRange: []
+        },
+    },
+});
+const { tableData } = toRefs(state);
+// 页面加载时
+onMounted(() => {
+    initTableData();
+});
+// 初始化表格数据
+const initTableData = () => {
+    flowDemoList()
+};
+/** 重置按钮操作 */
+const resetQuery = (formEl: FormInstance | undefined) => {
+    if (!formEl) return
+    formEl.resetFields()
+    flowDemoList()
+};
+// 获取列表数据
+const flowDemoList = ()=>{
+  loading.value = true
+  listFlowDemo(state.tableData.param).then((res:any)=>{
+    let list = res.data.list??[];
+    list.map((item:any)=>{
+        item.createdBy = item.createdUser?.userNickname
+    })
+    state.tableData.data = list;
+    state.tableData.total = res.data.total;
+    loading.value = false
+  })
+};
+const toggleSearch = () => {
+    showAll.value = !showAll.value;
+}
+// 审核状态字典翻译
+const statusFormat = (row:FlowDemoTableColumns) => {
+    return proxy.selectDictLabel(flow_status.value, row.status);
+}
+// 多选框选中数据
+const handleSelectionChange = (selection:Array<FlowDemoInfoData>) => {
+    state.ids = selection.map(item => item.id)
+    single.value = selection.length!=1
+    multiple.value = !selection.length
+}
+const handleAdd =  ()=>{
+    editRef.value.openDialog()
+}
+const handleUpdate = (row: FlowDemoTableColumns|null) => {
+    if(!row){
+        row = state.tableData.data.find((item:FlowDemoTableColumns)=>{
+            return item.id ===state.ids[0]
+        }) as FlowDemoTableColumns
+    }
+    editRef.value.openDialog(toRaw(row));
+};
+const handleDelete = (row: FlowDemoTableColumns|null) => {
+    let msg = '你确定要删除所选数据?';
+    let id:number[] = [] ;
+    if(row){
+    msg = `此操作将永久删除数据,是否继续?`
+    id = [row.id]
+    }else{
+    id = state.ids
+    }
+    if(id.length===0){
+        ElMessage.error('请选择要删除的数据。');
+        return
+    }
+    ElMessageBox.confirm(msg, '提示', {
+        confirmButtonText: '确认',
+        cancelButtonText: '取消',
+        type: 'warning',
+    })
+        .then(() => {
+            delFlowDemo(id).then(()=>{
+                ElMessage.success('删除成功');
+                flowDemoList();
+            })
+        })
+        .catch(() => {});
+}
+const handleView = (row:FlowDemoTableColumns)=>{
+    detailRef.value.openDialog(toRaw(row));
+}
+const handleStartFlow =(row: FlowDemoTableColumns|null)=>{
+  ckFlowRef.value.handleStartFlow(row)
+}
+const columnColor=(row:FlowDemoTableColumns)=>{
+  switch (row.status.toString()){
+    case '-1':
+      return "danger"
+    case '0':
+      return "info"
+    case '1':
+      return "warning"
+    case '2':
+      return "success"
+  }
+}
+</script>
+<style lang="scss" scoped>
+    .colBlock {
+        display: block;
+    }
+    .colNone {
+        display: none;
+    }
+    .ml-2{margin: 3px;}
+</style>

+ 302 - 0
src/views/flow/flowForm/center/index.vue

@@ -0,0 +1,302 @@
+<template>
+	<div class="splitpanes-container">
+		<el-card shadow="hover" header="表单中心">
+			<el-alert
+				title="用于发起自定义表单审批流程,点击选择左侧表单类型进行表单数据管理"
+				type="success"
+				:closable="false"
+				class="mb15"
+			></el-alert>
+			<splitpanes class="default-theme">
+				<pane :size="20">
+          <el-card shadow="hover" header="流程表单">
+            <el-table v-loading="loading" :data="tableData.data" @current-change="handleCurrentForm" highlight-current-row>
+              <el-table-column prop="id" label="ID" width="100" />
+              <el-table-column prop="name" label="表单名称"  />
+            </el-table>
+            <pagination
+                v-show="tableData.total>0"
+                :total="tableData.total"
+                v-model:page="tableData.param.pageNum"
+                v-model:limit="tableData.param.pageSize"
+                @pagination="flowFormList"
+                layout="prev, next"
+            />
+          </el-card>
+        </pane>
+				<pane :size="80">
+          <el-card shadow="hover" :header="'表单数据'+(currentForm.name?('-'+currentForm.name):'')">
+            <el-row :gutter="10" class="mb8" v-show="showTablePanel">
+              <el-col :span="1.5">
+                <el-button
+                    type="primary"
+                    @click="handleDataAdd"
+                    v-auth="'api/v1/flow/flowForm/addFormData'"
+                ><el-icon><ele-Plus /></el-icon>发起表单审批</el-button>
+              </el-col>
+              <el-col :span="1.5">
+                <el-button
+                    type="success"
+                    :disabled="single"
+                    @click="handleDataUpdate(null)"
+                    v-auth="'api/v1/flow/flowForm/editFormData'"
+                ><el-icon><ele-Edit /></el-icon>修改</el-button>
+              </el-col>
+              <el-col :span="1.5">
+                <el-button
+                    type="danger"
+                    :disabled="multiple"
+                    @click="handleDataDelete(null)"
+                    v-auth="'api/v1/flow/flowForm/delFormData'"
+                ><el-icon><ele-Delete /></el-icon>删除</el-button>
+              </el-col>
+              <el-col :span="1.5">
+                <el-button  @click="getFormDataList"><el-icon><ele-Refresh /></el-icon>刷新</el-button>
+              </el-col>
+            </el-row>
+            <el-table v-loading="formLoading" :data="tableFormData" @selection-change="handleSelectionChange">
+              <el-table-column type="selection" width="55" align="center" />
+              <el-table-column label="主键" align="center" prop="id"
+                               min-width="150px"
+              />
+              <el-table-column v-for="(item,index) in fromFields" :key="item.field" :label="item.title" align="center" :prop="item.field"
+                               min-width="150px"
+              />
+              <el-table-column label="状态" align="center" prop="status" min-width="150px">
+                <template #default="scope">
+                  <el-tag :type="columnColor(scope.row)">{{ statusFormat(scope.row) }}</el-tag>
+                </template>
+              </el-table-column>
+
+              <el-table-column label="创建时间" align="center" prop="createdAt"
+                               min-width="150px"
+              >
+                <template #default="scope">
+                  <span>{{ proxy.parseTime(scope.row.created_at, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+                </template>
+              </el-table-column>
+              <el-table-column label="创建人" align="center" prop="created_user.userNickname"
+                               min-width="150px"
+              />
+              <el-table-column label="操作" align="center" class-name="small-padding" min-width="200px" fixed="right">
+                <template #default="scope">
+                  <el-button
+                      type="primary"
+                      link
+                      @click="handleDataView(scope.row)"
+                      v-auth="'api/v1/flow/flowForm/getFormData'"
+                  ><el-icon><ele-View /></el-icon>详情</el-button>
+                  <el-button
+                      type="primary"
+                      link
+                      @click="handleDataUpdate(scope.row)"
+                      v-auth="'api/v1/flow/flowForm/editFormData'"
+                  ><el-icon><ele-EditPen /></el-icon>修改</el-button>
+                  <el-button
+                      v-if="scope.row.actionBtn && scope.row.actionBtn.type!='disabled'"
+                      type="primary"
+                      link
+                      @click="handleStartFlow(scope.row)"
+                  ><el-icon><ele-Coordinate/></el-icon>{{scope.row.actionBtn.title}}</el-button>
+                  <el-button
+                      type="primary"
+                      link
+                      @click="handleDataDelete(scope.row)"
+                      v-auth="'api/v1/flow/flowForm/delFormData'"
+                  ><el-icon><ele-DeleteFilled /></el-icon>删除</el-button>
+                </template>
+              </el-table-column>
+            </el-table>
+            <pagination
+                v-show="tableFormParam.total>0"
+                :total="tableFormParam.total"
+                v-model:page="tableFormParam.pageNum"
+                v-model:limit="tableFormParam.pageSize"
+                @pagination="getFormDataList"
+            />
+          </el-card>
+				</pane>
+			</splitpanes>
+		</el-card>
+    <add-form-data
+        ref="addFormDataRef"
+        @getFormDataList="getFormDataList"
+    >
+    </add-form-data>
+    <data-detail
+        ref="dataDetailRef"
+    >
+    </data-detail>
+    <checkFlow ref="ckFlowRef" @getList="getFormDataList"></checkFlow>
+	</div>
+</template>
+
+<script lang="ts" setup>
+import checkFlow from "/@/components/gFlow/checkFlow.vue"
+import { Splitpanes, Pane } from 'splitpanes';
+import 'splitpanes/dist/splitpanes.css';
+import {getCurrentInstance, onMounted, reactive, ref, toRefs, unref} from "vue";
+import {delFlowFormData, listFlowForm, ListFlowFormData} from "/@/api/flow/flowForm";
+import {
+  FlowFormTableColumns,
+  FlowFormTableDataState,
+  FormFieldsData
+} from "/@/views/flow/flowForm/list/component/model";
+import AddFormData from "/@/views/flow/flowForm/list/component/addFormData.vue";
+import {FlowDemoTableColumns} from "/@/views/flow/flowDemo/list/component/model";
+import {ElMessage, ElMessageBox} from "element-plus";
+import DataDetail from "/@/views/flow/flowForm/list/component/dataDetail.vue";
+defineOptions({ name: "apiV1FlowFlowFormDataList"})
+const {proxy} = <any>getCurrentInstance()
+const loading = ref(false)
+const single = ref(true)
+const multiple = ref(true)
+const ckFlowRef = ref()
+const showTablePanel = ref(false)
+const currentForm = ref<FlowFormTableColumns>({} as FlowFormTableColumns)
+const addFormDataRef = ref()
+const dataDetailRef = ref()
+const formLoading = ref(false)
+const fromFields = ref<FormFieldsData[]>([])
+const tableFormData = ref<any[]>([])
+const tableFormParam = ref({
+  total:0,
+  pageNum: 1,
+  pageSize: 10,
+  formId: 0
+})
+const state = reactive<FlowFormTableDataState>({
+  ids:[],
+  tableData: {
+    data: [],
+    total: 0,
+    loading: false,
+    param: {
+      pageNum: 1,
+      pageSize: 10,
+      name: undefined,
+      status: 1,
+      isPub:true,
+      createdAt: undefined,
+      dateRange: []
+    },
+  },
+});
+const {tableData}  = toRefs(state)
+onMounted(()=>{
+  initTableData();
+})
+const initTableData = ()=>{
+  flowFormList();
+}
+const flowFormList = ()=>{
+  loading.value = true
+  listFlowForm(state.tableData.param).then((res:any)=>{
+    let list = res.data.list??[];
+    list.map((item:any)=>{
+      item.createdBy = item.createdUser?.userNickname
+    })
+    state.tableData.data = list;
+    state.tableData.total = res.data.total;
+    loading.value = false
+  })
+}
+const handleCurrentForm = (row:FlowFormTableColumns)=>{
+  showTablePanel.value = true
+  currentForm.value = row
+  tableFormParam.value = {
+    total:0,
+    pageNum: 1,
+    pageSize: 10,
+    formId: row.id
+  }
+  getFormDataList()
+}
+const getFormDataList = ()=>{
+  formLoading.value = true
+  ListFlowFormData(tableFormParam.value).then((res:any)=>{
+    tableFormData.value = res.data.list
+    tableFormParam.value.total = res.data.total
+    fromFields.value = res.data.fields.filter((item:FormFieldsData)=>{
+      return item.type=='input' && item.display && !item.hidden
+    }).slice(0,3)
+    formLoading.value = false
+  })
+}
+// 多选框选中数据
+const handleSelectionChange = (selection:Array<any>) => {
+  state.ids = selection.map(item => item.id)
+  single.value = selection.length!=1
+  multiple.value = !selection.length
+}
+const columnColor=(row:FlowDemoTableColumns)=>{
+  switch (row.status.toString()){
+    case '-1':
+      return "danger"
+    case '0':
+      return "info"
+    case '1':
+      return "warning"
+    case '2':
+      return "success"
+  }
+}
+// 字典选项数据
+const {
+  flow_status,
+} = proxy.useDict(
+    'flow_status',
+)
+// 审核状态字典翻译
+const statusFormat = (row:FlowDemoTableColumns) => {
+  return proxy.selectDictLabel(flow_status.value, row.status);
+}
+const handleDataAdd = ()=>{
+  currentForm.value.dataId = 0
+  addFormDataRef.value.openDialog(currentForm.value)
+}
+const handleDataView = (row:any)=>{
+  currentForm.value.dataId = row.id as number
+  currentForm.value.actionBtn = row.actionBtn
+  dataDetailRef.value.openDialog(currentForm.value)
+}
+const handleDataUpdate = (row:any)=>{
+  if(row==null|| typeof row == 'undefined'){
+    currentForm.value.dataId = state.ids[0]
+  }else{
+    currentForm.value.dataId = row.id as number
+  }
+  addFormDataRef.value.openDialog(currentForm.value)
+}
+const handleStartFlow =(row: FlowDemoTableColumns|null)=>{
+  ckFlowRef.value.handleStartFlow(row)
+}
+const handleDataDelete = (row:any)=>{
+  let msg = '你确定要删除所选数据?';
+  let id:number[] = [] ;
+  if(row){
+    msg = `此操作将永久删除数据,是否继续?`
+    id = [row.id]
+  }else{
+    id = state.ids
+  }
+  if(id.length===0){
+    ElMessage.error('请选择要删除的数据。');
+    return
+  }
+  ElMessageBox.confirm(msg, '提示', {
+    confirmButtonText: '确认',
+    cancelButtonText: '取消',
+    type: 'warning',
+  }).then(() => {
+    delFlowFormData({formId:currentForm.value.id,ids:id}).then(()=>{
+      ElMessage.success('删除成功');
+      getFormDataList();
+    })
+  }).catch()
+}
+</script>
+
+<style scoped lang="scss">
+
+</style>

+ 170 - 0
src/views/flow/flowForm/list/component/addFormData.vue

@@ -0,0 +1,170 @@
+<template>
+  <!-- 流程表单详情抽屉 -->
+  <div class="flow-flowForm-detail">
+    <el-drawer v-model="isShowDialog" size="80%" direction="ltr">
+      <template #header>
+        <h4>流程表单详情-{{state.formData.name}}</h4>
+      </template>
+      <div class="form-create-show">
+        <FormCreate :option="detailData.option" :rule="detailData.rule" @submit="handleSubmit" v-model="formData" />
+      </div>
+    </el-drawer>
+  </div>
+</template>
+<script lang="ts" setup>
+// 引入 form-create
+import formCreate from '@form-create/element-ui'
+// 引入 form-create-edit
+import FcEditor from "@form-create/component-wangeditor";
+import {reactive, ref, getCurrentInstance, toRefs} from 'vue';
+import {addFlowFormData, editFlowFormData, getFlowForm, getFlowFormData} from "/@/api/flow/flowForm";
+import {
+  FlowFormInfoData,
+  FlowFormEditState, FlowFormTableColumns
+} from "/@/views/flow/flowForm/list/component/model"
+import {setConfAndFields2} from "/@/utils/formCreate";
+import {ElMessage} from "element-plus";
+formCreate.component(FcEditor)
+//获取 formCreate 组件
+const FormCreate = formCreate.$form();
+defineOptions({ name: "addFormData"})
+const props = defineProps({
+  statusOptions:{
+    type:Array,
+    default:()=>[]
+  },
+})
+const emit = defineEmits(['getFormDataList'])
+const {proxy} = <any>getCurrentInstance()
+const formRef = ref<HTMLElement | null>(null);
+const menuRef = ref();
+const dataId = ref(0)
+const formData = ref({});
+const detailData = ref({
+  rule: [],
+  option: {}
+})
+const state = reactive<FlowFormEditState>({
+  loading:false,
+  isShowDialog: false,
+  formData: {
+    id: undefined,
+    name: undefined,
+    status: false ,
+    remark: undefined,
+    createdAt: undefined,
+    updatedAt: undefined,
+    deletedAt: undefined,
+    createdBy: undefined,
+    updatedBy: undefined,
+    conf: undefined,
+    fields: undefined,
+  },
+  // 表单校验
+  rules: {
+    name : [
+      { required: true, message: "表单名不能为空", trigger: "blur" }
+    ],
+    status : [
+      { required: true, message: "状态不能为空", trigger: "blur" }
+    ],
+  }
+});
+const {isShowDialog} = toRefs(state);
+// 打开弹窗
+const openDialog = async (row?: FlowFormTableColumns) => {
+  resetForm();
+  if(row) {
+    await getFlowForm(row.id!).then((res:any)=>{
+      const data = res.data;
+      data.createdBy = data.createdUser?.userNickname
+      data.updatedBy = data.updatedUser?.userNickname
+      state.formData = data;
+      setConfAndFields2(detailData, data.conf, data.fields)
+    })
+    if(row.dataId && row.dataId!=0){
+      dataId.value = row.dataId
+      //获取表单数据
+      getFlowFormData({formId:row.id,dataId:row.dataId}).then((res:any)=>{
+        formData.value = res.data.data
+      })
+    }
+  }
+  state.isShowDialog = true;
+};
+// 关闭弹窗
+const closeDialog = () => {
+  state.isShowDialog = false;
+};
+// 取消
+const onCancel = () => {
+  closeDialog();
+};
+const resetForm = ()=>{
+  state.formData = {
+    id: undefined,
+    name: undefined,
+    status: false ,
+    remark: undefined,
+    createdAt: undefined,
+    updatedAt: undefined,
+    deletedAt: undefined,
+    createdBy: undefined,
+    updatedBy: undefined,
+    conf: undefined,
+    fields: undefined,
+  }
+  dataId.value = 0
+  formData.value = {};
+};
+
+const handleSubmit = (data:any)=>{
+ const formData = {
+    formId:state.formData.id,
+    data :data,
+    dataId:0
+  }
+  if(dataId.value!=0){
+    //修改
+    formData.dataId = dataId.value
+    editFlowFormData(formData).then(()=>{
+      ElMessage.success('修改成功');
+      onCancel()
+      emit('getFormDataList')
+    })
+  }else{
+    //添加
+    addFlowFormData(formData).then(()=>{
+      ElMessage.success('发起成功');
+      onCancel()
+      emit('getFormDataList')
+    })
+  }
+
+}
+defineExpose({openDialog})
+</script>
+<style scoped>
+.flow-flowForm-detail :deep(.el-form-item__label){
+  font-weight: bolder;
+}
+.pic-block{
+  margin-right: 8px;
+}
+.file-block{
+  width: 100%;
+  border: 1px solid var(--el-border-color);
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+  transition: var(--el-transition-duration-fast);
+  margin-bottom: 5px;
+  padding: 3px 6px;
+}
+.ml-2{margin-right: 5px;}
+.form-create-show{
+  width: 100%;
+  padding: 16px;
+}
+</style>

+ 177 - 0
src/views/flow/flowForm/list/component/dataDetail.vue

@@ -0,0 +1,177 @@
+<template>
+  <!-- 流程表单详情抽屉 -->
+  <div class="flow-flowForm-detail">
+    <el-drawer v-model="isShowDialog" size="80%" direction="ltr">
+      <template #header>
+        <h4>流程表单详情-{{state.formData.name}}</h4>
+      </template>
+      <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick" style="margin: 8px;">
+        <el-tab-pane label="表单详情" name="0">
+          <div class="form-create-show">
+            <FormCreate :option="detailData.option" :rule="detailData.rule" :disabled="true" v-model="formData" />
+          </div>
+        </el-tab-pane>
+        <el-tab-pane label="审批记录" name="1">
+          <FlowLog ref="flowLogRef" :form-id="formId" :form-table="formTable" :key="formId"/>
+        </el-tab-pane>
+        <el-tab-pane label="流程图" name="2">
+          <ShowFlowDesign ref="showFlowCheckRef" />
+        </el-tab-pane>
+      </el-tabs>
+    </el-drawer>
+  </div>
+</template>
+<script lang="ts" setup>
+// 引入 form-create
+import formCreate from '@form-create/element-ui'
+// 引入 form-create-edit
+import FcEditor from "@form-create/component-wangeditor";
+import {reactive, ref, getCurrentInstance, toRefs} from 'vue';
+import {getFlowForm, getFlowFormData} from "/@/api/flow/flowForm";
+import {
+  FlowFormEditState, FlowFormTableColumns
+} from "/@/views/flow/flowForm/list/component/model"
+import {setConfAndFields2} from "/@/utils/formCreate";
+import FlowLog from "/@/components/gFlow/flowLog.vue";
+import ShowFlowDesign from "/@/components/gFlow/showDesign.vue";
+import {TabsPaneContext} from "element-plus";
+import {getRunStep} from "/@/api/flow/flowModel";
+formCreate.component(FcEditor)
+//获取 formCreate 组件
+const FormCreate = formCreate.$form();
+defineOptions({ name: "dataDetail"})
+const props = defineProps({
+  statusOptions:{
+    type:Array,
+    default:()=>[]
+  },
+})
+const flowLogRef = ref()
+const showFlowCheckRef = ref()
+const formId = ref(0)
+const formTable = ref('')
+const activeName = ref('0')
+const handleClick = (tab: TabsPaneContext) => {
+  if(tab.index=="1"){
+    flowLogRef.value.getLogList()
+  }else if(tab.index=="2"){
+    getRunStep({formTable:formTable.value,formId:formId.value}).then((res:any)=>{
+      showFlowCheckRef.value.showDesign({flowId:res.data.data?.runFlow||'0',processId:res.data.data?.runFlowNode||''})
+    })
+  }
+}
+const {proxy} = <any>getCurrentInstance()
+const dataId = ref(0)
+const formData = ref({});
+const detailData = ref({
+  rule: [],
+  option: {} as any,
+})
+const state = reactive<FlowFormEditState>({
+  loading:false,
+  isShowDialog: false,
+  formData: {
+    id: undefined,
+    name: undefined,
+    status: false ,
+    remark: undefined,
+    createdAt: undefined,
+    updatedAt: undefined,
+    deletedAt: undefined,
+    createdBy: undefined,
+    updatedBy: undefined,
+    conf: undefined,
+    fields: undefined,
+  },
+  // 表单校验
+  rules: {
+    name : [
+      { required: true, message: "表单名不能为空", trigger: "blur" }
+    ],
+    status : [
+      { required: true, message: "状态不能为空", trigger: "blur" }
+    ],
+  }
+});
+const {isShowDialog} = toRefs(state);
+// 打开弹窗
+const openDialog = async (row?: FlowFormTableColumns) => {
+  resetForm();
+  if(row) {
+    formId.value = row.actionBtn.wfFid
+    formTable.value = row.actionBtn.wfType
+    await getFlowForm(row.id!).then((res:any)=>{
+      const data = res.data;
+      data.createdBy = data.createdUser?.userNickname
+      data.updatedBy = data.updatedUser?.userNickname
+      state.formData = data;
+      setConfAndFields2(detailData, data.conf, data.fields)
+      detailData.value.option.submitBtn = false //隐藏提交按钮
+      detailData.value.option.resetBtn = false //隐藏重置按钮
+    })
+    if(row.dataId && row.dataId!=0){
+      dataId.value = row.dataId
+      //获取表单数据
+      getFlowFormData({formId:row.id,dataId:row.dataId}).then((res:any)=>{
+        formData.value = res.data.data
+      })
+    }
+  }
+  state.isShowDialog = true;
+};
+// 关闭弹窗
+const closeDialog = () => {
+  state.isShowDialog = false;
+};
+// 取消
+const onCancel = () => {
+  closeDialog();
+};
+const resetForm = ()=>{
+  state.formData = {
+    id: undefined,
+    name: undefined,
+    status: false ,
+    remark: undefined,
+    createdAt: undefined,
+    updatedAt: undefined,
+    deletedAt: undefined,
+    createdBy: undefined,
+    updatedBy: undefined,
+    conf: undefined,
+    fields: undefined,
+  }
+  dataId.value = 0
+  formData.value = {};
+  activeName.value = '0'
+};
+defineExpose({openDialog})
+</script>
+<style scoped>
+/*.flow-flowForm-detail :deep(.el-form-item__content ._fc-submit-btn),
+.flow-flowForm-detail :deep(.el-form-item__content ._fc-reset-btn){
+  display: none;
+}*/
+.flow-flowForm-detail :deep(.el-form-item__label){
+  font-weight: bolder;
+}
+.pic-block{
+  margin-right: 8px;
+}
+.file-block{
+  width: 100%;
+  border: 1px solid var(--el-border-color);
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+  transition: var(--el-transition-duration-fast);
+  margin-bottom: 5px;
+  padding: 3px 6px;
+}
+.ml-2{margin-right: 5px;}
+.form-create-show{
+  width: 100%;
+  padding: 16px;
+}
+</style>

+ 147 - 0
src/views/flow/flowForm/list/component/detail.vue

@@ -0,0 +1,147 @@
+<template>
+  <!-- 流程表单详情抽屉 -->
+  <div class="flow-flowForm-detail">
+    <el-drawer v-model="isShowDialog" size="80%" direction="ltr">
+      <template #header>
+        <h4>流程表单详情</h4>
+      </template>
+      <div class="form-create-show">
+        <FormCreate :option="detailData.option" :rule="detailData.rule" />
+      </div>
+    </el-drawer>
+  </div>
+</template>
+<script lang="ts">
+  // 引入 form-create
+  import formCreate from '@form-create/element-ui'
+  // 引入 form-create-edit
+  import FcEditor from "@form-create/component-wangeditor";
+  import { reactive, toRefs, defineComponent,ref,unref,getCurrentInstance,computed } from 'vue';
+  import {getFlowForm} from "/@/api/flow/flowForm";
+  import {
+    FlowFormInfoData,
+    FlowFormEditState
+  } from "/@/views/flow/flowForm/list/component/model"
+  import {setConfAndFields2} from "/@/utils/formCreate";
+  formCreate.component(FcEditor)
+  //获取 formCreate 组件
+  const FormCreate = formCreate.$form();
+  export default defineComponent({
+    name:"ApiV1FlowFlowFormDetail",
+    components:{
+      FormCreate
+    },
+    props:{
+      statusOptions:{
+        type:Array,
+        default:()=>[]
+      },
+    },
+    setup(props,{emit}) {
+      const {proxy} = <any>getCurrentInstance()
+      const formRef = ref<HTMLElement | null>(null);
+      const menuRef = ref();
+      const detailData = ref({
+        rule: [],
+        option: {}
+      })
+      const state = reactive<FlowFormEditState>({
+        loading:false,
+        isShowDialog: false,
+        formData: {
+          id: undefined,
+          name: undefined,
+          status: false ,
+          remark: undefined,
+          createdAt: undefined,
+          updatedAt: undefined,
+          deletedAt: undefined,
+          createdBy: undefined,
+          updatedBy: undefined,
+          conf: undefined,
+          fields: undefined,
+        },
+        // 表单校验
+        rules: {
+          name : [
+              { required: true, message: "表单名不能为空", trigger: "blur" }
+          ],
+          status : [
+              { required: true, message: "状态不能为空", trigger: "blur" }
+          ],
+        }
+      });
+        // 打开弹窗
+        const openDialog = (row?: FlowFormInfoData) => {
+          resetForm();
+          if(row) {
+            getFlowForm(row.id!).then((res:any)=>{
+              const data = res.data;
+              data.createdBy = data.createdUser?.userNickname
+              data.updatedBy = data.updatedUser?.userNickname
+              state.formData = data;
+              setConfAndFields2(detailData, data.conf, data.fields)
+            })
+          }
+          state.isShowDialog = true;
+        };
+        // 关闭弹窗
+        const closeDialog = () => {
+          state.isShowDialog = false;
+        };
+        // 取消
+        const onCancel = () => {
+          closeDialog();
+        };
+        const resetForm = ()=>{
+          state.formData = {
+            id: undefined,
+            name: undefined,
+            status: false ,
+            remark: undefined,
+            createdAt: undefined,
+            updatedAt: undefined,
+            deletedAt: undefined,
+            createdBy: undefined,
+            updatedBy: undefined,
+            conf: undefined,
+            fields: undefined,
+          }
+        };
+        return {
+          proxy,
+          openDialog,
+          closeDialog,
+          onCancel,
+          menuRef,
+          formRef,
+          detailData,
+          ...toRefs(state),
+        };
+      }
+  })
+</script>
+<style scoped>
+  .flow-flowForm-detail :deep(.el-form-item--large .el-form-item__label){
+    font-weight: bolder;
+  }
+  .pic-block{
+    margin-right: 8px;
+  }
+  .file-block{
+    width: 100%;
+    border: 1px solid var(--el-border-color);
+    border-radius: 6px;
+    cursor: pointer;
+    position: relative;
+    overflow: hidden;
+    transition: var(--el-transition-duration-fast);
+    margin-bottom: 5px;
+    padding: 3px 6px;
+  }
+  .ml-2{margin-right: 5px;}
+  .form-create-show{
+    width: 100%;
+    padding: 16px;
+  }
+</style>

+ 179 - 0
src/views/flow/flowForm/list/component/edit.vue

@@ -0,0 +1,179 @@
+<template>
+  <div class="flow-flowForm-edit">
+    <!-- 添加或修改流程表单对话框 -->
+    <el-dialog v-model="isShowDialog" width="800px" :close-on-click-modal="false" :destroy-on-close="true">
+      <template #header>
+        <div v-drag="['.flow-flowForm-edit .el-dialog', '.flow-flowForm-edit .el-dialog__header']">{{(!formData.id || formData.id==0?'添加':'修改')+'流程表单'}}</div>
+      </template>
+      <el-form ref="formRef" :model="formData" :rules="rules" label-width="120px">
+        <el-form-item label="表单名" prop="name">
+          <el-input v-model="formData.name" placeholder="请输入表单名" />
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-radio-group v-model="formData.status">
+            <el-radio
+              v-for="dict in statusOptions"
+              :key="dict.value"
+              :value="dict.value"
+            >{{dict.label }}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="formData.remark" type="textarea" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
+          <el-button @click="onCancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+<script lang="ts">
+import { reactive, toRefs, defineComponent,ref,unref,getCurrentInstance } from 'vue';
+import {ElMessageBox, ElMessage, FormInstance,UploadProps} from 'element-plus';
+import {
+  listFlowForm,
+  getFlowForm,
+  delFlowForm,
+  addFlowForm,
+  updateFlowForm,
+} from "/@/api/flow/flowForm";
+import {
+  FlowFormTableColumns,
+  FlowFormInfoData,
+  FlowFormTableDataState,
+  FlowFormEditState
+} from "/@/views/flow/flowForm/list/component/model"
+export default defineComponent({
+  name:"ApiV1FlowFlowFormEdit",
+  components:{
+  },
+  props:{
+    statusOptions:{
+      type:Array,
+      default:()=>[]
+    },
+  },
+  setup(props,{emit}) {
+    const {proxy} = <any>getCurrentInstance()
+    const formRef = ref<HTMLElement | null>(null);
+    const menuRef = ref();
+    const state = reactive<FlowFormEditState>({
+      loading:false,
+      isShowDialog: false,
+      formData: {
+        id: undefined,
+        name: undefined,
+        status: false ,
+        remark: undefined,
+        createdAt: undefined,
+        updatedAt: undefined,
+        deletedAt: undefined,
+        createdBy: undefined,
+        updatedBy: undefined,
+        conf: undefined,
+        fields: undefined,
+      },
+      // 表单校验
+      rules: {
+        name : [
+            { required: true, message: "表单名不能为空", trigger: "blur" }
+        ],
+        status : [
+            { required: true, message: "状态不能为空", trigger: "blur" }
+        ],
+      }
+    });
+    // 打开弹窗
+    const openDialog = (row?: FlowFormInfoData) => {
+      resetForm();
+      if(row) {
+        getFlowForm(row.id!).then((res:any)=>{
+          const data = res.data;
+          data.status = ''+data.status
+          state.formData = data;
+        })
+      }
+      state.isShowDialog = true;
+    };
+    const setFormDesignData = (fields:any,conf:any)=>{
+      state.formData.fields = fields
+      state.formData.conf = conf
+    }
+    // 关闭弹窗
+    const closeDialog = () => {
+      state.isShowDialog = false;
+    };
+    // 取消
+    const onCancel = () => {
+      closeDialog();
+    };
+    // 提交
+    const onSubmit = () => {
+      emit('setFormData')
+      const formWrap = unref(formRef) as any;
+      if (!formWrap) return;
+      formWrap.validate((valid: boolean) => {
+        if (valid) {
+          state.loading = true;
+          if(!state.formData.id || state.formData.id===0){
+            //添加
+          addFlowForm(state.formData).then(()=>{
+              ElMessage.success('添加成功');
+              closeDialog(); // 关闭弹窗
+              emit('flowFormList')
+              emit('close')
+            }).finally(()=>{
+              state.loading = false;
+            })
+          }else{
+            //修改
+          updateFlowForm(state.formData).then(()=>{
+              ElMessage.success('修改成功');
+              closeDialog(); // 关闭弹窗
+              emit('flowFormList')
+              emit('close')
+            }).finally(()=>{
+              state.loading = false;
+            })
+          }
+        }
+      });
+    };
+    const resetForm = ()=>{
+      state.formData = {
+        id: undefined,
+        name: undefined,
+        status: false ,
+        remark: undefined,
+        createdAt: undefined,
+        updatedAt: undefined,
+        deletedAt: undefined,
+        createdBy: undefined,
+        updatedBy: undefined,
+        conf: undefined,
+        fields: undefined,
+      }
+    };
+    return {
+      proxy,
+      openDialog,
+      closeDialog,
+      onCancel,
+      onSubmit,
+      menuRef,
+      formRef,
+      setFormDesignData,
+      ...toRefs(state),
+    };
+  }
+})
+</script>
+<style scoped>
+  .kv-label{margin-bottom: 15px;font-size: 14px;}
+  .mini-btn i.el-icon{margin: unset;}
+  .kv-row{margin-bottom: 12px;}
+</style>

+ 80 - 0
src/views/flow/flowForm/list/component/formDesign.vue

@@ -0,0 +1,80 @@
+<template>
+  <div class="flow-formDesign-container">
+    <el-card shadow="hover">
+      <!-- 表单设计器 -->
+      <FcDesigner ref="designer" height="780px" :config="config">
+        <template #handle>
+          <el-button round size="small" type="primary" @click="handleSave">
+            <el-icon><ele-Plus /></el-icon>
+            保存
+          </el-button>
+        </template>
+      </FcDesigner>
+    </el-card>
+    <ApiV1FlowFlowFormEdit
+        ref="editRef"
+        :statusOptions="flow_form_status"
+        @setFormData="setFormData"
+        @flowFormList="flowFormList"
+        @close="close"
+    ></ApiV1FlowFlowFormEdit>
+  </div>
+</template>
+<script setup lang="ts">
+  import { useRoute } from 'vue-router';
+  import {getCurrentInstance, onMounted, ref} from "vue";
+  import FcDesigner from '@form-create/designer'
+  import ApiV1FlowFlowFormEdit from "/@/views/flow/flowForm/list/component/edit.vue";
+  import {encodeConf, encodeFields, setConfAndFields} from "/@/utils/formCreate";
+  import {getFlowForm} from "/@/api/flow/flowForm";
+  import {FlowFormInfoData} from "/@/views/flow/flowForm/list/component/model";
+  defineOptions({ name: 'apiV1FlowFlowFormDesign' })
+  const {proxy} = <any>getCurrentInstance()
+  // 字典选项数据
+  const {
+    flow_form_status,
+  } = proxy.useDict(
+      'flow_form_status',
+  )
+  const config = {
+    //控制字段ID输入框能否输入
+    fieldReadonly: false
+  }
+  /** 处理保存按钮 */
+  const designer =ref()
+  const editRef = ref()
+  const route = useRoute();
+  const formData = ref<FlowFormInfoData>()
+  onMounted(()=>{
+    if (route.query.id){
+      let id = parseInt(route.query.id as string)
+      getFlowForm(id).then((res:any)=>{
+        const data = res.data;
+        formData.value = data
+        setConfAndFields(designer, data.conf, data.fields)
+      })
+    }
+  })
+  const handleSave = () => {
+    if(formData.value){
+      editRef.value.openDialog(formData.value)
+    }else{
+      editRef.value.openDialog()
+    }
+  }
+  const setFormData = ()=>{
+    let fields = encodeFields(designer) // 表单字段
+    let conf = encodeConf(designer) // 表单配置
+    editRef.value.setFormDesignData(fields,conf)
+  }
+  const close = ()=>{
+    proxy.mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 1, ...route }));
+  }
+  const emit = defineEmits(['flowFormList'])
+  const flowFormList = ()=>{
+    emit('flowFormList')
+  }
+</script>
+<style scoped lang="scss">
+
+</style>

+ 61 - 0
src/views/flow/flowForm/list/component/model.ts

@@ -0,0 +1,61 @@
+export interface FlowFormTableColumns {
+    id:number;  // 主键
+    name:string;  // 表单名
+    status:number;  // 状态
+    remark:string;  // 备注
+    createdAt:string;  // 创建时间
+    createdBy:string;  // 创建人
+    isPub:boolean;//是否已部署
+    dataId:number;//表单数据ID
+    actionBtn?:any
+}
+
+
+export interface FlowFormInfoData {
+    id:number|undefined;        // 主键
+    name:string|undefined; // 表单名
+    status:boolean; // 状态
+    remark:string|undefined; // 备注
+    createdAt:string|undefined; // 创建时间
+    updatedAt:string|undefined; // 修改时间
+    deletedAt:string|undefined; // 删除时间
+    createdBy:number|undefined; // 创建人
+    updatedBy:number|undefined; // 修改人
+    conf:string|undefined; // 表单配置
+    fields:string|undefined; // 表单字段
+}
+
+
+export interface FlowFormTableDataState {
+    ids:any[];
+    tableData: {
+        data: Array<FlowFormTableColumns>;
+        total: number;
+        loading: boolean;
+        param: {
+            pageNum: number;
+            pageSize: number;
+            name: string|undefined;
+            status: number|undefined;
+            createdAt: string|undefined;
+            dateRange: string[];
+            isPub:boolean|undefined;
+        };
+    };
+}
+
+
+export interface FlowFormEditState{
+    loading:boolean;
+    isShowDialog: boolean;
+    formData:FlowFormInfoData;
+    rules: object;
+}
+
+export interface  FormFieldsData{
+    field:string;
+    hidden:boolean;
+    display:boolean;
+    title:string;
+    type:string;
+}

+ 355 - 0
src/views/flow/flowForm/list/index.vue

@@ -0,0 +1,355 @@
+<template>
+  <div class="flow-flowForm-container">
+    <el-card shadow="hover">
+        <div class="flow-flowForm-search mb15">
+            <el-form :model="tableData.param" ref="queryRef" :inline="true" label-width="100px">
+            <el-row>
+                <el-col :span="8" class="colBlock">
+                  <el-form-item label="表单名" prop="name">
+                    <el-input
+                        v-model="tableData.param.name"
+                        placeholder="请输入表单名"
+                        clearable
+                        @keyup.enter.native="flowFormList"
+                    />
+                  </el-form-item>
+                </el-col>
+                <el-col :span="8" class="colBlock">
+                  <el-form-item label="状态" prop="status">
+                    <el-select v-model="tableData.param.status" placeholder="请选择状态" clearable style="width: 160px">
+                        <el-option
+                            v-for="dict in flow_form_status"
+                            :key="dict.value"
+                            :label="dict.label"
+                            :value="dict.value"
+                        />
+                    </el-select>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="8" :class="!showAll ? 'colBlock' : 'colNone'">
+                  <el-form-item>
+                    <el-button type="primary"  @click="flowFormList"><el-icon><ele-Search /></el-icon>搜索</el-button>
+                    <el-button  @click="resetQuery(queryRef)"><el-icon><ele-Refresh /></el-icon>重置</el-button>
+                    <el-button type="primary" link  @click="toggleSearch">
+                      {{ word }}
+                      <el-icon v-show="showAll"><ele-ArrowUp/></el-icon>
+                      <el-icon v-show="!showAll"><ele-ArrowDown /></el-icon>
+                    </el-button>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="8" :class="showAll ? 'colBlock' : 'colNone'">
+                  <el-form-item label="创建时间" prop="createdAt">
+                    <el-date-picker
+                        clearable  style="width: 200px"
+                        v-model="tableData.param.createdAt"
+                        format="YYYY-MM-DD HH:mm:ss"
+                        value-format="YYYY-MM-DD HH:mm:ss"
+                        type="datetime"
+                        placeholder="选择创建时间"
+                    ></el-date-picker>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="8" :class="showAll ? 'colBlock' : 'colNone'">
+                  <el-form-item>
+                    <el-button type="primary"  @click="flowFormList"><el-icon><ele-Search /></el-icon>搜索</el-button>
+                    <el-button  @click="resetQuery(queryRef)"><el-icon><ele-Refresh /></el-icon>重置</el-button>
+                    <el-button type="primary" link  @click="toggleSearch">
+                        {{ word }}
+                        <el-icon v-show="showAll"><ele-ArrowUp/></el-icon>
+                        <el-icon v-show="!showAll"><ele-ArrowDown /></el-icon>
+                    </el-button>
+                  </el-form-item>
+                </el-col>
+              </el-row>
+            </el-form>
+            <el-row :gutter="10" class="mb8">
+              <el-col :span="1.5">
+                <el-button
+                  type="primary"
+                  @click="handleAdd"
+                  v-auth="'api/v1/flow/flowForm/add'"
+                ><el-icon><ele-Plus /></el-icon>新增</el-button>
+              </el-col>
+              <el-col :span="1.5">
+                <el-button
+                  type="success"
+                  :disabled="single"
+                  @click="handleUpdate(null)"
+                  v-auth="'api/v1/flow/flowForm/edit'"
+                ><el-icon><ele-Edit /></el-icon>修改</el-button>
+              </el-col>
+              <el-col :span="1.5">
+                <el-button
+                  type="danger"
+                  :disabled="multiple"
+                  @click="handleDelete(null)"
+                  v-auth="'api/v1/flow/flowForm/delete'"
+                ><el-icon><ele-Delete /></el-icon>删除</el-button>
+              </el-col>
+            </el-row>
+        </div>
+        <el-table v-loading="loading" :data="tableData.data" @selection-change="handleSelectionChange">
+          <el-table-column type="selection" width="55" align="center" />
+          <el-table-column label="主键" align="center" prop="id"
+            min-width="150px"
+             />
+          <el-table-column label="表单名" align="center" prop="name"
+            min-width="150px"
+             />
+          <el-table-column label="状态" align="center" prop="status" :formatter="statusFormat"
+            min-width="150px"
+             />
+          <el-table-column label="部署情况" align="center" prop="status" :formatter="isPubFormat"
+                           min-width="150px"
+          />
+          <el-table-column label="备注" align="center" prop="remark"
+            min-width="150px"
+             />
+          <el-table-column label="创建时间" align="center" prop="createdAt"
+            min-width="150px"
+            >
+            <template #default="scope">
+                <span>{{ proxy.parseTime(scope.row.createdAt, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="创建人" align="center" prop="createdBy"
+            min-width="150px"
+             />
+          <el-table-column label="操作" align="center" class-name="small-padding" min-width="200px" fixed="right">
+            <template #default="scope">
+              <el-button
+                type="primary"
+                link
+                @click="handleView(scope.row)"
+                v-auth="'api/v1/flow/flowForm/get'"
+              ><el-icon><ele-View /></el-icon>详情</el-button>
+              <el-button
+                type="primary"
+                link
+                @click="handleUpdate(scope.row)"
+                v-auth="'api/v1/flow/flowForm/edit'"
+              ><el-icon><ele-EditPen /></el-icon>修改</el-button>
+              <el-button
+                  type="primary"
+                  link
+                  @click="handleGen(scope.row)"
+                  v-auth="'api/v1/flow/flowForm/gen'"
+              ><el-icon><ele-Position /></el-icon>部署表单</el-button>
+              <el-button
+                type="primary"
+                link
+                @click="handleDelete(scope.row)"
+                v-auth="'api/v1/flow/flowForm/delete'"
+              ><el-icon><ele-DeleteFilled /></el-icon>删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <pagination
+            v-show="tableData.total>0"
+            :total="tableData.total"
+            v-model:page="tableData.param.pageNum"
+            v-model:limit="tableData.param.pageSize"
+            @pagination="flowFormList"
+        />
+    </el-card>
+    <ApiV1FlowFlowFormDetail
+      ref="detailRef"
+      :statusOptions="flow_form_status"
+      @flowFormList="flowFormList"
+    ></ApiV1FlowFlowFormDetail>
+  </div>
+</template>
+<script lang="ts">
+import {toRefs, reactive, onMounted, ref, defineComponent, computed,getCurrentInstance,toRaw} from 'vue';
+import {ElMessageBox, ElMessage, FormInstance} from 'element-plus';
+import {
+  listFlowForm,
+  delFlowForm, genFlowForm,
+} from "/@/api/flow/flowForm";
+import {
+    FlowFormTableColumns,
+    FlowFormInfoData,
+    FlowFormTableDataState,
+} from "/@/views/flow/flowForm/list/component/model"
+import ApiV1FlowFlowFormDetail from "/@/views/flow/flowForm/list/component/detail.vue"
+import {useRouter} from "vue-router";
+export default defineComponent({
+    name: "ApiV1FlowFlowFormList",
+    components:{
+        ApiV1FlowFlowFormDetail
+    },
+    setup() {
+        const router = useRouter();
+        const {proxy} = <any>getCurrentInstance()
+        const loading = ref(false)
+        const queryRef = ref()
+        const editRef = ref();
+        const detailRef = ref();
+        // 是否显示所有搜索选项
+        const showAll =  ref(false)
+        // 非单个禁用
+        const single = ref(true)
+        // 非多个禁用
+        const multiple =ref(true)
+        const word = computed(()=>{
+            if(showAll.value === false) {
+                //对文字进行处理
+                return "展开搜索";
+            } else {
+                return "收起搜索";
+            }
+        })
+        // 字典选项数据
+        const {
+            flow_form_status,
+        } = proxy.useDict(
+            'flow_form_status',
+        )
+        const state = reactive<FlowFormTableDataState>({
+            ids:[],
+            tableData: {
+                data: [],
+                total: 0,
+                loading: false,
+                param: {
+                    pageNum: 1,
+                    pageSize: 10,
+                    name: undefined,
+                    status: undefined,
+                    createdAt: undefined,
+                    dateRange: [],
+                    isPub:undefined
+                },
+            },
+        });
+        // 页面加载时
+        onMounted(() => {
+            initTableData();
+        });
+        // 初始化表格数据
+        const initTableData = () => {
+            flowFormList()
+        };
+        /** 重置按钮操作 */
+        const resetQuery = (formEl: FormInstance | undefined) => {
+            if (!formEl) return
+            formEl.resetFields()
+            flowFormList()
+        };
+        // 获取列表数据
+        const flowFormList = ()=>{
+          loading.value = true
+          listFlowForm(state.tableData.param).then((res:any)=>{
+            let list = res.data.list??[];
+            list.map((item:any)=>{
+                item.createdBy = item.createdUser?.userNickname
+            })
+            state.tableData.data = list;
+            state.tableData.total = res.data.total;
+            loading.value = false
+          })
+        };
+        const toggleSearch = () => {
+            showAll.value = !showAll.value;
+        }
+        // 状态字典翻译
+        const statusFormat = (row:FlowFormTableColumns) => {
+            return proxy.selectDictLabel(flow_form_status.value, row.status);
+        }
+        const isPubFormat = (row:FlowFormTableColumns)=>{
+          return row.isPub?"已部署":"未部署"
+        }
+        // 多选框选中数据
+        const handleSelectionChange = (selection:Array<FlowFormInfoData>) => {
+            state.ids = selection.map(item => item.id)
+            single.value = selection.length!=1
+            multiple.value = !selection.length
+        }
+        const handleAdd =  ()=>{
+          router.push("/flow/flowForm/formDesign")
+        }
+        const handleUpdate = (row: FlowFormTableColumns) => {
+            if(!row){
+                row = state.tableData.data.find((item:FlowFormTableColumns)=>{
+                    return item.id ===state.ids[0]
+                }) as FlowFormTableColumns
+            }
+            router.push("/flow/flowForm/formDesign?id="+row.id)
+        };
+        const handleGen = (row: FlowFormTableColumns) => {
+            ElMessageBox.confirm('您确定要部署表单?部署将覆盖原有数据,请确认是否已备份。', '提示', {
+              confirmButtonText: '确认',
+              cancelButtonText: '取消',
+              type: 'warning',
+            }).then(()=>{
+              genFlowForm(row.id).then(()=>{
+                ElMessage.success('部署成功');
+                flowFormList();
+              })
+            }).catch()
+        }
+        const handleDelete = (row: FlowFormTableColumns) => {
+            let msg = '你确定要删除所选数据?';
+            let id:number[] = [] ;
+            if(row){
+            msg = `此操作将永久删除数据,是否继续?`
+            id = [row.id]
+            }else{
+            id = state.ids
+            }
+            if(id.length===0){
+                ElMessage.error('请选择要删除的数据。');
+                return
+            }
+            ElMessageBox.confirm(msg, '提示', {
+                confirmButtonText: '确认',
+                cancelButtonText: '取消',
+                type: 'warning',
+            })
+                .then(() => {
+                    delFlowForm(id).then(()=>{
+                        ElMessage.success('删除成功');
+                        flowFormList();
+                    })
+                })
+                .catch(() => {});
+        }
+        const handleView = (row:FlowFormTableColumns)=>{
+            detailRef.value.openDialog(toRaw(row));
+        }
+        return {
+            proxy,
+            editRef,
+            detailRef,
+            showAll,
+            loading,
+            single,
+            multiple,
+            word,
+            queryRef,
+            resetQuery,
+            flowFormList,
+            toggleSearch,
+            statusFormat,
+            flow_form_status,
+            handleSelectionChange,
+            handleAdd,
+            handleUpdate,
+            handleDelete,
+            handleView,
+            handleGen,
+            isPubFormat,
+            ...toRefs(state),
+        }
+    }
+})
+</script>
+<style lang="scss" scoped>
+    .colBlock {
+        display: block;
+    }
+    .colNone {
+        display: none;
+    }
+    .ml-2{margin: 3px;}
+</style>

+ 280 - 0
src/views/flow/flowModel/list/component/design.vue

@@ -0,0 +1,280 @@
+<template>
+  <div class="FL-container getting-started">
+    <!-- 辅助工具栏 -->
+    <Control class="demo-control" v-if="lf.container" :lf="lf as LogicFlow" @catData="$_catData" @saveModel="$_saveModel"></Control>
+    <!-- 画布 -->
+    <div class="app-content" ref="logicFlowContainerRef"></div>
+    <!-- 属性面板 -->
+    <el-drawer title="设置节点属性" v-model="dialogVisible" direction="rtl" size="900px" :before-close="closeDialog">
+      <PropertyDialog v-if="dialogVisible" :nodeData="clickNode" :lf="lf as LogicFlow" @setPropertiesFinish="closeDialog"></PropertyDialog>
+    </el-drawer>
+    <!-- 数据查看面板 -->
+    <el-dialog title="数据" v-model="dataVisible" width="50%">
+      <DataDialog :graphData="graphData"></DataDialog>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+import LogicFlow from "@logicflow/core";
+import {DndPanel, Menu, MiniMap, SelectionSelect} from '@logicflow/extension';
+import "@logicflow/core/lib/style/index.css";
+import '@logicflow/extension/lib/style/index.css';
+import {onMounted, ref} from "vue";
+import Control from "/@/components/gFlow/Control.vue"
+import {setPatternItems, setTheme} from "/@/components/gFlow/config";
+
+import {
+  registerEnd,
+  registerStart,
+  registerConcurrent,
+  registerPush,
+  registerCondition,
+  registerUserTask
+} from "/@/components/gFlow/registerNode";
+
+import { Snapshot } from "@logicflow/extension";
+import PropertyDialog from "/@/components/gFlow/propertySetting/PropertyDialog.vue";
+import DataDialog from "/@/components/gFlow/DataDialog.vue";
+import {useRoute} from "vue-router";
+import {ElMessage} from "element-plus";
+import {getNodeData, saveModeNode} from "/@/api/flow/flowModel";
+import {
+  FlowCheckRuleDept,
+  FlowCheckRuleDeptLeader, FlowCheckRulePost,
+  FlowCheckRuleRole,
+  FlowCheckRuleUser
+} from "/@/components/gFlow/consts";
+import GraphConfigData = LogicFlow.GraphConfigData;
+defineOptions({ name: "logicFlowDesign"})
+const route = useRoute()
+const modelId = ref(0)
+const logicFlowContainerRef = ref()
+const lf = ref<LogicFlow>({} as LogicFlow)
+const dataVisible = ref(false)
+const graphData = ref<GraphConfigData>()
+const addPanelStyle = ref({
+  top: '0',
+  left: '0',
+})
+const showAddPanel = ref(false)
+const addClickNode = ref<any>()
+const clickNode = ref({})
+const dialogVisible = ref(false)
+const moveData = ref({})
+onMounted(()=>{
+  if (route.query.id){
+    modelId.value = parseInt(route.query.id as string)
+  }else{
+    ElMessage.error('参数错误');
+    return
+  }
+  lf.value = new LogicFlow({
+    container: logicFlowContainerRef.value,
+    grid: true,
+    plugins: [DndPanel, SelectionSelect,Snapshot,Menu, MiniMap],
+    pluginsOptions: {
+      miniMap: {
+        isShowHeader: false,
+        isShowCloseIcon: true,
+        headerTitle: 'MiniMap'
+      }
+    }
+  })
+  registerNode()
+  initLF()
+})
+//注册节点信息
+const registerNode = ()=>{
+  const logicFlow = lf.value as LogicFlow
+  registerStart(logicFlow)
+  registerEnd(logicFlow)
+  registerConcurrent(logicFlow)
+  registerPush(logicFlow)
+  registerCondition(logicFlow)
+  registerUserTask(logicFlow)
+}
+
+const initLF=()=>{
+  const logicFlow = lf.value as LogicFlow;
+  setPatternItems(logicFlow)
+  setTheme(logicFlow)
+  $_render()
+  $_LfEvent()
+}
+const $_render = ()=>{
+  //获取节点数据
+  getNodeData(modelId.value).then((res:any)=>{
+    const nodes = (res.data.nodes??[]).map((item:any)=>{
+      const node = {
+        id: item.nodeId,
+        type: item.nodeType,
+        x: item.nodePosition.x,
+        y: item.nodePosition.y,
+        text: item.nodeText??{},
+        properties: {
+          text: item.nodeText?.value,
+          actionRule: item.nodeActionRule,
+          approveRule: item.nodeRule,
+          notice: item.notice ?? [],
+          rollback: item.rollback,
+          nodeExt: item.nodeExt??[],
+					deptProv: item.deptProv??1
+        }
+      }
+      setReceiver(node,item.nodeReceiver)
+      return node
+    })
+    const edges = (res.data.edges??[]).map((item:any)=>{
+      return {
+        id: item.id,
+        type: item.lineType,
+        sourceNodeId: item.sourceNodeId,
+        targetNodeId: item.targetNodeId,
+        startPoint:item.startPoint,
+        endPoint:item.endPoint,
+        properties: item.properties,
+        pointsList: item.pointsList,
+        text:item.text
+      }
+    })
+    lf.value.render({nodes,edges});
+    $_LfEvent();
+  })
+}
+const setReceiver = (node:any,receivers:Array<string>)=>{
+  switch(node.properties.actionRule){
+    case FlowCheckRuleRole://角色
+      node.properties.roleIds = receivers
+      break
+    case FlowCheckRuleDept://部门
+    case FlowCheckRuleDeptLeader://部门负责人
+      node.properties.deptIds = receivers
+      break
+    case FlowCheckRuleUser://指定人员
+      node.properties.userIds = receivers
+      break
+    case FlowCheckRulePost://岗位
+      node.properties.postIds = receivers
+  }
+}
+const $_catData = () => {
+  graphData.value = lf.value.getGraphData() as GraphConfigData;
+  dataVisible.value = true;
+}
+const $_saveModel = ()=>{
+  const data = lf.value.getGraphData() as any
+  const nodes = data.nodes.map((item:any)=>{
+    return {
+      nodeId:item.id,
+      modelId:modelId.value,
+      nodeType:item.type,
+      nodePosition:{x:item.x,y:item.y},
+      nodeText:item.text,
+      nodeActionRule:item.properties?.actionRule,
+      nodeReceiver: getNodeReceiver(item.properties?.actionRule,item),
+      nodeRule:item.properties?.approveRule,
+      notice:item.properties?.notice,
+      rollback:item.properties?.rollback,
+      nodeExt:item.properties?.nodeExt,
+			deptProv:item.properties?.deptProv
+    }
+  })
+  const edges = data.edges.map((item:any)=>{
+    return {
+      modelId:modelId.value,
+      lineType:item.type,
+      sourceNodeId:item.sourceNodeId,
+      targetNodeId:item.targetNodeId,
+      startPoint:item.startPoint,
+      endPoint:item.endPoint,
+      properties:item.properties,
+      text:item.text,
+      pointsList:item.pointsList
+    }
+  })
+  const postData = {
+    modelId:modelId.value,
+    nodes:nodes,
+    edges:edges
+  }
+  saveModeNode(postData).then((res:any)=>{
+    if(res.code===0){
+      ElMessage.success('保存成功');
+    }else{
+      ElMessage.error(res.data.message);
+    }
+  })
+}
+const $_LfEvent=()=>{
+  const logicFlow = lf.value as LogicFlow;
+  logicFlow.on('node:click', (data) => {
+    console.log('node:click', data);
+    clickNode.value = data.data;
+    dialogVisible.value = true;
+  })
+  logicFlow.on('edge:click', ({ data }) => {
+    console.log('edge:click', data);
+    //this.$data.clickNode = data;
+    //this.$data.dialogVisible = true;
+  });
+  logicFlow.on('element:click', () => {
+    hideAddPanel();
+  });
+  logicFlow.on('edge:add', ({ data }) => {
+    console.log('edge:add', data);
+  });
+  logicFlow.on('node:mousemove', ({ data }) => {
+    console.log('node:mousemove');
+    moveData.value = data;
+  });
+  logicFlow.on('blank:click', () => {
+    hideAddPanel();
+  });
+  logicFlow.on('connection:not-allowed', (data) => {
+    console.log('connection:not-allowed',data)
+  });
+  logicFlow.on('node:mousemove', () => {
+    console.log('on mousemove');
+  });
+}
+const hideAddPanel = () => {
+  showAddPanel.value = false;
+  addPanelStyle.value.top = '0';
+  addPanelStyle.value.left = '0';
+  addClickNode.value = null;
+}
+const closeDialog = () => {
+  dialogVisible.value = false;
+}
+const getNodeReceiver = (rule:number,item:any)=>{
+  switch(rule){
+    case FlowCheckRuleRole://角色
+      return item.properties.roleIds
+    case FlowCheckRuleDept://部门
+    case FlowCheckRuleDeptLeader://部门负责人
+      return item.properties.deptIds
+    case FlowCheckRuleUser://指定人员
+      return item.properties.userIds
+    case FlowCheckRulePost://岗位
+      return item.properties.postIds
+  }
+  return []
+}
+</script>
+
+<style scoped lang="scss">
+.FL-container {
+  width: 100%;
+  overflow: hidden;
+  .app-content {
+    height: calc(100vh - 120px);
+  }
+}
+.demo-control{
+  position: absolute;
+  top: 20px;
+  right: 50px;
+  z-index: 2;
+}
+</style>

+ 221 - 0
src/views/flow/flowModel/list/component/detail.vue

@@ -0,0 +1,221 @@
+<template>
+  <!-- 流程模型详情抽屉 -->
+  <div class="flow-flowModel-detail">
+    <el-drawer v-model="isShowDialog" size="80%" direction="ltr">
+      <template #header>
+        <h4>流程模型详情</h4>
+      </template>
+      <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick" style="margin: 8px;">
+        <el-tab-pane label="表单详情" name="0">
+          <el-form ref="formRef" :model="formData" label-width="100px">
+            <el-row>
+              <el-col :span="12">
+                <el-form-item label="主键">{{ formData.id }}</el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="流程名称">{{ formData.name }}</el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="表单类型">{{ proxy.getOptionValue(formData.flowType, flowTypeOptions,'value','label') }}</el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="流程表单类别">{{ formData.linkedFlowFormCate?formData.linkedFlowFormCate.name:'' }}</el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="流程描述">{{ formData.remark }}</el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="业务表单类别">{{ proxy.getOptionValue(formData.flowBusinessCate, flowBusinessCateOptions,'value','label') }}</el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="流程状态">{{ proxy.getOptionValue(formData.status, statusOptions,'value','label') }}</el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="创建时间">{{ proxy.parseTime(formData.createdAt, '{y}-{m}-{d} {h}:{i}:{s}') }}</el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="创建人">{{ formData.createdBy }}</el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="修改人">{{ formData.updatedBy }}</el-form-item>
+              </el-col>
+            </el-row>
+          </el-form>
+        </el-tab-pane>
+        <el-tab-pane label="流程图" name="1">
+          <ShowFlowDesign ref="showFlowCheckRef" />
+        </el-tab-pane>
+      </el-tabs>
+    </el-drawer>
+  </div>
+</template>
+<script lang="ts">
+  import ShowFlowDesign from "/@/components/gFlow/showDesign.vue";
+  import { reactive, toRefs, defineComponent,ref,getCurrentInstance,computed } from 'vue';
+  import {
+    getFlowModel,
+  } from "/@/api/flow/flowModel";
+  import {
+    FlowModelInfoData,
+    FlowModelEditState
+  } from "/@/views/flow/flowModel/list/component/model"
+  import {TabsPaneContext} from "element-plus";
+  export default defineComponent({
+    name:"ApiV1FlowFlowModelDetail",
+    components:{
+      ShowFlowDesign
+    },
+    props:{
+      flowTypeOptions:{
+        type:Array,
+        default:()=>[]
+      },
+      flowFormCateOptions:{
+        type:Array,
+        default:()=>[]
+      },
+      flowBusinessCateOptions:{
+        type:Array,
+        default:()=>[]
+      },
+      statusOptions:{
+        type:Array,
+        default:()=>[]
+      },
+    },
+    setup(props,{emit}) {
+      const showFlowCheckRef = ref()
+      const activeName = ref('0')
+      const handleClick = (tab: TabsPaneContext) => {
+        if(tab.index=="1"){
+          showFlowCheckRef.value.showDesign({flowId:state.formData.id,processId:''})
+        }
+      }
+      const {proxy} = <any>getCurrentInstance()
+      const formRef = ref<HTMLElement | null>(null);
+      const menuRef = ref();
+      const state = reactive<FlowModelEditState>({
+        loading:false,
+        isShowDialog: false,
+        formData: {
+          id: undefined,
+          name: undefined,
+          flowType: undefined ,
+          flowFormCate: undefined,
+          linkedFlowFormCate:{id:undefined,name:undefined },
+          remark: undefined,
+          flowBusinessCate: undefined,
+          sort: undefined,
+          status: undefined ,
+          createdAt: undefined,
+          updatedAt: undefined,
+          deletedAt: undefined,
+          createdBy: undefined,
+          updatedBy: undefined,
+          linkedFlowModelFlowForm: {
+            id:undefined,    // 主键
+            name:undefined,    // 表单名
+          },
+        },
+        // 表单校验
+        rules: {
+          id : [
+              { required: true, message: "主键不能为空", trigger: "blur" }
+          ],
+          name : [
+              { required: true, message: "流程名称不能为空", trigger: "blur" }
+          ],
+          status : [
+              { required: true, message: "流程状态不能为空", trigger: "blur" }
+          ],
+        }
+      });
+        // 打开弹窗
+        const openDialog = (row?: FlowModelInfoData) => {
+          resetForm();
+          if(row) {
+            getFlowModel(row.id!).then((res:any)=>{
+              const data = res.data;
+              data.createdBy = data.createdUser?.userNickname
+              data.updatedBy = data.updatedUser?.userNickname
+              state.formData = data;
+            })
+          }
+          state.isShowDialog = true;
+        };
+        // 关闭弹窗
+        const closeDialog = () => {
+          state.isShowDialog = false;
+        };
+        // 取消
+        const onCancel = () => {
+          closeDialog();
+        };
+        const resetForm = ()=>{
+          state.formData = {
+            id: undefined,
+            name: undefined,
+            flowType: undefined ,
+            flowFormCate: undefined,
+            linkedFlowFormCate:{id:undefined,name:undefined },
+            remark: undefined,
+            flowBusinessCate: undefined,
+            sort: undefined,
+            status: undefined ,
+            createdAt: undefined,
+            updatedAt: undefined,
+            deletedAt: undefined,
+            createdBy: undefined,
+            updatedBy: undefined,
+            linkedFlowModelFlowForm: {
+              id:undefined,    // 主键
+              name:undefined,    // 表单名
+            },
+          }
+          activeName.value = '0'
+        };
+        //关联flow_form表选项
+        const getFlowFormItemsFlowFormCate = () => {
+          emit("getFlowFormItemsFlowFormCate")
+        }
+        const getFlowFormCateOp = computed(()=>{
+          getFlowFormItemsFlowFormCate()
+          return props.flowFormCateOptions
+        })
+        return {
+          proxy,
+          openDialog,
+          closeDialog,
+          onCancel,
+          menuRef,
+          formRef,
+          getFlowFormItemsFlowFormCate,
+          getFlowFormCateOp,
+          showFlowCheckRef,
+          activeName,
+          handleClick,
+          ...toRefs(state),
+        };
+      }
+  })
+</script>
+<style scoped>
+  .flow-flowModel-detail :deep(.el-form-item--large .el-form-item__label){
+    font-weight: bolder;
+  }
+  .pic-block{
+    margin-right: 8px;
+  }
+  .file-block{
+    width: 100%;
+    border: 1px solid var(--el-border-color);
+    border-radius: 6px;
+    cursor: pointer;
+    position: relative;
+    overflow: hidden;
+    transition: var(--el-transition-duration-fast);
+    margin-bottom: 5px;
+    padding: 3px 6px;
+  }
+  .ml-2{margin-right: 5px;}
+</style>

+ 233 - 0
src/views/flow/flowModel/list/component/edit.vue

@@ -0,0 +1,233 @@
+<template>
+  <div class="flow-flowModel-edit">
+    <!-- 添加或修改流程模型对话框 -->
+    <el-dialog v-model="isShowDialog" width="800px" :close-on-click-modal="false" :destroy-on-close="true">
+      <template #header>
+        <div v-drag="['.flow-flowModel-edit .el-dialog', '.flow-flowModel-edit .el-dialog__header']">{{(!formData.id || formData.id==0?'添加':'修改')+'流程模型'}}</div>
+      </template>
+      <el-form ref="formRef" :model="formData" :rules="rules" label-width="120px">
+        <el-form-item label="流程名称" prop="name">
+          <el-input v-model="formData.name" placeholder="请输入流程名称" />
+        </el-form-item>
+        <el-form-item label="表单类型" prop="flowType">
+          <el-radio-group v-model="formData.flowType">
+            <el-radio
+              v-for="dict in flowTypeOptions"
+              :key="dict.value"
+              :value="dict.value"
+            >{{dict.label }}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="流程表单类别" prop="flowFormCate" v-if="formData.flowType=='1'">
+          <el-select v-model="formData.flowFormCate" placeholder="请选择流程表单类别"   >
+              <el-option
+                  v-for="item in flowFormCateOptions"
+                  :key="item.key"
+                  :value="item.key"
+                  :label="item.value"
+              ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="业务表单类别" prop="flowBusinessCate" v-if="formData.flowType=='2'">
+          <el-select v-model="formData.flowBusinessCate" placeholder="请选择业务表单类别" >
+            <el-option
+                v-for="dict in flowBusinessCateOptions"
+                :key="dict.value"
+                :value="dict.value"
+                :label="dict.label"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="流程描述" prop="remark">
+          <el-input v-model="formData.remark" type="textarea" placeholder="请输入流程描述" />
+        </el-form-item>
+        <el-form-item label="排序" prop="sort">
+          <el-input-number v-model="formData.sort" placeholder="请输入排序"  />
+        </el-form-item>
+        <el-form-item label="流程状态" prop="status">
+          <el-radio-group v-model="formData.status">
+            <el-radio
+              v-for="dict in statusOptions"
+              :key="dict.value"
+              :value="dict.value"
+            >{{dict.label }}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="onSubmit" :disabled="loading">确 定</el-button>
+          <el-button @click="onCancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+<script lang="ts">
+import { reactive, toRefs, defineComponent,ref,unref,getCurrentInstance } from 'vue';
+import {ElMessageBox, ElMessage, FormInstance,UploadProps} from 'element-plus';
+import {
+  listFlowModel,
+  getFlowModel,
+  delFlowModel,
+  addFlowModel,
+  updateFlowModel,
+} from "/@/api/flow/flowModel";
+import {
+  FlowModelTableColumns,
+  FlowModelInfoData,
+  FlowModelTableDataState,
+  FlowModelEditState
+} from "/@/views/flow/flowModel/list/component/model"
+export default defineComponent({
+  name:"ApiV1FlowFlowModelEdit",
+  components:{
+  },
+  props:{
+    flowTypeOptions:{
+      type:Array,
+      default:()=>[]
+    },
+    flowFormCateOptions:{
+      type:Array,
+      default:()=>[]
+    },
+    flowBusinessCateOptions:{
+      type:Array,
+      default:()=>[]
+    },
+    statusOptions:{
+      type:Array,
+      default:()=>[]
+    },
+  },
+  setup(props,{emit}) {
+    const {proxy} = <any>getCurrentInstance()
+    const formRef = ref<HTMLElement | null>(null);
+    const menuRef = ref();
+    const state = reactive<FlowModelEditState>({
+      loading:false,
+      isShowDialog: false,
+      formData: {
+        id: undefined,
+        name: undefined,
+        flowType: undefined ,
+        flowFormCate: undefined,
+        remark: undefined,
+        flowBusinessCate: undefined,
+        sort: undefined,
+        status: '1' ,
+        createdAt: undefined,
+        updatedAt: undefined,
+        deletedAt: undefined,
+        createdBy: undefined,
+        updatedBy: undefined,
+        linkedFlowModelFlowForm: {
+          id:undefined,    // 主键
+          name:undefined,    // 表单名
+        },
+      },
+      // 表单校验
+      rules: {
+        id : [
+            { required: true, message: "主键不能为空", trigger: "blur" }
+        ],
+        name : [
+            { required: true, message: "流程名称不能为空", trigger: "blur" }
+        ],
+        status : [
+            { required: true, message: "流程状态不能为空", trigger: "blur" }
+        ],
+      }
+    });
+    // 打开弹窗
+    const openDialog = (row?: FlowModelInfoData) => {
+      resetForm();
+      if(row) {
+        getFlowModel(row.id!).then((res:any)=>{
+          const data = res.data;
+          data.flowType = ''+data.flowType
+          data.flowFormCate = ''+data.flowFormCate
+          data.flowBusinessCate = ''+data.flowBusinessCate
+          data.status = ''+data.status
+          state.formData = data;
+      })
+    }
+      state.isShowDialog = true;
+    };
+    // 关闭弹窗
+    const closeDialog = () => {
+      state.isShowDialog = false;
+    };
+    // 取消
+    const onCancel = () => {
+      closeDialog();
+    };
+    // 提交
+    const onSubmit = () => {
+      const formWrap = unref(formRef) as any;
+      if (!formWrap) return;
+      formWrap.validate((valid: boolean) => {
+        if (valid) {
+          state.loading = true;
+          if(!state.formData.id || state.formData.id===0){
+            //添加
+          addFlowModel(state.formData).then(()=>{
+              ElMessage.success('添加成功');
+              closeDialog(); // 关闭弹窗
+              emit('flowModelList')
+            }).finally(()=>{
+              state.loading = false;
+            })
+          }else{
+            //修改
+          updateFlowModel(state.formData).then(()=>{
+              ElMessage.success('修改成功');
+              closeDialog(); // 关闭弹窗
+              emit('flowModelList')
+            }).finally(()=>{
+              state.loading = false;
+            })
+          }
+        }
+      });
+    };
+    const resetForm = ()=>{
+      state.formData = {
+        id: undefined,
+        name: undefined,
+        flowType: undefined ,
+        flowFormCate: undefined,
+        remark: undefined,
+        flowBusinessCate: undefined,
+        sort: undefined,
+        status: '1' ,
+        createdAt: undefined,
+        updatedAt: undefined,
+        deletedAt: undefined,
+        createdBy: undefined,
+        updatedBy: undefined,
+        linkedFlowModelFlowForm: {
+          id:undefined,    // 主键
+          name:undefined,    // 表单名
+        },
+      }
+    };
+    return {
+      proxy,
+      openDialog,
+      closeDialog,
+      onCancel,
+      onSubmit,
+      menuRef,
+      formRef,
+      ...toRefs(state),
+    };
+  }
+})
+</script>
+<style scoped>
+  .kv-label{margin-bottom: 15px;font-size: 14px;}
+  .mini-btn i.el-icon{margin: unset;}
+  .kv-row{margin-bottom: 12px;}
+</style>

+ 67 - 0
src/views/flow/flowModel/list/component/model.ts

@@ -0,0 +1,67 @@
+export interface FlowModelTableColumns {
+    id:number;  // 主键
+    name:string;  // 流程名称
+    flowType:number;  // 表单类型
+    flowFormCate:string;  // 流程表单类别
+    linkedFlowFormCate?:LinkedFlowModelFlowForm; // 流程表单类别
+    flowBusinessCate:string;  // 业务表单类别
+    status:number;  // 流程状态
+    createdAt:string;  // 创建时间
+    createdBy:string;  // 创建人
+    linkedFlowModelFlowForm:LinkedFlowModelFlowForm;
+    isRunning:boolean;//流程是否运行中
+}
+
+
+export interface FlowModelInfoData {
+    id:number|undefined;        // 主键
+    name:string|undefined; // 流程名称
+    flowType:string|undefined; // 表单类型
+    flowFormCate:string|undefined; // 流程表单类别
+    linkedFlowFormCate?:LinkedFlowModelFlowForm; // 流程表单类别
+    remark:string|undefined; // 流程描述
+    flowBusinessCate:string|undefined; // 业务表单类别
+    sort:number|undefined; // 排序
+    status:string|undefined; // 流程状态
+    createdAt:string|undefined; // 创建时间
+    updatedAt:string|undefined; // 修改时间
+    deletedAt:string|undefined; // 删除时间
+    createdBy:number|undefined; // 创建人
+    updatedBy:number|undefined; // 修改人
+    linkedFlowModelFlowForm?:LinkedFlowModelFlowForm;
+}
+
+
+export interface LinkedFlowModelFlowForm {
+    id:number|undefined;    // 主键
+    name:string|undefined;    // 表单名
+}
+
+
+export interface FlowModelTableDataState {
+    ids:any[];
+    tableData: {
+        data: Array<FlowModelTableColumns>;
+        total: number;
+        loading: boolean;
+        param: {
+            pageNum: number;
+            pageSize: number;
+            name: string|undefined;
+            flowType: number|undefined;
+            flowFormCate: string|undefined;
+            flowBusinessCate: string|undefined;
+            sort: number|undefined;
+            status: number|undefined;
+            dateRange: string[];
+        };
+    };
+}
+
+
+export interface FlowModelEditState{
+    loading:boolean;
+    isShowDialog: boolean;
+    formData:FlowModelInfoData;
+    rules: object;
+}

+ 448 - 0
src/views/flow/flowModel/list/index.vue

@@ -0,0 +1,448 @@
+<template>
+  <div class="flow-flowModel-container">
+    <el-card shadow="hover">
+        <div class="flow-flowModel-search mb15">
+            <el-form :model="tableData.param" ref="queryRef" :inline="true" label-width="100px">
+            <el-row>
+                <el-col :span="8" class="colBlock">
+                  <el-form-item label="流程名称" prop="name">
+                    <el-input
+                        v-model="tableData.param.name"
+                        placeholder="请输入流程名称"
+                        clearable
+                        @keyup.enter.native="flowModelList"
+                    />
+                  </el-form-item>
+                </el-col>
+                <el-col :span="8" class="colBlock">
+                  <el-form-item label="表单类型" prop="flowType">
+                    <el-select v-model="tableData.param.flowType" placeholder="请选择表单类型" clearable style="width: 160px">
+                        <el-option
+                            v-for="dict in flow_model_type"
+                            :key="dict.value"
+                            :label="dict.label"
+                            :value="dict.value"
+                        />
+                    </el-select>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="8" :class="!showAll ? 'colBlock' : 'colNone'">
+                  <el-form-item>
+                    <el-button type="primary"  @click="flowModelList"><el-icon><ele-Search /></el-icon>搜索</el-button>
+                    <el-button  @click="resetQuery(queryRef)"><el-icon><ele-Refresh /></el-icon>重置</el-button>
+                    <el-button type="primary" link  @click="toggleSearch">
+                      {{ word }}
+                      <el-icon v-show="showAll"><ele-ArrowUp/></el-icon>
+                      <el-icon v-show="!showAll"><ele-ArrowDown /></el-icon>
+                    </el-button>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="8" :class="showAll ? 'colBlock' : 'colNone'">
+                  <el-form-item label="流程表单类别" prop="flowFormCate">
+                    <el-select v-model="tableData.param.flowFormCate" placeholder="请选择流程表单类别" clearable  style="width: 180px">
+                      <el-option
+                          v-for="item in flowFormCateOptions"
+                          :key="item.key"
+                          :label="item.value"
+                          :value="item.key"
+                      />
+                    </el-select>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="8" :class="showAll ? 'colBlock' : 'colNone'">
+                  <el-form-item label="业务表单类别" prop="flowBusinessCate">
+                    <el-select v-model="tableData.param.flowBusinessCate" placeholder="请选择业务表单类别" clearable style="width: 180px">
+                        <el-option
+                            v-for="dict in flow_model_cate"
+                            :key="dict.value"
+                            :label="dict.label"
+                            :value="dict.value"
+                        />
+                    </el-select>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="8" :class="showAll ? 'colBlock' : 'colNone'">
+                  <el-form-item label="流程状态" prop="status">
+                    <el-select v-model="tableData.param.status" placeholder="请选择流程状态" clearable style="width: 180px">
+                        <el-option
+                            v-for="dict in flow_form_status"
+                            :key="dict.value"
+                            :label="dict.label"
+                            :value="dict.value"
+                        />
+                    </el-select>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="8" :class="showAll ? 'colBlock' : 'colNone'">
+                  <el-form-item>
+                    <el-button type="primary"  @click="flowModelList"><el-icon><ele-Search /></el-icon>搜索</el-button>
+                    <el-button  @click="resetQuery(queryRef)"><el-icon><ele-Refresh /></el-icon>重置</el-button>
+                    <el-button type="primary" link  @click="toggleSearch">
+                        {{ word }}
+                        <el-icon v-show="showAll"><ele-ArrowUp/></el-icon>
+                        <el-icon v-show="!showAll"><ele-ArrowDown /></el-icon>
+                    </el-button>
+                  </el-form-item>
+                </el-col>
+              </el-row>
+            </el-form>
+            <el-row :gutter="10" class="mb8">
+              <el-col :span="1.5">
+                <el-button
+                  type="primary"
+                  @click="handleAdd"
+                  v-auth="'api/v1/flow/flowModel/add'"
+                ><el-icon><ele-Plus /></el-icon>新增</el-button>
+              </el-col>
+              <el-col :span="1.5">
+                <el-button
+                  type="success"
+                  :disabled="single"
+                  @click="handleUpdate(null)"
+                  v-auth="'api/v1/flow/flowModel/edit'"
+                ><el-icon><ele-Edit /></el-icon>修改</el-button>
+              </el-col>
+              <el-col :span="1.5">
+                <el-button
+                  type="danger"
+                  :disabled="multiple"
+                  @click="handleDelete(null)"
+                  v-auth="'api/v1/flow/flowModel/delete'"
+                ><el-icon><ele-Delete /></el-icon>删除</el-button>
+              </el-col>
+             <el-col :span="1.5">
+                <el-button
+                        type="warning"
+                        @click="handleExport()"
+                        v-auth="'api/v1/flow/flowModel/export'"
+                ><el-icon><ele-Download /></el-icon>导出Excel</el-button>
+             </el-col>
+                <el-col :span="1.5">
+                    <el-button
+                            type="success"
+                            @click="handleImport()"
+                            v-auth="'api/v1/flow/flowModel/import'"
+                    ><el-icon><ele-Upload /></el-icon>导入Excel</el-button>
+                </el-col>
+            </el-row>
+        </div>
+        <el-table v-loading="loading" :data="tableData.data" @selection-change="handleSelectionChange">
+          <el-table-column type="selection" width="55" align="center" />
+          <el-table-column label="主键" align="center" prop="id"
+            min-width="150px"
+             />
+          <el-table-column label="流程名称" align="center" prop="name"
+            min-width="150px"
+             />
+          <el-table-column label="表单类型" align="center" prop="flowType" :formatter="flowTypeFormat"
+            min-width="150px"
+             />
+          <el-table-column label="流程表单类别" align="center" prop="linkedFlowFormCate.name"
+            min-width="150px"
+             />
+          <el-table-column label="业务表单类别" align="center" prop="flowBusinessCate" :formatter="flowBusinessCateFormat"
+            min-width="150px"
+             />
+          <el-table-column label="流程状态" align="center" prop="status" :formatter="statusFormat"
+            min-width="150px"
+             />
+          <el-table-column label="创建时间" align="center" prop="createdAt"
+            min-width="150px"
+            >
+            <template #default="scope">
+                <span>{{ proxy.parseTime(scope.row.createdAt, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="创建人" align="center" prop="createdBy"
+            min-width="150px"
+             />
+          <el-table-column label="操作" align="center" class-name="small-padding" min-width="200px" fixed="right">
+            <template #default="scope">
+              <el-button
+                type="primary"
+                link
+                @click="handleView(scope.row)"
+                v-auth="'api/v1/flow/flowModel/get'"
+              ><el-icon><ele-View /></el-icon>详情</el-button>
+              <el-button
+                  v-show="!scope.row.isRunning"
+                  type="primary"
+                  link
+                  @click="handleUpdate(scope.row)"
+                  v-auth="'api/v1/flow/flowModel/edit'"
+              ><el-icon><ele-EditPen /></el-icon>修改</el-button>
+              <el-button
+                  v-show="!scope.row.isRunning"
+                  type="primary"
+                  link
+                  @click="handleDesign(scope.row)"
+                  v-auth="'api/v1/flow/flowModel/design'"
+              ><el-icon><ele-Notification /></el-icon>流程设计</el-button>
+              <el-button
+                  v-show="!scope.row.isRunning"
+                  type="primary"
+                  link
+                  @click="handleDelete(scope.row)"
+                  v-auth="'api/v1/flow/flowModel/delete'"
+              ><el-icon><ele-DeleteFilled /></el-icon>删除</el-button>
+              <el-tag v-show="scope.row.isRunning" type="danger">流程运行中</el-tag>
+            </template>
+          </el-table-column>
+        </el-table>
+        <pagination
+            v-show="tableData.total>0"
+            :total="tableData.total"
+            v-model:page="tableData.param.pageNum"
+            v-model:limit="tableData.param.pageSize"
+            @pagination="flowModelList"
+        />
+    </el-card>
+    <ApiV1FlowFlowModelEdit
+       ref="editRef"
+       :flowTypeOptions="flow_model_type"
+       :flowFormCateOptions="flowFormCateOptions"
+       :flowBusinessCateOptions="flow_model_cate"
+       :statusOptions="flow_form_status"
+       @flowModelList="flowModelList"
+    ></ApiV1FlowFlowModelEdit>
+    <ApiV1FlowFlowModelDetail
+      ref="detailRef"
+      :flowTypeOptions="flow_model_type"
+      :flowFormCateOptions="flowFormCateOptions"
+      :flowBusinessCateOptions="flow_model_cate"
+      :statusOptions="flow_form_status"
+      @flowModelList="flowModelList"
+    ></ApiV1FlowFlowModelDetail>
+    <loadExcel ref="loadExcelFlowModelRef" @getList="flowModelList"
+               upUrl="api/v1/flow/flowModel/import"
+               tplUrl="/api/v1/flow/flowModel/excelTemplate"></loadExcel>
+  </div>
+</template>
+<script lang="ts">
+import {ItemOptions} from "/@/api/items";
+import {toRefs, reactive, onMounted, ref, defineComponent, computed,getCurrentInstance,toRaw} from 'vue';
+import {ElMessageBox, ElMessage, FormInstance} from 'element-plus';
+import {
+    listFlowModel,
+    delFlowModel,
+    linkedDataSearch
+} from "/@/api/flow/flowModel";
+import {
+    FlowModelTableColumns,
+    FlowModelInfoData,
+    FlowModelTableDataState,
+} from "/@/views/flow/flowModel/list/component/model"
+import ApiV1FlowFlowModelEdit from "/@/views/flow/flowModel/list/component/edit.vue"
+import ApiV1FlowFlowModelDetail from "/@/views/flow/flowModel/list/component/detail.vue"
+import {downLoadXml} from "/@/utils/zipdownload";
+import loadExcel from "/@/components/loadExcel/index.vue"
+import {useRouter} from "vue-router";
+export default defineComponent({
+    name: "ApiV1FlowFlowModelList",
+    components:{
+        loadExcel,
+        ApiV1FlowFlowModelEdit,
+        ApiV1FlowFlowModelDetail
+    },
+    setup() {
+        const router = useRouter();
+        const {proxy} = <any>getCurrentInstance()
+        const loading = ref(false)
+        const queryRef = ref()
+        const editRef = ref();
+        const detailRef = ref();
+        const loadExcelFlowModelRef = ref();
+        // 是否显示所有搜索选项
+        const showAll =  ref(false)
+        // 非单个禁用
+        const single = ref(true)
+        // 非多个禁用
+        const multiple =ref(true)
+        const word = computed(()=>{
+            if(showAll.value === false) {
+                //对文字进行处理
+                return "展开搜索";
+            } else {
+                return "收起搜索";
+            }
+        })
+        // 字典选项数据
+        const {
+            flow_model_type,
+            flow_model_cate,
+            flow_form_status,
+        } = proxy.useDict(
+            'flow_model_type',
+            'flow_model_cate',
+            'flow_form_status',
+        )
+        // flowFormCateOptions关联表数据
+        const flowFormCateOptions = ref<Array<ItemOptions>>([])
+        const state = reactive<FlowModelTableDataState>({
+            ids:[],
+            tableData: {
+                data: [],
+                total: 0,
+                loading: false,
+                param: {
+                    pageNum: 1,
+                    pageSize: 10,
+                    name: undefined,
+                    flowType: undefined,
+                    flowFormCate: undefined,
+                    flowBusinessCate: undefined,
+                    sort: undefined,
+                    status: undefined,
+                    dateRange: []
+                },
+            },
+        });
+        // 页面加载时
+        onMounted(() => {
+            initTableData();
+        });
+        // 初始化表格数据
+        const initTableData = () => {
+            linkedData()
+            flowModelList()
+        };
+        const linkedData = ()=>{
+            linkedDataSearch().then((res:any)=>{
+                //关联flow_form表选项
+                flowFormCateOptions.value = proxy.setItems(res, 'id', 'name','linkedFlowModelFlowForm')
+            })
+        }
+        /** 重置按钮操作 */
+        const resetQuery = (formEl: FormInstance | undefined) => {
+            if (!formEl) return
+            formEl.resetFields()
+            flowModelList()
+        };
+        // 获取列表数据
+        const flowModelList = ()=>{
+          loading.value = true
+          listFlowModel(state.tableData.param).then((res:any)=>{
+            let list = res.data.list??[];
+            list.map((item:any)=>{
+                item.createdBy = item.createdUser?.userNickname
+            })
+            state.tableData.data = list;
+            state.tableData.total = res.data.total;
+            loading.value = false
+          })
+        };
+        const toggleSearch = () => {
+            showAll.value = !showAll.value;
+        }
+        // 表单类型字典翻译
+        const flowTypeFormat = (row:FlowModelTableColumns) => {
+            return proxy.selectDictLabel(flow_model_type.value, row.flowType);
+        }
+        // 业务表单类别字典翻译
+        const flowBusinessCateFormat = (row:FlowModelTableColumns) => {
+            return proxy.selectDictLabel(flow_model_cate.value, row.flowBusinessCate);
+        }
+        // 流程状态字典翻译
+        const statusFormat = (row:FlowModelTableColumns) => {
+            return proxy.selectDictLabel(flow_form_status.value, row.status);
+        }
+        // 多选框选中数据
+        const handleSelectionChange = (selection:Array<FlowModelInfoData>) => {
+            state.ids = selection.map(item => item.id)
+            single.value = selection.length!=1
+            multiple.value = !selection.length
+        }
+        const handleAdd =  ()=>{
+            editRef.value.openDialog()
+        }
+        const handleUpdate = (row: FlowModelTableColumns) => {
+            if(!row){
+                row = state.tableData.data.find((item:FlowModelTableColumns)=>{
+                    return item.id ===state.ids[0]
+                }) as FlowModelTableColumns
+            }
+            editRef.value.openDialog(toRaw(row));
+        };
+        const handleDesign = (row :FlowModelTableColumns) =>{
+          router.push('/flow/flowModel/design?id='+row.id)
+        }
+        const handleDelete = (row: FlowModelTableColumns) => {
+            let msg = '你确定要删除所选数据?';
+            let id:number[] = [] ;
+            if(row){
+            msg = `此操作将永久删除数据,是否继续?`
+            id = [row.id]
+            }else{
+            id = state.ids
+            }
+            if(id.length===0){
+                ElMessage.error('请选择要删除的数据。');
+                return
+            }
+            ElMessageBox.confirm(msg, '提示', {
+                confirmButtonText: '确认',
+                cancelButtonText: '取消',
+                type: 'warning',
+            })
+                .then(() => {
+                    delFlowModel(id).then(()=>{
+                        ElMessage.success('删除成功');
+                        flowModelList();
+                    })
+                })
+                .catch(() => {});
+        }
+        const handleView = (row:FlowModelTableColumns)=>{
+            detailRef.value.openDialog(toRaw(row));
+        }
+        //导出excel
+        const handleExport = ()=>{
+            downLoadXml('/api/v1/flow/flowModel/export',state.tableData.param,'get')
+        }
+        const handleImport=()=>{
+            loadExcelFlowModelRef.value.open()
+        }
+        return {
+            proxy,
+            editRef,
+            detailRef,
+            showAll,
+            loading,
+            single,
+            multiple,
+            word,
+            queryRef,
+            resetQuery,
+            flowModelList,
+            toggleSearch,
+            flowTypeFormat,
+            flow_model_type,
+            //关联表数据选项
+            flowFormCateOptions,
+            flowBusinessCateFormat,
+            flow_model_cate,
+            statusFormat,
+            flow_form_status,
+            handleSelectionChange,
+            handleAdd,
+            handleUpdate,
+            handleDelete,
+            handleView,
+            handleExport,
+            handleImport,
+            handleDesign,
+            loadExcelFlowModelRef,
+            ...toRefs(state),
+        }
+    }
+})
+</script>
+<style lang="scss" scoped>
+    .colBlock {
+        display: block;
+    }
+    .colNone {
+        display: none;
+    }
+    .ml-2{margin: 3px;}
+</style>

+ 29 - 0
src/views/flow/flowModel/monitor/component/model.ts

@@ -0,0 +1,29 @@
+import {FlowModelTableColumns} from "/@/views/flow/flowModel/list/component/model";
+
+export interface MonitorTableColumns {
+  id: number;
+  runName:string;
+  dateline:string;
+  formId:number;
+  formTable:string;
+  formTitle:string;
+  flowInfo:FlowModelTableColumns;
+  formStatus:string;
+  actionBtn:any
+}
+
+export interface MonitorTableColumnsState {
+  ids:any[];
+  tableData: {
+    data: Array<MonitorTableColumns>;
+    total: number;
+    loading: boolean;
+    param: {
+      pageNum: number;
+      pageSize: number;
+      title: string|undefined;
+      status: number|undefined;
+      dateRange: string[];
+    };
+  };
+}

+ 210 - 0
src/views/flow/flowModel/monitor/index.vue

@@ -0,0 +1,210 @@
+<template>
+  <div class="flow-flowDemo-container">
+    <el-card shadow="hover">
+      <div class="flow-flowDemo-search mb15">
+        <el-form :model="tableData.param" ref="queryRef" :inline="true" label-width="100px">
+          <el-row>
+            <el-col :span="8" class="colBlock">
+              <el-form-item label="标题" prop="title">
+                <el-input
+                    v-model="tableData.param.title"
+                    placeholder="请输入标题"
+                    clearable
+                    @keyup.enter.native="monitorList"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :span="8" class="colBlock">
+              <el-form-item>
+                <el-button type="primary"   @click="monitorList"><el-icon><ele-Search /></el-icon>搜索</el-button>
+                <el-button  @click="resetQuery(queryRef)"><el-icon><ele-Refresh /></el-icon>重置</el-button>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button
+                type="danger"
+                :disabled="multiple"
+                @click="handleDelete(null)"
+                v-auth="'api/v1/flow/flowModel/stop'"
+            ><el-icon><ele-RemoveFilled/></el-icon>终止</el-button>
+          </el-col>
+        </el-row>
+      </div>
+      <el-table v-loading="loading" :data="tableData.data" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="运行ID" align="center" prop="id"
+                         min-width="150px"
+        />
+        <el-table-column label="流程名称" align="center" prop="flowInfo.name"
+                         min-width="150px"
+        />
+        <el-table-column label="流程类型" align="center" prop="formTable"
+                         min-width="150px"
+        />
+        <el-table-column label="业务名称" align="center" prop="runName"
+                         min-width="150px"
+        />
+        <el-table-column label="业务ID" align="center" prop="formId"
+                         min-width="150px"
+        />
+        <el-table-column label="流程执行时间" align="center" prop="dateline"
+                         min-width="150px"
+        />
+        <el-table-column label="操作" align="center" class-name="small-padding" min-width="200px" fixed="right">
+          <template #default="scope">
+            <el-button
+                type="primary"
+                link
+                @click="handleDelete(scope.row)"
+                v-auth="'api/v1/flow/flowModel/stopv'"
+            ><el-icon><ele-RemoveFilled /></el-icon>终止</el-button>
+            <el-button
+                type="primary"
+                link
+                @click="handleProxy(scope.row)"
+                v-auth="'api/v1/flow/flowModel/proxy'"
+            ><el-icon><ele-User /></el-icon>代审</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination
+          v-show="tableData.total>0"
+          :total="tableData.total"
+          v-model:page="tableData.param.pageNum"
+          v-model:limit="tableData.param.pageSize"
+          @pagination="monitorList"
+      />
+    </el-card>
+    <checkFlow ref="ckFlowRef" @getList="monitorList"></checkFlow>
+  </div>
+</template>
+<script setup lang="ts">
+import checkFlow from "/@/components/gFlow/checkFlow.vue"
+import {toRefs, reactive, onMounted, ref,  computed,getCurrentInstance,toRaw} from 'vue';
+import {ElMessageBox, ElMessage, FormInstance} from 'element-plus';
+import {getMonitor, stopRun} from "/@/api/flow/flowModel";
+import {MonitorTableColumnsState,MonitorTableColumns} from "/@/views/flow/flowModel/monitor/component/model";
+defineOptions({ name: "apiV1FlowFlowModelMonitor"})
+const {proxy} = <any>getCurrentInstance()
+const loading = ref(false)
+const queryRef = ref()
+// 是否显示所有搜索选项
+const showAll =  ref(false)
+// 非单个禁用
+const single = ref(true)
+// 非多个禁用
+const multiple =ref(true)
+const ckFlowRef = ref()
+const word = computed(()=>{
+  if(showAll.value === false) {
+    //对文字进行处理
+    return "展开搜索";
+  } else {
+    return "收起搜索";
+  }
+})
+const state = reactive<MonitorTableColumnsState>({
+  ids:[],
+  tableData: {
+    data: [],
+    total: 0,
+    loading: false,
+    param: {
+      pageNum: 1,
+      pageSize: 10,
+      title: undefined,
+      status: undefined,
+      dateRange: []
+    },
+  },
+});
+const { tableData } = toRefs(state);
+// 页面加载时
+onMounted(() => {
+  initTableData();
+});
+// 初始化表格数据
+const initTableData = () => {
+  monitorList()
+};
+/** 重置按钮操作 */
+const resetQuery = (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  formEl.resetFields()
+  monitorList()
+};
+// 获取列表数据
+const monitorList = ()=>{
+  loading.value = true
+  getMonitor(state.tableData.param).then((res:any)=>{
+    let list = res.data.list??[];
+    list.map((item:any)=>{
+      item.createdBy = item.createdUser?.userNickname
+    })
+    state.tableData.data = list;
+    state.tableData.total = res.data.total;
+    loading.value = false
+  })
+};
+const toggleSearch = () => {
+  showAll.value = !showAll.value;
+}
+
+// 多选框选中数据
+const handleSelectionChange = (selection:Array<MonitorTableColumns>) => {
+  state.ids = selection.map(item => item.id)
+  single.value = selection.length!=1
+  multiple.value = !selection.length
+}
+const handleDelete = (row: MonitorTableColumns|null) => {
+  let msg = '是否要终止流程【此操作不可恢复】?';
+  let id:number[] = [] ;
+  if(row){
+    id = [row.id]
+  }else{
+    id = state.ids
+  }
+  if(id.length===0){
+    ElMessage.error('请选择要终止的流程。');
+    return
+  }
+  ElMessageBox.confirm(msg, '提示', {
+    confirmButtonText: '确认',
+    cancelButtonText: '取消',
+    type: 'warning',
+  })
+      .then(() => {
+        stopRun(id).then(()=>{
+          ElMessage.success('终止成功');
+          monitorList();
+        })
+      })
+      .catch(() => {});
+}
+const handleProxy =(row: MonitorTableColumns)=>{
+  row.actionBtn = {
+    api: "wfCheck",
+    title: "代审",
+    type: "link",
+    wfFid: row.formId,
+    wfModelType: row.flowInfo.flowType,
+    wfStatusField: row.formStatus,
+    wfTitle: row.formTitle,
+    wfType: row.formTable,
+    isProxy:true
+  }
+  ckFlowRef.value.handleStartFlow(row)
+}
+</script>
+<style lang="scss" scoped>
+.colBlock {
+  display: block;
+}
+.colNone {
+  display: none;
+}
+.ml-2{margin: 3px;}
+</style>