24282 11 ماه پیش
والد
کامیت
85a833615c
37فایلهای تغییر یافته به همراه1867 افزوده شده و 49 حذف شده
  1. 1 0
      jy-flow/src/main/java/com/jy/flow/controller/DefController.java
  2. 8 0
      jy-system/src/main/java/com/jy/system/controller/SysDeptController.java
  3. 10 0
      jy-system/src/main/java/com/jy/system/controller/SysRoleController.java
  4. 2 7
      jy-system/src/main/java/com/jy/system/dao/SysDeptDao.java
  5. 24 0
      jy-system/src/main/java/com/jy/system/dao/SysRoleDao.java
  6. 1 0
      jy-system/src/main/java/com/jy/system/dao/SysUserDao.java
  7. 5 0
      jy-system/src/main/java/com/jy/system/service/SysDeptService.java
  8. 5 0
      jy-system/src/main/java/com/jy/system/service/SysRoleService.java
  9. 5 0
      jy-system/src/main/java/com/jy/system/service/impl/SysDeptServiceImpl.java
  10. 5 0
      jy-system/src/main/java/com/jy/system/service/impl/SysRoleServiceImpl.java
  11. 2 0
      jy-ui/package.json
  12. 1 1
      jy-ui/src/api/business/capital/account.ts
  13. 1 1
      jy-ui/src/api/business/capital/transactions.ts
  14. 1 1
      jy-ui/src/api/business/corporation/corporation.ts
  15. 15 0
      jy-ui/src/api/flow/definition.ts
  16. 4 0
      jy-ui/src/api/system/dept.ts
  17. 4 0
      jy-ui/src/api/system/role.ts
  18. 297 0
      jy-ui/src/components/flow/PropertySetting/between.vue
  19. 46 0
      jy-ui/src/components/flow/PropertySetting/end.vue
  20. 256 0
      jy-ui/src/components/flow/PropertySetting/index.vue
  21. 45 0
      jy-ui/src/components/flow/PropertySetting/parallel.vue
  22. 46 0
      jy-ui/src/components/flow/PropertySetting/serial.vue
  23. 87 0
      jy-ui/src/components/flow/PropertySetting/skip.vue
  24. 69 0
      jy-ui/src/components/flow/PropertySetting/start.vue
  25. 22 0
      jy-ui/src/components/flow/js/between.js
  26. 17 0
      jy-ui/src/components/flow/js/end.js
  27. 57 0
      jy-ui/src/components/flow/js/parallel.js
  28. 57 0
      jy-ui/src/components/flow/js/serial.js
  29. 33 0
      jy-ui/src/components/flow/js/skip.js
  30. 17 0
      jy-ui/src/components/flow/js/start.js
  31. 357 0
      jy-ui/src/components/flow/js/tool.js
  32. 0 1
      jy-ui/src/utils/request.ts
  33. 14 8
      jy-ui/src/views/business/capital/account/index.vue
  34. 18 12
      jy-ui/src/views/business/capital/transactions/index.vue
  35. 12 6
      jy-ui/src/views/business/corporation/index.vue
  36. 298 0
      jy-ui/src/views/flow/definition/design.vue
  37. 25 12
      jy-ui/src/views/flow/definition/index.vue

+ 1 - 0
jy-flow/src/main/java/com/jy/flow/controller/DefController.java

@@ -54,6 +54,7 @@ public class DefController {
     @PostMapping
     @Transactional(rollbackFor = Exception.class)
     public Boolean add(@RequestBody FlowDefinition flowDefinition) {
+        flowDefinition.setActivityStatus(0);
         return defService.checkAndSave(flowDefinition);
     }
 

+ 8 - 0
jy-system/src/main/java/com/jy/system/controller/SysDeptController.java

@@ -37,6 +37,14 @@ public class SysDeptController {
     private SysDeptService sysDeptService;
 
     /**
+     * 部门列表
+     */
+    @GetMapping("/getList")
+    public List<SysDeptVo> getList(SysDeptSelectDto dto) {
+        return sysDeptService.getList(dto);
+    }
+
+    /**
      * 部门分页
      */
     @GetMapping("/getTree")

+ 10 - 0
jy-system/src/main/java/com/jy/system/controller/SysRoleController.java

@@ -26,6 +26,8 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.List;
+
 /**
  * <p>
  * 角色 前端控制器
@@ -45,6 +47,14 @@ public class SysRoleController {
     private SysUserRoleService sysUserRoleService;
 
     /**
+     * 角色列表
+     */
+    @GetMapping("/getList")
+    public List<SysRoleVo> getList(SysRoleSelectDto dto) {
+        return sysRoleService.getList(dto);
+    }
+
+    /**
      * 角色分页
      */
     @GetMapping("/getPage")

+ 2 - 7
jy-system/src/main/java/com/jy/system/dao/SysDeptDao.java

@@ -24,17 +24,12 @@ public class SysDeptDao extends BaseDao<SysDeptMapper, SysDept> {
         return sql(SysDeptVo.class)
                 .select(
                         sd.id,
-                        sd.parentId,
                         sd.name,
-                        sd.code,
-                        sd.status,
-                        sd.sort,
-                        sd.remark
+                        sd.code
                 )
                 .from(sd)
                 .where(
-                        sd.status.eq(dto.getStatus()),
-                        sd.name.like(dto.getName())
+                        sd.status.eq(dto.getStatus())
                 )
                 .orderBy(
                         sd.sort.asc(),

+ 24 - 0
jy-system/src/main/java/com/jy/system/dao/SysRoleDao.java

@@ -18,6 +18,30 @@ import java.util.List;
 public class SysRoleDao extends BaseDao<SysRoleMapper, SysRole> {
 
     /**
+     * 角色列表
+     */
+    public List<SysRoleVo> getList(SysRoleSelectDto dto) {
+        SysRoleTable sr = SysRoleTable.sr;
+
+        return sql(SysRoleVo.class)
+                .select(
+                        sr.id,
+                        sr.name,
+                        sr.code
+                )
+                .from(sr)
+                .where(
+                        sr.status.eq(dto.getStatus())
+                )
+                .orderBy(
+                        sr.builtin.desc(),
+                        sr.sort.asc(),
+                        sr.id.desc()
+                )
+                .list();
+    }
+
+    /**
      * 角色分页
      */
     public Page<SysRoleVo> getPage(SysRoleSelectDto dto) {

+ 1 - 0
jy-system/src/main/java/com/jy/system/dao/SysUserDao.java

@@ -31,6 +31,7 @@ public class SysUserDao extends BaseDao<SysUserMapper, SysUser> {
         return sql(SysUserInfoVo.class)
                 .select(
                         su.id,
+                        su.username,
                         su.nickname
                 )
                 .from(su)

+ 5 - 0
jy-system/src/main/java/com/jy/system/service/SysDeptService.java

@@ -17,6 +17,11 @@ import java.util.List;
 public interface SysDeptService {
 
     /**
+     * 部门列表
+     */
+    List<SysDeptVo> getList(SysDeptSelectDto dto);
+
+    /**
      * 部门树形
      */
     List<SysDeptVo> getTree(SysDeptSelectDto dto);

+ 5 - 0
jy-system/src/main/java/com/jy/system/service/SysRoleService.java

@@ -23,6 +23,11 @@ import java.util.List;
 public interface SysRoleService {
 
     /**
+     * 角色列表
+     */
+    List<SysRoleVo> getList(SysRoleSelectDto dto);
+
+    /**
      * 角色分页
      */
     Page<SysRoleVo> getPage(SysRoleSelectDto dto);

+ 5 - 0
jy-system/src/main/java/com/jy/system/service/impl/SysDeptServiceImpl.java

@@ -36,6 +36,11 @@ public class SysDeptServiceImpl implements SysDeptService {
     private SysUserDao sysUserDao;
 
     @Override
+    public List<SysDeptVo> getList(SysDeptSelectDto dto) {
+        return sysDeptDao.getList(dto);
+    }
+
+    @Override
     public List<SysDeptVo> getTree(SysDeptSelectDto dto) {
         List<SysDeptVo> list = sysDeptDao.getList(dto);
         return TreeUtil.build(list);

+ 5 - 0
jy-system/src/main/java/com/jy/system/service/impl/SysRoleServiceImpl.java

@@ -61,6 +61,11 @@ public class SysRoleServiceImpl implements SysRoleService {
     private SysRoleMenuService sysRoleMenuService;
 
     @Override
+    public List<SysRoleVo> getList(SysRoleSelectDto dto) {
+        return sysRoleDao.getList(dto);
+    }
+
+    @Override
     public Page<SysRoleVo> getPage(SysRoleSelectDto dto) {
         return sysRoleDao.getPage(dto);
     }

+ 2 - 0
jy-ui/package.json

@@ -12,6 +12,8 @@
     "lint:prettier": "prettier --write \"**/*.{js,cjs,ts,json,tsx,css,less,scss,vue,html,md}\""
   },
   "dependencies": {
+    "@logicflow/core": "^1.2.15",
+    "@logicflow/extension": "^1.2.16",
     "@element-plus/icons-vue": "^2.3.1",
     "@vueuse/core": "^10.11.0",
     "axios": "^1.7.2",

+ 1 - 1
jy-ui/src/api/business/capital/account.ts

@@ -24,4 +24,4 @@ export function editApi(data: StrAnyObj): Promise<void> {
 // 资金账户删除
 export function deleteApi(data: StrAnyObj): Promise<void> {
   return request.post('/capitalAccount/delete', data)
-}
+}

+ 1 - 1
jy-ui/src/api/business/capital/transactions.ts

@@ -24,4 +24,4 @@ export function editApi(data: StrAnyObj): Promise<void> {
 // 资金流水删除
 export function deleteApi(data: StrAnyObj): Promise<void> {
   return request.post('/capitalTransactions/delete', data)
-}
+}

+ 1 - 1
jy-ui/src/api/business/corporation/corporation.ts

@@ -24,4 +24,4 @@ export function editApi(data: StrAnyObj): Promise<void> {
 // 公司信息删除
 export function deleteApi(data: StrAnyObj): Promise<void> {
   return request.post('/corporation/delete', data)
-}
+}

+ 15 - 0
jy-ui/src/api/flow/definition.ts

@@ -25,3 +25,18 @@ export function updateDefinitionApi(params: StrAnyObj): Promise<StrAnyObj> {
 export function deleteDefinitionApi(id: string): Promise<StrAnyObj> {
   return request.delete(`/flow/definition/${id}`)
 }
+
+// 保存流程定义xml字符串
+export function saveXmlApi(data: StrAnyObj): Promise<void> {
+  return request.post(`/flow/definition/saveXml`, data)
+}
+
+// 获取流程定义xml字符串
+export function getXmlApi(id: string): Promise<string> {
+  return request.get(`/flow/definition/xmlString/${id}`)
+}
+
+// 根据id查用户名
+export function getUsernameApi(id: string): Promise<string> {
+  return request.get(`/flow/definition/idReverseDisplayName/${id}`)
+}

+ 4 - 0
jy-ui/src/api/system/dept.ts

@@ -1,6 +1,10 @@
 import request from '@/utils/request'
 import { StrAnyObj, StrAnyObjArr } from '@/typings'
 
+export function getListApi(params: StrAnyObj): Promise<StrAnyObjArr> {
+  return request.get('/sysDept/getList', params)
+}
+
 export function getTreeApi(params: StrAnyObj): Promise<StrAnyObjArr> {
   return request.get('/sysDept/getTree', params)
 }

+ 4 - 0
jy-ui/src/api/system/role.ts

@@ -1,6 +1,10 @@
 import request from '@/utils/request'
 import { PageType, StrAnyObj, StrAnyObjArr } from '@/typings'
 
+export function getListApi(params: StrAnyObj): Promise<StrAnyObjArr> {
+  return request.get('/sysRole/getList', params)
+}
+
 export function getPageApi(params: StrAnyObj): Promise<PageType<StrAnyObj>> {
   return request.get('/sysRole/getPage', params)
 }

+ 297 - 0
jy-ui/src/components/flow/PropertySetting/between.vue

@@ -0,0 +1,297 @@
+<template>
+  <div class="between">
+    <el-form ref="formRef" :model="form" label-width="120px" size="small" :rules="rules" :disabled="disabled">
+      <slot name="form-item-task-nodeCode" :model="form" field="nodeCode">
+        <el-form-item label="节点编码">
+          <el-input v-model="form.nodeCode" :disabled="disabled"></el-input>
+        </el-form-item>
+      </slot>
+      <slot name="form-item-task-nodeName" :model="form" field="nodeName">
+        <el-form-item label="节点名称">
+          <el-input v-model="form.nodeName" :disabled="disabled"></el-input>
+        </el-form-item>
+      </slot>
+      <slot name="form-item-task-collaborativeWay" :model="form" field="collaborativeWay">
+        <el-form-item label="协作方式">
+          <el-radio-group v-model="form.collaborativeWay" @change="collaborativeWayChange">
+            <el-radio label="1" v-if="form.collaborativeWay ==='1'">
+              <span class="flex-hc">
+                或签
+                <el-tooltip class="box-item" effect="dark" content="只需一个人审批">
+                  <el-icon :size="14" class="ml5">
+                    <WarningFilled />
+                  </el-icon>
+                </el-tooltip>
+              </span>
+            </el-radio>
+            <el-radio label="2" v-if="form.collaborativeWay ==='2'">
+              <span class="flex-hc">
+                票签
+                <el-tooltip class="box-item" effect="dark" content="部分办理人审批,只支持选择用户">
+                  <el-icon :size="14" class="ml5">
+                    <WarningFilled />
+                  </el-icon>
+                </el-tooltip>
+              </span>
+            </el-radio>
+            <el-radio label="3" v-if="form.collaborativeWay ==='3'">
+              <span class="flex-hc">
+                会签
+                <el-tooltip class="box-item" effect="dark" content="所有办理都需要审批,只支持选择用户">
+                  <el-icon :size="14" class="ml5">
+                    <WarningFilled />
+                  </el-icon>
+                </el-tooltip>
+              </span>
+            </el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </slot>
+      <slot name="form-item-task-nodeRatio" :model="form" field="nodeRatio" v-if="form.collaborativeWay === '2'">
+        <el-form-item label="票签占比" prop="nodeRatio">
+          <el-input v-model="form.nodeRatio" type="number" placeholder="请输入"></el-input>
+          <div class="placeholder">票签比例范围:(0-100)的值</div>
+        </el-form-item>
+      </slot>
+      <slot name="form-item-task-permissionFlag" :model="form" field="permissionFlag">
+        <el-tooltip
+          effect="dark"
+          :content="userNameList"
+          :disabled="!disabled"
+        >
+          <el-form-item label="办理人选择">
+            <el-select v-model="form.permissionFlag" allow-create multiple collapse-tags :disabled="disabled" :clearable="!disabled" filterable v-if="form.collaborativeWay === '1'">
+              <el-option-group
+                v-for="groupOption in groupOptions"
+                :key="groupOption.label"
+                :label="groupOption.label"
+                :disabled="disabled">
+                <el-option
+                  v-for="item in groupOption.options"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value">
+                </el-option>
+              </el-option-group>
+            </el-select>
+            <el-select
+              v-else
+              v-model="form.permissionFlag"
+              multiple
+              collapse-tags
+              ref="userSelect"
+              :disabled="disabled"
+              :clearable="!disabled"
+              @focus="initUser"
+              popper-class="dialogSelect"
+              :popper-append-to-body="false"
+            >
+              <el-option
+                v-for="item in form.permissionFlag"
+                :key="item"
+                :label="item"
+                :value="item">
+              </el-option>
+            </el-select>
+          </el-form-item>
+        </el-tooltip>
+      </slot>
+      <slot name="form-item-task-skipAnyNode" :model="form" field="skipAnyNode">
+        <el-form-item label="是否跳转任意节点">
+          <el-radio-group v-model="form.skipAnyNode">
+            <el-radio label="N">否</el-radio>
+            <el-radio label="Y">是</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </slot>
+      <slot name="form-item-task-listenerType" :model="form" field="listenerType">
+        <el-form-item label="监听器类型">
+          <el-select v-model="form.listenerType" multiple>
+            <el-option label="任务创建" value="create"></el-option>
+            <el-option label="任务开始办理" value="start"></el-option>
+            <el-option label="分派监听器" value="assignment"></el-option>
+            <el-option label="权限认证" value="permission"></el-option>
+            <el-option label="任务完成" value="finish"></el-option>
+          </el-select>
+        </el-form-item>
+      </slot>
+      <slot name="form-item-task-listenerPath" :model="form" field="listenerPath">
+        <el-form-item label="监听器路径" description="输入监听器的路径,以@@分隔,顺序与监听器类型一致">
+          <el-input type="textarea" v-model="form.listenerPath" rows="8"></el-input>
+          <el-tooltip class="box-item" effect="dark" content="输入监听器的路径,以@@分隔,顺序与监听器类型一致">
+            <el-icon :size="14" class="mt5">
+              <WarningFilled />
+            </el-icon>
+          </el-tooltip>
+        </el-form-item>
+      </slot>
+      <slot name="form-item-task-formCustom" :model="form" field="formCustom">
+        <el-form-item label="审批表单是否自定义">
+          <el-select v-model="form.formCustom">
+            <el-option label="使用流程表单" :value="''"></el-option>
+            <!-- <el-option label="节点自定义表单" value="Y"></el-option> -->
+            <el-option label="节点表单路径" value="N"></el-option>
+          </el-select>
+        </el-form-item>
+      </slot>
+      <slot name="form-item-task-formPath" :model="form" field="formPath" v-if="form.formCustom === 'N'">
+        <el-form-item label="审批表单路径">
+          <el-input v-model="form.formPath"></el-input>
+        </el-form-item>
+      </slot>
+    </el-form>
+
+    <!-- 权限标识:会签票签选择用户 -->
+    <el-dialog title="用户选择" v-if="userVisible" v-model="userVisible" width="80%" append-to-body>
+<!--      <selectUser v-model:selectUser="form.permissionFlag" v-model:userVisible="userVisible" @handleUserSelect="handleUserSelect"></selectUser>-->
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {WarningFilled} from "@element-plus/icons-vue";
+import {getListApi as getRoleListApi} from "@/api/system/role";
+import {getListApi as getUserListApi} from "@/api/system/user";
+import {getListApi as getDeptListApi} from "@/api/system/dept";
+import {getUsernameApi} from "@/api/flow/definition";
+
+const { proxy } = getCurrentInstance();
+
+const props = defineProps({
+  modelValue: {
+    type: Object,
+    default () {
+      return {}
+    }
+  },
+  disabled: { // 是否禁止
+    type: Boolean,
+    default: false
+  },
+});
+
+const form = ref(props.modelValue);
+const userNameList = ref("");
+const groupOptions = ref([]);
+const rules = reactive({
+  nodeRatio: [
+    { required: false, message: "请输入", trigger: "change" },
+    { pattern: /^(?:[1-9]\d?|0\.\d{1,3}|[1-9]\d?\.\d{1,3})$/, message: "请输入(0, 100)的值,最多保留三位小数", trigger: ["change", "blur"] }
+  ]
+});
+const userVisible = ref(false);
+const emit = defineEmits(["change"]);
+
+watch(() => form, n => {
+  if (n) {
+    emit('change', n)
+  }
+},{ deep: true });
+
+
+// 根据id查用户名
+function getIdReverseDisplayName() {
+  if (form.value.collaborativeWay !== "1") {
+    getUsernameApi(form.value.permissionFlag.join(",")).then(res => {
+      userNameList.value = res.data ? res.data.map(e => e.nickName).join(",") : "";
+    });
+  }
+}
+
+/** 选择角色权限范围触发 */
+function getPermissionFlag() {
+  if (form.value.permissionFlag) {
+    form.value.permissionFlag = form.value.permissionFlag.split(",")
+  }
+  if (form.value.listenerType) {
+    form.value.listenerType = form.value.listenerType.split(",")
+  }
+  getRoleListApi({ status: 1 }).then(resp => {
+    let groupOptionCreateBy = {
+      label: '创建人',
+      options: [{
+        value: 'warmFlowInitiator',
+        label: '流程发起人'
+      }]
+    }
+    groupOptions.value.push(groupOptionCreateBy);
+    let groupOption = {
+      label: '角色',
+      options: resp.map(item =>{
+            return {
+              value: 'role:' + item.id,
+              label: item.name
+            }
+          }
+      )
+    }
+    groupOptions.value.push(groupOption);
+    getUserListApi({status: 1}).then(resp => {
+      let groupOption = {
+        label: '用户',
+        options: resp.map(item =>{
+              return {
+                value: item.id,
+                label: item.nickname
+              }
+            }
+        )
+      }
+      groupOptions.value.push(groupOption);
+      getDeptListApi().then(resp => {
+        let groupOption = {
+          label: '部门',
+          options: resp.map(item =>{
+                return {
+                  value: 'dept:' + item.id,
+                  label: item.name
+                }
+              }
+          )
+        }
+        groupOptions.value.push(groupOption);
+        if (props.disabled && form.value.collaborativeWay === "1") {
+          let userNameList = [];
+          groupOptions.value.forEach(e => {
+            e.options.forEach(o => {
+              if (form.value.permissionFlag.includes(o.value)) userNameList.push(o.label);
+            });
+          });
+          userNameList.value = userNameList.join(",");
+        }
+      });
+    });
+  });
+}
+
+function collaborativeWayChange(val) {
+  form.value.permissionFlag = [];
+  form.value.nodeRatio = val === "1" ? "0.000" : val === "3" ? "100.000" : "";
+}
+
+// 打开用户选择弹窗
+function initUser() {
+  userVisible.value = true;
+  proxy.$refs.userSelect.blur();
+}
+
+// 获取选中用户数据
+function handleUserSelect(checkedItemList) {
+  form.value.permissionFlag = checkedItemList.map(e => {
+    return e.userId;
+  });
+}
+
+getPermissionFlag();
+if (props.disabled) getIdReverseDisplayName();
+</script>
+
+<style scoped>
+.dialogSelect {
+  display: none;
+}
+.placeholder {
+  color: #828f9e;
+  font-size: 12px;
+}
+</style>

+ 46 - 0
jy-ui/src/components/flow/PropertySetting/end.vue

@@ -0,0 +1,46 @@
+<template>
+  <div>
+    <el-form ref="formRef" :model="form" label-width="120px" size="small" :disabled="disabled">
+      <slot name="form-item-task-name" :model="form" field="nodeCode">
+        <el-form-item label="节点编码">
+          <el-input v-model="form.nodeCode" :disabled="disabled"></el-input>
+        </el-form-item>
+      </slot>
+      <slot name="form-item-task-name" :model="form" field="nodeName">
+        <el-form-item label="节点名称">
+          <el-input v-model="form.nodeName" :disabled="disabled"></el-input>
+        </el-form-item>
+      </slot>
+    </el-form>
+  </div>
+</template>
+
+<script setup lang="ts">
+
+const props = defineProps({
+  modelValue: {
+    type: Object,
+    default () {
+      return {}
+    }
+  },
+  disabled: { // 是否禁止
+    type: Boolean,
+    default: false
+  },
+});
+
+const form = ref(props.modelValue);
+const emit = defineEmits(["change"]);
+
+watch(() => form, n => {
+  if (n) {
+    emit('change', n)
+  }
+},{ deep: true });
+
+</script>
+
+<style scoped>
+
+</style>

+ 256 - 0
jy-ui/src/components/flow/PropertySetting/index.vue

@@ -0,0 +1,256 @@
+<template>
+  <div>
+    <a-dialog :title="title" v-model="drawer" @close="handleClose">
+      <component :is="componentType" v-model="form" :disabled="disabled" :skipConditionShow="skipConditionShow">
+        <template v-slot:[key]="data" v-for="(item, key) in $slots">
+          <slot :name="key" v-bind="data || {}"></slot>
+        </template>
+      </component>
+    </a-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+import start from './start.vue'
+import between from './between.vue'
+import serial from './serial.vue'
+import parallel from './parallel.vue'
+import end from './end.vue'
+import skip from './skip.vue'
+
+const COMPONENT_LIST = {
+  start,
+  between,
+  serial,
+  parallel,
+  end,
+  skip
+}
+
+const props = defineProps({
+  value: {
+    type: Object,
+    default () {
+      return {}
+    }
+  },
+  node: {
+    type: Object,
+    default () {
+      return {}
+    }
+  },
+  lf: {
+    type: Object,
+    default () {
+      return null
+    }
+  },
+  disabled: { // 是否禁止
+    type: Boolean,
+    default: false
+  },
+  skipConditionShow: { // 是否显示跳转条件
+    type: Boolean,
+    default: true
+  },
+});
+
+const drawer = ref(false);
+const form = ref({});
+const objId = ref(undefined);
+const nodeCode = ref(null);
+const title = computed(() => {
+  if (props.node && props.node.type === 'skip') {
+    return '设置边属性'
+  } else if (props.node && props.node.type === 'serial') {
+    return '设置串行网关属性'
+  } else if (props.node && props.node.type === 'parallel') {
+    return '设置并行网关属性'
+  } else if (props.node && props.node.type === 'start') {
+    return '设置开始属性'
+  } else if (props.node && props.node.type === 'end') {
+    return '设置结束属性'
+  }
+  return '设置中间属性'
+});
+// 组件类型
+const componentType = computed(() => {
+  if (!props.node || !props.node.type) return
+  return COMPONENT_LIST[props.node.type]
+})
+
+
+watch(() => props.node, n => {
+  if (n) {
+    objId.value = n.id
+    if (n.type === 'skip') {
+      let skipCondition = n.properties.skipCondition
+      let conditionSpl = skipCondition ? skipCondition.split('@@|') : []
+      let conditionSplTwo = conditionSpl && conditionSpl.length > 0 ? conditionSpl[1]: []
+      let condition, conditionType, conditionValue = '';
+      if (conditionSpl && conditionSpl.length > 0 && conditionSpl[0] === '@@spel') {
+        conditionType = 'spel'
+        conditionValue = conditionSplTwo
+      } else if (conditionSpl && conditionSpl.length > 0 && conditionSpl[0] !== '@@spel') {
+        condition = conditionSplTwo && conditionSplTwo.length > 0 ? conditionSplTwo.split("@@")[0] : ''
+        conditionType = conditionSplTwo && conditionSplTwo.length > 0 ? conditionSplTwo.split("@@")[1] : ''
+        conditionValue = conditionSplTwo && conditionSplTwo.length > 0 ? conditionSplTwo.split("@@")[2] : ''
+      }
+      form.value = {
+        nodeType: n.type,
+        skipType: n.properties.skipType,
+        skipName: n.text instanceof Object ? n.text.value : n.text,
+        skipCondition: skipCondition,
+        condition: condition,
+        conditionType: conditionType,
+        conditionValue: conditionValue
+      }
+    } else {
+      let nodeRatio = n.properties.nodeRatio || "";
+      if (!n.properties.collaborativeWay) {
+        n.properties.collaborativeWay = nodeRatio === "0.000" ? "1" : nodeRatio === "100.000" ? "3" : nodeRatio ? "2" : "1";
+      }
+      n.properties.formCustom = JSON.stringify(n.properties) === "{}" ? "N" : (n.properties.formCustom || "");
+      form.value = {
+        nodeType: n.type,
+        nodeCode: n.id,
+        ...n.properties,
+        nodeName: n.text instanceof Object ? n.text.value : n.text
+      }
+    }
+  }
+});
+
+watch(() => form.value.nodeCode, (n) => {
+  nodeCode.value = n;
+});
+
+watch(() => form.value.skipType, (n) => {
+  // 监听跳转属性变化并更新
+  props.lf.setProperties(objId.value, {
+    skipType: n
+  })
+
+});
+
+watch(() => form.value.nodeName, (n) => {
+  // 监听节点名称变化并更新
+  props.lf.updateText(objId.value, n)
+  // 监听节点名称变化并更新
+  props.lf.setProperties(objId.value, {
+    nodeName: n
+  })
+});
+
+watch(() => form.value.collaborativeWay, (n) => {
+  // 监听节点属性变化并更新
+  props.lf.setProperties(objId.value, {
+    nodeRatio: n === "1" ? "0.000" : n === "3" ? "100.000" : ""
+  })
+});
+
+watch(() => form.value.nodeRatio, (n) => {
+  // 监听节点属性变化并更新
+  props.lf.setProperties(objId.value, {
+    nodeRatio: n
+  })
+});
+
+watch(() => form.value.permissionFlag, (n) => {
+  // 监听节点属性变化并更新
+  props.lf.setProperties(objId.value, {
+    permissionFlag: Array.isArray(n) ? n.join(',') : n
+  })
+});
+
+watch(() => form.value.skipAnyNode, (n) => {
+  // 监听跳转属性变化并更新
+  props.lf.setProperties(objId.value, {
+    skipAnyNode: n
+  })
+});
+watch(() => form.value.listenerType, (n) => {
+  // 确保 n 是一个数组
+  if (!Array.isArray(n)) {
+    n = [n]; // 将 n 转换为数组
+  }
+
+  // 将数组元素连接为字符串
+  let listenerTypeStr = n.join(",");
+  // 监听监听器类型变化并更新
+  props.lf.setProperties(objId.value, {
+    listenerType: listenerTypeStr
+  })
+});
+
+watch(() => form.value.listenerPath, (n) => {
+  // 监听监听器路径变化并更新
+  props.lf.setProperties(objId.value, {
+    listenerPath: n
+  })
+});
+
+watch(() => form.value.formCustom, (n) => {
+  props.lf.setProperties(objId.value, {
+    formCustom: n || ""
+  })
+});
+
+watch(() => form.value.formPath, (n) => {
+  props.lf.setProperties(objId.value, {
+    formPath: n
+  })
+});
+
+watch(() => form.value.skipName, (n) => {
+  if (['skip'].includes(props.node.type)) {
+    // 监听跳转名称变化并更新
+    props.lf.updateText(objId.value, n)
+    // 监听跳转属性变化并更新
+    props.lf.setProperties(objId.value, {
+      skipName: n
+    })
+  }
+});
+
+watch(() => form.value.skipCondition, (n) => {
+  // 监听跳转属性变化并更新
+  props.lf.setProperties(objId.value, {
+    skipCondition: n
+  })
+
+});
+
+
+function show () {
+  drawer.value = true
+}
+
+function handleClose () {
+  // 监听节点编码变量并更新
+  if (nodeCode.value && objId.value) {
+    if (['skip'].includes(props.node?.type)) {
+      if (!props.lf.getEdgeModelById(nodeCode.value)) {
+        props.lf.changeEdgeId(objId.value, nodeCode.value)
+      }
+    } else {
+      if (!props.lf.getNodeModelById(nodeCode.value)) {
+        props.lf.changeNodeId(objId.value, nodeCode.value)
+      }
+    }
+  }
+  drawer.value = false
+}
+
+defineExpose({
+  show,
+  handleClose
+})
+</script>
+
+<style scoped>
+.el-drawer__container ::-webkit-scrollbar {
+  display: none;
+}
+</style>

+ 45 - 0
jy-ui/src/components/flow/PropertySetting/parallel.vue

@@ -0,0 +1,45 @@
+<template>
+  <div>
+    <el-form ref="formRef" :model="form" label-width="120px" size="small" :disabled="disabled">
+      <slot name="form-item-task-name" :model="form" field="nodeCode">
+        <el-form-item label="节点编码">
+          <el-input v-model="form.nodeCode" :disabled="disabled"></el-input>
+        </el-form-item>
+      </slot>
+      <slot name="form-item-task-name" :model="form" field="nodeName">
+        <el-form-item label="节点名称">
+          <el-input v-model="form.nodeName" :disabled="disabled"></el-input>
+        </el-form-item>
+      </slot>
+    </el-form>
+  </div>
+</template>
+
+<script setup lang="ts">
+
+const props = defineProps({
+  modelValue: {
+    type: Object,
+    default () {
+      return {}
+    }
+  },
+  disabled: { // 是否禁止
+    type: Boolean,
+    default: false
+  },
+});
+
+const form = ref(props.modelValue);
+const emit = defineEmits(["change"]);
+
+watch(() => form, n => {
+  if (n) {
+    emit('change', n)
+  }
+},{ deep: true });
+</script>
+
+<style scoped>
+
+</style>

+ 46 - 0
jy-ui/src/components/flow/PropertySetting/serial.vue

@@ -0,0 +1,46 @@
+<template>
+  <div>
+    <el-form ref="formRef" :model="form" label-width="120px" size="small" :disabled="disabled">
+      <slot name="form-item-task-name" :model="form" field="nodeCode">
+        <el-form-item label="节点编码">
+          <el-input v-model="form.nodeCode" :disabled="disabled"></el-input>
+        </el-form-item>
+      </slot>
+      <slot name="form-item-task-name" :model="form" field="nodeName">
+        <el-form-item label="节点名称">
+          <el-input v-model="form.nodeName" :disabled="disabled"></el-input>
+        </el-form-item>
+      </slot>
+    </el-form>
+  </div>
+</template>
+
+<script setup lang="ts">
+
+const props = defineProps({
+  modelValue: {
+    type: Object,
+    default () {
+      return {}
+    }
+  },
+  disabled: { // 是否禁止
+    type: Boolean,
+    default: false
+  },
+});
+
+const form = ref(props.modelValue);
+const emit = defineEmits(["change"]);
+
+watch(() => form, n => {
+  if (n) {
+    emit('change', n)
+  }
+},{ deep: true });
+
+</script>
+
+<style scoped>
+
+</style>

+ 87 - 0
jy-ui/src/components/flow/PropertySetting/skip.vue

@@ -0,0 +1,87 @@
+<template>
+  <div>
+    <el-form ref="formRef" :model="form" label-width="120px" size="small" :disabled="disabled">
+      <slot name="form-item-task-skipName" v-if="skipConditionShow" :model="form" field="skipName">
+        <el-form-item label="跳转名称">
+          <el-input v-model="form.skipName" placeholder="跳转名称"/>
+        </el-form-item>
+      </slot>
+      <slot name="form-item-task-skipType" :model="form" field="skipType">
+        <el-form-item label="跳转类型">
+          <el-select v-model="form.skipType">
+            <el-option sel label="审批通过" value="PASS"/>
+            <el-option label="退回" value="REJECT"/>
+          </el-select>
+        </el-form-item>
+      </slot>
+      <slot name="form-item-task-skipCondition" v-if="skipConditionShow" :model="form" field="skipCondition">
+        <el-form-item label="跳转条件">
+          <el-input v-model="form.condition" v-if="!spelFlag" placeholder="条件名" style="width: 20%"/>
+          <el-select v-model="form.conditionType" placeholder="请选择条件方式" style="width: 35%;margin-left: 1%" @change="changeOper">
+            <el-option label="大于" value="gt"/>
+            <el-option label="大于等于" value="ge"/>
+            <el-option label="等于" value="eq"/>
+            <el-option label="不等于" value="ne"/>
+            <el-option label="小于" value="lt"/>
+            <el-option label="小于等于" value="le"/>
+            <el-option label="包含" value="like"/>
+            <el-option label="不包含" value="notNike"/>
+            <el-option label="spel表达式" value="spel"/>
+          </el-select>
+          <el-input v-model="form.conditionValue" placeholder="条件值" style="width: 42%;margin-left: 1%;margin-right: 1%;"/>
+        </el-form-item>
+      </slot>
+    </el-form>
+  </div>
+</template>
+
+<script setup lang="ts">
+
+const props = defineProps({
+  modelValue: {
+    type: Object,
+    default() {
+      return {}
+    }
+  },
+  disabled: { // 是否禁止
+    type: Boolean,
+    default: false
+  },
+  skipConditionShow: { // 是否显示跳转条件
+    type: Boolean,
+    default: true
+  },
+});
+
+const spelFlag = ref(false);
+const form = ref(props.modelValue);
+const emit = defineEmits(["change"]);
+
+watch(() => form, n => {
+  n = n.value;
+  let skipCondition = n.skipCondition;
+  skipCondition = "@@" + n.conditionType + "@@|";
+  if (n.conditionType !== 'spel') {
+    skipCondition = skipCondition
+      + (n.condition ? n.condition : '') + "@@"
+      + n.conditionType + "@@";
+  }
+  n.skipCondition = skipCondition
+    + (n.conditionValue ? n.conditionValue : '')
+  if (n) {
+    emit('change', n)
+  }
+}, {deep: true});
+
+function changeOper(obj) {
+  spelFlag.value = obj === 'spel';
+}
+
+if (props.modelValue?.conditionType === 'spel') spelFlag.value = true;
+
+</script>
+
+<style scoped>
+
+</style>

+ 69 - 0
jy-ui/src/components/flow/PropertySetting/start.vue

@@ -0,0 +1,69 @@
+<template>
+  <div>
+    <el-form ref="formRef" :model="form" label-width="120px" size="small" :disabled="disabled">
+      <slot name="form-item-task-name" :model="form" field="nodeCode">
+        <el-form-item label="节点编码">
+          <el-input v-model="form.nodeCode" :disabled="disabled"></el-input>
+        </el-form-item>
+      </slot>
+      <slot name="form-item-task-name" :model="form" field="nodeName">
+        <el-form-item label="节点名称">
+          <el-input v-model="form.nodeName" :disabled="disabled"></el-input>
+        </el-form-item>
+      </slot>
+      <slot name="form-item-task-listenerType" :model="form" field="listenerType">
+        <el-form-item label="监听器类型">
+          <el-select v-model="form.listenerType" multiple>
+            <el-option label="任务创建" value="create"></el-option>
+            <el-option label="任务开始办理" value="start"></el-option>
+            <el-option label="分派监听器" value="assignment"></el-option>
+            <el-option label="权限认证" value="permission"></el-option>
+            <el-option label="任务完成" value="finish"></el-option>
+          </el-select>
+        </el-form-item>
+      </slot>
+      <slot name="form-item-task-listenerPath" :model="form" field="listenerPath">
+        <el-form-item label="监听器路径" description="输入监听器的路径,以@@分隔,顺序与监听器类型一致">
+          <el-input type="textarea" v-model="form.listenerPath" rows="8"></el-input>
+          <el-tooltip class="item" effect="dark" content="输入监听器的路径,以@@分隔,顺序与监听器类型一致">
+            <i class="el-icon-question"></i>
+          </el-tooltip>
+        </el-form-item>
+      </slot>
+    </el-form>
+  </div>
+</template>
+
+<script setup lang="ts">
+
+const props = defineProps({
+  modelValue: {
+    type: Object,
+    default () {
+      return {}
+    }
+  },
+  disabled: { // 是否禁止
+    type: Boolean,
+    default: false
+  },
+});
+
+const form = ref(props.modelValue);
+const emit = defineEmits(["change"]);
+
+watch(() => form, n => {
+  if (n) {
+    emit('change', n)
+  }
+},{ deep: true });
+
+
+if (form.value.listenerType) {
+  form.value.listenerType = form.value.listenerType.split(",")
+}
+</script>
+
+<style scoped>
+
+</style>

+ 22 - 0
jy-ui/src/components/flow/js/between.js

@@ -0,0 +1,22 @@
+import {RectNode, RectNodeModel} from "@logicflow/core";
+
+class BetweenModel extends RectNodeModel {
+
+  initNodeData(data) {
+    super.initNodeData(data);
+    this.width = 100;
+    this.height = 80;
+    this.radius = 5;
+  }
+  getNodeStyle() {
+    return super.getNodeStyle()
+  }
+}
+
+class BetweenView extends RectNode {}
+
+export default {
+  type: "between",
+  model: BetweenModel,
+  view: BetweenView,
+};

+ 17 - 0
jy-ui/src/components/flow/js/end.js

@@ -0,0 +1,17 @@
+import { CircleNode, CircleNodeModel } from "@logicflow/core";
+
+class endModel extends CircleNodeModel {
+
+  initNodeData(data) {
+    super.initNodeData(data);
+    this.r = 20
+  }
+}
+
+class endView extends CircleNode {}
+
+export default {
+  type: "end",
+  model: endModel,
+  view: endView,
+};

+ 57 - 0
jy-ui/src/components/flow/js/parallel.js

@@ -0,0 +1,57 @@
+import { h, PolygonNode, PolygonNodeModel } from '@logicflow/core'
+
+class ParallelModel extends PolygonNodeModel {
+  static extendKey = 'ParallelModel';
+  constructor (data, graphModel) {
+    if (!data.text) {
+      data.text = ''
+    }
+    if (data.text && typeof data.text === 'string') {
+      data.text = {
+        value: data.text,
+        x: data.x,
+        y: data.y + 40
+      }
+    }
+    super(data, graphModel)
+    this.points = [
+      [25, 0],
+      [50, 25],
+      [25, 50],
+      [0, 25]
+    ]
+  }
+
+}
+
+class ParallelView extends PolygonNode {
+  static extendKey = 'ParallelNode';
+  getShape () {
+    const { model } = this.props
+    const { x, y, width, height, points } = model
+    const style = model.getNodeStyle()
+    return h(
+      'g',
+      {
+        transform: `matrix(1 0 0 1 ${x - width / 2} ${y - height / 2})`
+      },
+      h('polygon', {
+        ...style,
+        x,
+        y,
+        points
+      }),
+      h('path', {
+        d:
+          'm 23,10 0,12.5 -12.5,0 0,5 12.5,0 0,12.5 5,0 0,-12.5 12.5,0 0,-5 -12.5,0 0,-12.5 -5,0 z',
+        ...style
+      })
+    )
+  }
+}
+
+export default {
+  type: 'parallel',
+  view: ParallelView,
+  model: ParallelModel
+};

+ 57 - 0
jy-ui/src/components/flow/js/serial.js

@@ -0,0 +1,57 @@
+import { h, PolygonNode, PolygonNodeModel } from '@logicflow/core'
+
+class SerialModel extends PolygonNodeModel {
+  static extendKey = 'SerialModel';
+  constructor (data, graphModel) {
+    if (!data.text) {
+      data.text = ''
+    }
+    if (data.text && typeof data.text === 'string') {
+      data.text = {
+        value: data.text,
+        x: data.x,
+        y: data.y + 40
+      }
+    }
+    super(data, graphModel)
+    this.points = [
+      [25, 0],
+      [50, 25],
+      [25, 50],
+      [0, 25]
+    ]
+  }
+
+}
+
+class SerialView extends PolygonNode {
+  static extendKey = 'SerialNode';
+  getShape () {
+    const { model } = this.props
+    const { x, y, width, height, points } = model
+    const style = model.getNodeStyle()
+    return h(
+      'g',
+      {
+        transform: `matrix(1 0 0 1 ${x - width / 2} ${y - height / 2})`
+      },
+      h('polygon', {
+        ...style,
+        x,
+        y,
+        points
+      }),
+      h('path', {
+        d:
+          'm 16,15 7.42857142857143,9.714285714285715 -7.42857142857143,9.714285714285715 3.428571428571429,0 5.714285714285715,-7.464228571428572 5.714285714285715,7.464228571428572 3.428571428571429,0 -7.42857142857143,-9.714285714285715 7.42857142857143,-9.714285714285715 -3.428571428571429,0 -5.714285714285715,7.464228571428572 -5.714285714285715,-7.464228571428572 -3.428571428571429,0 z',
+        ...style
+      })
+    )
+  }
+}
+
+export default {
+  type: 'serial',
+  view: SerialView,
+  model: SerialModel
+};

+ 33 - 0
jy-ui/src/components/flow/js/skip.js

@@ -0,0 +1,33 @@
+import { PolylineEdge, PolylineEdgeModel } from "@logicflow/core";
+
+class SkipModel extends PolylineEdgeModel {
+  setAttributes() {
+    this.offset = 20;
+  }
+
+  getEdgeStyle() {
+    const style = super.getEdgeStyle();
+    const { properties } = this;
+    if (properties.isActived) {
+      style.strokeDasharray = "4 4";
+    }
+    return style;
+  }
+
+  /**
+   * 重写此方法,使保存数据是能带上锚点数据。
+   */
+  getData() {
+    const data = super.getData();
+    data.sourceAnchorId = this.sourceAnchorId;
+    data.targetAnchorId = this.targetAnchorId;
+    return data;
+  }
+
+}
+
+export default {
+  type: "skip",
+  view: PolylineEdge,
+  model: SkipModel,
+};

+ 17 - 0
jy-ui/src/components/flow/js/start.js

@@ -0,0 +1,17 @@
+import { CircleNode, CircleNodeModel } from "@logicflow/core";
+
+class StartModel extends CircleNodeModel {
+
+  initNodeData(data) {
+    super.initNodeData(data);
+    this.r = 20
+  }
+}
+
+class StartView extends CircleNode {}
+
+export default {
+  type: "start",
+  model: StartModel,
+  view: StartView,
+};

+ 357 - 0
jy-ui/src/components/flow/js/tool.js

@@ -0,0 +1,357 @@
+/**
+ * 节点样式处理方法
+ * @param _this
+ * @param style
+ * @returns {*}
+ */
+export const nodeStyleHandle = (_this, style) => {
+  if (_this.properties.status === "pass") {
+    style.stroke = "green";
+  } else if (_this.properties.status === "reject") {
+    style.stroke = "#ffba00";
+  } else if (_this.properties.status === "approval") {
+    style.stroke = "red";
+  } else {
+    style.stroke = "#909399";
+  }
+  return style
+}
+
+/**
+ * 节点大小处理方法
+ * @param _this
+ * @param style
+ * @returns {*}
+ */
+export const nodeSizeHandle = (_this) => {
+  _this.width = 120;
+  _this.height = 80;
+  _this.radius = 5;
+}
+
+/**
+ * 节点大小处理方法
+ * @param _this
+ * @param style
+ * @returns {*}
+ */
+export const skipText = (skipType) => {
+  let text = ''
+  if (skipType && skipType === 'PASS') {
+    text = '审批通过'
+  } else if (skipType && skipType === 'REJECT') {
+    text = '退回'
+  }
+  return text
+}
+
+
+/**
+ * 解析xml成Dom对象
+ * @param {} xml
+ * @returns
+ */
+export const parseXml2Dom = (xml) => {
+  let xmlDoc = null
+  if (window.DOMParser) {
+    const parser = new DOMParser()
+    xmlDoc = parser.parseFromString(xml, 'text/xml')
+  } else { // Internet Explorer
+    // eslint-disable-next-line no-undef
+    xmlDoc = new ActiveXObject('Microsoft.XMLDOM')
+    xmlDoc.async = false
+    xmlDoc.loadXML(xml)
+  }
+  return xmlDoc
+}
+
+// 节点标签
+const NODE_NAMES = ['start', 'between', 'serial', 'parallel', 'end']
+// 流程节点属性
+const DEFINITION_KEYS = ['flowCode', 'flowName', 'version', 'fromCustom', 'fromPath']
+// 节点属性
+const NODE_ATTR_KEYS = ['nodeType', 'nodeCode', 'nodeName', 'coordinate', 'nodeRatio', 'permissionFlag', "skipAnyNode"
+    , "listenerType", "listenerPath", "formCustom", "formPath"]
+// 变迁节点属性
+const SKIP_ATTR_KEYS = ['skipName', 'skipType', 'coordinate', 'skipCondition']
+
+/**
+ * 将warm-flow的定义文件转成LogicFlow支持的数据格式
+ * @param {*} xml
+ * @returns
+ */
+export const xml2LogicFlowJson = (xml) => {
+  const graphData = {
+    nodes: [],
+    edges: []
+  }
+  const xmlDoc = parseXml2Dom(xml)
+  const definitionDom = xmlDoc.getElementsByTagName('definition')
+  if (!definitionDom.length) {
+    return graphData
+  }
+  let value = null
+  // 解析definition属性
+  DEFINITION_KEYS.forEach(key => {
+    value = definitionDom[0].getAttribute(key)
+    if (value) {
+      graphData[key] = value
+    }
+  })
+  let nodeEles = null
+  let node = null
+  let lfNode = {}
+  // 解析节点
+  nodeEles = definitionDom[0].getElementsByTagName("node")
+  if (nodeEles.length) {
+    for (var i = 0, len = nodeEles.length; i < len; i++) {
+      node = nodeEles[i]
+      lfNode = {
+        text:{},
+        properties: {}
+      }
+      // 处理节点
+      NODE_ATTR_KEYS.forEach(attrKey => {
+        value = node.getAttribute(attrKey)
+        if (value) {
+          if (attrKey === 'nodeType') {
+            lfNode.type = value
+          } else if (attrKey === 'nodeCode') {
+            lfNode.id = value
+          } else if (attrKey === 'coordinate') {
+            const attr = value.split('|')
+            const nodeXy = attr[0].split(',')
+            lfNode.x = parseInt(nodeXy[0])
+            lfNode.y = parseInt(nodeXy[1])
+            if (attr.length === 2) {
+              const textXy = attr[1].split(',')
+              lfNode.text.x = parseInt(textXy[0])
+              lfNode.text.y = parseInt(textXy[1])
+            }
+          } else if (attrKey === 'nodeName') {
+            lfNode.text.value = value
+          } else {
+            lfNode.properties[attrKey] = value
+          }
+        }
+      })
+      graphData.nodes.push(lfNode)
+      // 处理边
+      let skipEles = null
+      let skipEle = null
+      let edge = {}
+      skipEles = node.getElementsByTagName('skip')
+      for (var j = 0, lenn = skipEles.length; j < lenn; j++) {
+        skipEle = skipEles[j]
+        edge = {
+          text: {},
+          properties: {},
+        }
+        edge.id = skipEle.getAttribute('id')
+        edge.type = 'skip'
+        edge.sourceNodeId = lfNode.id
+        edge.targetNodeId = skipEle.textContent
+        edge.text = {
+          value: skipEle.getAttribute('skipName')
+
+        }
+        edge.properties.skipCondition = skipEle.getAttribute('skipCondition')
+        edge.properties.skipName = skipEle.getAttribute('skipName')
+        edge.properties.skipType = skipEle.getAttribute('skipType')
+        const expr = skipEle.getAttribute('expr')
+        if (expr) {
+          edge.properties.expr = expr
+        }
+        const coordinate = skipEle.getAttribute('coordinate')
+        if (coordinate) {
+          const coordinateXy = coordinate.split('|')
+          edge.pointsList = []
+          coordinateXy[0].split(';').forEach((item) => {
+            const pointArr = item.split(',')
+            edge.pointsList.push({
+              x: parseInt(pointArr[0]),
+              y: parseInt(pointArr[1])
+            })
+          })
+          edge.startPoint = edge.pointsList[0]
+          edge.endPoint = edge.pointsList[edge.pointsList.length - 1]
+          if (coordinateXy.length > 1) {
+            let textXy = coordinateXy[1].split(",");
+            edge.text.x = parseInt(textXy[0])
+            edge.text.y = parseInt(textXy[1])
+          }
+        }
+        graphData.edges.push(edge)
+      }
+    }
+  }
+
+  return graphData
+}
+
+/**
+ * 将LogicFlow的数据转成warm-flow的定义文件
+ * @param {*} data(...definitionInfo,nodes,edges)
+ * @returns
+ */
+export const logicFlowJsonToFlowXml = (data) => {
+  let xml = ''
+  // data的数据由流程定义文件信息+logicFlow数据构成
+  // 先构建成流程对象
+  const definitionObj = {
+    flowCode: data.flowCode, // 流程定义编码
+    flowName: data.flowName, // 流程定义名称
+    version: data.version, // 流程定义版本号
+    fromCustom: data.fromCustom, // 表单自定义
+    fromPath: data.fromPath, // 表单自定义路径
+  }
+  /**
+   * 获取开始节点
+   * @returns
+   */
+  const getStartNode = () => {
+    return data.nodes.find((node) => {
+      return node.type === 'start'
+    })
+  }
+  /**
+   * 获取当前节点的所有下一个节点集合
+   * @param {*} id 当前节点名称
+   * @returns
+   */
+  const getNextNodes = (id) => {
+    return data.edges.filter(edge => {
+      return edge.sourceNodeId === id
+    }).map(edge => {
+      return data.nodes.find((node) => {
+        return node.id === edge.targetNodeId
+      })
+    })
+  }
+  /**
+   * 获取节点所有跳转
+   * @param {*} id
+   * @returns
+   */
+  const getSkip = (id) => {
+    return data.edges.filter((edge) => {
+      return edge.sourceNodeId === id
+    }).map(edge => {
+      let coordinate = ''
+      for (let i = 0; i < edge.pointsList.length; i++) {
+        coordinate = coordinate + parseInt(edge.pointsList[i].x) + ',' + parseInt(edge.pointsList[i].y)
+        if (i !== edge.pointsList.length - 1) {
+          coordinate = coordinate + ';'
+        }
+      }
+      if (edge.text) {
+        coordinate = coordinate + '|' + parseInt(edge.text.x) + ',' + parseInt(edge.text.y)
+      }
+      return {
+        skipType: edge.properties.skipType,
+        skipCondition: edge.properties.skipCondition,
+        skipName: edge?.text?.value || edge.properties.skipName,
+        textContent: edge.targetNodeId, // 目地节点id
+        coordinate: coordinate,
+      }
+    })
+  }
+  /**
+   * 构建节点属性
+   * @param {} node
+   * @returns
+   */
+  const buildNode = (node) => {
+    let textXy = '';
+    if (node.text) {
+      textXy = '|' + node.text.x + ',' + node.text.y;
+    }
+    return {
+      nodeType: node.type,
+      nodeCode: node.id,
+      nodeName: (node.text instanceof String || node.text === undefined) ? node.text : node.text.value,
+      permissionFlag: node.properties.permissionFlag,
+      nodeRatio: node.properties.nodeRatio,
+      skipAnyNode: node.properties.skipAnyNode,
+      listenerType: node.properties.listenerType,
+      listenerPath: node.properties.listenerPath,
+      coordinate: node.x + ',' + node.y + textXy,
+      skip: getSkip(node.id),
+      formCustom: node.properties.formCustom,
+      formPath: node.properties.formPath
+    }
+  }
+  /**
+   * 特殊字符转义
+   * @param {*} text
+   * @returns
+   */
+  const textEncode = (text) => {
+    text = text.replace(/&/g, '&amp;')
+      .replace(/"/g, '&quot;')
+      .replace(/</g, '&lt;')
+      .replace(/>/g, '&gt;')
+    return text
+  }
+  /**
+   * 递归构建节点属性
+   * @param {} node
+   */
+  const recursionBuildNode = (node) => {
+    const nodeName = node.type
+    if (!definitionObj[nodeName + '_' + node.id]) {
+      definitionObj[nodeName + '_' + node.id] = buildNode(node)
+      const nextNodes = getNextNodes(node.id)
+      nextNodes.forEach(nextNode => {
+        recursionBuildNode(nextNode)
+      })
+    }
+  }
+  const startNode = getStartNode()
+  if (!startNode) {
+    // 开始节点不存在,xml不合法
+    return ''
+  }
+  recursionBuildNode(startNode)
+  xml = '<?xml version="1.0" encoding="UTF-8"?>\n'
+  xml += '<definition'
+  Object.keys(definitionObj).forEach(key => {
+    const value = definitionObj[key]
+    if (DEFINITION_KEYS.includes(key) && value) {
+      xml += ' ' + key + '=' + '"' + textEncode(value) + '"'
+    }
+  })
+  xml += '>\n'
+  // 生成节点xml
+  Object.keys(definitionObj).forEach(key => {
+    const value = definitionObj[key]
+    let nodeName = key.split('_')[0]
+    if (NODE_NAMES.includes(nodeName)) {
+      xml += '\t<node'
+      // 构造属性
+      Object.keys(value).forEach(nodeAttrKey => {
+        if (NODE_ATTR_KEYS.includes(nodeAttrKey) && value[nodeAttrKey]) {
+          xml += ' ' + nodeAttrKey + '=' + '"' + textEncode(value[nodeAttrKey]) + '"'
+        }
+      })
+      xml += '>\n\t'
+      // 构建skip
+      if (value.skip) {
+        value.skip.forEach(skip => {
+          xml += '\t<skip'
+          // skip属性
+          Object.keys(skip).forEach(skipAttrKey => {
+            if (SKIP_ATTR_KEYS.includes(skipAttrKey) && skip[skipAttrKey]) {
+              xml += ' ' + skipAttrKey + '=' + '"' + textEncode(skip[skipAttrKey]) + '"'
+            }
+          })
+          xml += '>'
+          xml += skip['textContent'] + '</skip>\n'
+        })
+      }
+      xml += '\t</node>\n'
+    }
+  })
+  xml += '</definition>'
+  return xml
+}

+ 0 - 1
jy-ui/src/utils/request.ts

@@ -124,7 +124,6 @@ class RequestHttp {
   delete<T>(url: string, params?: object, _object = {}): Promise<T> {
     return this.service.delete(url, { params, ..._object })
   }
-
 }
 
 // 序列化参数

+ 14 - 8
jy-ui/src/views/business/capital/account/index.vue

@@ -5,7 +5,13 @@ import { ToolbarConfigType } from '@/components/AToolbar/type'
 import { ColumnConfigType } from '@/components/ATable/type'
 import { StrAnyObj, StrAnyObjArr } from '@/typings'
 import { useHandleData } from '@/utils/useHandleData'
-import { getPageApi, getDetailApi, addApi, editApi, deleteApi } from '@/api/business/capital/account'
+import {
+  getPageApi,
+  getDetailApi,
+  addApi,
+  editApi,
+  deleteApi
+} from '@/api/business/capital/account'
 import { getPageApi as getCorporationPageApi } from '@/api/business/corporation/corporation'
 
 const queryRef = ref<InstanceType<typeof AForm>>()
@@ -30,7 +36,7 @@ const queryConfig: FormConfigType[] = [
     keyName: 'id',
     labelName: 'name',
     async option() {
-      const data = await getCorporationPageApi({searchAll: true})
+      const data = await getCorporationPageApi({ searchAll: true })
       return data.records
     }
   },
@@ -152,7 +158,7 @@ const formConfig: FormConfigType[] = [
     prop: 'corporationId',
     label: '归属公司',
     async option() {
-      const data = await getCorporationPageApi({searchAll: true})
+      const data = await getCorporationPageApi({ searchAll: true })
       return data.records
     },
     keyName: 'id',
@@ -168,29 +174,29 @@ const formConfig: FormConfigType[] = [
   {
     type: 'input',
     prop: 'depositBank',
-    label: '开户银行',
+    label: '开户银行'
   },
   {
     type: 'input',
     prop: 'accountName',
-    label: '账户名',
+    label: '账户名'
   },
   {
     type: 'input',
     prop: 'account',
-    label: '账号',
+    label: '账号'
   },
   {
     type: 'input',
     prop: 'correspondentNumber',
-    label: '联行号',
+    label: '联行号'
   },
   {
     type: 'input',
     prop: 'remark',
     itemType: 'textarea',
     rows: 5,
-    label: '备注',
+    label: '备注'
   }
 ]
 

+ 18 - 12
jy-ui/src/views/business/capital/transactions/index.vue

@@ -5,7 +5,13 @@ import { ToolbarConfigType } from '@/components/AToolbar/type'
 import { ColumnConfigType } from '@/components/ATable/type'
 import { StrAnyObj, StrAnyObjArr } from '@/typings'
 import { useHandleData } from '@/utils/useHandleData'
-import { getPageApi, getDetailApi, addApi, editApi, deleteApi } from '@/api/business/capital/transactions'
+import {
+  getPageApi,
+  getDetailApi,
+  addApi,
+  editApi,
+  deleteApi
+} from '@/api/business/capital/transactions'
 import { getPageApi as getCapitalAccountPageApi } from '@/api/business/capital/account'
 import { getPageApi as getCorporationPageApi } from '@/api/business/corporation/corporation'
 
@@ -31,7 +37,7 @@ const queryConfig: FormConfigType[] = [
     keyName: 'id',
     labelName: 'name',
     async option() {
-      const data = await getCorporationPageApi({searchAll: true})
+      const data = await getCorporationPageApi({ searchAll: true })
       return data.records
     }
   },
@@ -65,8 +71,8 @@ const queryConfig: FormConfigType[] = [
       {
         key: 0,
         label: '支出'
-      },
-    ],
+      }
+    ]
   },
   {
     type: 'select',
@@ -196,8 +202,8 @@ const formConfig: FormConfigType[] = [
     prop: 'tradingTime',
     label: '交易时间',
     datePickerType: 'datetime',
-    format: "YYYY-MM-DD hh:mm:ss",
-    valueFormat: "YYYY-MM-DD hh:mm:ss",
+    format: 'YYYY-MM-DD hh:mm:ss',
+    valueFormat: 'YYYY-MM-DD hh:mm:ss',
     defaultTime: new Date(),
     rule: [{ required: true, message: '交易时间不能为空', trigger: 'blur' }]
   },
@@ -213,7 +219,7 @@ const formConfig: FormConfigType[] = [
       {
         key: 0,
         label: '支出'
-      },
+      }
     ],
     rule: [{ required: true, message: '交易类型不能为空', trigger: 'blur' }]
   },
@@ -235,25 +241,25 @@ const formConfig: FormConfigType[] = [
   {
     type: 'input',
     prop: 'targetAccountName',
-    label: '对方账户名',
+    label: '对方账户名'
   },
   {
     type: 'input',
     prop: 'targetDepositBank',
-    label: '对方开户银行',
+    label: '对方开户银行'
   },
   {
     type: 'input',
     prop: 'targetAccount',
-    label: '对方账号',
+    label: '对方账号'
   },
   {
     type: 'input',
     prop: 'remark',
     itemType: 'textarea',
     rows: 5,
-    label: '摘要',
-  },
+    label: '摘要'
+  }
 ]
 
 onMounted(() => {

+ 12 - 6
jy-ui/src/views/business/corporation/index.vue

@@ -5,7 +5,13 @@ import { ToolbarConfigType } from '@/components/AToolbar/type'
 import { ColumnConfigType } from '@/components/ATable/type'
 import { StrAnyObj, StrAnyObjArr } from '@/typings'
 import { useHandleData } from '@/utils/useHandleData'
-import { getPageApi, getDetailApi, addApi, editApi, deleteApi } from '@/api//business/corporation/corporation'
+import {
+  getPageApi,
+  getDetailApi,
+  addApi,
+  editApi,
+  deleteApi
+} from '@/api//business/corporation/corporation'
 
 const queryRef = ref<InstanceType<typeof AForm>>()
 const formRef = ref<InstanceType<typeof AForm>>()
@@ -16,7 +22,7 @@ const pageTotal = ref<number>(0)
 
 const queryData = ref<StrAnyObj>({ pageNum: 1, pageSize: 10 })
 const tableData = ref<StrAnyObjArr>([])
-const formData = ref<StrAnyObj>({ })
+const formData = ref<StrAnyObj>({})
 
 const dialogTitle = ref<string>('')
 const dialogVisible = ref<boolean>(false)
@@ -149,22 +155,22 @@ const formConfig: FormConfigType[] = [
   {
     type: 'input',
     prop: 'legalPersonName',
-    label: '法定代表人',
+    label: '法定代表人'
   },
   {
     type: 'input',
     prop: 'registeredCapital',
-    label: '注册资本',
+    label: '注册资本'
   },
   {
     type: 'input',
     prop: 'taxpayerQualification',
-    label: '纳税人资质',
+    label: '纳税人资质'
   },
   {
     type: 'input',
     prop: 'corporationNumber',
-    label: '公司电话',
+    label: '公司电话'
   },
   {
     type: 'input',

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 298 - 0
jy-ui/src/views/flow/definition/design.vue


+ 25 - 12
jy-ui/src/views/flow/definition/index.vue

@@ -11,10 +11,14 @@ import {
   getDefinitionApi,
   getDefinitionPageApi,
   updateDefinitionApi
-} from "@/api/flow/definition";
+} from '@/api/flow/definition'
+import Design from "@/views/flow/definition/design.vue";
 
 const queryRef = ref<InstanceType<typeof AForm>>()
 const formRef = ref<InstanceType<typeof AForm>>()
+const designVisibleRef = ref<InstanceType<typeof Design>>()
+
+const designVisible = ref<boolean>(false)
 
 const showQuery = ref<boolean>(true)
 const pageTotal = ref<number>(0)
@@ -40,7 +44,7 @@ const queryConfig: FormConfigType[] = [
   {
     type: 'version',
     prop: 'version',
-    label: '流程版本',
+    label: '流程版本'
   }
 ]
 
@@ -84,15 +88,17 @@ const columnConfig: ColumnConfigType[] = [
   },
   {
     prop: 'ext',
-    label: '扩展字段',
+    label: '扩展字段'
   },
   {
     prop: 'isPublish',
-    label: '是否发布'
+    label: '是否发布',
+    dict: 'is_publish'
   },
   {
     prop: 'activityStatus',
-    label: '激活状态'
+    label: '激活状态',
+    dict: 'activity_status'
   },
   {
     prop: 'createTime',
@@ -102,6 +108,12 @@ const columnConfig: ColumnConfigType[] = [
     width: 200,
     handleConfig: [
       {
+        text: '流程设计',
+        click(row) {
+          designVisibleRef.value?.open(row.id)
+        }
+      },
+      {
         common: 'update',
         permissions: 'sysConfig:edit',
         click(row) {
@@ -110,7 +122,7 @@ const columnConfig: ColumnConfigType[] = [
           getDefinitionApi(row.id).then((resp: StrAnyObj) => {
             formData.value = resp
             if (formData.value.listenerType) {
-              formData.value.listenerType = formData.value.listenerType.split(",")
+              formData.value.listenerType = formData.value.listenerType.split(',')
             }
           })
         }
@@ -142,17 +154,17 @@ const formConfig: FormConfigType[] = [
   {
     type: 'input',
     prop: 'version',
-    label: '流程版本',
+    label: '流程版本'
   },
   {
     type: 'input',
     prop: 'ext',
-    label: '扩展字段',
+    label: '扩展字段'
   },
   {
     type: 'input',
     prop: 'formPath',
-    label: '审批表单路径',
+    label: '审批表单路径'
   },
   {
     type: 'select',
@@ -187,7 +199,7 @@ const formConfig: FormConfigType[] = [
     itemType: 'textarea',
     prop: 'listenerPath',
     label: '监听器路径',
-    rows: 8,
+    rows: 8
   }
 ]
 
@@ -197,7 +209,6 @@ onMounted(() => {
 
 function getPage() {
   getDefinitionPageApi(queryData.value).then((resp) => {
-    console.log(resp)
     tableData.value = resp.list
     pageTotal.value = resp.total
   })
@@ -205,7 +216,7 @@ function getPage() {
 
 function formSubmit() {
   formRef.value?.validate(() => {
-    formData.value.listenerType = formData.value.listenerType?.join(",")
+    formData.value.listenerType = formData.value.listenerType?.join(',')
 
     if (formData.value.id) {
       updateDefinitionApi(formData.value).then(() => {
@@ -264,5 +275,7 @@ function handleRemove(id: string) {
     >
       <a-form ref="formRef" v-model="formData" :config="formConfig" :span="24"> </a-form>
     </a-dialog>
+
+    <design ref="designVisibleRef" v-model="designVisible" />
   </div>
 </template>

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است