瀏覽代碼

条件分支面板

CzRger 3 月之前
父節點
當前提交
9e7938a57e

+ 14 - 3
src/components/czr-ui/CzrFormColumn.vue

@@ -5,6 +5,7 @@
     span3: filterSpan == 3,
     span4: filterSpan == 4,
     span5: filterSpan == 5,
+    transparent: transparent
   }" :span="span" :offset="offset" ref="ref_czrFormColumn">
     <el-form-item :label="label" :label-width="labelWidth" :class="{
       ['link_' + link + ($attrs.type ? '_' + $attrs.type : '')]: true,
@@ -253,7 +254,8 @@ const props = defineProps({
   defaultErrorMsg: {default: null}, // 默认校验错误提示
   unit: {default: '', type: String},  // 单位
   otherInfo: {}, // 其他信息
-  layout: {}
+  layout: {},
+  transparent: {default: false}
 })
 const attrs = (getCurrentInstance() as ComponentInternalInstance).attrs
 const state = reactive({
@@ -309,7 +311,7 @@ const handleValidate = (val: any = undefined, val2: any = undefined) => {
   }
   return state.errorMessage
 }
-const formLayout = inject('form-layout')
+const formLayout = inject('form-layout', 'x')
 const handleEnterFunc = inject('handle-enter', () => {})
 const handleEnter = () => {
   handleEnterFunc?.()
@@ -327,7 +329,7 @@ watch(() => state.errorMessage, (n) => {
       }
     }, 200)
   } else {
-    p.style.marginBottom = '18px'
+    p.style.marginBottom = props.transparent ? 0 : '18px'
   }
 })
 onMounted(() => {
@@ -385,6 +387,15 @@ defineExpose({
     max-width: 100%;
     flex: unset;
   }
+  &.transparent {
+    :deep(.el-form-item) {
+      margin-bottom: 0;
+      .el-input__wrapper {
+        background-color: transparent;
+        box-shadow: none;
+      }
+    }
+  }
   :deep(.el-form-item) {
     &.link_time {
       margin-top: 1px;

+ 1 - 1
src/utils/czr-util.ts

@@ -332,7 +332,7 @@ export const findParent = (data: any, target: any, result: any) => {
   for (let item of data) {
     if (item.deptName === target) {
       //将查找到的目标数据加入结果数组中
-      //可根据需求unshift(item.id)或unshift(item)
+      //可根据需求unshift(ConditionItem.id)或unshift(ConditionItem)
       result.unshift(item.deptName);
       return true;
     }

+ 149 - 0
src/views/workflow/instance/component/condition/condition-item.vue

@@ -0,0 +1,149 @@
+<template>
+  <div class="condition-item">
+    <div class="condition-item-body">
+      <div class="top">
+        <div class="left">
+          <slot name="source" :value="item" :index="index"/>
+        </div>
+        <div class="_p_split"/>
+        <selectPopover class="w-[60px]" v-model:value="item.method" :options="item.source.type === 'Number' ? OptionsConditionNumber : OptionsConditionString"/>
+      </div>
+      <div class="bottom" :style="{
+        padding: item.type === ConditionType.Constant ? '2px 6px' : '6px'
+      }">
+        <selectPopover class="w-[50px]" v-model:value="item.type" :options="OptionsConditionType"/>
+        <div class="_p_split"/>
+        <div class="target">
+          <template v-if="item.type === ConditionType.Constant">
+            <CzrFormColumn
+              :span="24"
+              label-width="0"
+              :link="item.source.type === 'Number' ? 'number' : 'input'"
+              v-model:param="item.target"
+              :transparent="true"
+            />
+          </template>
+          <template v-else-if="item.type === ConditionType.Variable">
+            <slot name="target" :value="item" :index="index"/>
+          </template>
+        </div>
+      </div>
+    </div>
+<!--     @click="$emit('update:conditions', conditions.filter((_, i) => i !== index))"-->
+    <div class="condition-item-del __hover" @click="$emit('onDel')">
+      <SvgIcon name="czr_del" size="14" color="#666666"/>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {getCurrentInstance, reactive, watch} from "vue";
+import {
+  ConditionMode, ConditionNumber, ConditionString, ConditionType,
+  OptionsConditionNumber,
+  OptionsConditionString,
+  OptionsConditionType
+} from "@/views/workflow/types";
+import selectPopover from '@/views/workflow/instance/component/select-popover/index.vue'
+
+const emits = defineEmits(['onDel'])
+const props = defineProps({
+  item: <any>{},
+  index: {},
+})
+const {proxy}: any = getCurrentInstance()
+const state: any = reactive({})
+watch(() => props.item.source, (n) => {
+  if (n.type === 'Number') {
+    props.item.method = ConditionNumber.Equals
+  } else {
+    props.item.method = ConditionString.Includes
+  }
+  props.item.type = ConditionType.Constant
+  props.item.target = ''
+}, {deep: true})
+</script>
+
+<style lang="scss" scoped>
+@use "@/views/workflow/instance/component/style";
+
+.condition-main {
+  flex: 1;
+  display: flex;
+  .condition-mode {
+    height: calc(100% - 28px);
+    margin: 14px 6px 14px 0;
+    width: 44px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    position: relative;
+    >div:nth-child(1) {
+      border: style.$borderStyle;
+      width: 10px;
+      height: 100%;
+      border-radius: 8px 0 0 8px;
+      border-right: none;
+      position: absolute;
+      right: 4px;
+    }
+    >div:nth-child(2) {
+      z-index: 2;
+      position: absolute;
+      right: 0;
+      width: 20px;
+      height: 30px;
+      background-color: #ffffff;
+    }
+    >div:nth-child(3) {
+      z-index: 3;
+      color: var(--czr-main-color);
+      border: style.$borderStyle;
+      border-radius: 4px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      width: 32px;
+      height: 22px;
+      background-color: #ffffff;
+      font-size: 12px;
+    }
+  }
+  .condition-list {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+    .condition-item {
+      display: flex;
+      .condition-item-body {
+        border-radius: 8px;
+        background-color: style.$inputBg;
+        flex: 1;
+        .top {
+          border-bottom: style.$borderStyle;
+          padding: 6px;
+          display: flex;
+          align-items: center;
+          .left {
+            flex: 1;
+          }
+          .right {
+            width: 40px;
+          }
+        }
+        .bottom {
+          display: flex;
+          align-items: center;
+          .target {
+            flex: 1;
+          }
+        }
+      }
+      .condition-item-del {
+        margin: 10px 0 0 6px;
+      }
+    }
+  }
+}
+</style>

+ 20 - 20
src/views/workflow/instance/component/condition/index.vue

@@ -7,25 +7,14 @@
     </div>
     <div class="condition-list">
       <template v-for="(item, index) in conditions">
-        <div class="condition-item">
-          <div class="condition-item-body">
-            <div class="top">
-              <div class="left">
-                <slot name="source" :value="item"/>
-              </div>
-              <selectPopover class="w-[60px]" :popoverWidth="40" v-model:value="item.method" :options="item.type === 'Number' ? OptionsConditionNumber : OptionsConditionString"/>
-            </div>
-            <div class="bottom">
-              <div>变量</div>
-              <div>
-                <slot name="target" :value="item"/>
-              </div>
-            </div>
-          </div>
-          <div class="condition-item-del __hover" @click="$emit('update:conditions', conditions.filter((_, i) => i !== index))">
-            <SvgIcon name="czr_del" size="14" color="#666666"/>
-          </div>
-        </div>
+        <conditionItem :item="item" :index="index" @onDel="$emit('update:conditions', conditions.filter((_, i) => i !== index))">
+          <template #source>
+            <slot name="source" :value="item" :index="index"/>
+          </template>
+          <template #target>
+            <slot name="target" :value="item" :index="index"/>
+          </template>
+        </conditionItem>
       </template>
     </div>
   </div>
@@ -33,8 +22,14 @@
 
 <script setup lang="ts">
 import {getCurrentInstance, reactive} from "vue";
-import {ConditionMode, OptionsConditionNumber, OptionsConditionString} from "@/views/workflow/types";
+import {
+  ConditionMode, ConditionType,
+  OptionsConditionNumber,
+  OptionsConditionString,
+  OptionsConditionType
+} from "@/views/workflow/types";
 import selectPopover from '@/views/workflow/instance/component/select-popover/index.vue'
+import conditionItem from './condition-item.vue'
 
 const emits = defineEmits(['update:mode', 'update:conditions'])
 const props = defineProps({
@@ -115,6 +110,11 @@ const state: any = reactive({})
         }
         .bottom {
           padding: 6px;
+          display: flex;
+          align-items: center;
+          .target {
+            flex: 1;
+          }
         }
       }
       .condition-item-del {

+ 11 - 10
src/views/workflow/instance/component/select-popover/index.vue

@@ -5,16 +5,15 @@
       placement="bottom"
       trigger="click"
       :popper-style="{
-        padding: 0
+        padding: 0,
+        minWidth: 0,
+        width: popoverWidth ? `${popoverWidth}px` : 'fit-content'
       }"
-      :width="popoverWidth"
     >
       <template #reference>
-        <div @click="state.show = !state.show" class="display">
-          <span>
-          {{options.filter(v => v.value === value)[0]?.label || ''}}
-          </span>
-          <SvgIcon name="czr_arrow" size="8" rotate="90"/>
+        <div @click="state.show = !state.show" class="display __hover-bg">
+          <span>{{options.filter(v => v.value === value)[0]?.label || ''}}</span>
+          <SvgIcon name="czr_arrow" size="8" rotate="90" color="#33333377"/>
         </div>
       </template>
       <div class="select-popover" :select-popover="true">
@@ -32,9 +31,9 @@ import {domRootHasAttr} from "@/utils/czr-util";
 
 const emits = defineEmits(['update:value'])
 const props = defineProps({
-  options: {default: []},
+  options: {default: <any>[]},
   value: {default: ''},
-  popoverWidth: {default: 50},
+  popoverWidth: {default: 0},
 })
 const {proxy}: any = getCurrentInstance()
 const state: any = reactive({
@@ -60,13 +59,15 @@ watch(() => state.show, (n) => {
   display: flex;
   align-items: center;
   justify-content: center;
+  padding: 0 4px;
+  height: 24px;
   >span {
     flex: 1;
     text-align: right;
     font-size: 12px;
   }
   .svg-icon {
-    margin-left: 4px;
+    margin-left: 8px;
     margin-top: 2px;
   }
 }

+ 7 - 0
src/views/workflow/instance/component/style.scss

@@ -6,4 +6,11 @@ $inputBg: #c8ceda40 !default;
   display: flex;
   align-items: center;
   justify-content:  space-between;
+}
+
+._p_split {
+  width: 1px;
+  height: 12px;
+  background-color: #10182814;
+  margin: 0 4px;
 }

+ 9 - 3
src/views/workflow/instance/component/vars/vars-popover.vue

@@ -10,7 +10,7 @@
       }"
     >
       <template #reference>
-        <div @click="state.show = !state.show">
+        <div @click="state.show = !state.show" class="__hover">
           <slot name="default"/>
         </div>
       </template>
@@ -46,17 +46,23 @@ const WorkflowStore = useWorkflowStore()
 const emits = defineEmits(['setVars'])
 const props = defineProps({
   node: {},
+  filter: {default: ''}
 })
 const {proxy}: any = getCurrentInstance()
 const state: any = reactive({
   vars: null,
   options: [],
   text: '',
-  show: false
+  show: false,
 })
 watch(() => props.node, (n) => {
   if (n) {
-    state.options = WorkflowStore.getInVars(n)
+    const all = WorkflowStore.getInVars(n)
+    console.log(all)
+    state.options = props.filter.type ? all.map(v => {
+      v.options = v.options.filter(s => s.type === props.filter.type && `${s.nodeId}_${s.key}` !== `${props.filter.nodeId}_${props.filter.key}`)
+      return v
+    }).filter(v => v.options.length > 0) : all
   }
 }, {immediate: true})
 const optionsCpt = computed(() => {

+ 3 - 0
src/views/workflow/instance/component/vars/vars-value.vue

@@ -2,6 +2,9 @@
   <div class="vars-value" v-if="vars">
     {{vars.nodeTitle}} / <span class="text-[#155aef]">{{vars.key}}</span> · <span class="opacity-65">{{vars.label}} {{vars.type}}</span>
   </div>
+  <div v-else  class="opacity-65">
+    {x}请选择变量
+  </div>
 </template>
 
 <script setup lang="ts">

+ 5 - 1
src/views/workflow/instance/if-else/panel/index.vue

@@ -20,6 +20,11 @@
                   <varsValue :vars="value.source"/>
                 </varsPopover>
               </template>
+              <template #target="{value, index: conIndex}">
+                <varsPopover :node="props.node" @setVars="vars => port.cases[conIndex].target = vars" class="ml-auto" :filter="port.cases[conIndex].source">
+                  <varsValue :vars="value.target"/>
+                </varsPopover>
+              </template>
             </condition>
           </div>
         </div>
@@ -76,7 +81,6 @@ const onAddCase = () => {
   state.nodeData.ports.splice(state.nodeData.ports.length - 1, 0, data)
 }
 const onAddCondition = (caseIndex, vars) => {
-  console.log(vars)
   state.nodeData.ports[caseIndex].cases.push({
     id: v4(),
     source: vars,