Ver código fonte

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

caoliqin 13 horas atrás
pai
commit
2493f41207

+ 6 - 6
.env.prod-knt2 → .env.prod-hnyth

@@ -1,13 +1,13 @@
 # 页面标题
-VUE_APP_TITLE = 康年堂SCRM销售端
+VUE_APP_TITLE = 养天和SCRM销售端
 # 公司名称
-VUE_APP_COMPANY_NAME = 陕西康年堂医药连锁有限公司
+VUE_APP_COMPANY_NAME = 湖南养天和中医馆有限公司
 # ICP备案号
-VUE_APP_ICP_RECORD = 陕ICP备2023011686号-5
+VUE_APP_ICP_RECORD = 湘ICP备18014714号-16
 # ICP网站访问地址
 VUE_APP_ICP_URL =https://beian.miit.gov.cn
 # 网站LOG
-VUE_APP_LOG_URL =@/assets/logo/knt.jpg
+VUE_APP_LOG_URL =@/assets/logo/yth.png
 
 # 生产环境配置
 ENV = 'production'
@@ -20,7 +20,7 @@ VUE_CLI_BABEL_TRANSPILE_MODULES = true
 
 
 #项目所属
-VUE_APP_PROJECT_FROM=knt
+VUE_APP_PROJECT_FROM=hnyth
 
 #默认 1、会员 2、企微
-VUE_APP_COURSE_DEFAULT = 1
+VUE_APP_COURSE_DEFAULT = 2

+ 26 - 0
.env.prod-zlwh

@@ -0,0 +1,26 @@
+# 页面标题
+VUE_APP_TITLE =SCRM销售端
+# 公司名称
+VUE_APP_COMPANY_NAME =泽林文化
+# ICP备案号
+VUE_APP_ICP_RECORD =京ICP备2024100370号-1
+# ICP网站访问地址
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/zlwh.png
+
+# 生产环境配置
+ENV = 'production'
+
+# FS管理系统/开发环境
+VUE_APP_BASE_API = '/prod-api'
+
+
+#默认 1、会员 2、企微
+VUE_APP_COURSE_DEFAULT = 1
+
+#项目所属
+VUE_APP_PROJECT_FROM=bjczwh
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 2 - 1
package.json

@@ -19,7 +19,7 @@
     "build:prod-sxjz": "vue-cli-service build --mode prod-sxjz",
     "build:prod-jnmy": "vue-cli-service build --mode prod-jnmy",
     "build:prod-knt": "vue-cli-service build --mode prod-knt",
-    "build:prod-knt2": "vue-cli-service build --mode prod-knt2",
+    "build:prod-hnyth": "vue-cli-service build --mode prod-hnyth",
     "build:prod-hdt": "vue-cli-service build --mode prod-hdt",
     "build:prod-yzt": "vue-cli-service build --mode prod-yzt",
     "build:prod-xfk": "vue-cli-service build --mode prod-xfk",
@@ -57,6 +57,7 @@
     "build:prod-gzzdy": "vue-cli-service build --mode prod-gzzdy",
     "build:prod-shdn": "vue-cli-service build --mode prod-shdn",
     "build:prod-xcsw": "vue-cli-service build --mode prod-xcsw",
+    "build:prod-zlwh": "vue-cli-service build --mode prod-zlwh",
     "preview": "node build/index.js --preview",
     "lint": "eslint --ext .js,.vue src",
     "test:unit": "jest --clearCache && vue-cli-service test:unit",

+ 53 - 0
src/api/company/addwx.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询调用日志_加微信列表
+export function listAddwx(query) {
+  return request({
+    url: '/company/addwxLog/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// // 查询调用日志_加微信详细
+// export function getAddwx(logId) {
+//   return request({
+//     url: '/company/addwx/' + logId,
+//     method: 'get'
+//   })
+// }
+
+// // 新增调用日志_加微信
+// export function addAddwx(data) {
+//   return request({
+//     url: '/company/addwx',
+//     method: 'post',
+//     data: data
+//   })
+// }
+
+// // 修改调用日志_加微信
+// export function updateAddwx(data) {
+//   return request({
+//     url: '/company/addwx',
+//     method: 'put',
+//     data: data
+//   })
+// }
+
+// // 删除调用日志_加微信
+// export function delAddwx(logId) {
+//   return request({
+//     url: '/company/addwx/' + logId,
+//     method: 'delete'
+//   })
+// }
+
+// // 导出调用日志_加微信
+// export function exportAddwx(query) {
+//   return request({
+//     url: '/company/addwx/export',
+//     method: 'get',
+//     params: query
+//   })
+// }

+ 53 - 0
src/api/company/callphone.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询调用日志_ai打电话列表
+export function listCallphone(query) {
+  return request({
+    url: '/company/callphoneLog/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// // 查询调用日志_ai打电话详细
+// export function getCallphone(logId) {
+//   return request({
+//     url: '/company/callphone/' + logId,
+//     method: 'get'
+//   })
+// }
+
+// // 新增调用日志_ai打电话
+// export function addCallphone(data) {
+//   return request({
+//     url: '/company/callphone',
+//     method: 'post',
+//     data: data
+//   })
+// }
+
+// // 修改调用日志_ai打电话
+// export function updateCallphone(data) {
+//   return request({
+//     url: '/company/callphone',
+//     method: 'put',
+//     data: data
+//   })
+// }
+
+// // 删除调用日志_ai打电话
+// export function delCallphone(logId) {
+//   return request({
+//     url: '/company/callphone/' + logId,
+//     method: 'delete'
+//   })
+// }
+
+// // 导出调用日志_ai打电话
+// export function exportCallphone(query) {
+//   return request({
+//     url: '/company/callphone/export',
+//     method: 'get',
+//     params: query
+//   })
+// }

+ 9 - 1
src/api/company/companyVoiceRobotic.js

@@ -131,4 +131,12 @@ export function getSmsTempList() {
     url: '/company/companySmsTemp/getSmsTempList',
     method: 'get'
   })
-}
+}
+
+export function getCIDGroupList(params) {
+  return request({
+    url: 'company/companyVoiceRobotic/getCIDGroupList',
+    method: 'get',
+    params
+  })
+}

+ 62 - 0
src/api/company/sendmsg.js

@@ -0,0 +1,62 @@
+import request from '@/utils/request'
+
+// 查询调用日志_发送短信列表
+export function listSendmsg(query) {
+  return request({
+    url: '/company/sendmsgLog/list',
+    method: 'get',
+    params: query
+  })
+}
+
+
+export function listByCallerIdAndRoboticId(query) {
+  return request({
+    url: '/company/sendmsgLog/listByCallerIdAndRoboticId',
+    method: 'get',
+    params: query
+  })
+}
+
+// // 查询调用日志_发送短信详细
+// export function getSendmsg(logId) {
+//   return request({
+//     url: '/company/sendmsg/' + logId,
+//     method: 'get'
+//   })
+// }
+
+// // 新增调用日志_发送短信
+// export function addSendmsg(data) {
+//   return request({
+//     url: '/company/sendmsg',
+//     method: 'post',
+//     data: data
+//   })
+// }
+
+// // 修改调用日志_发送短信
+// export function updateSendmsg(data) {
+//   return request({
+//     url: '/company/sendmsg',
+//     method: 'put',
+//     data: data
+//   })
+// }
+
+// // 删除调用日志_发送短信
+// export function delSendmsg(logId) {
+//   return request({
+//     url: '/company/sendmsg/' + logId,
+//     method: 'delete'
+//   })
+// }
+
+// // 导出调用日志_发送短信
+// export function exportSendmsg(query) {
+//   return request({
+//     url: '/company/sendmsg/export',
+//     method: 'get',
+//     params: query
+//   })
+// }

+ 9 - 0
src/api/live/liveMsg.js

@@ -60,3 +60,12 @@ export function exportLiveMsg(query) {
     params: query
   })
 }
+
+// 导出直播评论
+export function exportLiveMsgComments(liveId) {
+  return request({
+    url: '/live/liveMsg/exportComments/' + liveId,
+    method: 'get',
+    responseType: 'blob'
+  })
+}

BIN
src/assets/logo/yth.png


BIN
src/assets/logo/zlwh.png


+ 21 - 5
src/views/company/companyVoiceRobotic/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="任务名称" prop="name">
+      <el-form-item label="任务名称1" prop="name">
         <el-input
           v-model="queryParams.name"
           placeholder="请输入任务名称"
@@ -201,6 +201,11 @@
             <el-select v-model="form.dialogId" filterable>
               <el-option v-for="item in dialogList" :label="item.name" :value="item.id"/>
             </el-select>
+          </el-form-item>
+           <el-form-item label="主叫分组" prop="cidGroupId">
+            <el-select v-model="form.cidGroupId" filterable>
+              <el-option v-for="item in CIDGroupList" :label="item.name" :value="item.id"/>
+            </el-select>
           </el-form-item>
           <el-form-item label="拨打客户" prop="userIds">
             <el-button @click="openSelect">选择客户({{ form.userIds ? form.userIds.length : 0 }})</el-button>
@@ -299,7 +304,7 @@
             <el-button
               size="mini"
               type="text"
-              @click="openCustomer(scope.row.userId)"
+              @click="openCustomer(scope.row.userId,scope.row.idToString,scope.row.roboticId)"
             >客户信息详情</el-button>
           </template>
         </el-table-column>
@@ -355,7 +360,8 @@ import {
   wxList,
   taskRun,
   getTypes,
-  getSmsTempList
+  getSmsTempList,
+  getCIDGroupList
 } from "@/api/company/companyVoiceRobotic";
 import draggable from 'vuedraggable'
 import { listAll } from '@/api/company/wxDialog';
@@ -372,6 +378,7 @@ export default {
     return {
       // 遮罩层
       loading: true,
+      CIDGroupList:[],
       // 选中数组
       ids: [],
       weekList: [
@@ -481,6 +488,15 @@ export default {
     })
     this.getList();
     this.getSmsTempDropList();
+
+    getCIDGroupList().then(res=>{
+      console.log("----------------------")
+      console.log(res);
+      this.CIDGroupList = res.data;
+    }).catch(res=>{
+      console.log("catch_____+++++++")
+      console.log(res);
+    });
   },
   methods: {
     getSmsTempDropList(){
@@ -700,10 +716,10 @@ export default {
         this.wx.loading = false;
       });
     },
-    openCustomer(id) {
+    openCustomer(id,calleesId,roboticId) {
       this.customerDetailShow=true;
       this.$nextTick(() => {
-        this.$refs.customerDetails.getDetails(id);
+        this.$refs.customerDetails.getDetails(id,calleesId,roboticId);
       })
     },
     startRoboticFun(id){

+ 42 - 1
src/views/course/courseUserStatistics/qw/index.vue

@@ -49,6 +49,18 @@
         />
       </el-form-item>
 
+      <!--企微主体选择框 -->
+      <el-form-item label="企微主体" prop="corpId">
+        <el-select v-model="queryParams.corpId" placeholder="企微主体" size="small" @change="updateCorpId()" clearable>
+          <el-option
+            v-for="dict in myQwCompanyList"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
       <el-form-item label="添加时间" prop="createTime">
         <el-date-picker
           v-model="createTime"
@@ -346,6 +358,22 @@
           </span>
         </template>
       </el-table-column>
+
+      <!-- 重粉数 -->
+      <el-table-column label="重粉数" align="center" prop="repeatCount">
+        <template slot-scope="scope">
+          <span>{{ scope.row.repeatCount }}</span>
+          <span
+            :style="{
+              'font-size': '12px',
+              'margin-left': '5px',
+              color: getPercentageColor((scope.row.repeatCount / scope.row.line) * 100),
+            }"
+          >
+            ({{ ((scope.row.repeatCount / scope.row.line) * 100).toFixed(2) }}%)
+          </span>
+        </template>
+      </el-table-column>
     </el-table>
 
     <pagination-more
@@ -375,10 +403,12 @@ import { treeselect } from "@/api/company/companyDept";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 import { getCompanyUserListLikeName } from "@/api/company/companyUser";
+import { getMyQwCompanyList } from '@/api/qw/user';
 import { getTask } from "@/api/common";
+import PaginationMore from "@/components/PaginationMore/index.vue";
 export default {
   name: "CourseWatchLog",
-  components: { Treeselect },
+  components: {PaginationMore, Treeselect },
   data() {
     return {
       activeName: "00",
@@ -433,12 +463,14 @@ export default {
         eTime: null,
         scheduleStartTime: null,
         scheduleEndTime: null,
+        corpId: null, // 企微主体ID
       },
       // 表单参数
       form: {},
       // 表单校验
       rules: {},
       scheduleTime: null,
+      myQwCompanyList: [], // 存储企微主体选项列表
     };
   },
   created() {
@@ -451,8 +483,16 @@ export default {
     });
     this.getTreeselect();
     this.getList();
+    // --- 获取企微主体列表 ---
+    getMyQwCompanyList().then(response => {
+      this.myQwCompanyList = response.data;
+    });
   },
   methods: {
+    updateCorpId() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
     getSummaries(param) {
       let totalNum = 0;
       const { columns, data } = param;
@@ -639,6 +679,7 @@ export default {
       this.queryParams.eTime = null;
       this.queryParams.scheduleStartTime = null;
       this.queryParams.scheduleEndTime = null;
+      this.queryParams.corpId = null; // 重置企微主体选择
       this.handleQuery();
     },
     // 多选框选中数据

+ 2 - 2
src/views/course/courseWatchLog/qw/statistics.vue

@@ -196,7 +196,7 @@ export default {
             column.property === "noUserWaitNumber" ||
             column.property === "onLineRate" ||
             column.property === "finishedRate" ||
-            column.property === "redAmount" 
+            column.property === "redAmount"
           ) {
           }
         } else {
@@ -213,7 +213,7 @@ export default {
             } else if(index === 13 && !!sums[9]){
               sums[index] =  (sums[7] * 100 / sums[9]).toFixed(2) + '%';
             }
-          } 
+          }
         }
       });
       console.log(sums);

+ 60 - 1
src/views/course/courseWatchLog/watchLog.vue

@@ -302,6 +302,21 @@
           />
         </el-select>
       </el-form-item>
+      <el-form-item label="会员状态" prop="externalStatus">
+        <el-select
+          v-model="queryParams.externalStatus"
+          placeholder="请选择会员状态"
+          clearable
+          size="small"
+          filterable>
+          <el-option
+            v-for="dict in externalStatusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
         <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
@@ -377,7 +392,19 @@
       :key="tableKey">
       <el-table-column type="selection" width="55" align="center"/>
       <el-table-column label="记录编号" align="center" prop="logId"/>
-     <el-table-column label="客户昵称" align="center" prop="externalUserName" v-if="queryParams.sendType == 2"/>
+      <el-table-column label="客户昵称" align="center" prop="externalUserName" v-if="queryParams.sendType == 2">
+        <template slot-scope="scope">
+          <span>{{ scope.row.externalUserName }}</span>
+          <i
+            ref="copyIcon"
+            class="el-icon-document-copy"
+            style="margin-left: 5px; cursor: pointer; color: #409EFF;"
+            @click="copyText(scope.row.externalUserName, $event)"
+            title="点击复制"
+          ></i>
+        </template>
+
+      </el-table-column>
 
       &lt;!&ndash;
       <el-table-column label="会员ID" align="center" prop="userId" v-if="queryParams.sendType == 1"/>
@@ -458,6 +485,11 @@
           </el-tag>
         </template>
       </el-table-column>
+      <el-table-column label="会员状态" align="center" prop="externalStatus">
+        <template slot-scope="scope">
+          <dict-tag :options="externalStatusOptions" :value="scope.row.externalStatus"/>
+        </template>
+      </el-table-column>
       <el-table-column
         fixed="right"
         label="操作"
@@ -739,6 +771,7 @@
 </template>
 
 <script>
+import ClipboardJS from 'clipboard';
 import {
   addCourseWatchLog,
   delCourseWatchLog,
@@ -823,6 +856,7 @@ export default {
       videoList: [],
       myQwUserList: [],
       logTypeOptions: [],
+      externalStatusOptions:[],
       // 遮罩层
       loading: true,
       // 导出遮罩层
@@ -914,6 +948,7 @@ export default {
         videoId: null,
         nickName: null,
         logType: 2,
+        externalStatus:null,
         qwExternalContactId: null,
         externalUserName:null,
         duration: null,
@@ -965,6 +1000,9 @@ export default {
     });
     this.getDicts("sys_course_project").then(response => {
       this.projectOptions = response.data;
+    });
+    this.getDicts("sys_qw_external_contact_status").then(response => {
+      this.externalStatusOptions = response.data;
     });
        // 查询营期名称
     listPeriodLabel().then(response => {
@@ -980,6 +1018,21 @@ export default {
 
   },
   methods: {
+    copyText(text, event) {
+      const clipboard = new ClipboardJS(event.currentTarget, {
+        text: () => text,
+      });
+
+      clipboard.on('success', (e) => {
+        this.$message.success('复制成功');
+        clipboard.destroy();
+      });
+
+      clipboard.on('error', (e) => {
+        this.$message.error('复制失败,请手动复制');
+        clipboard.destroy();
+      });
+    },
     setToday(){
       const today = new Date();
       const todayStart = new Date(today - 60*60*24*7*1000) ;
@@ -1296,6 +1349,7 @@ export default {
         userId: null,
         videoId: null,
         logType: null,
+        externalStatus:null,
         createTime: null,
         updateTime: null,
         qwExternalContactId: null,
@@ -1854,3 +1908,8 @@ export default {
   color: #606266;
 }
 </style>
+<style scoped>
+.el-icon-document-copy:hover {
+  color: #66b1ff; /* 悬停时的颜色 */
+}
+</style>

+ 76 - 0
src/views/crm/components/aiAddWxLog.vue

@@ -0,0 +1,76 @@
+<template>
+    <div>
+        <el-table border v-loading="loading" :data="list" >
+            <el-table-column label="ID" align="center" prop="logId" />
+            <el-table-column label="公司名" align="center" prop="companyName" />
+            <el-table-column label="客户名称" align="center" prop="wxClientName" />
+            <el-table-column label="加微微信" align="center" prop="wxAccountName" />
+            <el-table-column label="加微时间" align="center" prop="runTime" ></el-table-column>
+            <el-table-column label="状态" align="center" prop="status" >
+                <template slot-scope="scope">
+                    <el-tag prop="status" v-for="(item, index) in statusOptions"    v-if="scope.row.status==item.dictValue">{{item.dictLabel}}</el-tag>
+                </template>
+            </el-table-column>
+            <!-- <el-table-column label="备注" align="center" prop="remark" /> -->
+        </el-table>
+        <pagination
+        v-show="total>0"
+        :total="total"
+        :page.sync="queryParams.pageNum"
+        :limit.sync="queryParams.pageSize"
+        @pagination="getList"
+        />
+
+    </div>
+</template>
+  
+<script>
+import { listAddwx } from "@/api/company/addwx.js";
+
+import {getDicts} from "@/api/system/dict/data";
+export default {
+        name: "aiAddWxLog",
+        data() {
+            return {
+                statusOptions:[],
+                // 遮罩层
+                loading: true,
+                // 总条数
+                total: 0,
+                list: [],
+                // 查询参数
+                queryParams: {
+                    pageNum: 1,
+                    pageSize: 10,
+                    customerId: null,
+                    roboticId:null
+                },
+            };
+        },
+        created() {
+            getDicts("ai_call_task_status").then((response) => {
+                this.statusOptions = response.data;
+            });
+          
+        },
+        methods: {
+            getData(customerId,roboticId){
+                this.queryParams.roboticId=roboticId;
+                this.queryParams.customerId=customerId;
+                this.queryParams.pageNum=1;
+                this.getList();
+            },
+            getList(){
+                this.loading = true;
+                listAddwx(this.queryParams).then(response => {
+                    this.list = response.rows;
+                    this.total = response.total;
+                    this.loading = false;
+                });
+            },
+        }
+    };
+</script>
+<style lang="scss" scoped> 
+</style>
+ 

+ 38 - 22
src/views/crm/components/aiCallVoiceLog.vue

@@ -1,41 +1,44 @@
 <template>
     <div>
         <el-table border v-loading="loading" :data="list" >
-            <el-table-column label="ID" align="center" prop="voiceId" />
+            <el-table-column label="ID" align="center" prop="logId" />
             <el-table-column label="公司名" align="center" prop="companyName" />
-            <el-table-column label="员工姓名" align="center" prop="userNickName" />
-            <el-table-column label="录制地址" align="center"  show-overflow-tooltip prop="voiceUrl" width="350">
+            <el-table-column label="员工姓名" align="center" prop="companyUserName" />
+            <el-table-column label="录制地址" align="center"  show-overflow-tooltip prop="recordPath" width="350">
                 <template slot-scope="scope">
-                    <audio  v-if="scope.row.voiceUrl!=null"   controls :src="scope.row.voiceUrl"></audio>
+                    <audio  v-if="scope.row.recordPath!=null"   controls :src="handleRecordPath(scope.row.recordPath)"></audio>
                 </template>
             </el-table-column>
-            <el-table-column label="开始时间" align="center" prop="startTime" width="180">
+            <el-table-column label="呼入时间" align="center" prop="callCreateTime" width="180">
                 <template slot-scope="scope">
-                <span>{{ parseTime(scope.row.startTime) }}</span>
+                <span>{{ parseTime(scope.row.callCreateTime) }}</span>
                 </template>
             </el-table-column>
-            <el-table-column label="结束时间" align="center" prop="finishTime" width="180">
+            <el-table-column label="应答时间" align="center" prop="callAnswerTime" width="180">
                 <template slot-scope="scope">
-                <span>{{ parseTime(scope.row.finishTime) }}</span>
+                <span>{{ parseTime(scope.row.callAnswerTime) }}</span>
                 </template>
             </el-table-column>
-            <el-table-column label="主叫" align="center" prop="callerPhone" />
-            <el-table-column label="被叫" align="center" prop="calleePhone" />
-            <el-table-column label="时长(秒)" align="center" prop="times" width="180">
+            <el-table-column label="主叫" align="center" prop="callerNum" />
+            <el-table-column label="被叫" align="center" prop="calleeNum" />
+            <el-table-column label="时长(秒)" align="center" prop="callTime" width="180">
                 <template slot-scope="scope">
-                <span v-if="scope.row.voiceUrl!=null">{{ scope.row.times}}秒 </span>
+                <span v-if="scope.row.recordPath!=null">{{ scope.row.callTime}}秒 </span>
                 </template>
             </el-table-column>
-            <el-table-column label="计费时长(分)" align="center" prop="billingTime" width="180">
+            <el-table-column label="意向度" align="center" prop="intention" width="180">
+                <template slot-scope="scope">
+                    <el-tag v-for="item in levelList" v-if="scope.row.intention == item.dictValue">{{item.dictLabel}}</el-tag>
+                </template>
             </el-table-column>
-            <el-table-column label="主叫显示号" align="center" prop="displayCallerNumber" />
-            <el-table-column label="被叫显示号" align="center" prop="displayCalleeNumber" />
+            <!-- <el-table-column label="主叫显示号" align="center" prop="displayCallerNumber" />
+            <el-table-column label="被叫显示号" align="center" prop="displayCalleeNumber" /> -->
             <el-table-column label="状态" align="center" prop="status" >
                 <template slot-scope="scope">
                     <el-tag prop="status" v-for="(item, index) in statusOptions"    v-if="scope.row.status==item.dictValue">{{item.dictLabel}}</el-tag>
                 </template>
             </el-table-column>
-            <el-table-column label="备注" align="center" prop="remark" />
+            <!-- <el-table-column label="备注" align="center" prop="remark" /> -->
         </el-table>
         <pagination
         v-show="total>0"
@@ -50,12 +53,15 @@
   
 <script>
 import { listCompanyVoiceLogs, getCompanyVoiceLogs, delCompanyVoiceLogs, addCompanyVoiceLogs, updateCompanyVoiceLogs, exportCompanyVoiceLogs } from "@/api/company/companyVoiceLogs";
+import { listCallphone } from "@/api/company/callphone";
+
+import {getDicts} from "@/api/system/dict/data";
 export default {
-        name: "customerVisit",
+        name: "aiCallVoiceLog",
         data() {
             return {
-                 
                 statusOptions:[],
+                levelList:[],
                 // 遮罩层
                 loading: true,
                 // 总条数
@@ -66,29 +72,39 @@ export default {
                     pageNum: 1,
                     pageSize: 10,
                     customerId: null,
+                    callerId:null
                 },
             };
         },
         created() {
-            this.getDicts("company_voice_logs_status").then((response) => {
+            getDicts("ai_call_task_status").then((response) => {
                 this.statusOptions = response.data;
             });
+            getDicts("customer_intention_level").then(e => {
+                this.levelList = e.data;
+            })
           
         },
         methods: {
-            getData(customerId){
+            getData(customerId,calleesId){
                 this.queryParams.customerId=customerId;
+                this.queryParams.callerId=calleesId;
                 this.queryParams.pageNum=1;
                 this.getList();
             },
-            getList() {
+            getList(){
                 this.loading = true;
-                listCompanyVoiceLogs(this.queryParams).then(response => {
+                listCallphone(this.queryParams).then(response => {
                     this.list = response.rows;
                     this.total = response.total;
                     this.loading = false;
                 });
             },
+            handleRecordPath(url){
+                let path = 'http://118.24.138.129/recordFile/listen?file=' + url;
+                console.log(path);
+                return path;
+            }
         }
     };
 </script>

+ 80 - 0
src/views/crm/components/aiSendMsgLog.vue

@@ -0,0 +1,80 @@
+<template>
+    <div>
+        <el-table border v-loading="loading" :data="list" >
+            <el-table-column label="ID" align="center" prop="logId" />
+            <el-table-column label="公司名" align="center" prop="companyName" />
+            <el-table-column label="员工姓名" align="center" prop="companyUserName" />
+            
+            <el-table-column label="发送时间" align="center" prop="runTime" />
+            <el-table-column label="内容长度" align="center" prop="contentLen" />
+            <el-table-column label="短信模板" align="center" prop="smsTempName" />
+            <el-table-column label="状态" align="center" prop="status" >
+                <template slot-scope="scope">
+                    <el-tag prop="status" v-for="(item, index) in statusOptions"    v-if="scope.row.status==item.dictValue">{{item.dictLabel}}</el-tag>
+                </template>
+            </el-table-column>
+            <!-- <el-table-column label="备注" align="center" prop="remark" /> -->
+        </el-table>
+        <pagination
+        v-show="total>0"
+        :total="total"
+        :page.sync="queryParams.pageNum"
+        :limit.sync="queryParams.pageSize"
+        @pagination="getList"
+        />
+
+    </div>
+</template>
+  
+<script>
+import { listCompanyVoiceLogs, getCompanyVoiceLogs, delCompanyVoiceLogs, addCompanyVoiceLogs, updateCompanyVoiceLogs, exportCompanyVoiceLogs } from "@/api/company/companyVoiceLogs";
+import { listByCallerIdAndRoboticId } from "@/api/company/sendmsg";
+
+export default {
+        name: "aiSendMsgLog",
+        data() {
+            return {
+                statusOptions:[],
+                // 遮罩层
+                loading: true,
+                // 总条数
+                total: 0,
+                list: [],
+                // 查询参数
+                queryParams: {
+                    pageNum: 1,
+                    pageSize: 10,
+                    customerId: null,
+                    callerId:null,
+                    roboticId:null,
+                },
+            };
+        },
+        created() {
+            this.getDicts("ai_call_task_status").then((response) => {
+                this.statusOptions = response.data;
+            });
+          
+        },
+        methods: {
+            getData(customerId,calleesId,roboticId){
+                this.queryParams.customerId=customerId;
+                this.queryParams.callerId=calleesId;
+                this.queryParams.roboticId = roboticId;
+                this.queryParams.pageNum=1;
+                this.getList();
+            },
+            getList(){
+                this.loading = true;
+                listByCallerIdAndRoboticId(this.queryParams).then(response => {
+                    this.list = response.rows;
+                    this.total = response.total;
+                    this.loading = false;
+                });
+            },
+        }
+    };
+</script>
+<style lang="scss" scoped> 
+</style>
+ 

+ 31 - 2
src/views/crm/components/customerDetails.vue

@@ -197,6 +197,12 @@
             <el-tab-pane label="AI通话记录" name="aiVoiceLogs">
                 <ai-call-voice-log ref="aiVoiceRef"></ai-call-voice-log>
             </el-tab-pane>
+             <el-tab-pane label="AI加微记录" name="aiAddWxLogs">
+                <ai-add-wx-log ref="aiAddWxRef"></ai-add-wx-log>
+            </el-tab-pane>
+             <el-tab-pane label="AI短信记录" name="aiSendMsgLogs">
+                <ai-send-msg-log ref="aiSendMsgRef"></ai-send-msg-log>
+            </el-tab-pane>
         </el-tabs>
 
         <el-dialog :title="addTag.title" :visible.sync="addTag.open" width="600px" append-to-body>
@@ -235,6 +241,8 @@
     import customerContacts from './customerContacts.vue';
     import customerHisOrderList from '../components/customerHisOrderList.vue';
     import aiCallVoiceLog from './aiCallVoiceLog';
+    import aiAddWxLog from './aiAddWxLog';
+    import aiSendMsgLog from './aiSendMsgLog';
     import { getCustomerDetails1,updateCustomer,getCustomer1 } from "@/api/crm/customer";
     import addTag from './addTag.vue';
     import addRemark from './addRemark.vue';
@@ -242,9 +250,12 @@
     import addOrEditCustomer from '../components/addOrEditCustomer.vue';
     export default {
         name: "customer",
-        components: {customerHisOrderList,addOrEditCustomer,addSms,addTag,addRemark, customerContacts,customerVisitList,customerLogsList,customerVoiceLogsList,customerStoreOrderList,customerSmsLogsList,duplicateCustomer,aiCallVoiceLog },
+        components: {customerHisOrderList,addOrEditCustomer,addSms,addTag,addRemark, customerContacts,customerVisitList,customerLogsList,
+        customerVoiceLogsList,customerStoreOrderList,customerSmsLogsList,duplicateCustomer,aiCallVoiceLog,aiAddWxLog,aiSendMsgLog },
         data() {
             return {
+                calleesId:null,
+                roboticId:null,
                 customer:{
                     open:false,
                     title:"修改客户"
@@ -396,8 +407,26 @@
                 if(tab.name=="hisOrder"){
                     this.$refs.hisOrder.getData(this.item.customerId);
                 }
+                if(tab.name=="aiVoiceLogs"){
+                    console.log(this.item.customerId);
+                    this.$refs.aiVoiceRef.getData(this.item.customerId,this.calleesId);
+                } else if(tab.name=="aiAddWxLogs"){
+                    console.log(this.item.customerId);
+                    this.$refs.aiAddWxRef.getData(this.item.customerId,this.roboticId);
+                } else if(tab.name=="aiSendMsgLogs"){
+                    console.log(this.item.customerId);
+                    this.$refs.aiSendMsgRef.getData(this.item.customerId,this.calleesId,this.roboticId);
+                }
             },
-            getDetails(customerId) {
+            getDetails(customerId,calleesId,roboticId) {
+                if(!!calleesId){
+                    this.calleesId = calleesId;
+                    console.log(this.calleesId);
+                }
+                if(!!roboticId){
+                    this.roboticId = roboticId;
+                    console.log(this.roboticId);
+                }
                 var data={customerId:customerId}
                 this.customerId=customerId;
                 var that=this;

+ 2 - 1
src/views/hisStore/components/productOrder.vue

@@ -11,7 +11,7 @@
       <div>
 
       <el-card shadow="never" style="margin-top: 15px">
-      <div class="operate-container"  v-if="order!=null">
+      <div class="operate-container"  v-show="order!=null">
         <span  style="margin-left: 20px" class="color-danger">订单状态:
            <el-tag prop="status" v-for="(item, index) in statusOptions"    v-if="order.status==item.dictValue">{{item.dictLabel}}</el-tag>
         </span>
@@ -1374,6 +1374,7 @@ export default {
     },
     showExpress(){
       this.expressDialog.open=true;
+      this.traces = [];
       getExpress(this.orderId).then(response => {
           this.express = response.data;
           if(this.express!=null&&this.express.Traces!=null){

+ 57 - 1
src/views/live/live/index.vue

@@ -258,6 +258,12 @@
               >
                 <i class="el-icon-service"></i> 查看二维码
               </el-dropdown-item>
+<!--              <el-dropdown-item-->
+<!--                @click.native="handleExportComments(scope.row)"-->
+<!--                :disabled="exportingComments[scope.row.liveId]"-->
+<!--              >-->
+<!--                <i class="el-icon-download"></i> 导出评论-->
+<!--              </el-dropdown-item>-->
             </el-dropdown-menu>
           </el-dropdown>
 
@@ -433,6 +439,7 @@ import {
   finishLive,
   startLive, copyLive,generateCode
 } from "@/api/live/live";
+import { exportLiveMsgComments } from "@/api/live/liveMsg";
 import Editor from '@/components/Editor/wang';
 import user from '@/store/modules/user';
 import VideoUpload from "@/components/LiveVideoUpload/single.vue";
@@ -537,7 +544,9 @@ export default {
       videoUrl: "",
       qrcodeDialogVisible: false,  // 弹窗显示状态:默认隐藏
       currentQrcodeUrl: "",        // 当前要展示的二维码地址
-      defaultImg: "https://via.placeholder.com/400x400?text=二维码加载失败"  // 占位图
+      defaultImg: "https://via.placeholder.com/400x400?text=二维码加载失败",  // 占位图
+      // 导出评论状态:key为liveId,value为是否正在导出
+      exportingComments: {}
     };
   },
   created() {
@@ -988,7 +997,54 @@ export default {
         this.download(response.msg);
         this.exportLoading = false;
       }).catch(() => {});
+    },
+    /** 导出评论按钮操作 */
+    handleExportComments(row) {
+      const liveId = row.liveId;
+      // 检查是否正在导出
+      if (this.exportingComments[liveId]) {
+        this.$message.warning("正在导出中,请勿重复操作");
+        return;
+      }
+
+      // 检查是否有其他直播间正在导出
+      const hasExporting = Object.values(this.exportingComments).some(status => status === true);
+      if (hasExporting) {
+        this.$message.warning("当前已有导出任务进行中,请等待完成后再试");
+        return;
+      }
+
+      this.$confirm('是否确认导出该直播间的评论数据?', "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "info"
+      }).then(() => {
+        // 设置导出状态
+        this.$set(this.exportingComments, liveId, true);
+
+        exportLiveMsgComments(liveId).then(response => {
+          // 创建blob对象
+          const blob = new Blob([response], { type: 'application/vnd.ms-excel' });
+          // 创建下载链接
+          const url = window.URL.createObjectURL(blob);
+          const link = document.createElement('a');
+          link.href = url;
+          link.setAttribute('download', `直播评论_${row.liveName || liveId}_${new Date().getTime()}.xlsx`);
+          document.body.appendChild(link);
+          link.click();
+          document.body.removeChild(link);
+          window.URL.revokeObjectURL(url);
+
+          this.$message.success("导出成功");
+        }).catch(error => {
+          this.$message.error(error.msg || "导出失败");
+        }).finally(() => {
+          // 清除导出状态
+          this.$set(this.exportingComments, liveId, false);
+        });
+      }).catch(() => {});
     }
+
   }
 };
 </script>

+ 62 - 24
src/views/qw/sop/updateSop.vue

@@ -365,7 +365,19 @@
                 closable
                 :disable-transitions="false"
                 @close="handleClosegroupUser(id)">
-                <span v-for="list in companyUserList" :key="list.qwUserId" v-if="list.id==id">{{list.qwUserName}}</span>
+                <template>
+                  <!-- 匹配到对应项:展示用户名 -->
+                  <span
+                    v-for="list in companyUserList"
+                    :key="list.qwUserId"
+                    v-if="list.id == id">
+                      {{ list.qwUserName }}
+                  </span>
+                  <!-- 未匹配到任何项:直接展示userSelectList里的id(因为list无id,无法展示list.id) -->
+                  <span v-if="!companyUserList.some(list => list.qwUserId == id)">
+                    {{ id }}
+                  </span>
+                </template>
               </el-tag>
             </div>
           </el-form-item>
@@ -651,32 +663,58 @@ export default {
       // }
       // 找到对应的员工信息
       const user = this.companyUserList.find((list) => list.id == id);
-      console.log(user)
-      if (!user) return;
-      // 确认删除提醒
-      this.$confirm('确定要删除员工"'+user.qwUserName+'"吗?', '提示', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning',
-      })
-        .then(() => {
-          // 用户点击确定
-          const index = this.userSelectList.findIndex((t) => t === id);
-          if (index !== -1) {
-            this.userSelectList.splice(index, 1);
-          }
-          this.$message({
-            type: 'success',
-            message: '删除成功',
+
+      if (!user){
+        const qwUser = this.companyQwUserList.find((list) => list.id == id);
+        // 确认删除提醒
+        this.$confirm('确定要删除未绑定公司的企微员工"'+qwUser.qwUserName+'"吗?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning',
+        }).then(() => {
+            // 用户点击确定
+            const index = this.userSelectList.findIndex((t) => t === id);
+            if (index !== -1) {
+              this.userSelectList.splice(index, 1);
+            }
+            this.$message({
+              type: 'success',
+              message: '删除成功',
+            });
+          })
+          .catch(() => {
+            // 用户点击取消
+            this.$message({
+              type: 'info',
+              message: '已取消删除',
+            });
           });
+      }else{
+        // 确认删除提醒
+        this.$confirm('确定要删除员工"'+user.qwUserName+'"吗?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning',
         })
-        .catch(() => {
-          // 用户点击取消
-          this.$message({
-            type: 'info',
-            message: '已取消删除',
+          .then(() => {
+            // 用户点击确定
+            const index = this.userSelectList.findIndex((t) => t === id);
+            if (index !== -1) {
+              this.userSelectList.splice(index, 1);
+            }
+            this.$message({
+              type: 'success',
+              message: '删除成功',
+            });
+          })
+          .catch(() => {
+            // 用户点击取消
+            this.$message({
+              type: 'info',
+              message: '已取消删除',
+            });
           });
-        });
+      }
     },
     // 取消按钮
     cancel() {

+ 2 - 2
src/views/qw/user/index.vue

@@ -359,7 +359,7 @@
             icon="el-icon-unlock"
             plain
             v-hasPermi="['qw:user:aiStatus']"
-            v-if="scope.row.aiStatus == 0 && projectFrom === 'sxjz'"
+            v-if="scope.row.aiStatus == 0 && (projectFrom === 'sxjz' || projectFrom === 'myhk')"
             @click="updateFastGptRoleStatus(scope.row)"
           >Ai客服下线</el-button>
           <el-button
@@ -368,7 +368,7 @@
             icon="el-icon-unlock"
             plain
             v-hasPermi="['qw:user:aiStatus']"
-            v-if="scope.row.aiStatus == 1 && projectFrom === 'sxjz'"
+            v-if="scope.row.aiStatus == 1 && (projectFrom === 'sxjz' || projectFrom === 'myhk')"
             @click="updateFastGptRoleStatus(scope.row)"
           >Ai客服上线</el-button>
         </template>

+ 2 - 2
src/views/qw/user/myIndex.vue

@@ -345,7 +345,7 @@
             icon="el-icon-unlock"
             plain
             v-hasPermi="['qw:user:myAiStatus']"
-            v-if="scope.row.aiStatus == 0 && projectFrom === 'sxjz'"
+            v-if="scope.row.aiStatus == 0 && (projectFrom === 'sxjz' || projectFrom === 'myhk')"
             @click="updateFastGptRoleStatus(scope.row)"
           >Ai客服下线</el-button>
           <el-button
@@ -354,7 +354,7 @@
             icon="el-icon-unlock"
             plain
             v-hasPermi="['qw:user:myAiStatus']"
-            v-if="scope.row.aiStatus == 1 && projectFrom === 'sxjz'"
+            v-if="scope.row.aiStatus == 1 && (projectFrom === 'sxjz' || projectFrom === 'myhk')"
             @click="updateFastGptRoleStatus(scope.row)"
           >Ai客服上线</el-button>
         </template>