Browse Source

保存一版

CzRger 1 month ago
parent
commit
64770e62ac

+ 2 - 2
src/views/workflow/instance/answer/panel/index.vue

@@ -3,8 +3,8 @@
     <!--    <div class="_p-title" style="margin-top: 0">-->
     <!--      <div class="text-sm">可用变量</div>-->
     <!--    </div>-->
-    <!--    <varsSelect :node="props.node" />-->
-    <paramsTextarea />
+    <varsSelect :node="props.node" />
+    <paramsTextarea :node="props.node" class="max-h-50" />
   </div>
 </template>
 

+ 65 - 28
src/views/workflow/instance/component/params-textarea/index.vue

@@ -1,10 +1,17 @@
 <template>
-  <div class="flex flex-col rounded-xl bg-[#f2f4f7] px-3 py-2 shadow">
+  <div
+    class="flex size-full flex-col overflow-hidden rounded-xl bg-[#f2f4f7] px-3 py-2 shadow"
+  >
     <div
       class="flex items-center gap-2 py-1 text-xs font-semibold text-gray-700"
     >
       <div>回复</div>
-      <div class="ml-auto">字数</div>
+      <div class="ml-auto">{{ state.textCount }}</div>
+      <varsPopover :node="node" @setVars="setVars">
+        <el-tooltip content="变量" placement="top">
+          <SvgIcon name="vars" color="#364153" size="16" />
+        </el-tooltip>
+      </varsPopover>
       <el-tooltip content="复制" placement="top">
         <SvgIcon
           class="__hover"
@@ -15,46 +22,68 @@
         />
       </el-tooltip>
     </div>
-    <div
-      ref="ref_textarea"
-      class="text-text-secondary flex-1 py-1 text-[13px] break-words whitespace-pre-wrap outline-none select-text"
-      contenteditable="true"
-      @input="updateMarkdown"
-    ></div>
+    <div class="text-text-secondary flex-1 overflow-y-auto py-1 text-[13px]">
+      <div
+        class="break-all"
+        style="line-height: 1.5"
+        ref="ref_textarea"
+        contenteditable="true"
+        @input="updateMarkdown"
+      ></div>
+    </div>
   </div>
 </template>
 
 <script setup lang="ts">
-import { ref, computed, onMounted, reactive } from 'vue'
+import {
+  ref,
+  computed,
+  onMounted,
+  reactive,
+  h,
+  render,
+  createApp,
+  watch,
+} from 'vue'
 import { copy } from '@/utils/czr-util'
 import { ElMessage } from 'element-plus'
 import SvgIcon from '@/components/SvgIcon/index.vue'
+import varsPopover from '@/views/workflow/instance/component/vars/vars-popover.vue'
+import paramValue from './param-value.vue'
+import { useWorkflowStore } from '@/stores'
 
+const WorkflowStore = useWorkflowStore()
 const emit = defineEmits(['update:modelValue'])
 const props = defineProps({
   modelValue: {
     type: String,
     default: '',
   },
+  node: {},
 })
 const state = reactive({
-  optionsMap: new Map([
-    ['123', { label: '变量1', id: '123', type: 'String' }],
-    ['223', { label: '变量变量变量变量变量2', id: '223', type: 'String' }],
-    [
-      '333',
-      {
-        label: '变量变量变量变量变量变量变量变量变量变量变量3',
-        id: '333',
-        type: 'Number',
-      },
-    ],
-  ]),
+  textCount: 0,
+  optionsMap: new Map(),
 })
 const ref_textarea = ref()
+watch(
+  () => props.node,
+  (n) => {
+    if (n) {
+      const all = WorkflowStore.getInVars(n)
+      const map = new Map()
+      all.forEach((p) => {
+        p.options.forEach((v) => {
+          map.set(v.nodeId, v)
+        })
+      })
+      state.optionsMap = map
+    }
+  },
+  { immediate: true },
+)
 const updateMarkdown = (e) => {
   const selection: any = window.getSelection()
-  const range = selection.rangeCount > 0 ? selection.getRangeAt(0) : null
   let lastReplacedSpan: any = null
 
   const regex = /\{\{#([^#]+)#\}\}/g
@@ -76,13 +105,17 @@ const updateMarkdown = (e) => {
             document.createTextNode(text.substring(lastIndex, match.index)),
           )
         }
-        const span = document.createElement('span')
-        span.setAttribute('contenteditable', 'false')
-        span.className = 'border-1 bg-red-400'
         const key = match[1]
-        span.textContent = state.optionsMap.get(key)?.label || ''
-        fragment.appendChild(span)
-        lastReplacedSpan = span
+        const varsValue = document.createElement('div')
+        varsValue.setAttribute('contenteditable', 'false')
+        varsValue.style.display = 'inline-block'
+        const app = createApp(paramValue, {
+          vars: state.optionsMap.get(key),
+        })
+        app.component('SvgIcon', SvgIcon)
+        app.mount(varsValue)
+        fragment.appendChild(varsValue)
+        lastReplacedSpan = varsValue
         lastIndex = regex.lastIndex
       }
 
@@ -102,11 +135,15 @@ const updateMarkdown = (e) => {
     newSelection.removeAllRanges()
     newSelection.addRange(newRange)
   }
+  state.textCount = e.target.innerText?.length || 0
 }
 const onCopy = (text) => {
   copy(text)
   ElMessage.success('复制成功!')
 }
+const setVars = (vars) => {
+  console.log(vars)
+}
 onMounted(() => {})
 </script>
 

+ 44 - 0
src/views/workflow/instance/component/params-textarea/param-value.vue

@@ -0,0 +1,44 @@
+<template>
+  <div
+    class="mx-1 mt-1 flex translate-y-0.5 flex-wrap items-center rounded-sm bg-[#ffffff] px-2 py-1"
+    v-if="vars"
+  >
+    <template v-if="vars.source === VarsSource.Env">
+      <SvgIcon name="env_1" color="#7839ee" size="14" class="mr-1" />
+    </template>
+    <template v-else-if="vars.source === VarsSource.Root">
+      <SvgIcon name="earth" color="#fc9009" size="14" class="mr-1" />
+    </template>
+    <template v-else>
+      <SvgIcon name="vars" color="#155aef" size="14" class="mr-1" />
+    </template>
+    <div class="__text-ellipsis flex-1">
+      <span class="text-[12px]">
+        {{ nodeDataCpt.subTitle || nodeDataCpt.title }}
+      </span>
+      / <span class="text-[#155aef]">{{ vars.key }}</span>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, reactive } from 'vue'
+import { VarsSource } from '@/views/workflow/types'
+import { useWorkflowStore } from '@/stores'
+
+const WorkflowStore = useWorkflowStore()
+const props = defineProps({
+  vars: <any>{},
+})
+const state: any = reactive({})
+const nodeDataCpt = computed(() => {
+  if (props.vars.source === VarsSource.Env) {
+    return { title: '环境变量' }
+  } else {
+    const node = WorkflowStore.graph.getCellById(props.vars?.nodeId)
+    return node.data.workflowData
+  }
+})
+</script>
+
+<style lang="scss" scoped></style>

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

@@ -25,7 +25,7 @@
         </div>
         <div class="list">
           <template v-for="item in optionsCpt">
-            <div class="list-group">
+            <div class="list-group" v-if="item.options?.length > 0">
               <div class="mb-1 px-2 text-sm text-gray-400">
                 {{ item.label }}
               </div>

+ 8 - 17
src/views/workflow/instance/component/vars/vars-value.vue

@@ -1,13 +1,16 @@
 <template>
-  <div class="vars-value" v-if="vars">
+  <div
+    class="flex flex-wrap items-center rounded-sm bg-[#ffffff] px-2 py-1"
+    v-if="vars"
+  >
     <template v-if="vars.source === VarsSource.Env">
-      <SvgIcon name="env_1" color="#7839ee" size="14" />
+      <SvgIcon name="env_1" color="#7839ee" size="14" class="mr-1" />
     </template>
     <template v-else-if="vars.source === VarsSource.Root">
-      <SvgIcon name="earth" color="#fc9009" size="14" />
+      <SvgIcon name="earth" color="#fc9009" size="14" class="mr-1" />
     </template>
     <template v-else>
-      <SvgIcon name="vars" color="#155aef" size="14" />
+      <SvgIcon name="vars" color="#155aef" size="14" class="mr-1" />
     </template>
     <div class="__text-ellipsis flex-1">
       <span class="text-[12px]">{{
@@ -43,16 +46,4 @@ const nodeDataCpt = computed(() => {
 })
 </script>
 
-<style lang="scss" scoped>
-.vars-value {
-  background-color: #ffffff;
-  border-radius: 4px;
-  padding: 4px 8px;
-  display: flex;
-  align-items: center;
-  flex-wrap: wrap;
-  .svg-icon {
-    margin-right: 4px;
-  }
-}
-</style>
+<style lang="scss" scoped></style>