Forráskód Böngészése

Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_his_scrm_companyUI

caoliqin 1 napja
szülő
commit
db604efc38

+ 1 - 1
.env.development

@@ -36,7 +36,7 @@ ENV = 'development'
 VUE_APP_BASE_API = '/dev-api'
 
 #默认 1、会员 2、企微
-VUE_APP_COURSE_DEFAULT = 1
+VUE_APP_COURSE_DEFAULT = 2
 
 # 路由懒加载
 VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 8 - 0
src/api/hisStore/storeOrder.js

@@ -177,4 +177,12 @@ export function editPayDelivery(data) {
     data: data
   })
 }
+// 查询其余订单列表
+export function queryUserOtherOrderPage(query) {
+  return request({
+    url: '/store/store/storeOrder/queryUserOtherOrderPage',
+    method: 'get',
+    params: query
+  })
+}
 

+ 6 - 6
src/views/company/companyVoiceRobotic/index.vue

@@ -235,11 +235,11 @@
                       </el-tag>
                     </el-button>
                   </el-col>
-                  <el-col :span="form.addType == 1 ? 9 : 12">
+                  <!-- <el-col :span="form.addType == 1 ? 9 : 12">
                     <el-select v-model="item.wxDialogId" placeholder="选择话术" filterable size="small">
                       <el-option v-for="dialog in wxDialogList" :key="dialog.id" :label="dialog.name" :value="dialog.id"/>
                     </el-select>
-                  </el-col>
+                  </el-col> -->
                   <el-col :span="2">
                     <el-button type="danger" icon="el-icon-delete" circle @click="removeQwUser(index)" size="small"></el-button>
                   </el-col>
@@ -782,10 +782,10 @@ export default {
               this.msgError(`第 ${i + 1} 个账号请选择企微`);
               return;
             }
-            if(!account.wxDialogId) {
-              this.msgError(`第 ${i + 1} 个账号请选择话术`);
-              return;
-            }
+            // if(!account.wxDialogId) {
+            //   this.msgError(`第 ${i + 1} 个账号请选择话术`);
+            //   return;
+            // }
           }
           
           let list = [];

+ 81 - 19
src/views/company/companyWorkflow/design.vue

@@ -262,6 +262,20 @@
                 </div>
               </el-form-item>
             </div>
+             <!-- AI加微配置 -->
+            <div v-if="selectedNode.nodeType == 'AI_ADD_WX_TASK'" class="property-section">
+              <div class="section-title">
+                <i class="el-icon-chat-dot-round"></i>加微配置
+              </div>
+              <el-form-item label="加微话术">
+                <!-- <el-select v-model="selectedNode.nodeConfig.robot" filterable placeholder="请选择加微话术">
+                  <el-option v-for="item in robotList" :key="item.id" :label="item.name + '('+item.num+')'" :value="item.id"/>
+                </el-select> -->
+                 <el-select v-model="selectedNode.nodeConfig.dialogId" placeholder="请选择加微话术" filterable size="small">
+                      <el-option v-for="dialog in wxDialogList" :key="dialog.id" :label="dialog.name" :value="dialog.id"/>
+                    </el-select>
+              </el-form-item>
+            </div>
 
             <!-- AI外呼配置 -->
             <div v-if="selectedNode.nodeType == 'AI_CALL_TASK'" class="property-section">
@@ -288,7 +302,7 @@
                   <el-option label="呼叫机器人后挂断" :value="7"/>
                 </el-select>
               </el-form-item>
-              
+
               <div class="form-row">
                 <el-form-item label="呼叫倍率" class="half-width">
                   <el-select v-model="selectedNode.nodeConfig.multiplier" @change="handleConfigChange" placeholder="选择倍率">
@@ -307,7 +321,7 @@
                   <el-radio :label="1">是</el-radio>
                 </el-radio-group>
               </el-form-item>
-              
+
               <el-form-item label="重呼次数" v-if="selectedNode.nodeConfig.autoRecall == 1">
                 <el-select v-model="selectedNode.nodeConfig.recallTimes" @change="handleConfigChange" placeholder="选择重呼次数">
                   <el-option label="不自动重呼" :value="0"/>
@@ -320,6 +334,18 @@
               </el-form-item>
             </div>
 
+            <!-- AI短信配置 -->
+            <div v-if="selectedNode.nodeType == 'AI_SEND_MSG_TASK'" class="property-section">
+              <div class="section-title">
+                <i class="el-icon-phone"></i>短信配置
+              </div>
+              <el-form-item label="短信模版">
+                <el-select v-model="selectedNode.nodeConfig.smsTempId" filterable placeholder="请选择短信模版">
+                  <el-option v-for="item in smsTempList" :key="item.tempId" :label="item.title " :value="item.tempId"/>
+                </el-select>
+              </el-form-item>
+            </div>
+
             <!-- 样式设置 -->
             <div class="property-section">
               <div class="section-title">
@@ -388,7 +414,7 @@
                         <template slot="append">分钟</template>
                       </el-input>
                     </el-form-item>
-                    <el-form-item label="意向度">
+                    <el-form-item label="意向度" v-if="!!item.callConnected">
                       <el-select v-model="item.intention" placeholder="请选择意向等级" filterable clearable>
                         <el-option v-for="level in levelList" :key="level.dictValue" :label="level.dictLabel" :value="level.dictValue"/>
                       </el-select>
@@ -430,9 +456,28 @@
 
               <!-- 发短信任务条件 -->
               <div v-if="edgeSourceNode.nodeType == 'AI_SEND_MSG_TASK'" class="conditions-container">
-                <div class="empty-condition">
+                <div v-for="(item, index) in selectedEdge.conditionExprObj" :key="index" class="condition-item">
+                  <div class="condition-header">
+                    <span class="condition-number">条件 {{ index + 1 }}</span>
+                    <el-button type="danger" size="mini" icon="el-icon-delete" circle @click="removeCondition(index)"></el-button>
+                  </div>
+                  <div class="condition-content">
+                    <el-form-item label="发送状态">
+                      <el-select v-model="item.sendStatus" placeholder="请选择">
+                        <el-option :value="false" label="发送成功" />
+                        <el-option :value="true" label="发送失败" />
+                      </el-select>
+                    </el-form-item>
+                    <el-form-item label="等待时间" v-if="item.sendStatus == false">
+                      <el-input v-model="item.waitTime" placeholder="请输入时间">
+                        <template slot="append">分钟</template>
+                      </el-input>
+                    </el-form-item>
+                  </div>
+                </div>
+                <div v-if="selectedEdge.conditionExprObj.length === 0" class="empty-condition">
                   <i class="el-icon-info"></i>
-                  <span>此类型暂不支持条件设置</span>
+                  <span>暂无条件,请点击上方按钮添加</span>
                 </div>
               </div>
             </div>
@@ -470,10 +515,13 @@ import {
 import { getWorkflow, addWorkflow, updateWorkflow, getNodeTypes } from '@/api/company/companyWorkflow'
 import {getDicts} from "@/api/system/dict/data";
 
+import { listAll } from '@/api/company/wxDialog';
 export default {
   name: 'WorkflowDesign',
   data() {
     return {
+
+      wxDialogList: [],
       // 工作流ID
       workflowId: null,
       // 表单数据
@@ -539,10 +587,13 @@ export default {
         callTime: '',
         intention: '',
         isAdd: false,
-        addTime: ''
+        addTime: '',
+        sendStatus: false,
+        waitTime: ''
       },
       CIDGroupList:[],
       robotList: [],
+      smsTempList: [],
       dialogList: [],
     }
   },
@@ -552,6 +603,11 @@ export default {
     if (this.workflowId) {
       this.loadWorkflow()
     }
+    listAll().then(e => {
+      this.wxDialogList = e.data;
+      console.log("------")
+      console.log(this.wxDialogList)
+    })
   },
   mounted() {
     // 确保容器可获取焦点
@@ -605,7 +661,7 @@ export default {
       if (!this.selectedNode.nodeConfig || typeof this.selectedNode.nodeConfig !== 'object') {
         this.selectedNode.nodeConfig = {}
       }
-      
+
       this.selectedEdge = null
       this.edgeSourceNode = null
       if(this.selectedNode.nodeType == "AI_CALL_TASK"){
@@ -622,7 +678,7 @@ export default {
         if (!this.selectedNode.nodeConfig.recallTimes && this.selectedNode.nodeConfig.recallTimes !== 0) {
           this.$set(this.selectedNode.nodeConfig, 'recallTimes', 0)
         }
-        
+
         getTypes().then(e => {
           this.robotList = e.robot;
           this.dialogList = e.dialog;
@@ -633,6 +689,12 @@ export default {
           console.log(res);
         });
       }
+      if (this.selectedNode.nodeType === 'AI_SEND_MSG_TASK') {
+        getSmsTempList().then(res => {
+          this.smsTempList = res.data || []
+        })
+        console.log('smsTempList:', this.smsTempList)
+      }
       this.focusCanvasContainer()
     },
 
@@ -748,7 +810,7 @@ export default {
         AI_SEND_MSG_TASK: '#eb2f96',
         DELAY_TASK: '#13c2c2'
       }
-      
+
       const categoryMap = {
         basic: { key: 'basic', name: '基础节点', types: [] },
         logic: { key: 'logic', name: '逻辑节点', types: [] },
@@ -845,7 +907,7 @@ export default {
         return
       }
       e.preventDefault()
-      
+
       // 创建新节点,复制所有属性
       const newNode = {
         ...this.copiedNode,
@@ -856,15 +918,15 @@ export default {
         // 深拷贝 nodeConfig
         nodeConfig: this.copiedNode.nodeConfig ? JSON.parse(JSON.stringify(this.copiedNode.nodeConfig)) : {}
       }
-      
+
       this.nodes.push(newNode)
       // 选中新节点
       this.selectedNode = newNode
       this.selectedEdge = null
-      
+
       // 检查是否需要扩展画布
       this.checkAndExpandCanvas(newNode)
-      
+
       this.$message.success('节点已粘贴')
     },
     /** 显示右键菜单 */
@@ -894,7 +956,7 @@ export default {
         this.$message.warning('没有可粘贴的节点')
         return
       }
-      
+
       const newNode = {
         ...this.copiedNode,
         nodeKey: this.generateKey(),
@@ -902,12 +964,12 @@ export default {
         posY: this.copiedNode.posY + 30,
         nodeConfig: this.copiedNode.nodeConfig ? JSON.parse(JSON.stringify(this.copiedNode.nodeConfig)) : {}
       }
-      
+
       this.nodes.push(newNode)
       this.selectedNode = newNode
       this.selectedEdge = null
       this.checkAndExpandCanvas(newNode)
-      
+
       this.$message.success('节点已粘贴')
       this.hideContextMenu()
     },
@@ -1154,7 +1216,7 @@ export default {
           cp1y = y1 + offset
           cp1x = x1
       }
-      
+
       // 根据目标节点锚点方向设置第二个控制点
       switch(targetAnchor) {
         case 'top':
@@ -1257,11 +1319,11 @@ export default {
       nodes.filter(node => typeof node.nodeConfig == 'object').forEach(node => {
         node.nodeConfig = JSON.stringify(node.nodeConfig);
       })
-      
+
       // 查找开始节点和结束节点
       const startNode = this.nodes.find(node => node.nodeType === 'START')
       const endNode = this.nodes.find(node => node.nodeType === 'END')
-      
+
       const data = {
         workflowId: this.workflowId,
         workflowName: this.form.workflowName,

+ 18 - 18
src/views/course/courseWatchLog/index.vue

@@ -350,24 +350,24 @@
           @click="handleExport"
           v-hasPermi="['course:courseWatchLog:export']"
         >导出</el-button>
-        <el-col :span="1.5" v-if="queryParams.sendType == 2">
-          <el-button
-            type="primary"
-            plain
-            size="mini"
-            @click="addUserTag"
-            v-hasPermi="['qw:externalContact:addTag']"
-          >批量添加标签</el-button>
-        </el-col>
-        <el-col :span="1.5" v-if="queryParams.sendType == 2" >
-          <el-button
-            type="primary"
-            plain
-            size="mini"
-            @click="delUserTag"
-            v-hasPermi="['qw:externalContact:delTag']"
-          >批量移除标签</el-button>
-        </el-col>
+<!--        <el-col :span="1.5" v-if="queryParams.sendType == 2">-->
+<!--          <el-button-->
+<!--            type="primary"-->
+<!--            plain-->
+<!--            size="mini"-->
+<!--            @click="addUserTag"-->
+<!--            v-hasPermi="['qw:externalContact:addTag']"-->
+<!--          >批量添加标签</el-button>-->
+<!--        </el-col>-->
+<!--        <el-col :span="1.5" v-if="queryParams.sendType == 2" >-->
+<!--          <el-button-->
+<!--            type="primary"-->
+<!--            plain-->
+<!--            size="mini"-->
+<!--            @click="delUserTag"-->
+<!--            v-hasPermi="['qw:externalContact:delTag']"-->
+<!--          >批量移除标签</el-button>-->
+<!--        </el-col>-->
       </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>

+ 18 - 18
src/views/course/courseWatchLog/myCourseWatchLog.vue

@@ -103,24 +103,24 @@
           v-hasPermi="['course:courseWatchLog:myExport']"
         >导出</el-button>
       </el-col>
-      <el-col :span="1.5" v-if="queryParams.sendType == 2">
-        <el-button
-          type="primary"
-          plain
-          size="mini"
-          @click="addUserTag"
-          v-hasPermi="['qw:externalContact:addTag']"
-        >批量添加标签</el-button>
-      </el-col>
-      <el-col :span="1.5" v-if="queryParams.sendType == 2">
-        <el-button
-          type="primary"
-          plain
-          size="mini"
-          @click="delUserTag"
-          v-hasPermi="['qw:externalContact:delTag']"
-        >批量移除标签</el-button>
-      </el-col>
+<!--      <el-col :span="1.5" v-if="queryParams.sendType == 2">-->
+<!--        <el-button-->
+<!--          type="primary"-->
+<!--          plain-->
+<!--          size="mini"-->
+<!--          @click="addUserTag"-->
+<!--          v-hasPermi="['qw:externalContact:addTag']"-->
+<!--        >批量添加标签</el-button>-->
+<!--      </el-col>-->
+<!--      <el-col :span="1.5" v-if="queryParams.sendType == 2">-->
+<!--        <el-button-->
+<!--          type="primary"-->
+<!--          plain-->
+<!--          size="mini"-->
+<!--          @click="delUserTag"-->
+<!--          v-hasPermi="['qw:externalContact:delTag']"-->
+<!--        >批量移除标签</el-button>-->
+<!--      </el-col>-->
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 

+ 271 - 88
src/views/course/courseWatchLog/watchLog.vue

@@ -19,23 +19,23 @@
           />
         </el-select>
       </el-form-item>
-<!--      <el-form-item label="项目" prop="project">-->
-<!--        <el-select  v-model="queryParams.project" placeholder="请选择项目" clearable size="small" >-->
-<!--          <el-option-->
-<!--            v-for="item in projectOptions"-->
-<!--            :key="item.dictValue"-->
-<!--            :label="item.dictLabel"-->
-<!--            :value="item.dictValue"-->
-<!--          />-->
-<!--        </el-select>-->
-<!--      </el-form-item>-->
+      <!--      <el-form-item label="项目" prop="project">-->
+      <!--        <el-select  v-model="queryParams.project" placeholder="请选择项目" clearable size="small" >-->
+      <!--          <el-option-->
+      <!--            v-for="item in projectOptions"-->
+      <!--            :key="item.dictValue"-->
+      <!--            :label="item.dictLabel"-->
+      <!--            :value="item.dictValue"-->
+      <!--          />-->
+      <!--        </el-select>-->
+      <!--      </el-form-item>-->
       <el-form-item label="企微账号" prop="qwUserId" v-if="queryParams.sendType == 2">
         <el-select v-model="queryParams.qwUserId" placeholder="企微账号" clearable size="small"
                    @change="updateQwuser()">
           <el-option
             v-for="dict in myQwUserList"
             :key="dict.dictValue"
-            :label="dict.dictLabel + '('+dict.corpName+')'"
+            :label="dict.dictLabel + '('+dict.qwUserId+':'+dict.corpName+')'"
             :value="dict.dictValue"
           />
         </el-select>
@@ -49,24 +49,24 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-     <el-form-item label="会员ID" prop="userId" v-if="queryParams.sendType == 1">
-       <el-input
-         v-model="queryParams.userId"
-         placeholder="请输入会员ID"
-         clearable
-         size="small"
-         @keyup.enter.native="handleQuery"
-       />
-     </el-form-item>
-     <el-form-item label="会员昵称" prop="nickName" v-if="queryParams.sendType == 1">
-       <el-input
-         v-model="queryParams.nickName"
-         placeholder="请输入会员昵称"
-         clearable
-         size="small"
-         @keyup.enter.native="handleQuery"
-       />
-     </el-form-item>
+      <el-form-item label="会员ID" prop="userId" v-if="queryParams.sendType == 1">
+        <el-input
+          v-model="queryParams.userId"
+          placeholder="请输入会员ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="会员昵称" prop="nickName" v-if="queryParams.sendType == 1">
+        <el-input
+          v-model="queryParams.nickName"
+          placeholder="请输入会员昵称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
       <el-form-item label="企微客户昵称" prop="nickName" v-if="queryParams.sendType == 2">
         <el-input
           v-model="queryParams.externalUserName"
@@ -168,7 +168,7 @@
           end-placeholder="结束日期"
           value-format="yyyy-MM-dd"
           style="width: 240px"
-           @change="handleScheduleTimeChange"
+          @change="handleScheduleTimeChange"
         />
       </el-form-item>
       <!-- 创建时间 -->
@@ -215,7 +215,7 @@
           :key="updateCalendarKey"
         />
       </el-form-item> -->
-        <el-form-item label="最新更新时间" prop="updateTime">
+      <el-form-item label="最新更新时间" prop="updateTime">
         <el-date-picker
           v-model="updateTimeText"
           type="datetimerange"
@@ -223,7 +223,7 @@
           start-placeholder="开始日期"
           end-placeholder="结束日期"
           value-format="yyyy-MM-dd HH:mm:ss"
-           @change="updateChange"
+          @change="updateChange"
           :default-time="['00:00:00', '23:59:59']"
         />
       </el-form-item>
@@ -243,7 +243,7 @@
           :key="qecCalendarKey"
         />
       </el-form-item> -->
-       <el-form-item label="进线时间" prop="qecCreateTime">
+      <el-form-item label="进线时间" prop="qecCreateTime">
         <el-date-picker
           v-model="qecCreateTimeText"
           type="daterange"
@@ -272,20 +272,20 @@
         </el-date-picker>
       </el-form-item>
 
-<!--      <el-form-item label="是否注册" prop="isVip">-->
-<!--        <el-select-->
-<!--          filterable-->
-<!--          v-model="queryParams.isVip"-->
-<!--          placeholder="请选择是否注册"-->
-<!--          clearable size="small">-->
-<!--          <el-option-->
-<!--            v-for="dict in isVipList"-->
-<!--            :key="dict.dictValue"-->
-<!--            :label="dict.dictLabel"-->
-<!--            :value="dict.dictValue"-->
-<!--          />-->
-<!--        </el-select>-->
-<!--      </el-form-item>-->
+      <!--      <el-form-item label="是否注册" prop="isVip">-->
+      <!--        <el-select-->
+      <!--          filterable-->
+      <!--          v-model="queryParams.isVip"-->
+      <!--          placeholder="请选择是否注册"-->
+      <!--          clearable size="small">-->
+      <!--          <el-option-->
+      <!--            v-for="dict in isVipList"-->
+      <!--            :key="dict.dictValue"-->
+      <!--            :label="dict.dictLabel"-->
+      <!--            :value="dict.dictValue"-->
+      <!--          />-->
+      <!--        </el-select>-->
+      <!--      </el-form-item>-->
       <!-- 记录类型 - 仅在全部选项卡时显示 -->
       <el-form-item label="记录类型" prop="logType" v-if="activeName === '00'">
         <el-select
@@ -340,19 +340,37 @@
             type="primary"
             plain
             size="mini"
-            @click="addUserTag"
-            v-hasPermi="['qw:externalContact:addTag']"
+            @click="addUserTag(false)"
+            v-hasPermi="['qw:externalContact:addTagByWatch']"
           >批量添加标签</el-button>
         </el-col>
+        <el-col :span="1.5">
+          <el-button
+            type="primary"
+            plain
+            size="mini"
+            @click="addUserTag(true)"
+            v-hasPermi="['qw:externalContact:addTagByWatch']"
+          >批量添加标签(筛选条件)</el-button>
+        </el-col>
         <el-col :span="1.5" v-if="queryParams.sendType == 2">
           <el-button
             type="primary"
             plain
             size="mini"
-            @click="delUserTag"
-            v-hasPermi="['qw:externalContact:delTag']"
+            @click="delUserTag(false)"
+            v-hasPermi="['qw:externalContact:delTagByWatch']"
           >批量移除标签</el-button>
         </el-col>
+        <el-col :span="1.5">
+          <el-button
+            type="primary"
+            plain
+            size="mini"
+            @click="delUserTag(true)"
+            v-hasPermi="['qw:externalContact:delTagByWatch']"
+          >批量移除标签(筛选条件)</el-button>
+        </el-col>
       </el-col>
       <el-col :span="1.5" v-if="queryParams.sendType == 2">
         <el-button
@@ -383,7 +401,7 @@
       <el-tab-pane label="全部" name="00"></el-tab-pane>
       <el-tab-pane v-for="(item,index) in logTypeOptions" :label="item.dictLabel" :name="item.dictValue"></el-tab-pane>
     </el-tabs>
-<!--    <el-table border v-loading="loading" :data="courseWatchLogList" @selection-change="handleSelectionChange">-->
+    <!--    <el-table border v-loading="loading" :data="courseWatchLogList" @selection-change="handleSelectionChange">-->
     <el-table
       border
       v-loading="loading"
@@ -409,17 +427,17 @@
       &lt;!&ndash;
       <el-table-column label="会员ID" align="center" prop="userId" v-if="queryParams.sendType == 1"/>
       &ndash;&gt;
-<!--     <el-table-column label="客户头像" align="center" prop="externalUserAvatar" v-if="queryParams.sendType == 2">-->
-<!--       <template slot-scope="scope">-->
-<!--         <el-popover-->
-<!--           placement="right"-->
-<!--           title=""-->
-<!--           trigger="hover">-->
-<!--           <img slot="reference" :src="scope.row.externalUserAvatar" style="width: 50px;height: 50px">-->
-<!--           <img :src="scope.row.externalUserAvatar" style="max-width: 200px;max-height: 200px">-->
-<!--         </el-popover>-->
-<!--       </template>-->
-<!--     </el-table-column>-->
+      <!--     <el-table-column label="客户头像" align="center" prop="externalUserAvatar" v-if="queryParams.sendType == 2">-->
+      <!--       <template slot-scope="scope">-->
+      <!--         <el-popover-->
+      <!--           placement="right"-->
+      <!--           title=""-->
+      <!--           trigger="hover">-->
+      <!--           <img slot="reference" :src="scope.row.externalUserAvatar" style="width: 50px;height: 50px">-->
+      <!--           <img :src="scope.row.externalUserAvatar" style="max-width: 200px;max-height: 200px">-->
+      <!--         </el-popover>-->
+      <!--       </template>-->
+      <!--     </el-table-column>-->
       <el-table-column label="头像" align="center">
         <template slot-scope="scope">
           <img
@@ -445,23 +463,34 @@
           <img v-else :src="scope.row.externalUserAvatar" style="width:50px;height:50px" />
         </template>
       </el-table-column>
-      <el-table-column label="营期名称" align="center" prop="periodIdName" v-if="this.queryParams.sendType==1" />
-      <el-table-column label="课程名称" align="center" prop="courseName"/>
-      <el-table-column label="小节名称" align="center" prop="videoName"/>
-      <el-table-column label="记录类型" align="center" prop="logType">
+      <el-table-column label="标签" align="center" prop="tagIdsName" width="200px" v-if="queryParams.sendType == 2">
         <template slot-scope="scope">
-          <dict-tag :options="logTypeOptions" :value="scope.row.logType"/>
+          <div class="tag-container">
+            <div class="tag-list">
+              <el-tag
+                v-for="name in scope.row.tagIdsName"
+                :key="name"
+                type="success"
+                size="small"
+              >
+                {{ name }}
+              </el-tag>
+            </div>
+          </div>
         </template>
       </el-table-column>
+      <el-table-column label="营期名称" align="center" prop="periodIdName" v-if="this.queryParams.sendType==1" />
+      <el-table-column label="课程名称" align="center" prop="courseName"/>
+      <el-table-column label="小节名称" align="center" prop="videoName"/>
       <el-table-column label="播放时长" align="center" prop="duration"/>
       <el-table-column label="看课类型" align="center">
         <template slot-scope="{ row }">
           {{ row.watchType === 1 ? 'APP' : row.watchType === 2 ? '小程序' : '-' }}
         </template>
       </el-table-column>
-<!--      <el-table-column label="所属销售" align="center" prop="companyUserName"/>-->
-<!--      <el-table-column label="所属公司" align="center" prop="companyName"/>-->
-<!--      <el-table-column label="企微员工名称" align="center" prop="qwUserName"/>-->
+      <!--      <el-table-column label="所属销售" align="center" prop="companyUserName"/>-->
+      <!--      <el-table-column label="所属公司" align="center" prop="companyName"/>-->
+      <!--      <el-table-column label="企微员工名称" align="center" prop="qwUserName"/>-->
       <!-- 所属企微列 -->
       <el-table-column
         label="所属企微"
@@ -485,6 +514,11 @@
           </el-tag>
         </template>
       </el-table-column>
+      <el-table-column label="记录类型" align="center" prop="logType">
+        <template slot-scope="scope">
+          <dict-tag :options="logTypeOptions" :value="scope.row.logType"/>
+        </template>
+      </el-table-column>
       <el-table-column label="会员状态" align="center" prop="externalStatus">
         <template slot-scope="scope">
           <dict-tag :options="externalStatusOptions" :value="scope.row.externalStatus"/>
@@ -564,7 +598,7 @@
           </template>
         </el-table-column>
         <el-table-column label="小节名称" align="center" prop="title" />
-<!--        <el-table-column label="会员id" align="center" prop="userId" />-->
+        <!--        <el-table-column label="会员id" align="center" prop="userId" />-->
         <el-table-column label="会员用户" align="center" prop="fsNickName">
           <template slot-scope="scope">
             <div style="display: flex;white-space: nowrap">
@@ -581,17 +615,17 @@
             </div>
           </template>
         </el-table-column>
-<!--        <el-table-column label="会员电话" align="center" prop="phone" />-->
-<!--        <el-table-column label="所属销售" align="center" prop="companyUserName" />-->
-<!--        <el-table-column label="所属公司" align="center" prop="companyName" />-->
+        <!--        <el-table-column label="会员电话" align="center" prop="phone" />-->
+        <!--        <el-table-column label="所属销售" align="center" prop="companyUserName" />-->
+        <!--        <el-table-column label="所属公司" align="center" prop="companyName" />-->
         <el-table-column label="转账金额" align="center" prop="amount" />
         <el-table-column label="状态" align="center" prop="status" >
           <template slot-scope="scope">
             <el-tag>
               {{
                 scope.row.status === 0 ? "发送中" :
-                scope.row.status === 2 ? "待补发" :
-                "已完成"
+                  scope.row.status === 2 ? "待补发" :
+                    "已完成"
               }}
             </el-tag>
           </template>
@@ -669,7 +703,7 @@
                 @click="tagSelection(tagItem)"
                 :class="{ 'tag-selected': tagItem.isSelected }"
               >
-                {{ tagItem.name }}
+                {{ tagItem.name }} 【{{tagItem.corpName}}】
               </a>
             </div>
           </div>
@@ -699,7 +733,7 @@
         <el-button @click="resultDialogVisible = false">关闭</el-button>
       </span>
     </el-dialog>
-     <el-dialog title="批量添加客户备注" :visible.sync="notesOpen.open" width="800px" append-to-body>
+    <el-dialog title="批量添加客户备注" :visible.sync="notesOpen.open" width="800px" append-to-body>
       <el-card>
         <el-row>
           <el-col>
@@ -916,11 +950,12 @@ export default {
       },
       addTagFormByWatch:{
         logId:[],
-        tagIds:[]
+        tagIds:[],
+        filter: false,
       },
       tagGroupList: [],
       tagTotal:0,
-
+      tagFilter:false,
       tagDelOpen:false,
 
       queryTagParams:{
@@ -1004,7 +1039,7 @@ export default {
     this.getDicts("sys_qw_external_contact_status").then(response => {
       this.externalStatusOptions = response.data;
     });
-       // 查询营期名称
+    // 查询营期名称
     listPeriodLabel().then(response => {
       this.scheduleLists = response.rows;
     });
@@ -1517,9 +1552,13 @@ export default {
       })
     },
 
-    addUserTag(){
+    addUserTag(tagFilter){
+
+      if (this.queryParams.sendType == 2  &&  !this.queryParams.qwUserId){
+        return  this.$message.warning('请先选择要打标签的 企微账号');
+      }
 
-      if(this.ids==null||this.ids==""){
+      if(!tagFilter && (this.ids==null||this.ids=="")){
         return  this.$message('请选择需要添加标签的客户');
       }
 
@@ -1536,12 +1575,18 @@ export default {
 
 
       this.tagOpen = true;
-
+      this.tagFilter = tagFilter;
     },
 
-    delUserTag(){
 
-      if(this.ids==null||this.ids==""){
+
+    delUserTag(tagFilter){
+
+      if (this.queryParams.sendType == 2 &&  !this.queryParams.qwUserId){
+        return  this.$message.warning('请先选择要打标签的 企微账号');
+      }
+
+      if(!tagFilter && (this.ids==null||this.ids=="")){
         return  this.$message('请选择需要移除标签的客户');
       }
       this.getPageListTagGroup();
@@ -1555,6 +1600,7 @@ export default {
       }, 200);
 
       this.tagDelOpen = true;
+      this.tagFilter = tagFilter;
 
     },
 
@@ -1622,6 +1668,10 @@ export default {
       }
 
       this.addTagFormByWatch.logIds=this.ids;
+      this.addTagFormByWatch.filter = this.tagFilter;
+
+      // 修改这里:正确处理参数对象
+      this.addTagFormByWatch.param = JSON.parse(JSON.stringify(this.queryParams));
 
 
       let loadingRock = this.$loading({
@@ -1664,8 +1714,11 @@ export default {
       if(this.addTagFormByWatch.tagIds==[]||this.addTagFormByWatch.tagIds==null||this.addTagFormByWatch.tagIds==""){
         return  this.$message('请选择标签');
       }
-      this.addTagFormByWatch.corpId=this.queryParams.corpId
+
       this.addTagFormByWatch.logIds=this.ids;
+      this.addTagFormByWatch.filter = this.tagFilter;
+      // 修改这里:正确处理参数对象
+      this.addTagFormByWatch.param = JSON.parse(JSON.stringify(this.queryParams));
 
       let loadingRock = this.$loading({
         lock: true,
@@ -1941,4 +1994,134 @@ export default {
     align-items: center;
   }
 }
+/* CSS 样式 */
+.tag-container {
+  display: flex;
+  flex-wrap: wrap; /* 超出宽度时自动换行 */
+  gap: 8px; /* 设置标签之间的间距 */
+}
+.name-background {
+  display: inline-block;
+  background-color: #abece6; /* 背景颜色 */
+  padding: 4px 8px; /* 调整内边距,让背景包裹文字 */
+  border-radius: 4px; /* 可选:设置圆角 */
+}
+/* CSS 样式 */
+.tag-container {
+  display: flex;
+  flex-wrap: wrap; /* 超出宽度时自动换行 */
+  gap: 8px; /* 设置标签之间的间距 */
+}
+.name-background {
+  display: inline-block;
+  background-color: #abece6; /* 背景颜色 */
+  padding: 4px 8px; /* 调整内边距,让背景包裹文字 */
+  border-radius: 4px; /* 可选:设置圆角 */
+}
+.tag-box {
+  padding: 8px 12px;
+  border: 1px solid #989797;
+  border-radius: 4px;
+  cursor: pointer;
+  display: inline-block;
+}
+
+.tag-selected {
+  background-color: #00bc98;
+  color: #fff;
+  border-color: #00bc98;
+}
+
+.el-tag + .el-tag {
+  margin-left: 10px;
+}
+
+
+
+.button-new-tag {
+  margin-left: 10px;
+  height: 32px;
+  line-height: 30px;
+  padding-top: 0;
+  padding-bottom: 0;
+}
+.input-new-tag {
+  width: 90px;
+  margin-left: 10px;
+  vertical-align: bottom;
+}
+
+
+.suggestion-box {
+  position: absolute;
+  z-index: 999;
+  background: #fff;
+  border: 1px solid #ddd;
+  max-height: 200px;
+  overflow-y: auto;
+  width: 100%;
+}
+
+.suggestion-item {
+  padding: 10px;
+  cursor: pointer;
+}
+.suggestion-item:hover {
+  background-color: #f5f7fa;
+}
+/* 新增的滚动容器样式(不影响原有样式) */
+.scroll-wrapper {
+  max-height: 130px; /* 大约三行的高度 */
+  overflow-y: auto;  /* 垂直滚动 */
+  padding-right: 5px; /* 为滚动条留出空间 */
+}
+
+/* 美化滚动条(可选) */
+.scroll-wrapper::-webkit-scrollbar {
+  width: 6px;
+}
+.scroll-wrapper::-webkit-scrollbar-thumb {
+  background: rgba(0, 0, 0, 0.2);
+  border-radius: 3px;
+}
+
+.tag-container {
+  max-height: 200px;
+  overflow-y: auto;
+  padding: 1px;
+  border: 1px solid #ebeef5;
+  border-radius: 1px;
+  background-color: #fafafa;
+}
+.tag-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+.scroll-hint {
+  text-align: center;
+  color: #909399;
+  font-size: 12px;
+  padding: 1px 0;
+}
+.container {
+  max-width: 800px;
+  margin: 0 auto;
+  padding: 10px;
+}
+.title {
+  text-align: center;
+  color: #303133;
+  margin-bottom: 30px;
+}
+.demo-table {
+  width: 100%;
+  margin-bottom: 30px;
+}
+.instructions {
+  background-color: #f5f7fa;
+  padding: 15px;
+  border-radius: 1px;
+  margin-bottom: 20px;
+}
 </style>

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 479 - 329
src/views/hisStore/components/productOrder.vue


+ 0 - 5
src/views/qw/externalContact/index.vue

@@ -386,11 +386,6 @@
       <el-table-column label="备注" align="center" prop="remark" />
       <el-table-column label="描述信息" align="center" prop="description" />
       <el-table-column label="标签" align="center" prop="tagIdsName" width="300px">
-<!--        <template slot-scope="scope">-->
-<!--          <div v-for="name in scope.row.tagIdsName"  style="display: inline;">-->
-<!--          <el-tag type="success">{{ name }}</el-tag>-->
-<!--          </div>-->
-<!--        </template>-->
         <template slot-scope="scope">
           <div class="tag-container">
             <div class="tag-list">

+ 10 - 0
src/views/qw/externalContactTransfer/deptTransferIndex.vue

@@ -492,6 +492,14 @@ export default {
 
 
         if (valid) {
+
+          let loadingRock = this.$loading({
+            lock: true,
+            text: '正在执行中请稍后~~请不要刷新页面!!',
+            spinner: 'el-icon-loading',
+            background: 'rgba(0, 0, 0, 0.7)'
+          });
+
             var form={
               ids:this.ids,
               userId:this.form.userId,
@@ -503,6 +511,8 @@ export default {
               this.msgSuccess(response.msg);
               this.open = false;
               this.getList();
+            }).finally(res=>{
+              loadingRock.close();
             });
 
         }

+ 11 - 0
src/views/qw/externalContactTransfer/index.vue

@@ -533,6 +533,14 @@ export default {
           obj.tagIds = obj.tagIds.split(",");
         }
         if (valid) {
+
+          let loadingRock = this.$loading({
+            lock: true,
+            text: '正在执行中请稍后~~请不要刷新页面!!',
+            spinner: 'el-icon-loading',
+            background: 'rgba(0, 0, 0, 0.7)'
+          });
+
             var form={
               ids:this.ids,
               addType: 0,
@@ -543,10 +551,13 @@ export default {
 			        content:this.form.content,
               needClearTag: this.form.needClearTag
             }
+
             transfer(form).then(response => {
               this.msgSuccess(response.msg);
               this.open = false;
               this.getList();
+            }).finally(res=>{
+              loadingRock.close();
             });
 
         }

+ 11 - 1
src/views/qw/externalContactUnassigned/deptUnassignedIndex.vue

@@ -442,6 +442,14 @@ export default {
       this.nickName=null;
       this.$refs["form"].validate(valid => {
         if (valid) {
+
+            let loadingRock = this.$loading({
+              lock: true,
+              text: '正在执行中请稍后~~请不要刷新页面!!',
+              spinner: 'el-icon-loading',
+              background: 'rgba(0, 0, 0, 0.7)'
+            });
+
             var form={
               ids:this.ids,
               userId:this.form.userId,
@@ -452,7 +460,9 @@ export default {
               this.msgSuccess(response.msg);
               this.open = false;
               this.getList();
-            });
+            }).finally(res=>{
+            loadingRock.close();
+          });
 
         }
       });

+ 11 - 2
src/views/qw/externalContactUnassigned/index.vue

@@ -441,7 +441,7 @@ export default {
     },
     // 多选框选中数据
     handleSelectionChange(selection) {
-      
+
       this.ids = selection.map(item => item.id)
       this.single = selection.length!==1
       this.multiple = !selection.length
@@ -487,6 +487,13 @@ export default {
       this.nickName=null;
       this.$refs["form"].validate(valid => {
         if (valid) {
+
+            let loadingRock = this.$loading({
+              lock: true,
+              text: '正在执行中请稍后~~请不要刷新页面!!',
+              spinner: 'el-icon-loading',
+              background: 'rgba(0, 0, 0, 0.7)'
+            });
             var form={
               qwUserName:this.qwUserName,
               type:this.type,
@@ -499,7 +506,9 @@ export default {
               this.msgSuccess(response.msg);
               this.open = false;
               this.getList();
-            });
+            }).finally(res=>{
+            loadingRock.close();
+          });
 
         }
       });

+ 71 - 2
src/views/qw/sopTemp/deptIndex.vue

@@ -283,6 +283,17 @@
             </el-radio>
           </el-radio-group>
         </el-form-item>
+        <el-form-item label="是否开启app看课" v-if="showAppCourseToggle && form.sendType == 11 && (form.id === null || form.id === undefined)">
+          <el-radio-group v-model="form.openAppCourse">
+            <el-radio
+              v-for="dict in openOfficialOptions"
+              :key="dict.dictValue"
+              :label="dict.dictValue"
+            >{{ dict.dictLabel }}
+            </el-radio>
+          </el-radio-group>
+        </el-form-item>
+
         <el-form-item label="内容" prop="modeContent">
           <el-input v-model="form.modeContent" placeholder="请输入文字内容"  type="textarea" :rows="3"/>
         </el-form-item>
@@ -465,7 +476,8 @@ export default {
       // 状态字典
       statusOptions: [],
       openOfficialOptions: [],
-
+      // 控制“是否开启app看课”是否显示
+      showAppCourseToggle: false,
       shareOptions: {
         title: '分享模板',
         open: false,
@@ -580,6 +592,22 @@ export default {
     getCompanyList().then(response => {
       this.companys = response.data;
     });
+
+    //获取 app 看课配置
+    this.getOpenAppCourseStatus();
+  },
+  watch: {
+    //监听 openOfficial 和 openAppCourse 的变化,实现选项互斥
+    'form.openOfficial'(newVal) {
+      if (this.showAppCourseToggle && newVal === '1') {
+        this.$set(this.form, 'openAppCourse', '0');
+      }
+    },
+    'form.openAppCourse'(newVal) {
+      if (this.showAppCourseToggle && newVal === '1') {
+        this.$set(this.form, 'openOfficial', '0');
+      }
+    }
   },
   methods: {
 
@@ -699,6 +727,7 @@ export default {
         sendType: this.sendType,
         sort: 0,
         openOfficial: "1",
+        openAppCourse: "0", //默认 app 看课为关
         time: "",
         num: 1,
         timeList: [{value: "",desc:""}],
@@ -818,6 +847,13 @@ export default {
         if (command == 1) {
           this.title = "修改";
         }
+
+        if (this.showAppCourseToggle && this.form.sendType === 11) {
+          // 如果两个都是 "1",强制修正(理论上不会发生)
+          if (this.form.openOfficial === '1' && this.form.openAppCourse === '1') {
+            this.form.openAppCourse = '0';
+          }
+        }
         this.form = response.data;
         this.open = true;
       });
@@ -827,7 +863,23 @@ export default {
       delete this.form.rules
       this.$refs["form"].validate(valid => {
         if (valid) {
+          // 【新增校验】当 view_course_app=1 时,openOfficial 和 openAppCourse 必须二选一
+          if (this.showAppCourseToggle && this.form.sendType === 11 && !this.form.id) {
+            const official = this.form.openOfficial;
+            const appCourse = this.form.openAppCourse;
+
+            // 至少一个为 "1"
+            if (official !== '1' && appCourse !== '1') {
+              this.$message.error("请至少开启【官方群发】或【APP看课】中的一项!");
+              return;
+            }
 
+            // 不能同时为 "1"(虽然 watch 已处理,但以防绕过)
+            if (official === '1' && appCourse === '1') {
+              this.$message.error("【官方群发】与【APP看课】不能同时开启,请选择其一!");
+              return;
+            }
+          }
           if (this.command != 2 && this.form.id == null && this.form.sendType == 11){
 
             const hasEmptyFields = this.form.timeList.some(item => {
@@ -938,7 +990,24 @@ export default {
         let len = old - val;
         this.form.timeList.splice(Math.max(this.form.timeList.length - len, 0), len);
       }
-    }
+    },
+    getOpenAppCourseStatus(){
+      getConfigByKey("courseAppConfig.config").then(res => {
+        if (res.code === 200 && res.data?.configValue) {
+          try {
+            const config = JSON.parse(res.data.configValue);
+            this.showAppCourseToggle = config.view_course_app === 1;
+          } catch (e) {
+            console.error("解析 courseAppConfig.config 失败", e);
+            this.showAppCourseToggle = false;
+          }
+        } else {
+          this.showAppCourseToggle = false;
+        }
+      }).catch(() => {
+        this.showAppCourseToggle = false;
+      });
+    },
   }
 };
 </script>

+ 78 - 3
src/views/qw/sopTemp/myIndex.vue

@@ -266,6 +266,17 @@
             </el-radio>
           </el-radio-group>
         </el-form-item>
+        <el-form-item label="是否开启app看课" v-if="showAppCourseToggle && form.sendType == 11 && (form.id === null || form.id === undefined)">
+          <el-radio-group v-model="form.openAppCourse">
+            <el-radio
+              v-for="dict in openOfficialOptions"
+              :key="dict.dictValue"
+              :label="dict.dictValue"
+            >{{ dict.dictLabel }}
+            </el-radio>
+          </el-radio-group>
+        </el-form-item>
+
         <el-form-item label="内容" prop="modeContent">
           <el-input v-model="form.modeContent" placeholder="请输入文字内容"  type="textarea" :rows="3"/>
         </el-form-item>
@@ -399,7 +410,7 @@ import {
   redList,
   shareSopTemp,
   updateRedPackage,
-  updateTemp, listSopTempMyList
+  updateTemp, listSopTempMyList, getConfigByKey
 } from "../../../api/qw/sopTemp";
 import { getCompanyList, listCompany } from '@/api/company/company'
 import {courseList, getRoles} from "@/api/qw/sop";
@@ -447,7 +458,8 @@ export default {
       // 状态字典
       statusOptions: [],
       openOfficialOptions: [],
-
+      // 控制“是否开启app看课”是否显示
+      showAppCourseToggle: false,
       shareOptions: {
         title: '分享模板',
         open: false,
@@ -548,6 +560,23 @@ export default {
     getCompanyList().then(response => {
       this.companys = response.data;
     });
+
+    //获取 app 看课配置
+    this.getOpenAppCourseStatus();
+  },
+
+  watch: {
+    //监听 openOfficial 和 openAppCourse 的变化,实现选项互斥
+    'form.openOfficial'(newVal) {
+      if (this.showAppCourseToggle && newVal === '1') {
+        this.$set(this.form, 'openAppCourse', '0');
+      }
+    },
+    'form.openAppCourse'(newVal) {
+      if (this.showAppCourseToggle && newVal === '1') {
+        this.$set(this.form, 'openOfficial', '0');
+      }
+    }
   },
   methods: {
 
@@ -595,6 +624,7 @@ export default {
         sendType: this.sendType,
         sort: 0,
         openOfficial: "1",
+        openAppCourse: "0", //默认 app 看课为关
         time: "",
         num: 1,
         timeList: [{value: "",desc:""}],
@@ -714,7 +744,16 @@ export default {
         if (command == 1) {
           this.title = "修改";
         }
+
         this.form = response.data;
+
+        if (this.showAppCourseToggle && this.form.sendType === 11) {
+          // 如果两个都是 "1",强制修正(理论上不会发生)
+          if (this.form.openOfficial === '1' && this.form.openAppCourse === '1') {
+            this.form.openAppCourse = '0';
+          }
+        }
+
         this.open = true;
       });
     },
@@ -724,6 +763,24 @@ export default {
       this.$refs["form"].validate(valid => {
         if (valid) {
 
+          // 【新增校验】当 view_course_app=1 时,openOfficial 和 openAppCourse 必须二选一
+          if (this.showAppCourseToggle && this.form.sendType === 11 && !this.form.id) {
+            const official = this.form.openOfficial;
+            const appCourse = this.form.openAppCourse;
+
+            // 至少一个为 "1"
+            if (official !== '1' && appCourse !== '1') {
+              this.$message.error("请至少开启【官方群发】或【APP看课】中的一项!");
+              return;
+            }
+
+            // 不能同时为 "1"(虽然 watch 已处理,但以防绕过)
+            if (official === '1' && appCourse === '1') {
+              this.$message.error("【官方群发】与【APP看课】不能同时开启,请选择其一!");
+              return;
+            }
+          }
+
           if (this.command != 2 && this.form.id == null && this.form.sendType == 11){
 
             const hasEmptyFields = this.form.timeList.some(item => {
@@ -834,7 +891,25 @@ export default {
         let len = old - val;
         this.form.timeList.splice(Math.max(this.form.timeList.length - len, 0), len);
       }
-    }
+    },
+
+    getOpenAppCourseStatus(){
+      getConfigByKey("courseAppConfig.config").then(res => {
+        if (res.code === 200 && res.data?.configValue) {
+          try {
+            const config = JSON.parse(res.data.configValue);
+            this.showAppCourseToggle = config.view_course_app === 1;
+          } catch (e) {
+            console.error("解析 courseAppConfig.config 失败", e);
+            this.showAppCourseToggle = false;
+          }
+        } else {
+          this.showAppCourseToggle = false;
+        }
+      }).catch(() => {
+        this.showAppCourseToggle = false;
+      });
+    },
   }
 };
 </script>

+ 6 - 2
src/views/store/user/myList.vue

@@ -83,7 +83,7 @@
 
     <el-table v-loading="loading" border :data="userList" @selection-change="handleSelectionChange" >
       <el-table-column type="selection" width="55" align="center" />
-
+      <el-table-column label="会员ID" align="center" prop="userId"/>
       <el-table-column label="用户昵称" align="center" prop="nickname" width="150px"/>
       <el-table-column label="用户头像" align="center" prop="avatar" >
          <template slot-scope="scope">
@@ -101,7 +101,10 @@
               <dict-tag :options="userOptions" :value="scope.row.status"/>
          </template>
       </el-table-column>
-      <el-table-column label="注册时间" align="center" prop="createTime" width="150px" />
+      <el-table-column label="注册时间" align="center" prop="createTime" width="100px" />
+      <el-table-column label="APP来源" align="center" prop="source"/>
+      <el-table-column label="登录设备" align="center" prop="loginDevice"/>
+      <el-table-column label="最后一次登录IP" align="center" prop="lastIp"/>
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="150px">
         <template slot-scope="scope">
 
@@ -178,6 +181,7 @@ export default {
               open:false,
             },
       userOptions: [],
+      orOptions: [],
       // 遮罩层
       loading: true,
       // 导出遮罩层

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott