2 Komitmen 9577e22b66 ... 2bf0fff9b8

Pembuat SHA1 Pesan Tanggal
  kyoyue 2bf0fff9b8 Merge branch 'master' of http://git.ascrm.cn:3000/scrm/wechat-ui 4 bulan lalu
  kyoyue 8c8dafca83 sop调试、大纲、新增节点bug 4 bulan lalu

+ 39 - 0
src/api/wechat/sopTask.ts

@@ -28,6 +28,9 @@ enum Api {
   GetSopTaskRecordList = '/wechat-api/sop_task/record_list',
   GetSopTaskRecordMsg = '/wechat-api/message_records/list',
   CopySopTask = '/wechat-api/sop_task/copy',
+  OutlineSopTask = '/wechat-api/sop_task/outline',
+  SopMsgVar = '/wechat-api/sop_task/message_var',
+  DebugSop = '/wechat-api/sop_task/test_node',
 }
 
 /**
@@ -319,4 +322,40 @@ export const copySopTask = (params: BaseNodeReq, mode: ErrorMessageMode = 'notic
       errorMessageMode: mode,
     },
   );
+};
+
+/**
+ *  @description: sop大纲
+ */
+export const outlineSopTask = (params: BaseNodeReq, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseDataResp<BaseNodeReq>>(
+    { url: Api.OutlineSopTask, params: params },
+    {
+      errorMessageMode: mode,
+    },
+  );
+};
+
+/**
+ *  @description: sop消息变量
+ */
+export const sopMsgVar = (params: BaseNodeReq, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseDataResp<BaseNodeReq>>(
+    { url: Api.SopMsgVar, params: params },
+    {
+      errorMessageMode: mode,
+    },
+  );
+};
+
+/**
+ *  @description: sop调试
+ */
+export const debugSop = (params: BaseNodeReq, mode: ErrorMessageMode = 'notice') => {
+  return defHttp.post<BaseDataResp<BaseNodeReq>>(
+    { url: Api.DebugSop, params: params },
+    {
+      errorMessageMode: mode,
+    },
+  );
 };

+ 38 - 22
src/views/wechat/sop_task/add_sop/components/flowChart/components/nodeWrap.vue

@@ -19,7 +19,7 @@
                         <MenuItem @click="setNode(item, 'del')" key="del">删除</MenuItem>
                         <!-- <MenuItem @click="setNode(item, 'copy')" key="copy">复制</MenuItem> -->
                         <MenuItem @click="setNode(item, 'add')" key="add">添加节点</MenuItem>
-                        <!-- <MenuItem @click="setNode(item, 'debug')" key="debug">调试</MenuItem> -->
+                        <MenuItem @click="setNode(item, 'debug')" key="debug">调试</MenuItem>
                       </Menu>
                     </template>
                   </Dropdown>
@@ -63,32 +63,24 @@
       <BlankBox />
     </div>
   </div>
-  <!-- <Modal
+  <Modal
       width="500px"
       height="300px"
       v-model:open="modalVisible"
-      title="待调试节点:打招呼"
-      @ok="handleOk"
-      @cancel="handleCancel"
+      title="待调试节点:"
+      footer
       class="custom-modal"
     >
-      <Form :model="form" layout="inline" style="gap: 20px;height:auto;">
-        <FormItem name="id" label="用户回复:" style="margin-left: 30px">
-          <Select
-            v-model:value="form.id"
-            :options="modeList"
-            allowClear
-            size="middle"
-            placeholder="请选择"
-            :style="{ width: '330px', margin: '0 5px' }"
-          ></Select>
-          <Button type="primary">调试</Button>
+      <Form :model="form" layout="inline" style="gap: 20px;height:150px;">
+        <FormItem name="content" label="用户回复:" style="margin-left: 30px;display:flex;">
+          <Input v-model:value="form.content" placeholder="请输入" style="width: 300px;" allowClear ></Input>
+          <Button type="primary" style="margin-left: 10px;" size="large" @click="handleDebug">调试</Button>
         </FormItem>
-        <FormItem name="name" label="结果触发:" style="margin-left: 30px" >
-          <Tag>Tag 1</Tag>
+        <FormItem v-if="resultData.length>0" name="name" label="结果触发:" style="margin-left: 30px" >
+          <Tag v-for="(item, index) in resultData" :key="index">{{item}}</Tag>
         </FormItem>
       </Form>
-    </Modal> -->
+    </Modal>
   <!-- <nodeWrap v-if="nodeConfig.childNode" v-model:nodeConfig="nodeConfig.childNode" @update:nodeDrawerOpen="addType(item)"/> -->
 </template>
 <script setup lang="ts">
@@ -98,19 +90,23 @@
     computed,
     defineExpose,
     defineEmits,
+    reactive
   } from 'vue';
   import { SettingOutlined } from '@ant-design/icons-vue';
-  import { Dropdown, Menu, MenuItem, Button,Modal,Tag} from 'ant-design-vue';
+  import { Dropdown, Menu, MenuItem, Button,Modal,Tag,Form,FormItem,Input } from 'ant-design-vue';
   import nodeWrap from './nodeWrap.vue';
   import BlankBox from './blankBox.vue';
   import { useStore } from '../../../stores/index';
-  import { delSopStageNode, getSopStageNodeList } from '@/api/wechat/sopTask';
+  import { delSopStageNode, getSopStageNodeList,debugSop } from '@/api/wechat/sopTask';
   defineExpose({
     Dropdown,
     Menu,
     MenuItem,
     Modal,
+    Form,
+    FormItem,
     Tag,
+    Input
   });
   let emit = defineEmits<{
     (event: 'update:nodeDrawerOpen', value: { open: boolean; nodeId: number; isAdd: boolean }): void;
@@ -139,7 +135,15 @@
     //   resetConditionNodesErr();
     // }
   });
-
+  const debugNodeId = ref(undefined);
+  const modalVisible = ref(false);
+  const resultData = ref([]);
+  const form = reactive({
+        content: '',
+      });
+      const initialForm = reactive({
+        content: '',
+      });
   let store = useStore();
   let isTried = computed(() => store.isTried);
   let addBtnDisabled = ref(props.addBtnDisabled)
@@ -157,8 +161,16 @@
     } else if (key === 'add') {
       console.log('添加')
       addType(item)
+    }else if(key === 'debug'){
+      console.log('调试');
+      modalVisible.value = true;
+      debugNodeId.value = item.id
     }
   }
+  async function handleDebug() {
+    let res = await debugSop({type:2,content:form.content,id:debugNodeId.value});
+    resultData.value = res.data || [];
+  }
   async function handleDelNodeUpdate(payload: { reseat: boolean; stageId: number }) {
     console.log('(first)',payload.reseat,payload.stageId)
     emit('update:delNodeUpdate', { reseat: true, stageId: payload.stageId });
@@ -338,4 +350,8 @@
       }
     }
   }
+  ::v-deep .ant-form-item .ant-form-item-control-input-content{
+    width: 100%;
+    display: flex;
+  }
 </style>

+ 49 - 3
src/views/wechat/sop_task/add_sop/components/leftStage.vue

@@ -96,8 +96,10 @@
                   <div
                     class="title"
                     :style="{ background: stageName !== '' ? '#1677ff' : '#b8c1d6' }"
+                    style="display:flex;justify-content:space-between;color:#fff;"
                   >
                     <span>客户阶段设置</span>
+                    <ToolOutlined style="width: 20px;height: 20px;" @click="handleDebugOpen()"/>
                   </div>
                   <div class="phase-content" @click="setPerson">
                     <div class="left-content">
@@ -165,6 +167,25 @@
       </div>
     </div>
   </div>
+  <Modal
+      width="500px"
+      height="300px"
+      v-model:open="modalVisible"
+      title="待调试节点:"
+      footer
+      class="custom-modal"
+    >
+      <Form :model="form" layout="inline" style="gap: 20px;height:150px;">
+        <FormItem name="content" label="用户回复:" style="margin-left: 30px;display:flex;align-items:center;justify-content:center;">
+          <Input  placeholder="请输入" style="width: 300px;" allowClear ></Input>
+          <Button type="primary" style="margin-left: 10px;" size="large" @click="handleDebug">调试</Button>
+        </FormItem>
+        
+        <FormItem v-if="resultData.length>0" name="name" label="结果触发:" style="margin-left: 30px" >
+          <Tag v-for="(item, index) in resultData" :key="index">{{item}}</Tag>
+        </FormItem>
+      </Form>
+    </Modal>
   <!-- 节点配置弹窗 v-if="!loading"-->
   <Spin class="spin-style" :spinning="loading" tip="Loading...">
     <NodeConfigDrawer
@@ -181,7 +202,7 @@
 </template>
 
 <script setup lang="ts">
-  import { ref, onMounted, defineProps, toRefs } from 'vue';
+  import { ref, onMounted, defineProps, toRefs , reactive} from 'vue';
   import nodeWrap from '../components/flowChart/components/nodeWrap.vue';
   import UserPhasesDrawer from './userPhasesDrawer.vue';
   import NodeConfigDrawer from './nodeConfigDrawer.vue';
@@ -193,15 +214,17 @@
     delSopStage,
     moveSopStage,
     getSopStageById,
+    debugSop,
   } from '@/api/wechat/sopTask';
   import { useStore } from '../stores/index';
-  import { Modal, Dropdown, Menu, MenuItem, Spin, Button } from 'ant-design-vue';
+  import { Modal, Dropdown, Menu, MenuItem, Spin, Button ,Tag, Form, FormItem ,Input,} from 'ant-design-vue';
   import {
     SettingOutlined,
     FilterOutlined,
     BulbOutlined,
     ClockCircleOutlined,
     ThunderboltOutlined,
+    ToolOutlined
   } from '@ant-design/icons-vue';
   let store = useStore();
 
@@ -224,6 +247,15 @@
     };
   }>();
   let isAddNode = ref(true);
+  const debugNodeId = ref(undefined);
+  const modalVisible = ref(false);
+  const resultData = ref([]);
+  const form = reactive({
+        content: '',
+      });
+      const initialForm = reactive({
+        content: '',
+      });
   // let { setSopLabelList ,setSopStadeId} = useStore();
   let { editStageList, nameTimeValidation, isDisabled } = toRefs(props);
   const drawerVisible = ref(false);
@@ -277,8 +309,18 @@
     }
   }
 
+  function handleDebugOpen(){
+    modalVisible.value = true;
+  }
+  async function handleDebug() {
+    let res = await debugSop({type:1,content:form.content,id:stageItemId.value});
+    resultData.value = res.data || [];
+  }
+
   async function addType(val) {
+    console.log(val,'是这儿吗')
     ModalTips('node');
+    isAddNode.value = true;
     stageItemId.value = stageItemId.value;
     nodeId.value = val;
   }
@@ -516,7 +558,7 @@
 </script>
 
 <style scoped lang="less">
-  @import '../components/flowChart/css/workflow.css';
+  // @import '../components/flowChart/css/workflow.css';
   .flow-chart {
     width: 100%;
     height: 100%;
@@ -782,4 +824,8 @@
       }
     }
   }
+  ::v-deep .ant-form-item .ant-form-item-control-input-content{
+    display: flex;
+    align-items: center;
+  }
 </style>

+ 49 - 30
src/views/wechat/sop_task/add_sop/components/msgContant.vue

@@ -51,27 +51,36 @@
           <!-- @remove="emit('remove')" @moveUp="emit('moveUp')" @moveDown="emit('moveDown')":length="length" -->
           <CustomIcons :index="index" :iconDisable="msgDisabled" />
           <span v-show="area.content == ''" class="warning-style">请输入文本内容</span>
-          <div style="margin-bottom:5px">
-            <span style="margin-right: 10px;">变量:</span>
-            <a-button style="margin-right: 10px;" :disabled="msgDisabled" @click="insertVariable('${客户名称}', index)">客户名称</a-button>
-            <a-button style="margin-right: 10px;" :disabled="msgDisabled" @click="insertVariable('${客户称谓}', index)">客户称谓</a-button>
-            <a-button @click="insertVariable('${客户手机号}', index)" :disabled="msgDisabled">客户手机号</a-button>
+          <div style="margin-bottom: 5px">
+            <span style="margin-right: 10px">
+              变量:
+            </span>
+              <a-button
+              v-for="(item,id) in messageVar" :key="id"
+                style="margin-right: 10px"
+                :disabled="msgDisabled"
+                @click="insertVariable(item.value, index)"
+              >
+                {{item.label}}
+              </a-button>
+            <!-- <a-button style="margin-right: 10px;" :disabled="msgDisabled" @click="insertVariable('${客户称谓}', index)">客户称谓</a-button>
+            <a-button @click="insertVariable(`${item.value}`, index)" :disabled="msgDisabled">客户手机号</a-button> -->
           </div>
         </div>
       </a-form-item>
       <a-form-item v-else-if="area.type === 2" label="" name="content" class="message-content">
         <!-- class="upload-contant" -->
         <div :class="msgDisabled ? 'disabled-upload upload-contant' : 'upload-contant'">
-        <BasicUpload 
-          :maxSize="10"
-          :maxNumber="1"
-          @change="handleChange"
-          :api="uploadApi"
-          v-model:value="area.content"
-          :showPreviewNumber=false
-          emptyHidePreview
-        />
-        <!-- <div class="upload-file-style" v-if="area.content">{{String(area.content).split('/').pop()}}</div> -->
+          <BasicUpload
+            :maxSize="10"
+            :maxNumber="1"
+            @change="handleChange"
+            :api="uploadApi"
+            v-model:value="area.content"
+            :showPreviewNumber="false"
+            emptyHidePreview
+          />
+          <!-- <div class="upload-file-style" v-if="area.content">{{String(area.content).split('/').pop()}}</div> -->
           <CustomIcons :index="index" :length="length" :iconDisable="msgDisabled" />
         </div>
       </a-form-item>
@@ -112,19 +121,16 @@
   </div>
 </template>
 <script lang="ts">
-  import { defineComponent, ref, reactive, provide, props, watch ,nextTick} from 'vue';
+  import { defineComponent, ref, reactive, provide, props, watch, nextTick, onMounted } from 'vue';
   import { Form, Button, Dropdown, Menu, message, Input, SubMenu, Upload } from 'ant-design-vue';
-  import {
-    CloudUploadOutlined,
-    PlusCircleOutlined,
-    UserOutlined,
-  } from '@ant-design/icons-vue';
+  import { CloudUploadOutlined, PlusCircleOutlined, UserOutlined } from '@ant-design/icons-vue';
   import CustomIcons from './customIcons.vue';
   import ProductNote from './productNote.vue';
   import { BasicUpload } from '@/components/Upload';
   import { deleteFile, downloadFile, getFileList, uploadApi } from '@/api/fms/file';
   import ProductContant from './productContant.vue';
-  import type { UploadChangeParam, UploadProps } from 'ant-design-vue'
+  import { sopMsgVar } from '@/api/wechat/sopTask';
+  import type { UploadChangeParam, UploadProps } from 'ant-design-vue';
   export default defineComponent({
     name: 'MsgContant',
     components: {
@@ -163,23 +169,33 @@
       // const internalValue = ref([...props.value]);
       const internalValue = ref(addCanMoveProperties(props.value));
       const msgDisabled = ref(props.msgDisabled);
-       // 用于存储每个 textarea 的光标位置
+      // 用于存储每个 textarea 的光标位置
       const cursorPositions = ref<Record<number, number>>({});
+      
       // 更新光标位置
       const updateCursorPosition = (event: Event, index: number) => {
         const textarea = event.target as HTMLTextAreaElement;
         cursorPositions.value[index] = textarea.selectionStart;
       };
+
       const taskForm = reactive({
         fileContent: '',
       });
+      const messageVar = ref([]);
+      onMounted(async () => {
+        // let res = sopMsgVar();
+        // console.log(res);
+        // messageVar.value = res.data.messageVar || [];
+        // messageVar.value = [{ name: '客户名称', value: 'wang' }];
+      });
+
       function handleChange(list: string[]) {
         if (msgDisabled.value) {
-          return
+          return;
         }
-          // createMessage.info(`已上传文件${JSON.stringify(list)}`);
-          // console.log(list);
-        };
+        // createMessage.info(`已上传文件${JSON.stringify(list)}`);
+        // console.log(list);
+      }
       watch(
         internalValue,
         (newValue) => {
@@ -199,8 +215,8 @@
         const content = area.content || '';
 
         // 在光标位置插入变量
-        internalValue.value[index].content = 
-          content.slice(0, cursorPosition) + variable + content.slice(cursorPosition);
+        internalValue.value[index].content =
+          content.slice(0, cursorPosition) + '${' + variable + '}' + content.slice(cursorPosition);
 
         // 更新光标位置为插入变量之后
         nextTick(() => {
@@ -212,6 +228,7 @@
           }
         });
       };
+
       function addCanMoveProperties(items) {
         return items.map((item, index, array) => ({
           ...item,
@@ -355,6 +372,8 @@
         cursorPositions,
         updateCursorPosition,
         insertVariable,
+        sopMsgVar,
+        messageVar,
       };
     },
   });
@@ -461,7 +480,7 @@
   .upload:hover {
     border-color: #1890ff;
   }
-  .upload-file-style{
+  .upload-file-style {
     min-width: 400px;
     padding: 5px;
     display: inline-block;

+ 20 - 7
src/views/wechat/sop_task/add_sop/components/msgContantForwards.vue

@@ -66,11 +66,14 @@
           <span v-show="area.content == ''" class="warning-style">请输入文本内容</span>
           <div style="margin-bottom: 5px">
             <span style="margin-right: 10px">变量:</span>
-            <a-button style="margin-right: 10px" :disabled="msgDisabled" @click="insertVariable('${客户名称}', index)">客户名称</a-button>
-            <a-button style="margin-right: 10px" :disabled="msgDisabled" @click="insertVariable('${客户称谓}', index)">客户称谓</a-button>
-            <a-button style="margin-right: 10px" :disabled="msgDisabled" @click="insertVariable('${客户性别}', index)">客户性别</a-button>
-            <a-button style="margin-right: 10px" :disabled="msgDisabled" @click="insertVariable('${客户微信号}', index)">客户微信号</a-button>
-            <a-button style="margin-right: 10px" :disabled="msgDisabled" @click="insertVariable('${客户手机号}', index)">客户手机号</a-button>
+              <a-button
+              v-for="(item,id) in messageVar" :key="id"
+                style="margin-right: 10px"
+                :disabled="msgDisabled"
+                @click="insertVariable(item.value, index)"
+              >
+                {{item.label}}
+              </a-button>
           </div>
         </div>
       </a-form-item>
@@ -127,13 +130,14 @@
   </div>
 </template>
 <script lang="ts">
-  import { defineComponent, ref, reactive, provide, props, watch ,nextTick} from 'vue';
+  import { defineComponent, ref, reactive, provide, props, watch ,nextTick, onMounted } from 'vue';
   import { Form, Button, Dropdown, Menu, message, Input, SubMenu, Upload } from 'ant-design-vue';
   import { CloudUploadOutlined, PlusCircleOutlined, UserOutlined } from '@ant-design/icons-vue';
   import CustomIcons from './customIcons.vue';
   import ProductNote from './productNote.vue';
   import { BasicUpload } from '@/components/Upload';
   import { deleteFile, downloadFile, getFileList, uploadApi } from '@/api/fms/file';
+  import { sopMsgVar } from '@/api/wechat/sopTask';
   import ProductContant from './productContant.vue';
   import type { UploadChangeParam, UploadProps } from 'ant-design-vue';
   export default defineComponent({
@@ -201,6 +205,13 @@
         { deep: true },
       );
 
+      const messageVar = ref([]);
+      onMounted(async () => {
+        // let res = sopMsgVar();
+        // console.log(res);
+        // messageVar.value = res.data.forwardVar || [];
+        // messageVar.value = [{ label: '客户名称', value: 'wang' }];
+      });
       // 插入变量函数
       const insertVariable = (variable: string, index: number) => {
         const area = internalValue.value[index];
@@ -214,7 +225,7 @@
 
         // 在光标位置插入变量
         internalValue.value[index].content = 
-          content.slice(0, cursorPosition) + variable + content.slice(cursorPosition);
+          content.slice(0, cursorPosition) + '${' + variable + '}'+ content.slice(cursorPosition);
 
         // 更新光标位置为插入变量之后
         nextTick(() => {
@@ -372,6 +383,8 @@
         cursorPositions,
         updateCursorPosition,
         insertVariable,
+        sopMsgVar,
+        messageVar,
       };
     },
   });

+ 9 - 6
src/views/wechat/sop_task/add_sop/components/nodeConfigDrawer.vue

@@ -7,7 +7,6 @@
           <Step class="custom-step" title="节点触发条件"></Step>
           <Step class="custom-step" title="配置节点内容"></Step>
         </Steps>
-        <!-- <div v-if="isDataLoaded"> -->
         <div v-if="currentStep === 0" class="step-content">
           <Form :model="form" :label-col="{ span: 3 }" :wrapper-col="{ span: 19 }" ref="formRef" >
             <FormItem
@@ -239,7 +238,7 @@
                       :style="{ width: '240px', margin: '0 5px' }"
                       :max-tag-count="1"
                     ></Select>
-                    <span v-show="taskForm.tagValue.length === 0" class="warning-style">请选择标签</span>
+                    <!-- <span v-show="taskForm.tagValue.length === 0" class="warning-style">请选择标签</span> -->
                   </FormItem>
                   <FormItem
                     label="用户进入当前节点时,可以移出标签"
@@ -259,9 +258,9 @@
                       :style="{ width: '240px', margin: '0 5px' }"
                       :max-tag-count="1"
                     ></Select>
-                    <span v-show="taskForm.delTagValue.length === 0" class="warning-style">
+                    <!-- <span v-show="taskForm.delTagValue.length === 0" class="warning-style">
                       请选择标签
-                    </span>
+                    </span> -->
                   </FormItem>
                 </div>
               </Collapse.Panel>
@@ -451,7 +450,7 @@
       //   loading.value = false;
       //   isDataLoaded.value = true; // 数据加载完成后设置为 true,显示表单
       // }, 1000);
-    
+    console.log('????',unref(stageId),isAddNode.value,unref(nodeId));
     if (unref(stageId)) {
       let res = await getSopStageNodeList({ stageId: unref(stageId) });
       console.log('节点数组', res.data);
@@ -615,7 +614,11 @@
         actionForward,
       };
       const allData = actionMessage.every(item => item.content.trim()!== '');
-      if(isMsgAction.value && !allData || isTagAction.value && tagValue.length === 0 && delTagValue == 0){
+      // const allForwardsData = actionForward.action.every(item => item.content.trim()!== '');
+      // if(isMsgAction.value && !allData || isTagAction.value && tagValue.length === 0 && delTagValue == 0){
+      //   return;
+      // }
+      if(isMsgAction.value && !allData){
         return;
       }
       console.log('|||||||||||提交表单', !isAddNode.value, requestData);

+ 21 - 5
src/views/wechat/sop_task/add_sop/components/nodeMsgContant.vue

@@ -53,9 +53,14 @@
           <span v-show="area.content == ''" class="warning-style">请输入文本内容</span>
           <div style="margin-bottom:5px">
             <span style="margin-right: 10px;">变量:</span>
-            <a-button style="margin-right: 10px;" :disabled="msgDisabled" @click="insertVariable('${客户名称}', index)">客户名称</a-button>
-            <a-button style="margin-right: 10px;" :disabled="msgDisabled" @click="insertVariable('${客户称谓}', index)">客户称谓</a-button>
-            <a-button @click="insertVariable('${客户手机号}', index)" :disabled="msgDisabled">客户手机号</a-button>
+             <a-button
+              v-for="(item,id) in messageVar" :key="id"
+                style="margin-right: 10px"
+                :disabled="msgDisabled"
+                @click="insertVariable(item.value, index)"
+              >
+                {{item.label}}
+              </a-button>
           </div>
         </div>
       </a-form-item>
@@ -108,7 +113,7 @@
   </div>
 </template>
 <script lang="ts">
-  import { defineComponent, ref, reactive, provide, props, watch ,nextTick} from 'vue';
+  import { defineComponent, ref, reactive, provide, props, watch ,nextTick,onMounted} from 'vue';
   import { Form, Button, Dropdown, Menu, message, Input, SubMenu, Upload } from 'ant-design-vue';
   import { CloudUploadOutlined, PlusCircleOutlined, UserOutlined } from '@ant-design/icons-vue';
   import CustomIcons from './customIcons.vue';
@@ -116,6 +121,7 @@
   import { deleteFile, downloadFile, getFileList, uploadApi } from '@/api/fms/file';
   import ProductNote from './productNote.vue';
   import ProductContant from './productContant.vue';
+   import { sopMsgVar } from '@/api/wechat/sopTask';
   export default defineComponent({
     name: 'MsgContant',
     components: {
@@ -167,6 +173,14 @@
         fileContent: '',
       });
       
+      const messageVar = ref([]);
+      onMounted(async () => {
+        // let res = sopMsgVar();
+        // console.log(res);
+        // messageVar.value = res.data.messageVar || [];
+        // messageVar.value = [{ name: '客户名称', value: 'wang' }];
+      });
+
       watch(
         internalValue,
         (newValue) => {
@@ -187,7 +201,7 @@
 
         // 在光标位置插入变量
         internalValue.value[index].content = 
-          content.slice(0, cursorPosition) + variable + content.slice(cursorPosition);
+          content.slice(0, cursorPosition) + '${' + variable + '}' + content.slice(cursorPosition);
 
         // 更新光标位置为插入变量之后
         nextTick(() => {
@@ -368,6 +382,8 @@
         uploadApi,
         updateCursorPosition,
         insertVariable,
+         sopMsgVar,
+        messageVar,
       };
     },
   });

+ 21 - 8
src/views/wechat/sop_task/add_sop/components/nodeMsgContantForwards.vue

@@ -53,11 +53,14 @@
           <span v-show="area.content == ''" class="warning-style">请输入文本内容</span>
           <div style="margin-bottom: 5px">
             <span style="margin-right: 10px">变量:</span>
-            <a-button style="margin-right: 10px" :disabled="msgDisabled" @click="insertVariable('${客户名称}', index)">客户名称</a-button>
-            <a-button style="margin-right: 10px" :disabled="msgDisabled" @click="insertVariable('${客户称谓}', index)">客户称谓</a-button>
-            <a-button style="margin-right: 10px" :disabled="msgDisabled" @click="insertVariable('${客户性别}', index)">客户性别</a-button>
-            <a-button style="margin-right: 10px" :disabled="msgDisabled" @click="insertVariable('${客户微信号}', index)">客户微信号</a-button>
-            <a-button style="margin-right: 10px" :disabled="msgDisabled" @click="insertVariable('${客户手机号}', index)">客户手机号</a-button>
+             <a-button
+              v-for="(item,id) in messageVar" :key="id"
+                style="margin-right: 10px"
+                :disabled="msgDisabled"
+                @click="insertVariable(item.value, index)"
+              >
+                {{item.label}}
+              </a-button>
           </div>
         </div>
       </a-form-item>
@@ -110,13 +113,14 @@
   </div>
 </template>
 <script lang="ts">
-  import { defineComponent, ref, reactive, provide, props, watch ,nextTick} from 'vue';
+  import { defineComponent, ref, reactive, provide, props, watch ,nextTick, onMounted} from 'vue';
   import { Form, Button, Dropdown, Menu, message, Input, SubMenu, Upload } from 'ant-design-vue';
   import { CloudUploadOutlined, PlusCircleOutlined, UserOutlined } from '@ant-design/icons-vue';
   import CustomIcons from './customIcons.vue';
   import { BasicUpload } from '@/components/Upload';
   import { deleteFile, downloadFile, getFileList, uploadApi } from '@/api/fms/file';
   import ProductNote from './productNote.vue';
+    import { sopMsgVar } from '@/api/wechat/sopTask';
   import ProductContant from './productContant.vue';
   export default defineComponent({
     name: 'MsgContant',
@@ -169,7 +173,14 @@
       const taskForm = reactive({
         fileContent: '',
       });
-      
+      const messageVar = ref([]);
+       onMounted(async () => {
+        // let res = sopMsgVar();
+        // console.log(res);
+        // messageVar.value = res.data.forwardVar || [];
+        // messageVar.value = [{ label: '客户名称', value: 'wang' }];
+      });
+
       watch(
         internalValue,
         (newValue) => {
@@ -217,7 +228,7 @@
 
         // 在光标位置插入变量
         internalValue.value[index].content = 
-          content.slice(0, cursorPosition) + variable + content.slice(cursorPosition);
+          content.slice(0, cursorPosition) + '${' + variable + '}'+ content.slice(cursorPosition);
 
         // 更新光标位置为插入变量之后
         nextTick(() => {
@@ -374,6 +385,8 @@
         uploadApi,
         updateCursorPosition,
         insertVariable,
+        sopMsgVar,
+        messageVar,
       };
     },
   });

+ 8 - 5
src/views/wechat/sop_task/add_sop/components/userPhasesDrawer.vue

@@ -264,9 +264,9 @@
                       :style="{ width: '240px', margin: '0 5px' }"
                       :max-tag-count="1"
                     ></Select>
-                    <span v-show="taskForm.tagValue.length === 0" class="warning-style">
+                    <!-- <span v-show="taskForm.tagValue.length === 0" class="warning-style">
                       请选择标签
-                    </span>
+                    </span> -->
                   </FormItem>
                   <FormItem
                     label="用户进入当前阶段时,可以移出标签"
@@ -286,9 +286,9 @@
                       :style="{ width: '240px', margin: '0 5px' }"
                       :max-tag-count="1"
                     ></Select>
-                    <span v-show="taskForm.delTagValue.length === 0" class="warning-style">
+                    <!-- <span v-show="taskForm.delTagValue.length === 0" class="warning-style">
                       请选择标签
-                    </span>
+                    </span> -->
                   </FormItem>
                 </div>
               </Collapse.Panel>
@@ -617,7 +617,10 @@
         actionForward,
       };
       const allData = actionMessage.every((item) => item.content.trim() !== '');
-      if ((isMsgAction.value && !allData) || (isTagAction.value && tagValue.length === 0 && delTagValue == 0)) {
+      // if ((isMsgAction.value && !allData) || (isTagAction.value && tagValue.length === 0 && delTagValue == 0)) {
+      //   return;
+      // }
+      if ((isMsgAction.value && !allData)){
         return;
       }
       console.log(forwardMessage, wxid,'forwardMessage, wxid')

+ 44 - 41
src/views/wechat/sop_task/index.vue

@@ -1,6 +1,6 @@
 <template>
   <div>
-    <BasicTable @register="registerTable" :scroll="{ x: 'max-content', y: '500' }">
+    <BasicTable :loading="loading" @register="registerTable" :scroll="{ x: 'max-content', y: '500' }">
       <template #tableTitle>
         <Button
           type="primary"
@@ -25,21 +25,11 @@
       </template>
     </BasicTable>
     <!-- 树形控件展示 -->
-    <Modal v-model:visible="treeModalVisible" title="大纲" footer>
-      <Tree show-line :default-expanded-keys="['0-0-0']" :tree-data="treeData" @select="onSelect">
-        <template #icon><CarryOutOutlined /></template>
-        <template #title="{ dataRef }">
-          <template v-if="dataRef.key === '0-0-0-1'">
-            <div>multiple line title</div>
-            <!-- <div>multiple line title</div> -->
-          </template>
-          <template v-else>{{ dataRef.title }}</template>
-        </template>
-        <template #switcherIcon="{ dataRef, defaultIcon }">
-          <!-- <SmileTwoTone v-if="dataRef.key === '0-0-2'" /> -->
-          <component :is="defaultIcon" />
-        </template>
+    <Modal v-model:visible="treeModalVisible" title="大纲" height="500px" footer>
+      <div style="height: 500px;margin-left:50px;">
+        <Tree show-line :default-expanded-keys="expandedKeys" :tree-data="treeData" @select="onSelect">
       </Tree>
+      </div>
     </Modal>
     <!-- <Modal
       width="500px"
@@ -129,6 +119,7 @@
   import { getPermCode } from '@/api/sys/user';
   import { BasicUpload } from '@/components/Upload';
   import { deleteFile, downloadFile, getFileList, uploadApi } from '@/api/fms/file';
+  import {outlineSopTask} from '@/api/wechat/sopTask'
   export default defineComponent({
     name: 'SopTaskManagement',
     components: {
@@ -146,6 +137,8 @@
 
     setup() {
       const router = useRouter();
+      const loading = ref(false);
+      const expandedKeys = ref([]);
       const { t } = useI18n();
       const selectedIds = ref<number[] | string[]>();
       const showDeleteButton = ref<boolean>(false);
@@ -243,7 +236,8 @@
 
       //大纲
       async function handleTree(record: Recordable) {
-        treeModalVisible.value = true;
+        loading.value = true;
+        
         treeData.value = [
           {
             title: 'parent 1',
@@ -255,7 +249,7 @@
                 children: [
                   { title: 'leaf', key: '0-0-0-0' },
                   {
-                    key: '0-0-0-1',
+                    key: '0-0-0-1',title: 'leaf',
                   },
                   { title: 'leaf', key: '0-0-0-2' },
                 ],
@@ -293,11 +287,27 @@
             ],
           },
         ];
-
+        expandedKeys.value = getExpandedKeys(treeData.value); // 收集所有节点的key
+        loading.value = false;
+        treeModalVisible.value = true;
+        //   let res = await outlineSopTask({ id: record.id });
+        //   console.log(res.data)
+        // treeData.value = res.data;  
       }
 
+      // 递归收集所有 key
+    function getExpandedKeys(data){
+      let keys = [];
+      data.forEach((node) => {
+        keys.push(node.key);
+        if (node.children) {
+          keys = keys.concat(getExpandedKeys(node.children));
+        }
+      });
+      return keys;
+    }
       function onSelect(keys, event) {
-        console.log('Selected: ', keys, event);
+        // console.log('Selected: ', keys, event);
       }
       async function handleOk() {
         let res = await copySopTask({ id: recordId.value, name: form.name, organizationId: form.id });
@@ -374,18 +384,13 @@
               label: '复制',
               onClick: handleCopy.bind(null, record),
             },
-            // {
-            //   label: '大纲',
-            //   onClick: handleTree.bind(null, record),
-            // },
+            {
+              label: '大纲',
+              onClick: handleTree.bind(null, record),
+            },
           ];
         } else if (record.status === 2) {
           return [
-            // {
-            //   icon: 'clarity:note-edit-line',
-            //   onClick: handleEdit.bind(null, record),
-            //   tooltip: '编辑',
-            // },
             {
               onClick: handleOpen.bind(null, record),
               label: '启用',
@@ -406,18 +411,13 @@
               onClick: handleCopy.bind(null, record),
               ifShow: true,
             },
-            // {
-            //   label: '大纲',
-            //   onClick: handleTree.bind(null, record),
-            // },
+            {
+              label: '大纲',
+              onClick: handleTree.bind(null, record),
+            },
           ];
         } else if (record.status === 3) {
           return [
-            // {
-            //   icon: 'clarity:note-edit-line',
-            //   onClick: handleEdit.bind(null, record),
-            //   tooltip: '编辑',
-            // },
             {
               color: 'error',
               onClick: handleStop.bind(null, record),
@@ -435,10 +435,10 @@
               label: '复制',
               onClick: handleCopy.bind(null, record),
             },
-            // {
-            //   label: '大纲',
-            //   onClick: handleTree.bind(null, record),
-            // },
+            {
+              label: '大纲',
+              onClick: handleTree.bind(null, record),
+            },
           ];
         }
         return [];
@@ -474,6 +474,9 @@
         treeModalVisible,
         treeData,
         onSelect,
+        loading,
+        getExpandedKeys,
+        expandedKeys,
       };
     },
   });