Переглянути джерело

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

caoliqin 2 днів тому
батько
коміт
5fef26b3b3
45 змінених файлів з 9377 додано та 41 видалено
  1. 46 0
      .env.prod-zlwh
  2. 1 0
      package.json
  3. 7 0
      src/api/company/companySmsTemp.js
  4. 12 0
      src/api/company/companyUser.js
  5. 17 0
      src/api/course/courseRedPacketLog.js
  6. 8 0
      src/api/course/qw/courseWatchLog.js
  7. 8 0
      src/api/course/userCourseVideo.js
  8. 7 1
      src/api/crm/customer.js
  9. 53 0
      src/api/fastGpt/fastGptChatMsg.js
  10. 60 0
      src/api/fastGpt/fastGptChatMsgLogs.js
  11. 53 0
      src/api/fastGpt/fastGptChatSession.js
  12. 53 0
      src/api/qw/autoTags.js
  13. 53 0
      src/api/qw/autoTagsLogs.js
  14. 31 0
      src/api/qw/friendWelcome.js
  15. 93 0
      src/api/qw/groupMsg.js
  16. 71 0
      src/api/qw/groupMsgUser.js
  17. 34 0
      src/api/qw/qwUserVoiceLogTotal.js
  18. 15 0
      src/api/qw/tagGroup.js
  19. 6 0
      src/api/qw/user.js
  20. BIN
      src/assets/logo/zlwh.png
  21. 20 1
      src/views/components/course/userCourseCatalogDetails.vue
  22. 403 0
      src/views/course/courseRedPacketLogCount/index.vue
  23. 23 0
      src/views/course/courseWatchLog/qw/statistics.vue
  24. 6 1
      src/views/course/userCourse/index.vue
  25. 2 2
      src/views/course/videoResource/index.vue
  26. 74 0
      src/views/crm/components/addRemark.vue
  27. 143 0
      src/views/crm/components/addTag.vue
  28. 294 0
      src/views/fastGpt/fastGptChatMsg/index.vue
  29. 200 0
      src/views/fastGpt/fastGptChatSession/fastGptChatMsgDetails.vue
  30. 480 0
      src/views/fastGpt/fastGptChatSession/index.vue
  31. 46 34
      src/views/his/aiWorkflow/design.vue
  32. 0 2
      src/views/his/company/index.vue
  33. 1121 0
      src/views/qw/autoTags/dayPartingIndex.vue
  34. 457 0
      src/views/qw/autoTags/dayPartingIndexDetails.vue
  35. 210 0
      src/views/qw/autoTags/groupChat.vue
  36. 859 0
      src/views/qw/autoTags/groupIndex.vue
  37. 440 0
      src/views/qw/autoTags/groupIndexDetails.vue
  38. 308 0
      src/views/qw/autoTags/keyWordIndex.vue
  39. 205 0
      src/views/qw/friendWelcome/ImageUploadWeclome.vue
  40. 1418 0
      src/views/qw/friendWelcome/indexNew.vue
  41. 355 0
      src/views/qw/groupMsg/customerGroupDetails.vue
  42. 205 0
      src/views/qw/material/ImageUpload.vue
  43. 830 0
      src/views/qw/qwUserVoiceLogTotal/index.vue
  44. 432 0
      src/views/qw/tagGroup/index.vue
  45. 218 0
      src/views/qw/user/qwUserList.vue

+ 46 - 0
.env.prod-zlwh

@@ -0,0 +1,46 @@
+# 页面标题
+VUE_APP_TITLE =泽林文化泽林管理系统
+# 首页菜单标题
+VUE_APP_TITLE_INDEX 泽林文化管理系统
+# 公司名称
+VUE_APP_COMPANY_NAME =重庆云联融智科技有限公司
+# ICP备案号
+VUE_APP_ICP_RECORD =渝ICP备2024031984号-1
+# ICP网站访问地址
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/zlwh.png
+# 存储桶配置
+VUE_APP_OBS_ACCESS_KEY_ID = K2UTJGIN7UTZJR2XMXYG
+# 存储桶配置
+VUE_APP_OBS_SECRET_ACCESS_KEY = sbyeNJLbcYmH6copxeFP9pAoksM4NIT9Zw4x0SRX
+# 存储桶配置
+VUE_APP_OBS_SERVER = https://obs.cn-north-4.myhuaweicloud.com
+# 存储桶配置
+VUE_APP_OBS_BUCKET = zlwh-1323137866
+# 存储桶配置
+VUE_APP_COS_BUCKET = zlwh-1323137866
+# 存储桶配置
+VUE_APP_COS_REGION = ap-chongqing
+# 线路一地址
+VUE_APP_VIDEO_LINE_1 = https://zlwh.ylrzcloud.com
+# 线路二地址
+VUE_APP_VIDEO_LINE_2 = https://kytobs.ylrztop.com
+
+# 开发环境配置
+ENV = 'development'
+
+# FS管理系统/开发环境
+VUE_APP_BASE_API = '/prod-api'
+
+#默认 1、会员 2、企微
+VUE_APP_COURSE_DEFAULT = 2
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true
+
+#火山云视频地址域名
+VUE_APP_VIDEO_URL = https://zlwhvolcengine.ylrztop.com
+
+#火山云视频点播空间名
+VUE_APP_HSY_SPACE = zlwh-2114522511

+ 1 - 0
package.json

@@ -56,6 +56,7 @@
     "build:prod-jnsyj": "vue-cli-service build --mode prod-jnsyj",
     "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"
   },

+ 7 - 0
src/api/company/companySmsTemp.js

@@ -58,4 +58,11 @@ export function audit(data) {
     method: 'post',
     data: data
   })
+}
+export function getSmsTempList(query) {
+  return request({
+    url: '/company/companySmsTemp/getSmsTempList',
+    method: 'get',
+    params: query
+  })
 }

+ 12 - 0
src/api/company/companyUser.js

@@ -120,3 +120,15 @@ export function getCompanyUserListPage(query) {
     params: query
   })
 }
+export function getQwAllUserList(id,companyId) {
+  return request({
+    url: '/company/companyUser/getQwAllUserList/'+id+'/'+companyId,
+    method: 'get'
+  })
+}
+export function getCompanyListByCorpId(id) {
+  return request({
+    url: '/company/companyUser/getCompanyList/'+id,
+    method: 'get'
+  })
+}

+ 17 - 0
src/api/course/courseRedPacketLog.js

@@ -18,6 +18,14 @@ export function listCourseRedPacketLogPage(data) {
   })
 }
 
+export function getRedPacketLogCount(data) {
+  return request({
+    url: '/course/courseRedPacketLog/getRedPacketLogCount',
+    method: 'post',
+    data: data
+  })
+}
+
 // 查询短链课程看课记录详细
 export function getCourseRedPacketLog(logId) {
   return request({
@@ -77,3 +85,12 @@ export function exportCourseRedPacketLog(data) {
     data: data
   })
 }
+
+// 导出短链课程看课记录
+export function exportCourseRedPacketLogCountExport(data) {
+  return request({
+    url: '/course/courseRedPacketLog/countExport',
+    method: 'post',
+    data: data
+  })
+}

+ 8 - 0
src/api/course/qw/courseWatchLog.js

@@ -142,4 +142,12 @@ export function getSignProjectName() {
     method: 'get'
   })
 }
+// 获取档期列表
+export function fetchScheduleList(query) {
+  return request({
+    url: '/qw/course/courseWatchLog/fetchScheduleList',
+    method: 'get',
+    params: query
+  })
+}
 

+ 8 - 0
src/api/course/userCourseVideo.js

@@ -144,6 +144,14 @@ export function batchDownUserCourseVideo(videoId) {
   })
 }
 
+// 上架课堂视频
+export function batchUpUserCourseVideo(videoId) {
+  return request({
+    url: '/course/userCourseVideo/batchUp/' + videoId,
+    method: 'post'
+  })
+}
+
 // 修改视频封面
 export function batchEditCover(data) {
   return request({

+ 7 - 1
src/api/crm/customer.js

@@ -46,7 +46,13 @@ export function updateCustomerSource(data) {
   })
 }
 
-
+export function getCustomerDetails(query) {
+  return request({
+    url: '/crm/customer/getCustomerDetails/',
+    method: 'get',
+    params: query
+  })
+}
 
 // 删除客户
 export function delLineCustomer(customerId) {

+ 53 - 0
src/api/fastGpt/fastGptChatMsg.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询聊天记录列表
+export function listFastGptChatMsg(query) {
+  return request({
+    url: '/fastGpt/fastGptChatMsg/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询聊天记录详细
+export function getFastGptChatMsg(msgId) {
+  return request({
+    url: '/fastGpt/fastGptChatMsg/' + msgId,
+    method: 'get'
+  })
+}
+
+// 新增聊天记录
+export function addFastGptChatMsg(data) {
+  return request({
+    url: '/fastGpt/fastGptChatMsg',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改聊天记录
+export function updateFastGptChatMsg(data) {
+  return request({
+    url: '/fastGpt/fastGptChatMsg',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除聊天记录
+export function delFastGptChatMsg(msgId) {
+  return request({
+    url: '/fastGpt/fastGptChatMsg/' + msgId,
+    method: 'delete'
+  })
+}
+
+// 导出聊天记录
+export function exportFastGptChatMsg(query) {
+  return request({
+    url: '/fastGpt/fastGptChatMsg/export',
+    method: 'get',
+    params: query
+  })
+}

+ 60 - 0
src/api/fastGpt/fastGptChatMsgLogs.js

@@ -0,0 +1,60 @@
+import request from '@/utils/request'
+
+// 查询聊天记录日志列表
+export function listFastGptChatMsgLogs(query) {
+  return request({
+    url: '/fastGpt/fastGptChatMsgLogs/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function getChatMsgLogsList(query) {
+  return request({
+    url: '/fastGpt/fastGptChatMsgLogs/logsList',
+    method: 'get',
+    params: query
+  })
+}
+// 查询聊天记录日志详细
+export function getFastGptChatMsgLogs(logsId) {
+  return request({
+    url: '/fastGpt/fastGptChatMsgLogs/' + logsId,
+    method: 'get'
+  })
+}
+
+// 新增聊天记录日志
+export function addFastGptChatMsgLogs(data) {
+  return request({
+    url: '/fastGpt/fastGptChatMsgLogs',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改聊天记录日志
+export function updateFastGptChatMsgLogs(data) {
+  return request({
+    url: '/fastGpt/fastGptChatMsgLogs',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除聊天记录日志
+export function delFastGptChatMsgLogs(logsId) {
+  return request({
+    url: '/fastGpt/fastGptChatMsgLogs/' + logsId,
+    method: 'delete'
+  })
+}
+
+// 导出聊天记录日志
+export function exportFastGptChatMsgLogs(query) {
+  return request({
+    url: '/fastGpt/fastGptChatMsgLogs/export',
+    method: 'get',
+    params: query
+  })
+}

+ 53 - 0
src/api/fastGpt/fastGptChatSession.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询对话关系列表
+export function listFastGptChatSession(query) {
+  return request({
+    url: '/fastGpt/fastGptChatSession/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询对话关系详细
+export function getFastGptChatSession(sessionId) {
+  return request({
+    url: '/fastGpt/fastGptChatSession/' + sessionId,
+    method: 'get'
+  })
+}
+
+// 新增对话关系
+export function addFastGptChatSession(data) {
+  return request({
+    url: '/fastGpt/fastGptChatSession',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改对话关系
+export function updateFastGptChatSession(data) {
+  return request({
+    url: '/fastGpt/fastGptChatSession',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除对话关系
+export function delFastGptChatSession(sessionId) {
+  return request({
+    url: '/fastGpt/fastGptChatSession/' + sessionId,
+    method: 'delete'
+  })
+}
+
+// 导出对话关系
+export function exportFastGptChatSession(query) {
+  return request({
+    url: '/fastGpt/fastGptChatSession/export',
+    method: 'get',
+    params: query
+  })
+}

+ 53 - 0
src/api/qw/autoTags.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询自动打标签主列表
+export function listTags(query) {
+  return request({
+    url: '/qw/autoTags/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询自动打标签主详细
+export function getTags(id) {
+  return request({
+    url: '/qw/autoTags/' + id,
+    method: 'get'
+  })
+}
+
+// 新增自动打标签主
+export function addTags(data) {
+  return request({
+    url: '/qw/autoTags',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改自动打标签主
+export function updateTags(data) {
+  return request({
+    url: '/qw/autoTags',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除自动打标签主
+export function delTags(id) {
+  return request({
+    url: '/qw/autoTags/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出自动打标签主
+export function exportTags(query) {
+  return request({
+    url: '/qw/autoTags/export',
+    method: 'get',
+    params: query
+  })
+}

+ 53 - 0
src/api/qw/autoTagsLogs.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询自动打标签的日志列表
+export function listAutoTagsLogs(query) {
+  return request({
+    url: '/qw/autoTagsLogs/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询自动打标签的日志详细
+export function getAutoTagsLogs(id) {
+  return request({
+    url: '/qw/autoTagsLogs/' + id,
+    method: 'get'
+  })
+}
+
+// 新增自动打标签的日志
+export function addAutoTagsLogs(data) {
+  return request({
+    url: '/qw/autoTagsLogs',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改自动打标签的日志
+export function updateAutoTagsLogs(data) {
+  return request({
+    url: '/qw/autoTagsLogs',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除自动打标签的日志
+export function delAutoTagsLogs(id) {
+  return request({
+    url: '/qw/autoTagsLogs/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出自动打标签的日志
+export function exportAutoTagsLogs(query) {
+  return request({
+    url: '/qw/autoTagsLogs/export',
+    method: 'get',
+    params: query
+  })
+}

+ 31 - 0
src/api/qw/friendWelcome.js

@@ -16,3 +16,34 @@ export function getFriendWelcome(id) {
     method: 'get'
   })
 }
+// 删除好友欢迎语
+export function delFriendWelcome(id) {
+  return request({
+    url: '/qw/friendWelcome/' + id,
+    method: 'delete'
+  })
+}
+// 新增好友欢迎语
+export function addFriendWelcome(data) {
+  return request({
+    url: '/qw/friendWelcome',
+    method: 'post',
+    data: data
+  })
+}
+// 修改好友欢迎语
+export function updateFriendWelcome(data) {
+  return request({
+    url: '/qw/friendWelcome',
+    method: 'put',
+    data: data
+  })
+}
+// 导出好友欢迎语
+export function exportFriendWelcome(query) {
+  return request({
+    url: '/qw/friendWelcome/export',
+    method: 'get',
+    params: query
+  })
+}

+ 93 - 0
src/api/qw/groupMsg.js

@@ -0,0 +1,93 @@
+import request from '@/utils/request'
+
+// 查询客户群发记录主列表
+export function listGroupMsg(query) {
+  return request({
+    url: '/qw/groupMsg/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询客户群发记录主详细
+export function getGroupMsg(id) {
+  return request({
+    url: '/qw/groupMsg/' + id,
+    method: 'get'
+  })
+}
+
+
+// 新增客户群发记录主
+export function addGroupMsg(data) {
+  return request({
+    url: '/qw/groupMsg',
+    method: 'post',
+    data: data
+  })
+}
+
+/** 统计数据详情,已发送,未发送,已接收,未接收等 */
+export function countGroupMsgUser(groupMsgId){
+  return request({
+    url: '/qw/groupMsg/getCountGroupMsgUser/' + groupMsgId,
+    method: 'get'
+  })
+}
+
+
+/** 统计数据详情,已发送群主,送达群聊,未发送群主,未送达群聊等 */
+export function CountGroupMsgBaseUser(groupMsgId){
+  return request({
+    url: '/qw/groupMsg/getCountGroupMsgBaseUser/' + groupMsgId,
+    method: 'get'
+  })
+}
+
+
+/** 客户群发 发送/接收的数据详情 */
+export function CountGroupMsgUserDetails(query){
+  return request({
+    url: '/qw/groupMsg/getCountGroupMsgUserDetails',
+    method: 'get',
+    params: query
+  })
+}
+
+
+
+/** 提醒成员群发 */
+
+export function remindGroupMsg(query){
+  return request({
+    url: '/qw/groupMsg/remindGroupMsg',
+    method: 'get',
+    params: query
+  })
+}
+
+// 修改客户群发记录主
+export function updateGroupMsg(data) {
+  return request({
+    url: '/qw/groupMsg',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除客户群发记录主
+export function delGroupMsg(id) {
+  return request({
+    url: '/qw/groupMsg/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出客户群发记录主
+export function exportGroupMsg(query) {
+  return request({
+    url: '/qw/groupMsg/export',
+    method: 'get',
+    params: query
+  })
+}

+ 71 - 0
src/api/qw/groupMsgUser.js

@@ -0,0 +1,71 @@
+import request from '@/utils/request'
+
+// 查询群发成员发送任务及执行结果反馈记录列表
+export function listGroupMsgUser(query) {
+  return request({
+    url: '/qw/groupMsgUser/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询群发成员发送任务及执行结果反馈记录详细
+export function getGroupMsgUser(id) {
+  return request({
+    url: '/qw/groupMsgUser/' + id,
+    method: 'get'
+  })
+}
+
+// 新增群发成员发送任务及执行结果反馈记录
+export function addGroupMsgUser(data) {
+  return request({
+    url: '/qw/groupMsgUser',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改群发成员发送任务及执行结果反馈记录
+export function updateGroupMsgUser(data) {
+  return request({
+    url: '/qw/groupMsgUser',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除群发成员发送任务及执行结果反馈记录
+export function delGroupMsgUser(id) {
+  return request({
+    url: '/qw/groupMsgUser/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出群发成员发送任务及执行结果反馈记录
+export function exportGroupMsgUser(query) {
+  return request({
+    url: '/qw/groupMsgUser/export',
+    method: 'get',
+    params: query
+  })
+}
+
+/** 刷新/同步 客户群群发 结果 */
+export function refreshResultsGroupMsgUser(data){
+  return request({
+    url: '/qw/groupMsgUser/refreshResultsGroupMsgUser',
+    method: 'post',
+    data: data
+  })
+}
+
+/** 刷新/同步 客户群发 结果 */
+export function refreshResultsMsgUser(data){
+  return request({
+    url: '/qw/groupMsgUser/refreshResultsMsgUser',
+    method: 'post',
+    data: data
+  })
+}

+ 34 - 0
src/api/qw/qwUserVoiceLogTotal.js

@@ -0,0 +1,34 @@
+import request from '@/utils/request'
+
+// 查询企微用户通话记录列表
+export function listQwUserVoiceLogTotal(query) {
+  return request({
+    url: '/qw/qwUserVoiceLog/totalList',
+    method: 'get',
+    params: query
+  })
+}
+
+export function listQwUserVoiceLogSellTotal(query) {
+  return request({
+    url: '/qw/qwUserVoiceLog/sellTotalList',
+    method: 'get',
+    params: query
+  })
+}
+export function exportQwUserVoiceLogSellTotal(query) {
+  return request({
+    url: '/qw/qwUserVoiceLog/sellTotalExport',
+    method: 'get',
+    params: query
+  })
+}
+
+// 导出企微用户通话记录
+export function exportQwUserVoiceLogTotal(query) {
+  return request({
+    url: '/qw/qwUserVoiceLog/totalExport',
+    method: 'get',
+    params: query
+  })
+}

+ 15 - 0
src/api/qw/tagGroup.js

@@ -73,3 +73,18 @@ export function exportTagGroup(query) {
     params: query
   })
 }
+// 查询企微客户标签列表
+export function listTag(query) {
+  return request({
+    url: '/qw/tag/list',
+    method: 'get',
+    params: query
+  })
+}
+export function searchTags(data) {
+  return request({
+    url: '/qw/tag/searchTags',
+    method: 'post',
+    data: data
+  })
+}

+ 6 - 0
src/api/qw/user.js

@@ -66,6 +66,12 @@ export function getMyQwCompanyListAll() {
     method: 'get'
   })
 }
+export function getCompanyListByCorpId(id) {
+  return request({
+    url: '/company/companyUser/getCompanyList/'+id,
+    method: 'get'
+  })
+}
 
 
 

BIN
src/assets/logo/zlwh.png


+ 20 - 1
src/views/components/course/userCourseCatalogDetails.vue

@@ -58,6 +58,10 @@
                    v-hasPermi="['course:userCourseVideo:batchDown']">批量下架
         </el-button>
       </el-col>
+      <el-col :span="1.5">
+        <el-button type="primary" plain icon="el-icon-edit" size="mini" :disabled="multiple" @click="handleUp"
+                   v-hasPermi="['course:userCourseVideo:batchUp']">批量上架</el-button>
+      </el-col>
       <el-col :span="1.5">
         <el-button type="primary" plain icon="el-icon-edit" size="mini" :disabled="multiple" @click="handleEditCover"
                    v-hasPermi="['course:userCourseVideo:batchEditCover']">批量修改封面图
@@ -520,7 +524,7 @@ import {
   sortCourseVideo,
   updates,
   updateUserCourseVideo,
-  syncTemplate, batchDownUserCourseVideo, batchEditCover
+  syncTemplate, batchDownUserCourseVideo, batchEditCover, batchUpUserCourseVideo
 } from '@/api/course/userCourseVideo'
 // import {syncTemplate} from '@/api/course/userCourse'
 import QuestionBank from "@/views/course/courseQuestionBank/QuestionBank.vue";
@@ -1362,6 +1366,21 @@ export default {
       }).catch(() => {
       });
     },
+    /** 上架按钮操作 */
+    handleUp() {
+      const videoIds = this.ids;
+      this.$confirm('是否确认上架视频编号为"' + videoIds + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function () {
+        return batchUpUserCourseVideo(videoIds);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("上架成功");
+      }).catch(function () {
+      });
+    },
     /** 修改封面 **/
     handleEditCover() {
       this.batchEditCoverDialog.form = {

+ 403 - 0
src/views/course/courseRedPacketLogCount/index.vue

@@ -0,0 +1,403 @@
+<template>
+  <div class="course-red-packet-statistics">
+    <!-- 查询条件 -->
+    <el-card class="search-card">
+      <el-form :model="queryParams" ref="queryParams" label-width="80px" inline>
+          <el-form-item label="筛选类型" prop="status">
+            <el-select v-model="queryParams.changeType" placeholder="请选择筛选类型" clearable style="width: 100%" @change="changeType">
+              <el-option label="按销售公司" :value="1"></el-option>
+              <el-option label="按员工" :value="2"></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="公司名" prop="companyId" v-if="queryParams.changeType ==1 ">
+            <el-select filterable style="width: 220px" v-model="queryParams.companyIds"
+                       @change="handleSeller" placeholder="请选择公司名"
+                       clearable size="small"
+                       multiple >
+              <el-option
+                v-for="item in companys"
+                :key="item.companyId"
+                :label="item.companyName"
+                :value="item.companyId"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="选择员工" prop="userIds" v-if="queryParams.changeType ==2 ">
+            <select-tree
+              v-model="selectedCompanyList"
+              :raw-data="deptList"
+              :parentSelectable="true"
+              placeholder="请选择销售"
+              :multiple="true"
+              component-width="300px"
+              :max-display-tags="3"
+              :check-strictly="false"
+              :return-leaf-only="false"
+            ></select-tree>
+          </el-form-item>
+          <el-form-item label="状态" prop="status">
+            <el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width: 100%">
+              <el-option label="全部" value=""></el-option>
+              <el-option label="发送中" value="0"></el-option>
+              <el-option label="已发送" value="1"></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="创建时间" prop="createTime">
+            <el-date-picker
+              v-model="createTimeText"
+              type="datetimerange"
+              range-separator="至"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+              value-format="yyyy-MM-dd HH:mm:ss"
+              @change="createChange"
+              :default-time="['00:00:00', '23:59:59']"
+            />
+          </el-form-item>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button
+              type="warning"
+              plain
+              icon="el-icon-download"
+              size="mini"
+              :loading="exportLoading"
+              @click="handleExport"
+              v-hasPermi="['course:courseRedPacketLog:countExport']"
+            >导出
+            </el-button>
+          </el-col>
+          <el-col :span="24" class="text-right">
+            <el-button type="primary" @click="handleSearch">查询</el-button>
+            <el-button @click="resetQuery">重置</el-button>
+          </el-col>
+        </el-row>
+      </el-form>
+    </el-card>
+
+    <!-- 统计结果 -->
+    <el-card class="result-card">
+      <div slot="header">
+        <span>红包发送统计</span>
+      </div>
+
+      <el-table :data="statisticsData" border style="width: 100%" v-loading="loading"
+                show-summary :summary-method="getSummaries"> >
+        <el-table-column prop="companyName" label="公司名称" align="center"></el-table-column>
+        <div v-if="queryParams.changeType==2">
+          <el-table-column prop="nickName" label="员工姓名" align="center"></el-table-column>
+          <el-table-column prop="companyUserId" label="员工编号" align="center"></el-table-column>
+          <el-table-column prop="deptId" label="部门编号" align="center"></el-table-column>
+          <el-table-column prop="deptName" label="部门昵称" align="center"></el-table-column>
+        </div>
+        <el-table-column prop="amount" label="已发红包金额" align="center"></el-table-column>
+      </el-table>
+
+      <pagination
+        v-show="total>0"
+        :total="total"
+        :page.sync="queryParams.pageNum"
+        :limit.sync="queryParams.pageSize"
+        @pagination="getList"
+      />
+    </el-card>
+  </div>
+</template>
+
+<script>
+import {getCompanyList} from "@/api/company/company";
+import {getUserList} from "@/api/company/companyUser";
+import SelectTree from '@/components/TreeSelect/index.vue'
+import { getDeptData } from '@/api/system/employeeStats'
+import {
+  exportCourseRedPacketLogCountExport,
+  getRedPacketLogCount
+} from '@/api/course/courseRedPacketLog'
+
+export default {
+  name: 'courseRedPacketLogCount',
+  components: { SelectTree },
+  data() {
+    return {
+      // 总条数
+      total: 0,
+      companys:[],
+      companyUserList:[],
+      selectedCompanyList: [],
+      deptList: [],
+      createTimeText: [],
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        changeType: 1,
+        companyId: null,
+        companyIds: null,
+        companyUserId: null,
+        startTime:null,
+        endTime:null,
+        status: null,
+        sTime:null,
+        eTime:null,
+        userIds: null
+      },
+      exportLoading: false,
+      statisticsData: [],
+      loading: false,
+      pageInfo: {
+        currentPage: 1,
+        pageSize: 10,
+        total: 0
+      }
+    }
+  },
+  mounted() {
+  },
+  created() {
+      getCompanyList().then(response => {
+          this.companys = response.data;
+          if(this.companys!=null&&this.companys.length>0){
+            this.companyId=this.companys[0].companyId;
+          }
+      });
+
+    getDeptData().then(response => {
+      this.deptList = response.data;
+    })
+  },
+  methods: {
+
+    changeType(){
+      this.statisticsData=[];
+      if (this.queryParams.changeType == 1){
+        this.selectedCompanyList=[];
+      }
+      if (this.queryParams.changeType == 2){
+        this.queryParams.companyIds=null;
+      }
+    },
+
+    getSummaries(param) {
+      const { columns, data } = param; // data 就是当前表格的 statisticsData
+      const sums = [];
+
+      columns.forEach((column, index) => {
+        if (index === 0) {
+          sums[index] = '总计';
+          return;
+        }
+
+        if (column.property === 'amount') {
+          // 直接从当前表格数据计算
+          const total = data.reduce((sum, item) => {
+            return sum + (parseFloat(item.amount) || 0);
+          }, 0);
+          sums[index] = '¥' + this.formatAmount(total);
+        } else {
+          sums[index] = '';
+        }
+      });
+
+      return sums;
+    },
+
+
+    // 格式化金额(不四舍五入,保留两位小数)
+    formatAmount(value) {
+      if (isNaN(value)) return '0.00';
+
+      // 方法1:使用 Math.floor 截断
+      const truncated = Math.floor(value * 100) / 100;
+
+      // 方法2:更精确的截断方法
+      // const truncated = Number(value.toString().match(/^\d+(?:\.\d{0,2})?/));
+
+      return truncated.toFixed(2);
+    },
+
+
+    handleSearch() {
+      this.pageInfo.currentPage = 1
+      this.getList();
+    },
+
+    createChange(createTime) {
+      if (createTime && createTime.length >= 2) {
+        if(!this.checkDateRangeLimit(createTime)){
+          this.createTimeText = null;
+          this.queryParams.sTime=null;
+          this.queryParams.eTime=null;
+          return;
+        }
+
+        this.queryParams.sTime = this.formatDate(createTime[0]) || null;
+        this.queryParams.eTime = this.formatDate(createTime[1]) || null;
+      } else {
+        this.createTimeText = [];
+        this.queryParams.sTime = null;
+        this.queryParams.eTime = null;
+      }
+    },
+    formatDate(date) {
+      if (!date) return ''
+
+      // 确保 date 是 Date 对象
+      let dateObj = date
+      if (typeof date === 'string') {
+        dateObj = new Date(date)
+      }
+
+      // 如果转换失败,返回空字符串
+      if (!(dateObj instanceof Date) || isNaN(dateObj.getTime())) {
+        return ''
+      }
+
+      // 使用更安全的格式化方法
+      const year = dateObj.getFullYear()
+      const month = String(dateObj.getMonth() + 1).padStart(2, '0')
+      const day = String(dateObj.getDate()).padStart(2, '0')
+      const hours = String(dateObj.getHours()).padStart(2, '0')
+      const minutes = String(dateObj.getMinutes()).padStart(2, '0')
+      const seconds = String(dateObj.getSeconds()).padStart(2, '0')
+
+      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
+    },
+    checkDateRangeLimit(dateRange) {
+      if (dateRange && dateRange.length >= 2) {
+        const startDate = new Date(dateRange[0]);
+        const endDate = new Date(dateRange[1]);
+
+        // 设置时间为当天开始,避免时间部分影响计算
+        startDate.setHours(0, 0, 0, 0);
+        endDate.setHours(0, 0, 0, 0);
+
+        const timeDiff = Math.abs(endDate - startDate);
+        const diffDays = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));
+
+        if (diffDays > 31) { // maxDays-1 因为包含起始日
+          this.$message.warning('时间区间不能超过一个月');
+          return false;
+        }
+      }
+      return true;
+    },
+    handleSeller(){
+
+      if(this.queryParams.companyId != null) {
+        getUserList(this.queryParams.companyId).then(res=>{
+          if(res.code === 200) {
+            this.companyUserList = res.data
+          }
+        })
+      }
+    },
+
+    resetQuery() {
+      this.$refs.queryParams.resetFields();
+      this.createTimeText = [];
+      this.queryParams.dateRange = [];
+      this.selectedCompanyList = [];
+      this.statisticsData=[];
+      this.handleSearch()
+    },
+
+    getList() {
+
+      if (this.queryParams.changeType == 1 && this.queryParams.companyIds.length == 0) {
+        return this.$message.warning('请选择公司');
+      }
+
+      if (this.isEmptyArray(this.createTimeText)) {
+        this.$message.warning('请选择创建时间');
+        return;
+      }
+
+      console.log(this.queryParams.changeType)
+      console.log(this.selectedCompanyList)
+
+      if (this.queryParams.changeType == 2){
+        if( this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
+          this.queryParams.userIds = this.selectedCompanyList;
+        }else {
+          return this.$message.warning('请选择员工');
+        }
+      }
+
+      this.loading = true
+      // 查询统计
+      getRedPacketLogCount(this.queryParams).then(response => {
+        this.statisticsData = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    // 添加辅助方法
+    isEmptyArray(arr) {
+      return !arr || arr.length === 0;
+    },
+    handleSizeChange(val) {
+      this.pageInfo.pageSize = val
+      this.pageInfo.currentPage = 1
+      this.getList()
+    },
+
+    handleCurrentChange(val) {
+      this.pageInfo.currentPage = val
+      this.getList()
+    },
+
+    /** 导出按钮操作 */
+    handleExport() {
+
+      if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
+        this.queryParams.userIds = this.selectedCompanyList;
+      }else {
+        this.queryParams.userIds = [];
+      }
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有红包记录数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        const loadingInstance = this.$loading({
+          lock: true,
+          text: '正在导出数据,请稍候...',
+          background: 'rgba(0, 0, 0, 0.7)'
+        });
+
+        this.exportLoading = true;
+
+        return exportCourseRedPacketLogCountExport(queryParams).finally(res=>{
+          loadingInstance.close();
+        })
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {}).finally(res=>{
+
+      });
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.course-red-packet-statistics {
+  padding: 20px;
+
+  .search-card {
+    margin-bottom: 20px;
+  }
+
+  .result-card {
+    .pagination-container {
+      margin-top: 20px;
+      text-align: right;
+    }
+  }
+
+  .text-right {
+    text-align: right;
+  }
+}
+</style>

+ 23 - 0
src/views/course/courseWatchLog/qw/statistics.vue

@@ -35,6 +35,17 @@
           />
         </el-select>
       </el-form-item>
+
+      <el-form-item label="档期" prop="qwSopId">
+        <el-select filterable v-model="queryParams.qwSopId" placeholder="请选择档期" clearable size="small">
+          <el-option
+            v-for="item in scheduleList"
+            :key="item.qwSopId"
+            :label="item.qwSopName"
+            :value="item.qwSopId"
+          />
+        </el-select>
+      </el-form-item>
       <el-form-item label="小节" prop="videoId">
         <el-select filterable  v-model="queryParams.videoId" placeholder="请选择小节"  clearable size="small">
           <el-option
@@ -141,12 +152,14 @@ import {
 } from '@/api/course/qw/courseWatchLog'
 import { courseList,videoList } from '@/api/course/courseRedPacketLog'
 import {getCompanyList} from "@/api/company/company";
+  import { fetchScheduleList } from "@/api/course/qw/courseWatchLog";
 export default {
   name: "CourseWatchLog",
     components: {SelectTree},
 
   data() {
     return {
+      scheduleList: [], // 档期列表,结构为[{qwSopId: 'xxx', qwSopName: 'xxx'}]
       signProjectName:"",
       companys:[],
       activeName:"00",
@@ -188,6 +201,7 @@ export default {
         companyUserId: null,
         companyId: null,
         courseId: null,
+        qwSopId: null, // 档期ID
         sTime:null,
         eTime:null,
         scheduleStartTime: null,
@@ -233,8 +247,16 @@ export default {
       this.logTypeOptions = response.data;
     });
     this.initCompanyData();
+    // 获取档期列表
+    this.getScheduleList();
   },
   methods: {
+    // 获取档期列表
+    getScheduleList() {
+      fetchScheduleList({}).then(response => {
+        this.scheduleList = response.rows; // rows包含[{qwSopId: 'xxx', qwSopName: 'xxx'}]格式的数据
+      });
+    },
 
     handleStatisExport(){
       if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
@@ -370,6 +392,7 @@ export default {
       this.queryParams.eTime = null;
       this.queryParams.scheduleStartTime = null;
       this.queryParams.scheduleEndTime = null;
+      this.queryParams.qwSopId = null; // 重置档期选择
       this.handleQuery();
     },
     // 多选框选中数据

+ 6 - 1
src/views/course/userCourse/index.vue

@@ -426,6 +426,9 @@
           <i class="el-icon-warning"/>
           <span style="color: rgb(153, 169, 191)"> 多个支持单位,请用英文逗号隔开</span>
         </el-form-item>
+        <el-form-item label="监督投诉电话" prop="complaintPhone">
+          <el-input v-model="configDialog.form.complaintPhone" placeholder="请输入监督投诉电话" clearable/>
+        </el-form-item>
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button type="primary"
@@ -642,7 +645,9 @@ export default {
           teamEnable: 0,
           team: null,
           supportEnable: 0,
-          support: null
+          support: null,
+          //监督投诉电话
+          complaintPhone: null,
         },
         rules: {
           tv: [

+ 2 - 2
src/views/course/videoResource/index.vue

@@ -389,7 +389,7 @@
       </div>
     </el-dialog>
     <!-- 批量选择视频弹窗 -->
-    <el-dialog :title="'选择视频'" :visible.sync="batchAddVisible" width="1200px" append-to-body class="batch-dialog"
+    <minimizable-dialog :title="'选择视频'" :visible.sync="batchAddVisible" width="1200px" append-to-body class="batch-dialog"
       :close-on-click-modal="false" :before-close="cancelBeforeBatch" @minimize="hasMinimizableDialog = true"
       @restore="hasMinimizableDialog = false">
       <div class="filter-container">
@@ -650,7 +650,7 @@
         </div>
       </el-dialog>
 
-    </el-dialog>
+    </minimizable-dialog>
 
     <!-- 项目选择弹窗 -->
     <el-dialog

+ 74 - 0
src/views/crm/components/addRemark.vue

@@ -0,0 +1,74 @@
+<template>
+    <div>
+            <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+                <el-form-item label="备注" prop="remark">
+                    <el-input :rows="2" v-model="form.remark" type="textarea" placeholder="请输入内容" />
+                </el-form-item>
+            </el-form>
+            <div  class="footer">
+                <el-button type="primary" @click="submitForm">确 定</el-button>
+            </div>
+    </div>
+</template>
+  
+<script>
+    import { updateCustomer  } from "@/api/crm/customer";
+    export default {
+        name: "remark",
+        data() {
+            return {
+                form: {
+                    customerId:null,
+                    remark:null,
+                 
+                },
+                // 表单校验
+                rules: {
+                    remark: [
+                        { required: true, message: "备注不能为空", trigger: "change" }
+                    ],
+         
+                }
+                 
+            };
+        },
+        created() {
+        },
+        methods: {
+            reset(customer) {
+                this.form.customerId=customer.customerId;
+                this.form.remark=customer.remark;
+            },
+            submitForm() {
+                this.$refs["form"].validate(valid => {
+                    if (valid) {
+                        updateCustomer(this.form).then(response => {
+                            if (response.code === 200) {
+                                this.msgSuccess("操作成功");
+                                
+                                this.$emit('close');
+                            }
+                        });
+                    }
+                });
+            },
+        }
+    };
+</script>
+<style lang="scss" scoped>
+.contents{
+    height: 100%;
+    background-color: #fff;
+    padding: 20px;
+        
+}
+.footer{
+    display: flex;
+    align-items: center;
+    justify-content: flex-end;
+}
+</style>
+
+
+
+ 

+ 143 - 0
src/views/crm/components/addTag.vue

@@ -0,0 +1,143 @@
+<template>
+    <div>
+            <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+                <el-form-item label="标签库" >
+                    <el-select @change="tagChange" v-model="tag" placeholder="请选择" clearable size="small">
+                        <el-option
+                                v-for="item in tagsOptions"
+                                :key="item.dictValue"
+                                :label="item.dictLabel"
+                                :value="item.dictValue"
+                            />
+                    </el-select>
+                </el-form-item>
+                <el-form-item label="标签" prop="tags">
+                    <el-tag
+                        :key="tag"
+                        v-for="tag in tags"
+                        closable
+                        :disable-transitions="false"
+                        @close="handleClose(tag)">
+                        {{tag}}
+                    </el-tag>
+                    <el-input
+                        class="input-new-tag"
+                        v-if="inputVisible"
+                        v-model="inputValue"
+                        ref="saveTagInput"
+                        size="small"
+                        @keyup.enter.native="handleInputConfirm"
+                        @blur="handleInputConfirm"
+                    >
+                    </el-input>
+                    <el-button v-else class="button-new-tag" size="small" @click="showInput">添加标签+</el-button>
+                </el-form-item>
+            </el-form>
+            <div  class="footer">
+                <el-button type="primary" @click="submitForm">确 定</el-button>
+            </div>
+    </div>
+</template>
+  
+<script>
+    import { updateCustomer  } from "@/api/crm/customer";
+    export default {
+        name: "visit",
+        data() {
+            return {
+                tag:null,
+                tagsOptions:[],
+                inputVisible: false,
+                inputValue: '',
+                tags:[],
+                form: {
+                    customerId:null,
+                    tags:null,
+                 
+                },
+                // 表单校验
+                rules: {
+                    tags: [
+                        { required: true, message: "标签不能为空", trigger: "change" }
+                    ],
+         
+                }
+                 
+            };
+        },
+        created() {
+            this.getDicts("crm_customer_tag").then((response) => {
+                this.tagsOptions = response.data;
+            });
+            
+            
+        },
+        methods: {
+            tagChange(e){
+                console.log(e)
+                var v=this.tagsOptions.find(value=>value.dictValue==e);
+                console.log(v)
+                this.tags.push(v.dictLabel);
+                this.form.tags=this.tags.toString();
+
+            },
+            reset(customer) {
+                this.tags= [];
+                this.form.customerId=customer.customerId;
+                this.form.tags=customer.tags;
+                if(this.form.tags!=null){
+                    this.tags=this.form.tags.split(",")
+                }
+            },
+            handleClose(tag) {
+                this.tags.splice(this.tags.indexOf(tag), 1);
+                this.form.tags=this.tags.toString();
+            },
+            showInput() {
+                this.inputVisible = true;
+                this.$nextTick(_ => {
+                    this.$refs.saveTagInput.focus();
+                });
+            },
+            handleInputConfirm() {
+                let inputValue = this.inputValue;
+                if (inputValue) {
+                    this.tags.push(inputValue);
+                }
+                this.inputVisible = false;
+                this.inputValue = '';
+                this.form.tags=this.tags.toString();
+            },
+            submitForm() {
+                this.$refs["form"].validate(valid => {
+                    if (valid) {
+                        updateCustomer(this.form).then(response => {
+                            if (response.code === 200) {
+                                this.msgSuccess("操作成功");
+                                
+                                this.$emit('close');
+                            }
+                        });
+                    }
+                });
+            },
+        }
+    };
+</script>
+<style lang="scss" scoped>
+.contents{
+    height: 100%;
+    background-color: #fff;
+    padding: 20px;
+        
+}
+.footer{
+    display: flex;
+    align-items: center;
+    justify-content: flex-end;
+}
+</style>
+
+
+
+ 

+ 294 - 0
src/views/fastGpt/fastGptChatMsg/index.vue

@@ -0,0 +1,294 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="用户昵称" prop="nickName">
+        <el-input
+          v-model="queryParams.nickName"
+          placeholder="请输入用户昵称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="客服角色" prop="roleId">
+        <el-select v-model="queryParams.roleId" placeholder="请选择客服角色" clearable size="small">
+          <el-option
+                v-for="item in roles"
+                :key="item.roleId"
+                :label="item.roleName"
+                :value="item.roleId"
+              />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="消息类型" prop="msgType">
+          <el-select v-model="queryParams.msgType" placeholder="请选择类型" clearable size="small">
+           <el-option
+             v-for="item in typeOptions"
+               :key="item.dictValue"
+               :label="item.dictLabel"
+               :value="item.dictValue"
+             />
+          </el-select>
+      </el-form-item>
+
+      <el-form-item label="发送时间" prop="createTime">
+        <el-date-picker
+           style="width:220px"
+           clearable size="small"
+           v-model="dateRange"
+           type="daterange"
+           value-format="yyyy-MM-dd"
+           start-placeholder="开始日期"
+           end-placeholder="结束日期">
+        </el-date-picker>
+      </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>
+      </el-form-item>
+    </el-form>
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['chat:chatMsg:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="chatMsgList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="ID" align="center" prop="msgId" />
+      <el-table-column label="用户" align="center" prop="nickName" />
+      <el-table-column label="头像" width="150" align="center">
+        <template slot-scope="scope">
+          <img :src="scope.row.avatar" style="height: 80px">
+        </template>
+      </el-table-column>
+      <el-table-column label="AI客服" align="center" prop="roleName" />
+      <el-table-column show-overflow-tooltip label="消息内容" align="center" prop="content" />
+      <el-table-column  label="消息类型"  align="center" prop="msgType">
+            <template slot-scope="scope">
+                <el-tag prop="type" v-for="(item, index) in typeOptions"    v-if="scope.row.msgType==item.dictValue">{{item.dictLabel}}</el-tag>
+              </template>
+      </el-table-column>
+      <el-table-column  label="发送方式"  align="center" prop="sendType">
+            <template slot-scope="scope">
+                <el-tag prop="type" v-for="(item, index) in sendTypeOptions"    v-if="scope.row.sendType==item.dictValue">{{item.dictLabel}}</el-tag>
+            </template>
+      </el-table-column>
+
+      <el-table-column label="发送时间" align="center" prop="createTime" />
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+  </div>
+</template>
+
+<script>
+import { listFastGptChatMsg, getFastGptChatMsg, delFastGptChatMsg, addFastGptChatMsg, updateFastGptChatMsg, exportFastGptChatMsg } from "@/api/fastGpt/fastGptChatMsg";
+import { getAllRoleList } from "@/api/fastGpt/fastGptRole";
+
+export default {
+  name: "ChatMsg",
+  data() {
+    return {
+      show:{
+              title:"聊天详情",
+              open:false,
+            },
+      roles:[],
+      dateRange:[],
+      typeOptions:[],
+      sendTypeOptions:[],
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 聊天消息记录表格数据
+      chatMsgList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        chatId: null,
+        content: null,
+        msgType: null,
+        sendType: null,
+        companyId: null,
+        roleId: null,
+        companyUserId: null,
+        msgJson: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getDicts("chat_msg_type").then((response) => {
+      this.typeOptions = response.data;
+    });
+    this.getDicts("chat_msg_send_type").then((response) => {
+      this.sendTypeOptions = response.data;
+    });
+    getAllRoleList().then(response => {
+        this.roles = response.data;
+    });
+    this.getList();
+  },
+  methods: {
+    handleShow(){
+
+    },
+    /** 查询聊天消息记录列表 */
+    getList() {
+      this.loading = true;
+      listFastGptChatMsg(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+        this.chatMsgList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        msgId: null,
+        chatId: null,
+        content: null,
+        msgType: null,
+        sendType: null,
+        companyId: null,
+        roleId: null,
+        companyUserId: null,
+        createTime: null,
+        msgJson: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.dateRange=null
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.msgId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加聊天消息记录";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const msgId = row.msgId || this.ids
+      getFastGptChatMsg(msgId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改聊天消息记录";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.msgId != null) {
+            updateFastGptChatMsg(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addFastGptChatMsg(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const msgIds = row.msgId || this.ids;
+      this.$confirm('是否确认删除聊天消息记录编号为"' + msgIds + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delFastGptChatMsg(msgIds);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有聊天消息记录数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportFastGptChatMsg(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>
+
+<style lang="css">
+  .el-tooltip__popper{
+    max-width:40%
+  }
+</style>

+ 200 - 0
src/views/fastGpt/fastGptChatSession/fastGptChatMsgDetails.vue

@@ -0,0 +1,200 @@
+<template>
+    <div style="background-color: #f0f2f5; padding-bottom: 20px; min-height: 100%; " >
+      <div style="padding: 20px; background-color: #fff;">
+         查看聊天记录
+      </div>
+      <div class="contentx" v-if="item!=null">
+          <div class="desct"> 会话详情</div>
+          <el-descriptions title="" :column="3" border>
+            <el-descriptions-item label="会话标识"><span v-if="item!=null">{{item.chatId}}</span></el-descriptions-item>
+            <el-descriptions-item label="咨询客户"><span v-if="item!=null">{{item.nickName}}</span></el-descriptions-item>
+            <el-descriptions-item label="客服账号" span="3"><span v-if="item!=null">{{item.roleName}}</span></el-descriptions-item>
+            <el-descriptions-item label="接待时间"><span v-if="item!=null">{{item.createTime}}</span></el-descriptions-item>
+            <el-descriptions-item label="结束时间"><span v-if="item!=null">{{item.updateTime}}</span></el-descriptions-item>
+            <el-descriptions-item label="服务状态">
+              <span v-if="item!=null"><dict-tag :options="sessionStatusOptions" :value="item.status"/> </span>
+            </el-descriptions-item>
+          </el-descriptions>
+      </div>
+      <div class="contentx" v-if="item!=null">
+          <div class="desct"> 查看聊天记录</div>
+          <div class="block">
+            <el-timeline>
+              <el-timeline-item v-for="(i, index) in msgList" :key="index" :timestamp="i.createTime" placement="top">
+                <el-card>
+                  <h4 v-if="i.sendType==1">{{ item.nickName }}</h4>
+                  <h4 v-else>{{item.roleName}}</h4>
+                  <p>{{i.content}}</p>
+                 <!-- <p v-if="i.sendType==2" style="color: #c8cacb;">{{i.status==1?'正确':'未标记'}}</p>
+                  <el-link type="primary" :underline="false" v-if="i.sendType==2" class="ivu-pl-8" @click="updateLogs(i.msgId)" style="float: right; margin-right: 20px; margin-bottom: 20px;">修改记录</el-link>
+                  <el-link type="primary" :underline="false" v-if="i.sendType==2" class="ivu-pl-8" @click="updateMsgStatus(i.msgId)" style="float: right; margin-right: 20px; ">√</el-link>
+                  <el-link type="primary" :underline="false" v-if="i.sendType==2" class="ivu-pl-8" @click="updateMsg(i.msgId)" style="float: right; margin-right: 20px; ">X</el-link> -->
+                </el-card>
+              </el-timeline-item>
+            </el-timeline>
+          </div>
+      </div>
+    <!-- 添加或修改聊天消息记录对话框 -->
+    <el-dialog title="修改聊天消息" :visible.sync="open" width="700px" append-to-body>
+      <el-form ref="form" :model="form"  label-width="80px">
+        <el-form-item label="消息内容">
+          <el-input type="textarea" v-model="form.content" :rows="12"/>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+    <el-dialog title="修改记录" :visible.sync="logsOpen" width="800px" append-to-body>
+      <el-timeline>
+        <el-timeline-item v-for="(i, index) in chatMsgLogsList" :key="index" :timestamp="i.createTime" placement="top">
+          <el-card>
+            <h4 v-if="i.logsType==1">标记正确</h4>
+            <h4 v-else>修改回复</h4>
+            <p style="float: right;">{{i.nickName}}</p>
+            <p>{{i.content}}</p>
+          </el-card>
+        </el-timeline-item>
+      </el-timeline>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="logsCancel">确 定</el-button>
+      </div>
+    </el-dialog>
+
+
+    </div>
+</template>
+
+<script>
+import { getFastGptChatMsg, updateFastGptChatMsg } from "@/api/fastGpt/fastGptChatMsg";
+
+import { getFastGptChatSession } from "@/api/fastGpt/fastGptChatSession";
+import { getAllRoleList } from "@/api/fastGpt/fastGptRole";
+import { listFastGptChatMsgLogs} from "@/api/fastGpt/fastGptChatMsgLogs";
+  export default {
+    name: "fastGptChatMsgDetails",
+    data() {
+      return {
+        sessionStatusOptions:[],
+        open:false,
+        logsOpen:false,
+        // 方剂类型字典
+        typeOptions:[],
+        sendTypeOptions:[],
+        roles:[],
+        msgList:[],
+        chatMsgLogsList:[],
+        // 状态字典
+        statusOptions: [],
+        item:null,
+        form: {},
+      }
+    },
+    created() {
+      this.getDicts("sys_chat_session_status").then(response => {
+        this.sessionStatusOptions = response.data;
+      });
+      this.getDicts("chat_msg_type").then((response) => {
+        this.typeOptions = response.data;
+      });
+      this.getDicts("chat_msg_send_type").then((response) => {
+        this.sendTypeOptions = response.data;
+      });
+      getAllRoleList().then(response => {
+          this.roles = response.data;
+      });
+    },
+    methods: {
+      getDetails(id) {
+        this.item=null;
+        getFastGptChatSession(id).then(response => {
+            this.item = response.data;
+            this.msgList = response.list;
+        });
+      },
+      updateMsg(row){
+         this.form = null;
+          getFastGptChatMsg(row).then(response => {
+          this.open = true;
+          this.form = response.data;
+        });
+      },
+      updateMsgStatus(row){
+        var statusForm={
+          msgId:row,
+          status:1
+        }
+        this.$confirm('是否确认标记?', "警告", {
+            confirmButtonText: "确定",
+            cancelButtonText: "取消",
+            type: "warning"
+          }).then(() => {
+            this.exportLoading = true;
+            return updateFastGptChatMsg(statusForm);
+          }).then(response => {
+            this.msgSuccess("修改成功");
+            this.open = false;
+          var status=  this.msgList.find(item => item.msgId ==row);
+          status.status=1;
+          }).catch(() => {});
+
+
+      },
+      updateLogs(row){
+        this.logsOpen=true;
+        var queryParams= {
+          msgId: row
+        }
+        listFastGptChatMsgLogs(queryParams).then(response => {
+          this.chatMsgLogsList = response.rows;
+        });
+      },
+      logsCancel(){
+        this.logsOpen=false;
+      },
+      submitForm(){
+        var submitForm={
+          msgId:this.form.msgId,
+          content:this.form.content
+        }
+        updateFastGptChatMsg(submitForm).then(response => {
+          this.msgSuccess("修改成功");
+          this.open = false;
+          var status=  this.msgList.find(item => item.msgId ==this.form.msgId);
+          status.content=this.form.content;
+        });
+      },
+      cancel(){
+          this.open = false;
+      }
+    }
+  }
+</script>
+<style>
+  .contentx{
+      height: 100%;
+      background-color: #fff;
+      padding: 0px 20px 20px;
+
+
+      margin: 20px;
+  }
+  .el-descriptions-item__label.is-bordered-label{
+    font-weight: normal;
+  }
+  .el-descriptions-item__content {
+    max-width: 150px;
+    min-width: 100px;
+  }
+  .desct{
+      padding-top: 20px;
+      padding-bottom: 20px;
+      color: #524b4a;
+      font-weight: bold;
+    }
+  .padding-a{
+    padding-right: 10px;
+
+  }
+</style>

+ 480 - 0
src/views/fastGpt/fastGptChatSession/index.vue

@@ -0,0 +1,480 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="会话标识" prop="chatId">
+        <el-input
+          v-model="queryParams.chatId"
+          placeholder="请输入会话标识"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="客户昵称" prop="nickName">
+        <el-input
+          v-model="queryParams.nickName"
+          placeholder="请输入客户昵称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+	  <el-form-item label="角色昵称" prop="roleName">
+	    <el-input
+	      v-model="queryParams.roleName"
+	      placeholder="请输入角色昵称"
+	      clearable
+	      size="small"
+	      @keyup.enter.native="handleQuery"
+	    />
+	  </el-form-item>
+	  <el-form-item label="企微账号" prop="qwUserName">
+	    <el-input
+	      v-model="queryParams.qwUserName"
+	      placeholder="请输入企微账号"
+	      clearable
+	      size="small"
+	      @keyup.enter.native="handleQuery"
+	    />
+	  </el-form-item>
+      <el-form-item label="会话状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
+          <el-option
+            v-for="item in sessionStatusOptions"
+            :key="item.dictValue"
+            :label="item.dictLabel"
+            :value="item.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+		<el-form-item label="是否人工" prop="isArtificial">
+		  <el-select v-model="queryParams.isArtificial" placeholder="请选择状态" clearable size="small">
+		    <el-option
+		      v-for="item in orOptions"
+		      :key="item.dictValue"
+		      :label="item.dictLabel"
+		      :value="item.dictValue"
+		    />
+		  </el-select>
+		</el-form-item>
+      <el-form-item label="查看状态" prop="isLook">
+        <el-select v-model="queryParams.isLook" placeholder="请选择" clearable size="small">
+          <el-option
+            v-for="item in sessionLookOptions"
+            :key="item.dictValue"
+            :label="item.dictLabel"
+            :value="item.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="接待时间" prop="createTime">
+        <el-date-picker
+          style="width:220px"
+          clearable size="small"
+          v-model="dateRange"
+          type="daterange"
+          value-format="yyyy-MM-dd"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期">
+          @change="changeTime"
+        </el-date-picker>
+      </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>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+<!--      <el-col :span="1.5">-->
+<!--        <el-button-->
+<!--          type="primary"-->
+<!--          plain-->
+<!--          icon="el-icon-plus"-->
+<!--          size="mini"-->
+<!--          @click="handleAdd"-->
+<!--          v-hasPermi="['fastGpt:fastGptChatSession:add']"-->
+<!--        >新增</el-button>-->
+<!--      </el-col>-->
+<!--      <el-col :span="1.5">-->
+<!--        <el-button-->
+<!--          type="success"-->
+<!--          plain-->
+<!--          icon="el-icon-edit"-->
+<!--          size="mini"-->
+<!--          :disabled="single"-->
+<!--          @click="handleUpdate"-->
+<!--          v-hasPermi="['fastGpt:fastGptChatSession:edit']"-->
+<!--        >修改</el-button>-->
+<!--      </el-col>-->
+    <el-col :span="1.5">
+       <el-button
+         type="danger"
+         plain
+         icon="el-icon-delete"
+         size="mini"
+         :disabled="multiple"
+         @click="handleDelete"
+         v-hasPermi="['fastGpt:fastGptChatSession:remove']"
+       >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['fastGpt:fastGptChatSession:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" border :data="fastGptChatSessionList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="会话标识" align="center" prop="chatId" />
+      <el-table-column label="咨询客户" align="center" prop="nickName" />
+      <el-table-column label="头像" align="center" prop="avatar" >
+        <template slot-scope="scope">
+          <el-image
+            v-if="scope.row.avatar != null"
+            :src="scope.row.avatar"
+            :preview-src-list="[scope.row.avatar]"
+            :style="{ width: '100px', height: '100px' }"
+          ></el-image>
+        </template>
+      </el-table-column>
+      <el-table-column label="角色昵称" align="center" prop="roleName" />
+	  <el-table-column label="企微账号" align="center" prop="qwUserName" />
+	  
+      <el-table-column label="接待时间" align="center" prop="createTime" >
+        <template slot-scope="scope">
+          <span v-if="!scope.row.updateTime && scope.row.status === 1">
+            {{ scope.row.createTime }} - 未结束
+          </span>
+          <span v-else>
+            {{ scope.row.createTime }} - {{ scope.row.updateTime }}
+          </span>
+        </template>
+      </el-table-column>
+      <el-table-column label="会话状态" align="center" prop="status" >
+        <template slot-scope="scope">
+          <el-tag prop="status" v-for="(item, index) in sessionStatusOptions"    v-if="scope.row.status==item.dictValue">{{item.dictLabel}}</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="查看状态" align="center" prop="isLook" >
+        <template slot-scope="scope">
+          <el-tag prop="isLook" v-for="(item, index) in sessionLookOptions"    v-if="scope.row.isLook==item.dictValue">{{item.dictLabel}}</el-tag>
+        </template>
+      </el-table-column>
+	  <el-table-column label="是否人工" align="center" prop="isArtificial" >
+	    <template slot-scope="scope">
+	      <el-tag prop="isArtificial" v-for="(item, index) in orOptions"    v-if="scope.row.isArtificial==item.dictValue">{{item.dictLabel}}</el-tag>
+	    </template>
+	  </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            @click="handleDetails(scope.row)"
+          >查看</el-button>
+		  <el-button v-if="scope.row.isArtificial==0"
+		    size="mini"
+		    type="text"
+		    @click="Artificial(scope.row,1)"
+		  >转人工</el-button>
+		  <el-button v-if="scope.row.isArtificial==1"
+		    size="mini"
+		    type="text"
+		    @click="Artificial(scope.row,0)"
+		  >转Ai</el-button>
+        </template>
+
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+<!--    &lt;!&ndash; 添加或修改对话关系对话框 &ndash;&gt;-->
+<!--    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>-->
+<!--      <el-form ref="form" :model="form" :rules="rules" label-width="80px">-->
+<!--        <el-form-item label="聊天id" prop="chatId">-->
+<!--          <el-input v-model="form.chatId" placeholder="请输入聊天id" />-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="客户ID uid" prop="userId">-->
+<!--          <el-input v-model="form.userId" placeholder="请输入客户ID uid" />-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="客服ID 应用id?" prop="kfId">-->
+<!--          <el-input v-model="form.kfId" placeholder="请输入客服ID 应用id?" />-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="状态 1会话中 2已结束">-->
+<!--          <el-radio-group v-model="form.status">-->
+<!--            <el-radio label="1">请选择字典生成</el-radio>-->
+<!--          </el-radio-group>-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="公司ID" prop="companyId">-->
+<!--          <el-input v-model="form.companyId" placeholder="请输入公司ID" />-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="是否查看" prop="isLook">-->
+<!--          <el-input v-model="form.isLook" placeholder="请输入是否查看" />-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="用户类型 1微信用户 2小程序用户 3销售用户" prop="userType">-->
+<!--          <el-select v-model="form.userType" placeholder="请选择用户类型 1微信用户 2小程序用户 3销售用户">-->
+<!--            <el-option label="请选择字典生成" value="" />-->
+<!--          </el-select>-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="客户昵称" prop="nickName">-->
+<!--          <el-input v-model="form.nickName" placeholder="请输入客户昵称" />-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="头像" prop="avatar">-->
+<!--          <el-input v-model="form.avatar" placeholder="请输入头像" />-->
+<!--        </el-form-item>-->
+<!--      </el-form>-->
+<!--      <div slot="footer" class="dialog-footer">-->
+<!--        <el-button type="primary" @click="submitForm">确 定</el-button>-->
+<!--        <el-button @click="cancel">取 消</el-button>-->
+<!--      </div>-->
+<!--    </el-dialog>-->
+    <el-drawer
+      :with-header="false"
+      size="75%"  @close="handleDrawerClose"
+      :title="show.title" :visible.sync="show.open">
+      <fastGptChatMsgDetails  ref="Details" />
+    </el-drawer>
+  </div>
+</template>
+
+<script>
+import { listFastGptChatSession, getFastGptChatSession, delFastGptChatSession, addFastGptChatSession, updateFastGptChatSession, exportFastGptChatSession } from "@/api/fastGpt/fastGptChatSession";
+import fastGptChatMsgDetails from "@/views/fastGpt/fastGptChatSession/fastGptChatMsgDetails.vue";
+
+export default {
+  name: "FastGptChatSession",
+  components: {fastGptChatMsgDetails},
+  data() {
+    return {
+      show:{
+        title:"聊天详情",
+        open:false,
+      },
+      //接待时间
+      dateRange:[],
+      //会话状态
+      sessionStatusOptions:[],
+      //查看状态
+      sessionLookOptions:[],
+	  orOptions:[],
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 对话关系表格数据
+      fastGptChatSessionList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        chatId: null,
+        userId: null,
+        kfId: null,
+        status: null,
+        companyId: null,
+        isLook: null,
+        userType: null,
+        nickName: null,
+        avatar: null,
+		qwUserName: null,
+		roleName: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getDicts("sys_chat_session_status").then(response => {
+      this.sessionStatusOptions = response.data;
+    });
+    this.getDicts("sys_chat_session_look").then(response => {
+      this.sessionLookOptions = response.data;
+    });
+	this.getDicts("sys_company_or").then(response => {
+	  this.orOptions = response.data;
+	});
+    this.getList();
+  },
+  methods: {
+	  Artificial(row,id){
+		  this.form.sessionId=row.sessionId
+		  this.form.isArtificial=id
+		  updateFastGptChatSession(this.form).then(response => {
+		    this.msgSuccess("修改成功");
+		    this.open = false;
+		    this.getList();
+		  });
+	  },
+    /** 查询对话关系列表 */
+    getList() {
+      this.loading = true;
+      listFastGptChatSession(this.queryParams).then(response => {
+        this.fastGptChatSessionList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    //查看按钮
+    handleDetails(row){
+      this.show.open=true;
+      setTimeout(() => {
+        this.$refs.Details.getDetails(row.sessionId);
+      }, 500);
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        sessionId: null,
+        chatId: null,
+        userId: null,
+        kfId: null,
+        createTime: null,
+        updateTime: null,
+        status: 0,
+        companyId: null,
+        isLook: null,
+        userType: null,
+        nickName: null,
+        avatar: null
+      };
+      this.resetForm("form");
+    },
+    //关闭
+    handleDrawerClose(){
+      this.getList();
+    },
+    /**
+    * 会话时间
+    */
+    changeTime(){
+      if(this.dateRange!=null){
+        this.queryParams.beginTime=this.dateRange[0];
+        this.queryParams.endTime=this.dateRange[1];
+      }else{
+        this.queryParams.beginTime=null;
+        this.queryParams.endTime=null;
+      }
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.sessionId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加对话关系";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const sessionId = row.sessionId || this.ids
+      getFastGptChatSession(sessionId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改对话关系";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.sessionId != null) {
+            updateFastGptChatSession(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addFastGptChatSession(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const sessionIds = row.sessionId || this.ids;
+      this.$confirm('是否确认删除对话关系编号为"' + sessionIds + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delFastGptChatSession(sessionIds);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有对话关系数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportFastGptChatSession(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 46 - 34
src/views/his/aiWorkflow/design.vue

@@ -16,11 +16,11 @@
         </el-select>
       </div>
       <div class="toolbar-right">
-        <el-input 
-          v-model="form.workflowDesc" 
-          placeholder="工作流描述" 
-          size="small" 
-          style="width: 200px; margin-right: 10px" 
+        <el-input
+          v-model="form.workflowDesc"
+          placeholder="工作流描述"
+          size="small"
+          style="width: 200px; margin-right: 10px"
         />
         <el-divider direction="vertical" />
         <el-button icon="el-icon-zoom-in" size="small" @click="zoomIn">放大</el-button>
@@ -57,7 +57,7 @@
       <div
         class="canvas-container"
         ref="canvasContainer"
-        tabindex="0" 
+        tabindex="0"
         @drop="onDrop"
         @dragover.prevent
         @click="onCanvasClick"
@@ -74,7 +74,7 @@
             </pattern>
           </defs>
           <rect :width="canvasSize.width" :height="canvasSize.height" fill="url(#grid)" />
-          
+
           <!-- 连线 -->
           <g class="edges-layer" :transform="`translate(${canvasOffset.x}, ${canvasOffset.y}) scale(${scale})`">
             <g
@@ -159,16 +159,21 @@
           {{ selectedNode ? '节点属性' : '连线属性' }}
           <i class="el-icon-close" @click="clearSelection"></i>
         </div>
-        
+
         <!-- 节点属性 -->
         <el-form v-if="selectedNode" label-width="80px" size="small">
           <el-form-item label="节点内容">
-            <el-input 
-              v-model="selectedNode.nodeName" 
+            <el-input
+              v-model="selectedNode.nodeName"
               type="textarea"
               :autosize="{ minRows: 1, maxRows: 6 }"
             />
           </el-form-item>
+          <div v-if="selectedNode.nodeType == 'http'">
+            <el-form-item label="URL地址">
+              <el-input v-model="selectedNode.nodeConfig.url" />
+            </el-form-item>
+          </div>
           <el-form-item label="节点类型">
             <el-input :value="getNodeTypeName(selectedNode.nodeType)" disabled />
           </el-form-item>
@@ -276,7 +281,7 @@ export default {
     this.$nextTick(() => {
       this.$refs.canvasContainer.focus()  // 这里应该是 canvasContainer 不是 container
     })
-    
+
     // 添加全局键盘事件监听
     // window.addEventListener('keydown', this.handleGlobalKeydown)
     document.addEventListener('mousemove', this.onMouseMove)
@@ -292,33 +297,34 @@ export default {
     focusCanvasContainer() {
       this.$refs.canvasContainer.focus()
     },
-    
+
     // 点击画布时聚焦
     onCanvasClick() {
       this.clearSelection()
       this.focusCanvasContainer()
     },
-    
+
     // 点击节点时聚焦
     selectNode(node) {
       this.selectedNode = node
+      this.selectedNode.nodeConfig = JSON.parse(node.nodeConfig)
       this.selectedEdge = null
       this.focusCanvasContainer()
     },
-    
+
     // 点击连线时聚焦
     selectEdge(edge) {
       this.selectedEdge = edge
       this.selectedNode = null
       this.focusCanvasContainer()
     },
-    
+
     // 局部键盘事件
     handleDelete(event) {
       event.preventDefault() // 阻止默认行为(如浏览器后退)
       this.deleteSelected()
     },
-    
+
     // 全局键盘事件
     // handleGlobalKeydown(event) {
     //   // 检查是否按下了退格键或删除键
@@ -327,7 +333,7 @@ export default {
     //     this.deleteSelected()
     //   }
     // },
-    
+
     // 删除选中项的逻辑
     deleteSelected() {
       if (this.selectedNode) {
@@ -336,7 +342,7 @@ export default {
         this.deleteSelectedEdge()
       }
     },
-    
+
     // 删除选中节点
     deleteSelectedNode() {
       if (!this.selectedNode) return
@@ -349,16 +355,16 @@ export default {
         const key = this.selectedNode.nodeKey
         this.nodes = this.nodes.filter(n => n.nodeKey !== key)
         // 同时删除与该节点相关的连线
-        this.edges = this.edges.filter(e => 
+        this.edges = this.edges.filter(e =>
           e.sourceNodeKey !== key && e.targetNodeKey !== key)
         this.selectedNode = null
       }).catch(() => {})
     },
-    
+
     // 删除选中连线
     deleteSelectedEdge() {
       if (!this.selectedEdge) return
-      
+
       this.$confirm('是否确认删除该连线?', '警告', {
         confirmButtonText: '确定',
         cancelButtonText: '取消',
@@ -368,7 +374,7 @@ export default {
         this.selectedEdge = null
       }).catch(() => {})
     },
-    
+
     // 检查是否有输入框获得焦点
     isInputFocused() {
       const activeElement = document.activeElement
@@ -378,7 +384,7 @@ export default {
       const isNodeInput = activeElement.classList && activeElement.classList.contains('node-name-input')
       return isEditable || isNodeInput
     },
-    
+
     /** 加载节点类型 */
     loadNodeTypes() {
       getNodeTypes().then(res => {
@@ -405,6 +411,7 @@ export default {
         basic: { key: 'basic', name: '基础节点', types: [] },
         logic: { key: 'logic', name: '逻辑节点', types: [] },
         ai: { key: 'ai', name: 'AI节点', types: [] },
+        ai: { key: 'ai-cell', name: '外呼几点', types: [] },
         integration: { key: 'integration', name: '集成节点', types: [] }
       }
       this.nodeTypes.forEach(t => {
@@ -461,7 +468,7 @@ export default {
       const rect = this.$refs.canvasContainer.getBoundingClientRect()
       const x = (e.clientX - rect.left - this.canvasOffset.x) / this.scale
       const y = (e.clientY - rect.top - this.canvasOffset.y) / this.scale
-      
+
       const newNode = {
         nodeKey: this.generateKey(),
         nodeName: nodeType.typeName,
@@ -479,7 +486,7 @@ export default {
       // 检测并扩展画布
       this.checkAndExpandCanvas(newNode)
     },
-    
+
     /** 画布鼠标按下 */
     onCanvasMouseDown(e) {
       // 只响应左键且点击在空白区域
@@ -495,7 +502,7 @@ export default {
         e.preventDefault()
       }
     },
-    
+
     /** 清除选中 */
     clearSelection() {
       this.selectedNode = null
@@ -553,10 +560,10 @@ export default {
       const nodeHeight = node.height || 36
       const padding = 200 // 边缘预留空间
       const expandStep = 500 // 每次扩展的大小
-      
+
       const nodeRight = node.posX + this.nodeWidth
       const nodeBottom = node.posY + nodeHeight
-      
+
       // 检测右边缘
       if (nodeRight + padding > this.canvasSize.width) {
         this.canvasSize.width += expandStep
@@ -626,10 +633,10 @@ export default {
     },
     /** 创建连线 */
     createEdge(sourceKey, targetKey, sourceAnchor, targetAnchor) {
-      const exists = this.edges.find(e => 
+      const exists = this.edges.find(e =>
         e.sourceNodeKey === sourceKey && e.targetNodeKey === targetKey)
       if (exists) return
-      
+
       this.edges.push({
         edgeKey: 'edge_' + Date.now(),
         sourceNodeKey: sourceKey,
@@ -645,7 +652,7 @@ export default {
       const sourceNode = this.nodes.find(n => n.nodeKey === edge.sourceNodeKey)
       const targetNode = this.nodes.find(n => n.nodeKey === edge.targetNodeKey)
       if (!sourceNode || !targetNode) return ''
-      
+
       const start = this.getAnchorPos(sourceNode, edge.sourceAnchor || 'bottom')
       const end = this.getAnchorPos(targetNode, edge.targetAnchor || 'top')
       return this.calcPath(start.x, start.y, end.x, end.y)
@@ -689,16 +696,21 @@ export default {
         this.msgWarning('请输入工作流名称')
         return
       }
+      const nodes = JSON.parse(JSON.stringify(this.nodes))
+      nodes.filter(node => typeof node.nodeConfig == 'object').forEach(node => {
+        console.log(typeof node.nodeConfig)
+        node.nodeConfig = JSON.stringify(node.nodeConfig);
+      })
       const data = {
         workflowId: this.workflowId,
         workflowName: this.form.workflowName,
         workflowDesc: this.form.workflowDesc,
         workflowType: this.form.workflowType,
         canvasData: JSON.stringify({ scale: this.scale, offset: this.canvasOffset }),
-        nodes: this.nodes,
+        nodes: nodes,
         edges: this.edges
       }
-      
+
       if (this.workflowId) {
         updateWorkflow(data).then(() => {
           this.msgSuccess('保存成功')
@@ -717,4 +729,4 @@ export default {
 
 <style lang="scss" scoped>
 @import './design.scss';
-</style>
+</style>

+ 0 - 2
src/views/his/company/index.vue

@@ -197,7 +197,6 @@
           >扣款
           </el-button>
           <el-button
-            v-if="showRedPacket"
             size="mini"
             type="text"
             icon="el-icon-edit"
@@ -206,7 +205,6 @@
           >红包充值
           </el-button>
           <el-button
-            v-if="showRedPacket"
             size="mini"
             type="text"
             icon="el-icon-edit"

+ 1121 - 0
src/views/qw/autoTags/dayPartingIndex.vue

@@ -0,0 +1,1121 @@
+<template>
+  <div>
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+      <el-form-item label="企微公司" prop="corpId">
+        <el-select v-model="queryParams.corpId" placeholder="企微公司" size="small" @change="updateCorpId()">
+          <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="companyId">
+          <el-select v-model="queryParams.companyId" placeholder="公司"  size="small" @change="updateCompanyId()">
+            <el-option
+              v-for="dict in myCompanyList"
+              :key="dict.companyId"
+              :label="dict.companyName"
+              :value="dict.companyId"
+            />
+          </el-select>
+      </el-form-item> -->
+      <el-form-item label="规则名称:" prop="ruleName">
+        <el-input
+          v-model="queryParams.ruleName"
+          placeholder="请输入规则名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="生效成员:" prop="appleUserOne">
+        <el-select v-model="queryParams.appleUserOne" filterable clearable placeholder="选择成员" size="small">
+          <el-option
+            v-for="dict in userList"
+            :key="dict.id"
+            :label="dict.qwUserName"
+            :value="dict.id"
+          />
+        </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>
+        <el-button
+          type="primary"
+          size="mini"
+          plain
+          icon="el-icon-plus"
+          @click="handleAdd"
+          v-hasPermi="['qw:autoTags:add']"
+        >添加规则</el-button>
+      </el-form-item>
+
+    </el-form>
+    <!--      <div style="padding:0 0 15px 0">-->
+    <!--        <el-button-->
+    <!--          type="primary"-->
+    <!--          size="small"-->
+    <!--          plain-->
+    <!--          icon="el-icon-plus"-->
+    <!--          @click="handleAdd"-->
+    <!--          v-hasPermi="['shop:tags:add']"-->
+    <!--        >添加规则</el-button>-->
+    <!--      </div>-->
+    <el-table v-loading="loading" :data="dayPartingIndexList" border height="550px" >
+      <el-table-column label="规则名称" align="center" prop="ruleName" />
+      <el-table-column label="已打标签总数" align="center" prop="totalNumTagsCount" />
+      <el-table-column label="生效成员" align="center">
+        <template slot-scope="scope">
+               <span v-for="userId in JSON.parse(scope.row.applyUsers)" :key="userId" style="display: inline;width: 300px">
+                <el-tag :disable-transitions="false"  v-for="list in userList" :key="list.id" style="margin: 3px;" v-if="list.id==userId">{{list.qwUserName}}({{list.nickName}})</el-tag>
+              </span>
+        </template>
+      </el-table-column>
+      <el-table-column label="添加的标签" align="center" prop="tagIdsName">
+        <template slot-scope="scope">
+          <div class="tag-container">
+            <div class="tag-list">
+              <div v-for="name in scope.row.tagIdsName" style="display: inline;">
+                <el-tag type="success">{{ name }}</el-tag>
+              </div>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createTime" />
+      <el-table-column label="规则状态" align="center" prop="isApply">
+        <template slot-scope="scope">
+          <el-switch
+            v-model="scope.row.isApply"
+            active-color="#13ce66"
+            inactive-color="#ff4949"
+            active-value="1"
+            inactive-value="2"
+            @change="switchChange(scope.row)">
+          </el-switch>
+          <span v-if="scope.row.isApply == '1'" style="margin-left: 10px;color: #13ce66">已启用</span>
+          <span v-if="scope.row.isApply == '2'" style="margin-left: 10px;color: #ff4949">已关闭</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['qw:autoTags:edit']"
+          >修改成员</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleDetails(scope.row)"
+            v-hasPermi="['qw:autoTags:query']"
+          >详情</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['qw:autoTags:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改自动打标签主对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="1000px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-position="left"  label-width="120px">
+        <div class="app-container">
+          <div>
+            <span style="font-size: 15px">规则基础信息</span>
+            <el-divider></el-divider>
+          </div>
+          <el-alert
+            title="根据规则,当客户在设定时间段内成为企业微信客户,将自动被打上标签"
+            type="warning"
+            style="font-size: 15px;margin-bottom: 2%;"
+            :closable="false"
+            show-icon>
+          </el-alert>
+          <el-form-item label="规则名称:" prop="ruleName" style="width: 400px">
+            <el-input v-model="form.ruleName" placeholder="请输入规则名称(内部可见)" />
+          </el-form-item>
+
+          <el-form-item label="生效成员:" prop="applyUsers">
+            <div>
+              <el-button
+                size="medium"
+                icon="el-icon-circle-plus-outline"
+                plain
+                @click="handlelistUser">请选择使用成员</el-button>
+            </div>
+            <div>
+              <el-tag
+                style="margin-left: 5px"
+                size="medium"
+                :key="list.id"
+                v-for="list in userSelectList"
+                closable
+                :disable-transitions="false"
+                @close="handleClosegroupUser(list)">
+                {{list.qwUserName}}({{list.nickName}})
+              </el-tag>
+            </div>
+          </el-form-item>
+          <div style="margin-top: 5%">
+            <span style="font-size: 15px">设置打标签的规则</span>
+            <el-divider></el-divider>
+          </div>
+
+          <div  v-for="(item, index) in form.rulesTags"    :key="index" >
+            <div style="background-color: #fbfbfb;padding: 10px;  border: 1px solid #e6e6e6; margin-bottom: 10px;">
+              <el-form ref="rulesTagsFrom" :rules="rulesTagsRules" :model="item" >
+                <div>
+                  <el-form-item label="执行规则" prop="dayOrWeek" style="width: 500px;margin:5px 0 0 8%">
+                    <el-radio-group v-model="item.dayOrWeek">
+                      <el-radio :label="0">星期</el-radio>
+                      <el-radio :label="1">日期</el-radio>
+                    </el-radio-group>
+                  </el-form-item>
+                  <div style="display: flex; align-items: center; flex-wrap: nowrap;">
+                    <span style="margin-right: 10px;">规则 {{ index + 1 }}:</span>
+                    <el-form-item label="为每:" prop="week" style="flex: 8;margin-bottom: 0" v-if="item.dayOrWeek == 0">
+                      <el-select v-model="item.week" remote multiple placeholder="请选择时间" filterable style="width: 350px;">
+                        <el-option v-for="dict in weekOptions" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
+                      </el-select>
+                    </el-form-item>
+                    <el-form-item label="为每:" prop="days" style="flex: 8;margin-bottom: 0" v-if="item.dayOrWeek == 1">
+                      <el-date-picker
+                        clearable size="small"
+                        v-model="item.days"
+                        type="daterange"
+                        value-format="yyyy-MM-dd"
+                        start-placeholder="开始日期"
+                        end-placeholder="结束日期">
+                      </el-date-picker>
+                    </el-form-item>
+                    <el-form-item prop="startTime" style="margin:0 5px 0 5px">
+                      <el-time-select style="width: 120px;" placeholder="起始时间" v-model="item.startTime" :picker-options="{
+                              start: '00:00',
+                              step: '00:15',
+                              end: '24:00'
+                            }"></el-time-select>
+                    </el-form-item>
+                    <el-form-item prop="endTime" style="margin:0 5px 0 5px">
+                      <el-time-select style="width: 120px;" placeholder="结束时间" v-model="item.endTime" :picker-options="{
+                              start: '00:00',
+                              step: '00:15',
+                              end: '24:00',
+                              minTime: item.startTime
+                            }"></el-time-select>
+                    </el-form-item>
+                    <div style="display: flex; align-items: center;width: 100px">
+                      <span>添加的客户</span>
+                    </div>
+                  </div>
+
+                  <el-form-item prop="tags" style="width: 500px;margin:5px 0 0 8%">
+                    <div style="display: flex; align-items: center;">
+                      <div style="width: 50px">
+                        <span>打上</span>
+                      </div>
+                      <div @click="handleChangeTags(item,index)" style="cursor: pointer; border: 1px solid #e6e6e6; background-color: white; overflow: hidden; flex-grow: 1;width: 390px">
+                        <div style="min-height: 35px; max-height: 200px; overflow-y: auto;">
+                          <el-tag type="success"
+                                  closable
+                                  :disable-transitions="false"
+                                  v-for="list in tagListFormIndex[index]"
+                                  :key="list.tagId"
+                                  @close="handleCloseTag(list,index)"
+                                  style="margin: 3px;"
+                          >{{list.name}}
+                          </el-tag>
+                        </div>
+                      </div>
+                      <div style="width: 70px">
+                        <span style="margin:0px 10px;">的标签</span>
+                      </div>
+                    </div>
+                  </el-form-item>
+
+                  <el-form-item prop="remark" style="width: 500px;margin:5px 0 0 8%">
+                    <div style="display: flex; align-items: center;margin-top: 1%">
+                      <div style="width: 50px">
+                        <span>并备注</span>
+                      </div>
+                      <el-input v-model="item.remarks" style="width: 300px" placeholder="请输入备注(选填)"></el-input>
+                      <div style="width: 70px">
+                        <el-link v-if="form.rulesTags.length>1" icon="el-icon-delete-solid" @click="delItemList(index)" type="text" style="color: rgb(24, 144, 255);margin-left:10px;height: 40px " ></el-link>
+                      </div>
+                    </div>
+                  </el-form-item>
+                  <el-form-item label="备注日期"   prop="isDay" style="width: 500px;margin:5px 0 0 8%">
+                    <el-switch
+                      v-model="item.isDay"
+                      :active-value="1"
+                      :inactive-value="0"
+                    >
+                    </el-switch>
+                  </el-form-item>
+                </div>
+              </el-form>
+            </div>
+          </div>
+          <div>
+            <el-link type="primary" class="el-icon-plus" :underline="false" @click='addItemList()'>添加其他时段规则(最多7条)</el-link>
+          </div>
+        </div>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+
+    <!-- 选择成员账号弹窗   -->
+    <el-dialog :title="listUser.title" :visible.sync="listUser.open" width="1600px" append-to-body>
+      <qwUserList ref="QwUserList" @selectUserList="selectUserList"></qwUserList>
+    </el-dialog>
+    <!-- 选择成员账号弹窗修改   -->
+    <el-dialog :title="listUserUpdate.title" :visible.sync="listUserUpdate.open" width="1600px" append-to-body>
+      <qwUserList ref="QwUserList" @selectUserList="selectUserListUpdate"></qwUserList>
+    </el-dialog>
+
+    <el-dialog title="添加标签" :visible.sync="tagChange.open" width="800px" append-to-body>
+      <div>搜索标签:
+        <el-input v-model="queryTagParams.name" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags">搜索</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
+      </div>
+      <div v-for="item in tagGroupList" :key="item.id" >
+        <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
+          <span class="name-background">{{ item.name }}</span>
+        </div>
+        <!-- 添加外层滚动容器 -->
+        <div class="scroll-wrapper">
+          <div class="tag-container">
+            <a
+              v-for="tagItem in item.tag"
+              class="tag-box"
+              @click="tagSelection(tagItem)"
+              :class="{ 'tag-selected': tagItem.isSelected }"
+            >
+              {{ tagItem.name }}
+            </a>
+          </div>
+        </div>
+      </div>
+      <pagination
+        v-show="tagTotal>0"
+        :total="tagTotal"
+        :page.sync="queryTagParams.pageNum"
+        :limit.sync="queryTagParams.pageSize"
+        @pagination="getPageListTagGroup"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="addTagSubmitForm(tagChange.index)">确 定</el-button>
+        <el-button @click="addTagCancel(tagChange.index)">重 置</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 分时段详   -->
+    <el-drawer :title="detailFrom.title" :visible.sync="detailFrom.open" size="75%" style="font-weight: bolder">
+      <dayPartingIndexDetails :groupIndexFrom="detailListFrom"></dayPartingIndexDetails>
+    </el-drawer>
+
+    <!-- 单独修改员工标签   -->
+    <el-dialog :title="updateUserOpen.title" :visible.sync="updateUserOpen.open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" label-width="100px">
+        <el-form-item label="选择员工" prop="qwUserIds" style="margin-top: 2%">
+          <div>
+            <el-button
+              size="medium"
+              icon="el-icon-circle-plus-outline"
+              plain
+              @click="handlelistUserUpdate">请选择使用成员</el-button>
+          </div>
+          <div>
+            <el-tag
+              style="margin-left: 5px"
+              size="medium"
+              :key="id"
+              v-for="id in updateUserOpen.applyUsersUpdate"
+              closable
+              :disable-transitions="false"
+              @close="handleClosegroupUserUpdate(id)">
+              <span v-for="list in userList" :key="list.qwUserId" v-if="list.id==id">{{list.qwUserName}}({{list.nickName}})</span>
+            </el-tag>
+          </div>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer" >
+        <el-button  type="primary" @click="submitUpdateAutoTags">确 定</el-button>
+        <el-button  @click="cancelAutoTags">取 消</el-button>
+      </div>
+    </el-dialog>
+
+
+  </div>
+</template>
+
+<script>
+import { listTags,delTags, addTags, updateTags } from "../../../api/qw/autoTags";
+import qwUserList from '@/views/qw/user/qwUserList.vue'
+import {listTag, searchTags} from '@/api/qw/tag'
+import dayPartingIndexDetails from '@/views/qw/autoTags/dayPartingIndexDetails.vue'
+import { allListTagGroup } from '@/api/qw/tagGroup'
+import { listUser } from '@/api/qw/user'
+import { getMyQwUserList,getMyQwCompanyListAll } from "../../../api/qw/user";
+export default {
+  name: "autoTags",
+  components: { dayPartingIndexDetails, qwUserList },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      activeName:'2',
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      tagTotal:0,
+      // 自动打标签主表格数据
+      dayPartingIndexList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      myQwCompanyList:[],
+      //所有的标签组-标签
+      tagGroupList:[],
+
+      //所有标签
+      tagList:[],
+
+      //选择的标签
+      tagListFormIndex:[],
+
+      //成员信息
+      userList:[],
+
+      //标签弹窗选择
+      tagChange:{
+        open:false,
+        index:null,
+      },
+
+      queryTagParams: {
+        pageNum: 1,
+        pageSize: 5,
+        total:0,
+        name:null,
+        corpId:null,
+      },
+      //选择成员列表
+      listUser:{
+        title:"",
+        open:false
+      },
+
+      //选择成员列表 做修改
+      listUserUpdate:{
+        title:"",
+        open:false
+      },
+      //选择成员列表
+      userSelectList:[],
+
+      userSelectListUpdate:[],
+
+      //详情表单参数
+      detailListFrom:{},
+
+
+
+      //生效成员列表
+      updateUserOpen:{
+        title:"修改成员",
+        open:false,
+        id:null,
+        applyUsersUpdate:[],
+      },
+
+
+      //详情抽屉
+      detailFrom:{
+        open:false,
+        title:'',
+      },
+
+      weekOptions: [{
+        value: 1,
+        label: '星期一'
+      }, {
+        value: 2,
+        label: '星期二'
+      }, {
+        value: 3,
+        label: '星期三'
+      }, {
+        value: 4,
+        label: '星期四'
+      }, {
+        value: 5,
+        label: '星期五'
+      }
+        , {
+          value: 6,
+          label: '星期六'
+        }
+        , {
+          value: 7,
+          label: '星期天'
+        }],
+
+
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        type: 3,
+        createName: null,
+        applyUsers: null,
+        appleUserOne:null,
+        ruleName: null,
+        rulesTags: null,
+        totalNumTags: null,
+        numTagsTaday: null,
+        isApply: null,
+        corpId: null,
+        companyId: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        ruleName:[{ required: true, message: "规则名称不能为空", trigger: "blur" }],
+        applyUsers:[{ required: true, message: "成员不能为空", trigger: "blur" }],
+      },
+
+      //规则验证
+      rulesTagsRules:{
+        week: [
+          { required: true, message: '请选择发起时间的星期', trigger: 'submit' }
+        ],
+        startTime: [
+          { required: true, message: '请选择开始时间', trigger: 'submit' },
+        ],
+        endTime: [
+          { required: true, message: '请选择结束时间', trigger: 'submit' },
+
+        ],
+        tags: [
+          { required: true, message: '标签不能为空', trigger: 'submit' }
+        ],
+
+      },
+      //根据企微查出来的公司列表
+      // myCompanyList:[],
+
+    };
+  },
+
+  watch:{
+    // 监听 userSelectList 的变化,并同步更新 form.userIdsSelectList
+    userSelectList(newList) {
+      this.form.applyUsers = newList.map(item => item.id);
+    },
+
+    userSelectListUpdate(newList){
+      this.updateUserOpen.applyUsersUpdate = [...newList]
+    },
+
+    tagListFormIndex: {
+      handler(newList) {
+        // 遍历 tagListFormIndex 并将 tagId 放入对应位置的 tags
+        newList.forEach((tags, index) => {
+          if (!this.form.rulesTags[index]) {
+            this.$set(this.form.rulesTags, index, {tags:[],week:[1,2,3,4,5,6,7],startTime:null,endTime:null,remarks:null,dayOrWeek:0,days:null});
+          }
+
+          // 确保清空原来的 tags 数组
+          this.form.rulesTags[index].tags = [];
+
+          tags.forEach(item => {
+            // 将 tagId 放入对应位置的 rulesTags 中的 tags 数组
+            this.form.rulesTags[index].tags.push(item.tagId);
+          });
+        });
+      },
+      deep: true
+    }
+  },
+  created() {
+
+    getMyQwCompanyListAll().then(response => {
+      this.myQwCompanyList = response.data;
+      if(this.myQwCompanyList!=null){
+        this.queryParams.corpId=this.myQwCompanyList[0].dictValue
+        this.afreshData(this.queryParams.corpId);
+        this.getList();
+      }
+      // this.myQwCompanyList = response.data;
+      //       if(this.myQwCompanyList!=null){
+      //         this.queryParams.corpId=this.myQwCompanyList[0].dictValue;
+      //         getCompanyListByCorpId(this.queryParams.corpId).them(response =>{
+      //           this.myCompanyList = response.data;
+      //         })
+      //         if(this.myCompanyList != null){
+      //           this.queryParams.companyId = this.myCompanyList[0].companyId
+      //           this.afreshData(this.queryParams.corpId)
+      //           this.getList();
+      //         }
+      //       }
+    });
+  },
+  methods: {
+    updateCorpId(){
+//       this.myCompanyList = [];
+// getCompanyListByCorpId(this.queryParams.corpId).them(response =>{
+//                 this.myCompanyList = response.data;
+//               })
+      this.afreshData(this.queryParams.corpId);
+
+      this.getList();
+    },
+    // updateCompanyId(){
+      
+    //   this.afreshData(this.queryParams.corpId)
+    //   this.getList();
+    //  },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加规则";
+
+      this.getPageListTagGroup()
+
+      //所有的标签
+      listTag(this.queryTagParams).then(response => {
+        this.tagList = response.rows;
+      });
+
+    },
+
+    /**
+     * 重新获取 部分数据
+     */
+    afreshData(value){
+
+      this.resetSearchQueryTag()
+      this.queryTagParams.corpId=value;
+
+      //所有的员工
+      listUser({corpId:value}).then(res=>{
+        this.userList=res.rows;
+      })
+
+    },
+
+    resetSearchQueryTag(){
+
+      this.queryTagParams= {
+        pageNum: 1,
+        pageSize: 5,
+        total:0,
+        name:null,
+      };
+    },
+
+    //选择群发的企业成员账号
+    handlelistUser(){
+      setTimeout(() => {
+        this.$refs.QwUserList.getDetails(this.queryParams.corpId);
+      }, 1);
+      this.listUser.title="选择企业成员"
+      this.listUser.open=true;
+    },
+
+    //选择群发的企业成员账号做修改
+    handlelistUserUpdate(){
+      setTimeout(() => {
+        this.$refs.QwUserList.getDetails(this.queryParams.corpId);
+      }, 1);
+      this.listUserUpdate.title="选择企业成员"
+      this.listUserUpdate.open=true;
+    },
+
+    //选择的成员账号列表
+    selectUserList(list){
+
+      this.listUser.open=false;
+      //用于显示
+      // this.userSelectList=list;
+
+      list.forEach(obj => {
+        if (!this.form.applyUsers.some(item => item == obj.id)) {
+          this.userSelectList.push(obj);
+        }
+      });
+
+    },
+    //选择的成员账号列表 修改
+    selectUserListUpdate(list){
+
+      this.listUserUpdate.open=false;
+
+      list.forEach(obj => {
+        if (!this.updateUserOpen.applyUsersUpdate.some(item => item == obj.id)) {
+          this.userSelectListUpdate.push(obj.id);
+        }
+      });
+
+    },
+
+    handleSearchTags(){
+
+      if (!this.queryTagParams.name){
+        return this.$message.error("请输入要搜索的标签")
+      }
+      this.queryTagParams.corpId=this.queryParams.corpId;
+      searchTags(this.queryTagParams).then(response => {
+        this.tagGroupList = response.rows;
+        this.tagTotal = response.total;
+      });
+
+    },
+
+    getPageListTagGroup(){
+
+      this.queryTagParams.corpId=this.queryParams.corpId;
+
+      allListTagGroup(this.queryTagParams).then(response => {
+        this.tagGroupList = response.rows;
+        this.tagTotal = response.total;
+      });
+    },
+
+
+
+    cancelSearchTags(){
+      this.afreshData(this.queryParams.corpId)
+    },
+    //删除一些选择了的账号
+    handleClosegroupUser(list){
+
+      // 假设 list 对象具有一个 id 属性
+      const index = this.userSelectList.findIndex(t => t.id === list.id);
+      if (index !== -1) {
+        this.userSelectList.splice(index, 1);
+      }
+    },
+
+    //删除一些选择的标签
+    handleClosegroupUserUpdate(id){
+
+      const index = this.userSelectListUpdate.findIndex(item => item === id)
+      if (index !== -1) {
+        this.userSelectListUpdate.splice(index, 1)
+      }
+    },
+
+    /** 查询自动打标签主列表 */
+    getList() {
+      this.loading = true;
+      listTags(this.queryParams).then(response => {
+
+        this.dayPartingIndexList = response.rows;
+        // this.dayPartingIndexList.forEach(item => {
+        //   const tagsSet = new Set(); // 为每个项目创建一个新的 Set
+        //   try {
+        //     const data = JSON.parse(item.rulesTags); // 将每个 rulesTags JSON 字符串解析为 JavaScript 对象
+        //     data.forEach(entry => {
+        //       entry.tags.forEach(tag => {
+        //         tagsSet.add(tag); // 将每个 tag 添加到 Set 中
+        //       });
+        //     });
+        //   } catch (error) {
+        //     this.$message.error("Error parsing JSON:",error)
+        //   }
+        //   item.tagsSet = Array.from(tagsSet); // 将 Set 转换为数组并添加到当前项目
+        // });
+
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    //开关
+    switchChange(row){
+      updateTags(row).then(response => {
+        this.msgSuccess("修改成功");
+      });
+    },
+
+    //添加其他的规则
+    addItemList(){
+      if (this.form.rulesTags.length >=7) {
+        return this.$message.error('当前规则已达上限,无法添加规则');
+      }
+      this.form.rulesTags.push({tags:[],week:[1,2,3,4,5,6,7],startTime:null,endTime:null,remarks:null,dayOrWeek:0,days:null})
+    },
+
+    //选择标签弹窗
+    handleChangeTags(item,index){
+
+      for (let i = 0; i < this.tagGroupList.length; i++) {
+        for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+          this.tagGroupList[i].tag[x].isSelected=false;
+        }
+      }
+
+      this.tagChange.open=true;
+      this.tagChange.index=index;
+
+    },
+
+    //标签的选择
+    tagSelection(row){
+      row.isSelected= !row.isSelected;
+      this.$forceUpdate();
+    },
+
+    //选择标签
+    addTagSubmitForm(index){
+
+      for (let i = 0; i < this.tagGroupList.length; i++) {
+        for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+          if (this.tagGroupList[i].tag[x].isSelected === true) {
+            if (!this.tagListFormIndex[index]) {
+              this.$set(this.tagListFormIndex, index, []);
+            }
+
+            // 检查当前 tag 是否已经存在于 tagListFormIndex[index] 中
+            let tagExists = this.tagListFormIndex[index].some(
+              tag => tag.id === this.tagGroupList[i].tag[x].id
+            );
+
+            // 如果 tag 不存在于 tagListFormIndex[index] 中,则新增
+            if (!tagExists) {
+              this.tagListFormIndex[index].push(this.tagGroupList[i].tag[x]);
+            }
+          }
+        }
+      }
+      if (!this.tagListFormIndex[index] || this.tagListFormIndex[index].length === 0) {
+        return this.$message('请选择标签');
+      }
+
+      this.tagChange.open = false;
+    },
+    //取消选择标签
+    addTagCancel(index){
+      this.tagChange.open = false;
+      this.tagListFormIndex[index]=[];
+    },
+    //删除一些已经选择了的标签
+    handleCloseTag(list,index){
+
+      // 假设 list 对象具有一个 id 属性
+      const ls = this.tagListFormIndex[index].findIndex(t => t.tagId === list.tagId);
+      if (ls !== -1) {
+        this.tagListFormIndex[index].splice(ls, 1);
+        // 使用 Vue.set 方法
+        this.$set(this.tagListFormIndex, index, [...this.tagListFormIndex[index]]);
+      }
+    },
+
+    //删除某一个规则
+    delItemList(index){
+      this.form.rulesTags.splice(index,1)
+      this.tagListFormIndex.splice(index,1)
+    },
+
+
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        type: 3,
+        createName: null,
+        applyUsers: null,
+        ruleName: null,
+        rulesTags: [{tags:[],week:[1,2,3,4,5,6,7],startTime:null,endTime:null,remarks:null,dayOrWeek:0,days:null}],
+        totalNumTags: null,
+        numTagsTaday: null,
+        isApply: null,
+        createTime: null,
+        companyId: null,
+        remarks: null
+      };
+      //选择的成员
+      this.userSelectList=[];
+      //选择的标签
+      this.tagListFormIndex=[];
+
+      //规则
+      this.form.rulesTags=[{tags:[],week:[1,2,3,4,5,6,7],startTime:null,endTime:null,remarks:null,dayOrWeek:0,days:null}];
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.corpId= this.myQwCompanyList[0].dictValue
+      this.afreshData(this.queryParams.corpId)
+      this.handleQuery();
+    },
+
+    handleUpdate(row){
+
+
+      this.reset();
+
+      //所有的员工
+      listUser({corpId:this.queryParams.corpId}).then(res=>{
+        this.userList=res.rows;
+      })
+
+
+      // 深拷贝表单数据
+      const requestData = { ...row };
+      requestData.applyUsers = JSON.parse(row.applyUsers);
+
+      this.userSelectListUpdate=requestData.applyUsers;
+      this.updateUserOpen.id=requestData.id;
+      this.updateUserOpen.open=true;
+
+
+    },
+
+    submitUpdateAutoTags(){
+      if (this.updateUserOpen.id != null && this.updateUserOpen.applyUsersUpdate.length>0) {
+        updateTags({id:this.updateUserOpen.id,applyUsers:JSON.stringify(this.updateUserOpen.applyUsersUpdate)}).then(response => {
+          this.msgSuccess("修改成功");
+          this.updateUserOpen.open = false;
+          this.getList();
+        });
+      }else {
+        this.msgError("修改失败:成员不能为空 或 未选规则");
+      }
+    },
+    cancelAutoTags(){
+      this.reset();
+      this.updateUserOpen.open=false;
+      this.updateUserOpen.applyUsersUpdate=[];
+      this.updateUserOpen.id=null;
+      this.userSelectListUpdate=[];
+    },
+
+    /** 详情按钮操作 */
+    handleDetails(row) {
+
+      this.reset();
+
+      // 深拷贝表单数据
+      const requestData = { ...row };
+      // 将 `数据` 转为 JSON
+      requestData.rulesTags = JSON.parse(row.rulesTags);
+      requestData.applyUsers = JSON.parse(row.applyUsers);
+
+      this.detailListFrom = requestData;
+      this.detailFrom.open=true;
+      this.detailFrom.title='规则详情';
+    },
+
+
+
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          const itemForms = this.$refs.rulesTagsFrom;
+          if (Array.isArray(itemForms)) {
+            let allValid = true;
+
+            itemForms.forEach((itemFormRef, index) => {
+              itemFormRef.validate((itemValid) => {
+                allValid = itemValid;
+
+                if (index === itemForms.length - 1 && allValid) {
+                  //全表单验证通过
+                  this.commitForm();
+                }
+              });
+            });
+          }
+        }
+      });
+    },
+
+    //提交form表单
+    commitForm(){
+      // 深拷贝表单数据
+      const requestData = { ...this.form };
+      // 将 `form.rulesTags` 转为 JSON 字符串
+      requestData.rulesTags = JSON.stringify(this.form.rulesTags);
+      requestData.applyUsers = JSON.stringify(this.form.applyUsers);
+      requestData.corpId=this.queryParams.corpId;
+      requestData.companyId = this.queryParams.companyId
+      if (this.form.id != null) {
+        updateTags(requestData).then(response => {
+          this.msgSuccess("修改成功");
+          this.open = false;
+          this.getList();
+        });
+      } else {
+        addTags(requestData).then(response => {
+          this.msgSuccess("新增成功");
+          this.open = false;
+          this.getList();
+        });
+      }
+    },
+
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除自动打标签主编号为"' + ids + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return delTags(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+
+  }
+};
+</script>
+<style scoped>
+/* 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;
+}
+.text-container {
+  max-height: 5em; /* 设置最大高度为6行,根据字体大小调整 */
+  overflow-y: auto; /* 内容超出时显示滚动条 */
+  line-height: 1.5em; /* 行高设置,确保每行高度一致 */
+}
+/* 新增的滚动容器样式(不影响原有样式) */
+.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: 300px;
+   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>

+ 457 - 0
src/views/qw/autoTags/dayPartingIndexDetails.vue

@@ -0,0 +1,457 @@
+<template>
+  <div style="background-color:  rgb(240 242 245)">
+    <div style="display: flex;flex-wrap: nowrap;background-color: rgb(240 242 245);height: 500px;">
+      <div style="background-color: #FFFFFF;width: 100%" class="app-container">
+<!--        <span style="font-size: 15px">基础信息</span>-->
+        <div  class="desct">
+          基础信息
+        </div>
+<!--        <el-divider></el-divider>-->
+        <div style="display: flex;flex-wrap: nowrap">
+          <div style="width: 500px">
+            <el-descriptions :column="1" size="medium" >
+              <el-descriptions-item label="规则名称">
+                <span>{{groupIndexFrom.ruleName}}</span>
+              </el-descriptions-item>
+              <el-descriptions-item label="打标签方式">
+                <span>分时段加好友打标签</span>
+              </el-descriptions-item>
+              <el-descriptions-item label="创建者">
+                <span>{{groupIndexFrom.createName}}</span>
+              </el-descriptions-item>
+              <el-descriptions-item label="生效成员">
+              <span v-for="userId in groupIndexFrom.applyUsers" :key="userId" style="display: inline;width: 300px">
+                      <el-tag :disable-transitions="false"  v-for="list in userList" :key="list.id" style="margin: 3px;" v-if="list.id==userId">{{list.nickName}}</el-tag>
+                </span>
+              </el-descriptions-item>
+<!--              <el-descriptions-item label="添加的标签" labelStyle="width: 80px">-->
+<!--                <span v-for="tagId in groupIndexFrom.tagsSet" :key="tagId" style="display: inline;width: 300px">-->
+<!--                      <el-tag :disable-transitions="false"  v-for="list in tagList" :key="list.id" style="margin: 3px;" v-if="list.tagId==tagId">{{list.name}}</el-tag>-->
+<!--                </span>-->
+<!--              </el-descriptions-item>-->
+              <el-descriptions-item label="创建时间">{{groupIndexFrom.createTime}}</el-descriptions-item>
+              <el-descriptions-item label="规则状态">
+                <el-switch
+                  v-model="groupIndexFrom.isApply"
+                  active-color="#13ce66"
+                  inactive-color="#ff4949"
+                  active-value="1"
+                  inactive-value="2"
+                  disabled>
+                </el-switch>
+                <span v-if="groupIndexFrom.isApply == '1'" style="margin-left: 10px;color: #13ce66">已启用</span>
+                <span v-if="groupIndexFrom.isApply == '2'" style="margin-left: 10px;color: #ff4949">已关闭</span>
+              </el-descriptions-item>
+            </el-descriptions>
+          </div>
+          <div style="background-color: #fbfbfb;padding: 10px;  border: 1px solid #e6e6e6; margin-bottom: 20px;;width: 100%;height: 350px;overflow:auto">
+            <div >
+              <span class="spanSize">规则设置:共 {{groupIndexFrom.rulesTags.length}} 条规则</span>
+              <div v-for="(rtList,index) in groupIndexFrom.rulesTags">
+                <div style="margin-left: 10%;margin-top: 1%">
+                  <span class="spanSize">|规则 {{index +1}} </span>
+                  <div class="spanSize">客户在 每
+                    <span v-for="id in rtList.week" :key="id" style="display: inline;" v-if="rtList.dayOrWeek == 0">
+                      <el-tag :disable-transitions="false"  v-for="list in weekOptions" :key="list.value" style="margin: 3px;" v-if="list.value==id">{{list.label}}</el-tag>
+                    </span>
+                    <span style="display: inline;" v-if="rtList.dayOrWeek == 1">
+                      <el-tag>{{rtList.days[0]}}</el-tag> 到 <el-tag>{{rtList.days[1]}}</el-tag>
+                    </span>
+                    <span>【{{rtList.startTime}}~{{rtList.endTime}}】</span>
+                    时,打上标签
+                    <span v-for="tagId in rtList.tags" :key="tagId" style="display: inline;">
+                      <el-tag :disable-transitions="false"  v-for="list in tagList" :key="list.id" style="margin: 3px;" v-if="list.tagId==tagId">{{list.name}}</el-tag>
+                    </span>
+                  </div>
+                  <div class="spanSize">并备注上:
+                    <span>【{{rtList.remarks}}】</span>
+
+                  </div>
+                </div>
+
+              </div>
+            </div >
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div class="contentx">
+      <div class="desct">
+        数据分析
+      </div>
+      <div class="statistics-container">
+        <el-row :gutter="20" type="flex">
+          <el-col :span="6"  >
+            <el-card style="height: 100px">
+              <div class="statistic-item">
+                <h2>{{ groupIndexFrom.totalNumTagsCount }} </h2>
+                <p>打标签总数</p>
+              </div>
+            </el-card>
+          </el-col>
+          <el-col :span="6" >
+            <el-card style="height: 100px">
+              <div class="statistic-item">
+                <h2>{{ groupIndexFrom.numTagsTadayCount }} </h2>
+                <p>今日打标签数</p>
+              </div>
+            </el-card>
+          </el-col>
+        </el-row>
+      </div>
+    </div>
+
+    <div  style="background-color:  rgb(240 242 245);padding-bottom: 15px">
+      <div style="margin: 15px;  padding:15px;  background-color: #fff;">
+          <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="120px">
+            <el-form-item label="所属员工" prop="qwUserid">
+              <el-input
+                v-model="queryParams.qwUserid"
+                placeholder="请输入所属员工名称"
+                clearable
+                size="small"
+                @keyup.enter.native="handleQuery"
+              />
+            </el-form-item>
+            <el-form-item label="搜索客户" prop="externalUserId">
+              <el-input
+                v-model="queryParams.externalUserId"
+                placeholder="请输入客户名称"
+                clearable
+                size="small"
+                @keyup.enter.native="handleQuery"
+              />
+            </el-form-item>
+            <el-form-item label="添加好友时间" prop="addTime">
+              <el-date-picker
+                v-model="queryParams.addTime"
+                type="daterange"
+                align="right"
+                unlink-panels
+                range-separator="至"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                :picker-options="pickerOptions"
+                :default-time="['00:00:00', '23:59:59']">
+              </el-date-picker>
+            </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>
+            </el-form-item>
+          </el-form>
+
+          <el-table v-loading="loading" :data="autoTagsLogsList">
+            <el-table-column label="客户名称" align="center" prop="externalUserName" />
+            <el-table-column label="所属企微员工" align="center" prop="qwUsername" />
+            <el-table-column label="所属销售" align="center" prop="companyName" />
+            <el-table-column label="添加的标签" align="center" prop="tagIdsName" >
+              <template slot-scope="scope">
+                <div v-for="name in scope.row.tagIdsName" style="display: inline;">
+                  <el-tag type="success">{{ name }}</el-tag>
+                </div>
+              </template>
+            </el-table-column>
+            <el-table-column label="添加好友时间" align="center" prop="addTime" width="180"/>
+            <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+              <template slot-scope="scope">
+                <el-button v-if="scope.row.customerId"
+                           size="mini"
+                           type="text"
+                           icon="el-icon-paperclip"
+                           @click="handleShow(scope.row)"
+                >查看客户</el-button>
+                <el-tag  v-else type="danger"  size="mini">未绑定CRM客户</el-tag>
+              </template>
+            </el-table-column>
+          </el-table>
+
+          <pagination
+            v-show="total>0"
+            :total="total"
+            :page.sync="queryParams.pageNum"
+            :limit.sync="queryParams.pageSize"
+            @pagination="getList"
+          />
+        </div>
+
+      </div>
+
+    <!-- <el-drawer size="75%" :title="show.title" :visible.sync="show.open" append-to-body >
+      <customer-details  ref="customerDetails" />
+    </el-drawer> -->
+
+</div>
+
+
+
+</template>
+
+<script>
+import { listAutoTagsLogs, exportAutoTagsLogs } from "@/api/qw/autoTagsLogs";
+// import CustomerGroupDetails from '@/views/qw/groupMsg/customerGroupDetails.vue'
+import { listTag } from '@/api/qw/tag'
+import { listUser } from '@/api/qw/user'
+// import customerDetails from '@/views/qw/externalContact/customerDetails.vue'
+
+export default {
+  name: "AutoTagsLogs",
+  // components: { CustomerGroupDetails ,customerDetails},
+  props:{
+    groupIndexFrom:{},
+  },
+  watch:{
+    groupIndexFrom:{
+      handler(newVal){
+        //当表单发生变化时
+        this.getList(newVal.id)
+      },
+      deep:true
+    }
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: false,
+      // 导出遮罩层
+      exportLoading: false,
+
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 自动打标签的日志表格数据
+      autoTagsLogsList: [],
+
+      //所有的标签
+      tagList:[],
+
+      //成员信息
+      userList:[],
+
+      weekOptions: [{
+        value: 1,
+        label: '星期一'
+      }, {
+        value: 2,
+        label: '星期二'
+      }, {
+        value: 3,
+        label: '星期三'
+      }, {
+        value: 4,
+        label: '星期四'
+      }, {
+        value: 5,
+        label: '星期五'
+      }
+        , {
+          value: 6,
+          label: '星期六'
+        }
+        , {
+          value: 7,
+          label: '星期天'
+        }],
+
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        autoTagId: null,
+        type: 3,
+        qwUserid: null,
+        externalUserId: null,
+        effectiveRules: null,
+        addTime: [],
+        chatId: null,
+        joinScene: null,
+        companyId: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      },
+      show:{
+        title:"客户详情",
+        open:false,
+      },
+      //日期快捷选择
+      pickerOptions: {
+        shortcuts: [
+          {
+            text: '最近三天',
+            onClick(picker) {
+              const end = new Date();
+              end.setHours(23, 59, 59, 999);
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 3);
+              start.setHours(0, 0, 0, 0);
+              picker.$emit('pick', [start, end]);
+            }
+          },{
+            text: '最近一周',
+            onClick(picker) {
+              const end = new Date();
+              end.setHours(23, 59, 59, 999);
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+              start.setHours(0, 0, 0, 0);
+              picker.$emit('pick', [start, end]);
+            }
+          }, {
+            text: '最近一个月',
+            onClick(picker) {
+              const end = new Date();
+              end.setHours(23, 59, 59, 999);
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+              start.setHours(0, 0, 0, 0);
+              picker.$emit('pick', [start, end]);
+            }
+          }, {
+            text: '最近三个月',
+            onClick(picker) {
+              const end = new Date();
+              end.setHours(23, 59, 59, 999);
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
+              start.setHours(0, 0, 0, 0);
+              picker.$emit('pick', [start, end]);
+            }
+          }]
+      },
+    };
+  },
+  created() {
+
+    //所有的标签
+    listTag().then(response => {
+      this.tagList = response.rows;
+    });
+    listUser().then(res=>{
+      this.userList=res.rows;
+    })
+
+    this.getList(this.groupIndexFrom);
+  },
+  methods: {
+    /** 查询自动打标签的日志列表 */
+    getList() {
+      this.queryParams.autoTagId =  this.groupIndexFrom.id;
+      this.loading = true;
+
+      listAutoTagsLogs(this.queryParams).then(response => {
+        this.autoTagsLogsList = response.rows;
+
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        autoTagId: null,
+        type: 3,
+        qwUserid: null,
+        externalUserId: null,
+        effectiveRules: null,
+        addTime: [],
+        chatId: null,
+        joinScene: null,
+        companyId: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+
+    /** 查看客户详情 */
+    handleShow(row){
+      this.show.open=true;
+      var that=this;
+      const tab = "visit";
+      setTimeout(() => {
+        that.$refs.customerDetails.getDetails(row.customerId);
+        that.$refs.customerDetails.handleClick(tab);
+      }, 200);
+    },
+
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有自动打标签的日志数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportAutoTagsLogs(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
+    }
+  }
+};
+</script>
+<style scoped>
+
+.contentx{
+  height: 100%;
+  background-color: #fff;
+  padding: 0px 20px 20px;
+  margin:0 15px;
+}
+.desct{
+  padding-top: 20px;
+  padding-bottom: 20px;
+  color: #524b4a;
+  font-weight: bold;
+}
+
+.spanSize{
+  font-size: 15px;
+  font-weight: normal;
+}
+.statistics-container {
+  padding: 0 20px;
+}
+.statistic-item {
+  text-align: center;
+  margin-top: 5%;
+}
+.statistic-item h2 {
+  font-size: 15px;
+  margin: 0;
+  font-weight: normal;
+}
+.statistic-item p {
+  margin: 5px 0 0;
+  font-size: 15px;
+  color: #666;
+  font-weight: normal;
+}
+</style>

+ 210 - 0
src/views/qw/autoTags/groupChat.vue

@@ -0,0 +1,210 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px">
+      <el-form-item label="群名" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入群名"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </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>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" :data="groupChatList" ref="groupChatList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="群名" align="center" prop="name" >
+        <template slot-scope="scope">
+          <i class="el-icon-s-comment"></i>
+          {{scope.row.name}}
+        </template>
+      </el-table-column>
+      <el-table-column label="群人数" align="center" prop="groupSizeByChartUser"></el-table-column>
+
+
+    </el-table>
+    <div style="margin-top: 30px;display: flex;justify-content: center">
+      <el-button type="warning" icon="el-icon-search" @click="confirmSelect">确定选择</el-button>
+      <el-button icon="el-icon-refresh"  @click="resetSelect">重置选择</el-button>
+    </div>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="handlePaginationChange"
+    />
+
+  </div>
+</template>
+
+<script>
+import {
+  listGroupChat,
+} from '@/api/qw/groupChat'
+
+export default {
+  name: "GroupChat",
+  props:{
+    index:Number
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 客户群详情表格数据
+      groupChatList: [],
+
+      //选择的客户群列表
+      selectGroupChartList:[],
+
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        name: null,
+        owner: null,
+        notice: null,
+        memberVersion: null,
+        status: null,
+        companyId: null,
+        corpId: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+
+  },
+  methods: {
+
+    /** 查询客户群列表 */
+    getList() {
+      this.loading = true;
+      listGroupChat(this.queryParams).then(response => {
+        this.groupChatList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+
+      });
+    },
+    getDetails(corpId){
+
+      this.groupChatList = [];
+      this.queryParams.corpId=corpId;
+      this.getList();
+    },
+    handlePaginationChange(row) {
+      this.queryParams.pageNum = row.page;
+      this.queryParams.pageSize = row.limit;
+      this.getList();
+    },
+    //确定选择
+    confirmSelect(){
+      this.$emit("selectGroupChatList",this.selectGroupChartList,this.index);
+      this.resetSelect();
+    },
+    //重置选择
+    resetSelect(){
+      this.$refs.groupChatList.clearSelection();
+
+      this.selectGroupChartList=[];
+
+      //重置
+      this.queryParams={
+        pageNum: 1,
+        pageSize: 10,
+        name: null,
+        owner: null,
+        notice: null,
+        memberVersion: null,
+        status: null,
+        companyId: null,
+        corpId: null,
+      },
+        this.getList();
+    },
+
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        chatId: null,
+        id: null,
+        name: null,
+        owner: null,
+        notice: null,
+        memberVersion: null,
+        status: "0",
+        companyId: null,
+        corpId: null,
+        createTime: null,
+        updateTime: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+
+      // 保存当前页的选中项
+      const currentPageSelections = selection.map(item => item.chatId);
+
+      // 合并选中项
+      this.selectGroupChartList = this.selectGroupChartList.filter(item =>
+        this.groupChatList.some(tag => tag.chatId === item.chatId) ? currentPageSelections.includes(item.chatId) : true
+      ).concat(selection.filter(item => !this.selectGroupChartList.some(selected => selected.chatId === item.chatId)));
+
+      // 更新 ids 和 selectTagsList
+      this.ids = this.selectGroupChartList.map(item => item.chatId);
+
+      // 更新 single 和 multiple
+      this.single = this.selectGroupChartList.length !== 1;
+      this.multiple = !this.selectGroupChartList.length;
+
+    },
+  }
+};
+</script>

+ 859 - 0
src/views/qw/autoTags/groupIndex.vue

@@ -0,0 +1,859 @@
+<template>
+  <div class="app-container">
+    <el-tabs v-model="activeName" style="background-color: #fff;" @tab-click="handleClick" type="card">
+<!--      <el-tab-pane label="关键词打标签" name="1"></el-tab-pane>-->
+      <el-tab-pane label="客户入群行为打标签" name="2"></el-tab-pane>
+      <el-tab-pane label="分时段打标签" name="3"></el-tab-pane>
+    </el-tabs>
+
+    <div >
+      <div v-if="activeName==='1'">
+        <keyWordIndex></keyWordIndex>
+      </div>
+      <div v-if="activeName==='2'" >
+
+        <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+          <el-form-item label="企微公司" prop="corpId">
+                <el-select v-model="queryParams.corpId" placeholder="企微公司"  size="small" @change="updateCorpId()">
+                  <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="companyId">
+          <el-select v-model="queryParams.companyId" placeholder="公司"  size="small" @change="updateCompanyId()">
+            <el-option
+              v-for="dict in myCompanyList"
+              :key="dict.companyId"
+              :label="dict.companyName"
+              :value="dict.companyId"
+            />
+          </el-select>
+      </el-form-item> -->
+          <el-form-item label="规则名称:" prop="ruleName">
+            <el-input
+              v-model="queryParams.ruleName"
+              placeholder="请输入规则名称"
+              clearable
+              size="small"
+              @keyup.enter.native="handleQuery"
+            />
+          </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>
+            <el-button
+              type="primary"
+              size="mini"
+              plain
+              icon="el-icon-plus"
+              @click="handleAdd"
+              v-hasPermi="['qw:autoTags:add']"
+            >添加规则</el-button>
+          </el-form-item>
+
+        </el-form>
+<!--        <div style="padding:0 0 15px 0">-->
+<!--          <el-button-->
+<!--            type="primary"-->
+<!--            size="small"-->
+<!--            plain-->
+<!--            icon="el-icon-plus"-->
+<!--            @click="handleAdd"-->
+<!--            v-hasPermi="['shop:tags:add']"-->
+<!--          >添加规则</el-button>-->
+<!--        </div>-->
+
+        <el-table v-loading="loading" :data="groupIndexList" border  height="550px">
+          <el-table-column label="规则名称" align="center" prop="ruleName" />
+          <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>
+          </el-table-column>
+          <el-table-column label="已打标签总数" align="center" prop="totalNumTagsCount" />
+          <el-table-column label="规则状态" align="center" prop="isApply">
+            <template slot-scope="scope">
+              <el-switch
+                v-model="scope.row.isApply"
+                active-color="#13ce66"
+                inactive-color="#ff4949"
+                active-value="1"
+                inactive-value="2"
+                @change="switchChange(scope.row)">
+              </el-switch>
+              <span v-if="scope.row.isApply == '1'" style="margin-left: 10px;color: #13ce66">已启用</span>
+              <span v-if="scope.row.isApply == '2'" style="margin-left: 10px;color: #ff4949">已关闭</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+            <template slot-scope="scope">
+              <el-button
+                size="mini"
+                type="text"
+                icon="el-icon-edit"
+                @click="handleDetails(scope.row)"
+                v-hasPermi="['qw:autoTags:query']"
+              >详情</el-button>
+              <el-button
+                size="mini"
+                type="text"
+                icon="el-icon-delete"
+                @click="handleDelete(scope.row)"
+                v-hasPermi="['qw:autoTags:remove']"
+              >删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+
+
+        <pagination
+          v-show="total>0"
+          :total="total"
+          :page.sync="queryParams.pageNum"
+          :limit.sync="queryParams.pageSize"
+          @pagination="getList"
+        />
+
+      </div>
+      <div v-if="activeName==='3'">
+        <dayPartingIndex></dayPartingIndex>
+      </div>
+
+
+      <!-- 添加或修改自动打标签主对话框 -->
+      <el-dialog :title="title" :visible.sync="open" width="1200px" append-to-body>
+
+        <el-form  ref="form" :model="form" :rules="rules" label-position="left"  label-width="120px">
+          <div class="app-container">
+            <div>
+              <span style="font-size: 15px">规则基础信息</span>
+              <el-divider></el-divider>
+            </div>
+            <el-alert
+              title="设定规则,当用户加入规则内的群聊,自动给入群客户打标签"
+              type="warning"
+              style="font-size: 15px;margin-bottom: 2%;"
+              :closable="false"
+              show-icon>
+            </el-alert>
+            <el-form-item label="规则名称:" prop="ruleName" style="width: 400px">
+              <el-input v-model="form.ruleName" placeholder="请输入规则名称(内部可见)" />
+            </el-form-item>
+
+            <div style="margin-top: 5%">
+              <span style="font-size: 15px">设置打标签的规则</span>
+              <el-divider></el-divider>
+            </div>
+            <div v-for="(item, index) in form.rulesTags" :key="index">
+              <div style="background-color: #fbfbfb; padding: 10px; border: 1px solid #e6e6e6; margin-bottom: 20px;">
+                <el-form ref="rulesTagsFrom" :rules="rulesTagsRules" :model="item">
+                  <div style="display: flex">
+                    <el-form-item prop="rules" style="width: 500px">
+                      <div style="display: flex; align-items: center;">
+                        <div style="width: 150px">
+                          <span style="margin-right: 10px;">规则 {{ index + 1 }}:用户加入群聊</span>
+                        </div>
+                        <div @click="handleGroupChatList(item,index)" style="cursor: pointer; border: 1px solid #e6e6e6; background-color: white; overflow: hidden; flex-grow: 1;width: 350px">
+                          <div style="min-height: 40px; max-height: 200px; overflow-y: auto;">
+                            <el-tag
+                              style="margin-left: 5px"
+                              size="medium"
+                              :key="list.chatId"
+                              v-for="list in groupChatList[index]"
+                              closable
+                              :disable-transitions="false"
+                              @close="handleClosegroupChat(list,index)">
+                              {{list.name}}
+                            </el-tag>
+                          </div>
+                        </div>
+                      </div>
+                    </el-form-item>
+                    <el-form-item prop="tags" style="width: 500px">
+                      <div style="display: flex; align-items: center;">
+                        <div style="width: 110px">
+                          <span style="margin:0px 10px;">选择的标签:</span>
+                        </div>
+                        <div @click="handleChangeTags(item,index)" style="cursor: pointer; border: 1px solid #e6e6e6; background-color: white; overflow: hidden; flex-grow: 1;width: 390px">
+                          <div style="min-height: 40px; max-height: 200px; overflow-y: auto;">
+                            <el-tag type="success"
+                                    closable
+                                    :disable-transitions="false"
+                                    v-for="list in tagListFormIndex[index]"
+                                    :key="list.tagId"
+                                    @close="handleCloseTag(list,index)"
+                                    style="margin: 3px;"
+                                   >{{list.name}}
+                            </el-tag>
+                          </div>
+                        </div>
+
+                      </div>
+                    </el-form-item>
+                    <el-link v-if="form.rulesTags.length>1" icon="el-icon-delete-solid" @click="delItemList(index)" type="text" style="color: rgb(24, 144, 255);margin-left:10px;height: 40px " ></el-link>
+                  </div>
+                </el-form>
+              </div>
+            </div>
+            <div>
+              <el-link type="primary" class="el-icon-plus" :underline="false" @click='addItemList()'>添加其他规则(最多5条)</el-link>
+            </div>
+
+          </div>
+        </el-form>
+
+
+        <div slot="footer" class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </el-dialog>
+    </div>
+
+    <!-- 选择群聊    -->
+    <el-dialog :title="groupChart.title" :visible.sync="groupChart.open" style="width: 1300px;height: 100%" append-to-body>
+      <GroupChat ref="GroupChat" @selectGroupChatList="selectGroupChatList" :index="groupChart.index"></GroupChat>
+    </el-dialog>
+
+
+    <el-dialog title="添加标签" :visible.sync="tagChange.open" width="800px" append-to-body>
+      <div>搜索标签:
+        <el-input v-model="queryTagParams.name" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags">搜索</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
+      </div>
+      <div v-for="item in tagGroupList" :key="item.id" >
+        <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
+          <span class="name-background">{{ item.name }}</span>
+        </div>
+
+        <!-- 添加外层滚动容器 -->
+        <div class="scroll-wrapper">
+          <div class="tag-container">
+            <a
+              v-for="tagItem in item.tag"
+              class="tag-box"
+              @click="tagSelection(tagItem)"
+              :class="{ 'tag-selected': tagItem.isSelected }"
+            >
+              {{ tagItem.name }}
+            </a>
+          </div>
+        </div>
+      </div>
+      <pagination
+        v-show="tagTotal>0"
+        :total="tagTotal"
+        :page.sync="queryTagParams.pageNum"
+        :limit.sync="queryTagParams.pageSize"
+        @pagination="getPageListTagGroup"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="addTagSubmitForm(tagChange.index)">确 定</el-button>
+        <el-button @click="addTagCancel(tagChange.index)">重 置</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 群规则详情    -->
+    <el-drawer :title="detailFrom.title" :visible.sync="detailFrom.open" size="75%" style="font-weight: bolder">
+        <groupIndexDetails :groupIndexFrom="detailListFrom"></groupIndexDetails>
+    </el-drawer>
+
+  </div>
+
+</template>
+
+<script>
+import { listTags, getTags, delTags, addTags, updateTags, exportTags } from "@/api/qw/autoTags";
+import qwUserList from '@/views/qw/user/qwUserList.vue'
+import dayPartingIndex from '@/views/qw/autoTags/dayPartingIndex.vue'
+import keyWordIndex from '@/views/qw/autoTags/keyWordIndex.vue'
+import GroupChat from '@/views/qw/autoTags/groupChat.vue'
+import { allListTagGroup } from '@/api/qw/tagGroup'
+import {listTag, searchTags} from '@/api/qw/tag'
+import groupIndexDetails from '@/views/qw/autoTags/groupIndexDetails.vue'
+import { getMyQwUserList,getMyQwCompanyListAll,getCompanyListByCorpId } from "@/api/qw/user";
+export default {
+  name: "autoTags",
+  components: {GroupChat, qwUserList,dayPartingIndex,keyWordIndex,groupIndexDetails },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      activeName:'2',
+      myQwCompanyList:[],
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      tagTotal:0,
+      // 自动打标签主表格数据
+      groupIndexList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      //选择群聊
+      groupChart:{
+        title:"",
+        open:false,
+        index:null,
+      },
+
+      //选择的群聊
+      groupChatList:[],
+
+      //所有的标签组-标签
+      tagGroupList:[],
+
+      //所有的标签
+      // tagList:[],
+
+      //选择的标签
+      tagListFormIndex:[],
+
+      //标签弹窗选择
+      tagChange:{
+        open:false,
+        index:null,
+      },
+      //详情抽屉
+      detailFrom:{
+        open:false,
+        title:'',
+      },
+
+      queryTagParams: {
+        pageNum: 1,
+        pageSize: 5,
+        total:0,
+        name:null,
+        corpId:null,
+      },
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        type: 2,
+        createName: null,
+        applyUsers: null,
+        ruleName: null,
+        rulesTags: null,
+        totalNumTags: null,
+        numTagsTaday: null,
+        isApply: null,
+        corpId: null,
+        companyId: null
+      },
+      // 表单参数
+      form: {},
+      //详情表单参数
+      detailListFrom:{},
+      // 表单校验
+      rules: {
+        ruleName:[{ required: true, message: "规则名称不能为空", trigger: "submit" }],
+      },
+      //规则验证
+      rulesTagsRules:{
+        rules: [
+          { required: true, message: '请添加群', trigger: 'blur' }
+        ],
+        tags: [
+          { required: true, message: '请选择标签', trigger: 'blur' }
+        ]
+      },
+      //根据企微查出来的公司列表
+      // myCompanyList:[],
+    };
+  },
+  created() {
+    //所有的标签组-标签
+
+    getMyQwCompanyListAll().then(response => {
+            this.myQwCompanyList = response.data;
+            if(this.myQwCompanyList!=null){
+              this.queryParams.corpId=this.myQwCompanyList[0].dictValue;
+              // getCompanyListByCorpId(this.queryParams.corpId).then(response =>{
+              //   this.myCompanyList = response.data;
+              // })
+              // if(this.myCompanyList != null){
+                // this.queryParams.companyId = this.myCompanyList[0].companyId
+                this.afreshData(this.queryParams.corpId)
+                this.getList();
+              // }
+            }
+    });
+  },
+  watch: {
+    groupChatList: {
+      handler(newList) {
+        // 遍历 groupChatList 并将 chatId 放入对应位置的 rulesTags
+        newList.forEach((group, index) => {
+          if (!this.form.rulesTags[index]) {
+            this.$set(this.form.rulesTags, index, { rules: [], tags: [] });
+          }
+          // 确保清空原来的 tags 数组
+          this.form.rulesTags[index].rules = [];
+          group.forEach(item => {
+            // 将 chatId 放入对应位置的 rulesTags 中的 rules 数组
+            this.form.rulesTags[index].rules.push(item.chatId);
+          });
+        });
+      },
+      deep: true
+    },
+    tagListFormIndex: {
+      handler(newList) {
+        // 遍历 tagListFormIndex 并将 tagId 放入对应位置的 tags
+        newList.forEach((tags, index) => {
+          if (!this.form.rulesTags[index]) {
+            this.$set(this.form.rulesTags, index, { rules: [], tags: [] });
+          }
+
+          // 确保清空原来的 tags 数组
+          this.form.rulesTags[index].tags = [];
+
+          tags.forEach(item => {
+            // 将 tagId 放入对应位置的 rulesTags 中的 tags 数组
+            this.form.rulesTags[index].tags.push(item.tagId);
+          });
+        });
+      },
+      deep: true
+    }
+  },
+
+  methods: {
+    updateCorpId(){
+      // this.myCompanyList = [];
+      // getCompanyListByCorpId(this.queryParams.corpId).them(response =>{
+      //           this.myCompanyList = response.data;
+      //         })
+      this.afreshData(this.queryParams.corpId)
+      this.getList();
+     },
+    //  updateCompanyId(){
+      
+    //   this.afreshData(this.queryParams.corpId)
+    //   this.getList();
+    //  },
+    
+    /**
+     * 重新获取 部分数据
+     */
+    afreshData(value){
+
+      this.resetSearchQueryTag()
+      this.queryTagParams.corpId=value;
+
+    },
+
+    resetSearchQueryTag(){
+
+      this.queryTagParams= {
+        pageNum: 1,
+        pageSize: 5,
+        total:0,
+        name:null,
+      };
+    },
+
+    //选择的标签页
+    handleClick(tab, event) {
+      this.queryParams.type=tab.name
+      this.getList();
+    },
+    //选择群聊弹窗
+    handleGroupChatList(item,index){
+      this.groupChart.title="选择群聊"
+        setTimeout(() => {
+                  this.$refs.GroupChat.getDetails(this.queryParams.corpId);
+             }, 1);
+      this.groupChart.open=true;
+      this.groupChart.index=index
+    },
+
+    //选择群聊赋值
+    selectGroupChatList(list,index){
+
+      this.groupChart.open=false;
+
+      // 如果 this.groupChatList[index] 不存在,则初始化为一个空数组
+      if (!this.groupChatList[index]) {
+        this.$set(this.groupChatList, index, []);
+      }
+
+      // 获取当前 groupChatList[index] 中的值
+      let currentList = this.groupChatList[index];
+
+      // 遍历 list 中的每个值
+      list.forEach(item => {
+        let itemIndex = currentList.findIndex(currentItem => currentItem.chatId === item.chatId);
+
+        if (itemIndex !== -1) {
+          // 如果当前 item 在 currentList 中已经存在,则不管
+        } else {
+          // 如果当前 item 不在 currentList 中,则插入
+          currentList.push(item);
+        }
+      });
+
+      // 更新 groupChatList[index]
+      this.$set(this.groupChatList, index, currentList);
+    },
+
+    //删除一些选择了的群聊
+    handleClosegroupChat(list,index){
+
+      // 假设 list 对象具有一个 id 属性
+      const ls = this.groupChatList[index].findIndex(t => t.chatId === list.chatId);
+      if (ls !== -1) {
+        this.groupChatList[index].splice(ls, 1);
+      }
+    },
+
+    //选择标签弹窗
+    handleChangeTags(item,index){
+
+      for (let i = 0; i < this.tagGroupList.length; i++) {
+        for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+          this.tagGroupList[i].tag[x].isSelected=false;
+        }
+      }
+
+      this.tagChange.open=true;
+      this.tagChange.index=index;
+
+    },
+
+    handleSearchTags(){
+
+      if (!this.queryTagParams.name){
+        return this.$message.error("请输入要搜索的标签")
+      }
+
+      this.queryTagParams.corpId=this.queryParams.corpId;
+      searchTags(this.queryTagParams).then(response => {
+        this.tagGroupList = response.rows;
+        this.tagTotal = response.total;
+      });
+
+    },
+
+    getPageListTagGroup(){
+
+      this.queryTagParams.corpId=this.queryParams.corpId;
+
+      allListTagGroup(this.queryTagParams).then(response => {
+        this.tagGroupList = response.rows;
+        this.tagTotal = response.total;
+      });
+    },
+
+
+    cancelSearchTags(){
+      this.afreshData(this.queryParams.corpId)
+    },
+    //标签的选择
+    tagSelection(row){
+      row.isSelected= !row.isSelected;
+      this.$forceUpdate();
+    },
+
+    //选择标签
+    addTagSubmitForm(index){
+
+      for (let i = 0; i < this.tagGroupList.length; i++) {
+        for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+          if (this.tagGroupList[i].tag[x].isSelected === true) {
+            if (!this.tagListFormIndex[index]) {
+              this.$set(this.tagListFormIndex, index, []);
+            }
+
+            // 检查当前 tag 是否已经存在于 tagListFormIndex[index] 中
+            let tagExists = this.tagListFormIndex[index].some(
+              tag => tag.id === this.tagGroupList[i].tag[x].id
+            );
+
+            // 如果 tag 不存在于 tagListFormIndex[index] 中,则新增
+            if (!tagExists) {
+              this.tagListFormIndex[index].push(this.tagGroupList[i].tag[x]);
+            }
+          }
+        }
+      }
+      if (!this.tagListFormIndex[index] || this.tagListFormIndex[index].length === 0) {
+        return this.$message('请选择标签');
+      }
+
+      this.tagChange.open = false;
+    },
+
+    //取消选择标签
+    addTagCancel(index){
+      this.tagChange.open = false;
+      this.tagListFormIndex[index]=[];
+    },
+    //删除一些已经选择了的标签
+    handleCloseTag(list,index){
+
+      // 假设 list 对象具有一个 id 属性
+      const ls = this.tagListFormIndex[index].findIndex(t => t.tagId === list.tagId);
+      if (ls !== -1) {
+        this.tagListFormIndex[index].splice(ls, 1);
+        // 使用 Vue.set 方法
+        this.$set(this.tagListFormIndex, index, [...this.tagListFormIndex[index]]);
+      }
+    },
+
+    //删除某一个规则
+    delItemList(index){
+      this.form.rulesTags.splice(index,1)
+      this.tagListFormIndex.splice(index,1)
+      this.groupChatList.splice(index,1)
+    },
+
+    //添加规则
+    addItemList(){
+      if (this.form.rulesTags.length >=5) {
+        return this.$message.error('当前规则已达上限,无法添加规则');
+      }
+      this.form.rulesTags.push({rules:[],tags:[]})
+    },
+
+
+    /** 查询自动打标签主列表 */
+    getList() {
+      this.loading = true;
+      listTags(this.queryParams).then(response => {
+
+        this.groupIndexList = response.rows;
+
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        type: 2,
+        createName: null,
+        applyUsers: null,
+        ruleName: null,
+        rulesTags: [{rules:[],tags:[]}],
+        totalNumTags: null,
+        numTagsTaday: null,
+        isApply: 1,
+        createTime: null,
+        companyId: null
+      };
+      //选择的群
+      this.groupChatList=[];
+
+      //选择的标签
+      this.tagListFormIndex=[];
+
+      //规则
+      this.form.rulesTags=[{rules:[],tags:[]}];
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.corpId= this.myQwCompanyList[0].dictValue
+      this.afreshData(this.queryParams.corpId)
+      this.handleQuery();
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加规则";
+
+
+      this.getPageListTagGroup();
+
+      //所有的标签
+      listTag({corpId:this.queryParams.corpId}).then(response => {
+        this.tagList = response.rows;
+      });
+
+    },
+    handleAddThree(){
+
+    },
+
+    /** 详情按钮操作 */
+    handleDetails(row) {
+
+      this.reset();
+
+      // 深拷贝表单数据
+      const requestData = { ...row };
+      // 将 `数据` 转为 JSON
+      requestData.rulesTags = JSON.parse(row.rulesTags);
+
+      this.detailListFrom = requestData;
+      this.detailFrom.open=true;
+      this.detailFrom.title='规则详情';
+
+
+    },
+    /** 提交按钮 */
+    submitForm() {
+
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          this.form.corpId=this.queryParams.corpId;
+          const itemForms = this.$refs.rulesTagsFrom;
+          if (Array.isArray(itemForms)) {
+            let allValid = true;
+
+            itemForms.forEach((itemFormRef, index) => {
+              itemFormRef.validate((itemValid) => {
+                allValid = itemValid;
+
+                if (index === itemForms.length - 1 && allValid) {
+                  //全表单验证通过
+                  this.commitForm();
+                }
+              });
+            });
+          }
+        }
+
+
+      });
+
+    },
+
+    //提交form表单
+    commitForm(){
+
+      // 深拷贝表单数据
+      const requestData = { ...this.form };
+      // 将 `form.rulesTags` 转为 JSON 字符串
+      requestData.rulesTags = JSON.stringify(this.form.rulesTags);
+        requestData.corpId=this.queryParams.corpId;
+        requestData.companyId = this.queryParams.companyId;
+      if (this.form.id != null) {
+        updateTags(requestData).then(response => {
+          this.msgSuccess("修改成功");
+          this.open = false;
+          this.getList();
+        });
+      } else {
+        addTags(requestData).then(response => {
+          this.msgSuccess("新增成功");
+          this.open = false;
+          this.getList();
+        });
+      }
+    },
+
+    //状态开关
+    switchChange(row){
+      updateTags(row).then(response => {
+        this.msgSuccess("修改成功");
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除自动打标签规则名称为【' + row.ruleName + '】的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delTags(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+
+  }
+};
+</script>
+<style scoped>
+/* 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;
+}
+.text-container {
+  max-height: 5em; /* 设置最大高度为6行,根据字体大小调整 */
+  overflow-y: auto; /* 内容超出时显示滚动条 */
+  line-height: 1.5em; /* 行高设置,确保每行高度一致 */
+}
+/* 新增的滚动容器样式(不影响原有样式) */
+.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;
+}
+</style>

+ 440 - 0
src/views/qw/autoTags/groupIndexDetails.vue

@@ -0,0 +1,440 @@
+<template>
+  <div style="background-color:  rgb(240 242 245)">
+    <div style="display: flex;flex-wrap: nowrap;background-color: rgb(240 242 245);height: 350px;">
+      <div style="background-color: #FFFFFF;width: 100%" class="app-container">
+<!--        <span style="font-size: 15px">基础信息</span>-->
+<!--        <el-divider></el-divider>-->
+        <div  class="desct">
+          基础信息
+        </div>
+        <div style="display: flex;flex-wrap: nowrap">
+          <div style="width: 400px">
+            <el-descriptions :column="1" size="medium" >
+              <el-descriptions-item label="规则名称:">
+                <span>{{groupIndexFrom.ruleName}}</span>
+              </el-descriptions-item>
+              <el-descriptions-item label="打标签方式:">
+                <span>客户入群打标签</span>
+              </el-descriptions-item>
+              <el-descriptions-item label="创建者:">
+                <span>{{groupIndexFrom.createName}}</span>
+              </el-descriptions-item>
+              <el-descriptions-item label="创建时间:">{{groupIndexFrom.createTime}}</el-descriptions-item>
+              <el-descriptions-item label="规则状态:">
+                <el-switch
+                  v-model="groupIndexFrom.isApply"
+                  active-color="#13ce66"
+                  inactive-color="#ff4949"
+                  active-value="1"
+                  inactive-value="2"
+                  disabled>
+                </el-switch>
+                <span v-if="groupIndexFrom.isApply == '1'" style="margin-left: 10px;color: #13ce66">已启用</span>
+                <span v-if="groupIndexFrom.isApply == '2'" style="margin-left: 10px;color: #ff4949">已关闭</span>
+              </el-descriptions-item>
+            </el-descriptions>
+          </div>
+          <div style="background-color: #fbfbfb;padding: 10px;  border: 1px solid #e6e6e6; margin-bottom: 20px;;width: 100%;height: 220px;overflow:auto">
+            <div >
+              <span class="spanSize">规则设置:共 {{groupIndexFrom.rulesTags.length}} 条规则</span>
+              <div v-for="(rtList,index) in groupIndexFrom.rulesTags">
+                <div style="margin-left: 10%;margin-top: 1%">
+                  <span class="spanSize">|规则 {{index +1}} </span>
+                  <div class="spanSize">用户加入群聊
+                    <span v-for="chatId in rtList.rules" :key="chatId" style="display: inline;">
+                      <el-tag :disable-transitions="false"  v-for="list in groupChatList" :key="list.chatId" style="margin: 3px;" v-if="list.chatId==chatId">{{list.name}}</el-tag>
+                    </span>
+                      时,打上标签
+                    <span v-for="tagId in rtList.tags" :key="tagId" style="display: inline;">
+                      <el-tag :disable-transitions="false"  v-for="list in tagList" :key="list.id" style="margin: 3px;" v-if="list.tagId==tagId">{{list.name}}</el-tag>
+                    </span>
+                  </div>
+                </div>
+
+              </div>
+            </div >
+          </div>
+        </div>
+      </div>
+    </div>
+
+
+    <div class="contentx">
+      <div class="desct">
+        数据分析
+      </div>
+      <div class="statistics-container">
+        <el-row :gutter="20" type="flex">
+          <el-col :span="6"  >
+            <el-card style="height: 100px">
+              <div class="statistic-item">
+                <h2>{{ groupIndexFrom.totalNumTagsCount }} </h2>
+                <p>打标签总数</p>
+              </div>
+            </el-card>
+          </el-col>
+          <el-col :span="6" >
+            <el-card style="height: 100px">
+              <div class="statistic-item">
+                <h2>{{ groupIndexFrom.numTagsTadayCount }} </h2>
+                <p>今日打标签数</p>
+              </div>
+            </el-card>
+          </el-col>
+        </el-row>
+      </div>
+    </div>
+
+    <div  style="background-color:  rgb(240 242 245);padding-bottom: 15px">
+        <div style="margin: 15px;  padding:15px;  background-color: #fff;">
+          <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="120px">
+            <el-form-item label="所属员工" prop="qwUserid">
+              <el-input
+                v-model="queryParams.qwUserid"
+                placeholder="请输入所属员工名称"
+                clearable
+                size="small"
+                @keyup.enter.native="handleQuery"
+              />
+            </el-form-item>
+            <el-form-item label="搜索客户" prop="externalUserId">
+              <el-input
+                v-model="queryParams.externalUserId"
+                placeholder="请输入客户名称"
+                clearable
+                size="small"
+                @keyup.enter.native="handleQuery"
+              />
+            </el-form-item>
+            <el-form-item label="加入群聊时间" prop="addTime">
+              <el-date-picker
+                v-model="queryParams.addTime"
+                type="daterange"
+                align="right"
+                unlink-panels
+                range-separator="至"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                :picker-options="pickerOptions"
+                :default-time="['00:00:00', '23:59:59']">
+              </el-date-picker>
+            </el-form-item>
+            <el-form-item label="群聊名称" prop="chatId">
+              <el-input
+                v-model="queryParams.chatId"
+                placeholder="请输入群聊"
+                clearable
+                size="small"
+                @keyup.enter.native="handleQuery"
+              />
+            </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>
+            </el-form-item>
+          </el-form>
+          <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+
+          <el-table v-loading="loading" :data="autoTagsLogsList">
+            <el-table-column label="客户名称" align="center" prop="externalUserName" />
+            <el-table-column label="所属员工" align="center" prop="qwUsername" />
+            <el-table-column label="添加的标签" align="center" prop="effectiveRules" >
+              <template slot-scope="scope">
+                   <span v-for="tagId in JSON.parse(scope.row.effectiveRules)" :key="tagId" style="display: inline;">
+                    <el-tag :disable-transitions="false"  v-for="list in tagList" :key="list.id" style="margin: 3px;" v-if="list.tagId==tagId">{{list.name}}</el-tag>
+                  </span>
+              </template>
+            </el-table-column>
+            <el-table-column label="加入的群聊" align="center" prop="chatName" >
+            </el-table-column>
+            <el-table-column label="入群方式" align="center" prop="joinScene" >
+              <template slot-scope="scope">
+                <span v-for="(item,index) in groupChatUserScene" v-if="scope.row.joinScene==item.dictValue">{{item.dictLabel}}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="加入群聊时间" align="center" prop="addTime" width="180"/>
+            <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+              <template slot-scope="scope">
+
+                <el-button v-if="scope.row.customerId"
+                           size="mini"
+                           type="text"
+                           icon="el-icon-paperclip"
+                           @click="handleShow(scope.row)"
+                >查看客户</el-button>
+                <el-tag  v-else type="danger"  size="mini">未绑定CRM客户</el-tag>
+              </template>
+            </el-table-column>
+          </el-table>
+
+          <pagination
+            v-show="total>0"
+            :total="total"
+            :page.sync="queryParams.pageNum"
+            :limit.sync="queryParams.pageSize"
+            @pagination="getList"
+          />
+
+        </div>
+      </div>
+
+    <!-- <el-drawer size="75%" :title="show.title" :visible.sync="show.open" append-to-body>
+      <customer-details  ref="customerDetails" />
+    </el-drawer> -->
+
+    </div>
+
+
+</template>
+
+<script>
+import { listAutoTagsLogs, exportAutoTagsLogs } from "@/api/qw/autoTagsLogs";
+// import CustomerGroupDetails from '@/views/qw/groupMsg/customerGroupDetails.vue'
+import { listTag } from '@/api/qw/tag'
+import { listGroupChat } from '@/api/qw/groupChat'
+// import customerDetails from '@/views/qw/externalContact/customerDetails.vue'
+
+export default {
+  name: "AutoTagsLogs",
+  // components: { CustomerGroupDetails ,customerDetails},
+  props:{
+    groupIndexFrom:{},
+  },
+  watch:{
+    groupIndexFrom:{
+      handler(newVal){
+        //当表单发生变化时
+        // this.groupIndexList=newVal;
+        // console.log("this.groupIndexList",this.groupIndexList)
+        this.getList(newVal.id)
+      },
+      deep:true
+    }
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 自动打标签的日志表格数据
+      autoTagsLogsList: [],
+
+      //入群方式
+      groupChatUserScene:[],
+
+      //所有的标签
+      tagList:[],
+
+      //所有的群
+      groupChatList:[],
+
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        autoTagId: null,
+        type: 2,
+        qwUserid: null,
+        externalUserId: null,
+        effectiveRules: null,
+        addTime: [],
+        chatId: null,
+        joinScene: null,
+        companyId: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      },
+      show:{
+        title:"客户详情",
+        open:false,
+      },
+      //日期快捷选择
+      pickerOptions: {
+        shortcuts: [
+          {
+            text: '最近三天',
+            onClick(picker) {
+              const end = new Date();
+              end.setHours(23, 59, 59, 999);
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 3);
+              start.setHours(0, 0, 0, 0);
+              picker.$emit('pick', [start, end]);
+            }
+          },{
+            text: '最近一周',
+            onClick(picker) {
+              const end = new Date();
+              end.setHours(23, 59, 59, 999);
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+              start.setHours(0, 0, 0, 0);
+              picker.$emit('pick', [start, end]);
+            }
+          }, {
+            text: '最近一个月',
+            onClick(picker) {
+              const end = new Date();
+              end.setHours(23, 59, 59, 999);
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+              start.setHours(0, 0, 0, 0);
+              picker.$emit('pick', [start, end]);
+            }
+          }, {
+            text: '最近三个月',
+            onClick(picker) {
+              const end = new Date();
+              end.setHours(23, 59, 59, 999);
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
+              start.setHours(0, 0, 0, 0);
+              picker.$emit('pick', [start, end]);
+            }
+          }]
+      },
+    };
+  },
+  created() {
+
+    //所有的标签
+    listTag().then(response => {
+      this.tagList = response.rows;
+    });
+    //查询所有的群列表
+    listGroupChat().then(res=>{
+      this.groupChatList=res.rows
+    })
+
+    //入群方式字典
+    this.getDicts("sys_qw_groupChat_user_scene").then(response => {
+      this.groupChatUserScene = response.data;
+    });
+
+    this.getList(this.groupIndexFrom);
+  },
+  methods: {
+    /** 查询自动打标签的日志列表 */
+    getList() {
+      this.queryParams.autoTagId = this.groupIndexFrom.id;
+      this.loading = true;
+      listAutoTagsLogs(this.queryParams).then(response => {
+
+        this.autoTagsLogsList = response.rows;
+
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        autoTagId: null,
+        type: 2,
+        qwUserid: null,
+        externalUserId: null,
+        effectiveRules: null,
+        addTime: [],
+        chatId: null,
+        joinScene: null,
+        companyId: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 查看客户详情 */
+    handleShow(row){
+      this.show.open=true;
+      this.loading=false;
+      var that=this;
+      const tab = "visit";
+      setTimeout(() => {
+        // that.$refs.customerDetails.getDetails(row.customerId);
+        // that.$refs.customerDetails.handleClick(tab);
+
+      }, 200);
+    },
+
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有自动打标签的日志数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportAutoTagsLogs(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
+    }
+  }
+};
+</script>
+<style scoped>
+.desct{
+  padding-top: 20px;
+  padding-bottom: 20px;
+  color: #524b4a;
+  font-weight: bold;
+}
+.contentx{
+  height: 100%;
+  background-color: #fff;
+  padding: 0px 20px 20px;
+  margin:0 15px;
+}
+.spanSize{
+  font-size: 15px;
+  font-weight: normal;
+}
+.statistics-container {
+  padding: 0 20px;
+}
+.statistic-item {
+  text-align: center;
+  margin-top: 5%;
+}
+.statistic-item h2 {
+  font-size: 15px;
+  margin: 0;
+  font-weight: normal;
+}
+.statistic-item p {
+  margin: 5px 0 0;
+  font-size: 15px;
+  color: #666;
+  font-weight: normal;
+}
+</style>

+ 308 - 0
src/views/qw/autoTags/keyWordIndex.vue

@@ -0,0 +1,308 @@
+<template>
+    <div>
+
+      <el-table v-loading="loading" :data="tagsList" @selection-change="handleSelectionChange">
+        <el-table-column label="创建人" align="center" prop="createName" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template slot-scope="scope">
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-edit"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['shop:tags:edit']"
+            >修改</el-button>
+            <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-delete"
+              @click="handleDelete(scope.row)"
+              v-hasPermi="['shop:tags:remove']"
+            >删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-show="total>0"
+        :total="total"
+        :page.sync="queryParams.pageNum"
+        :limit.sync="queryParams.pageSize"
+        @pagination="getList"
+      />
+
+      <!-- 添加或修改自动打标签主对话框 -->
+      <el-dialog :title="title" :visible.sync="open" width="1000px" append-to-body>
+        <el-form v-if="form.type==='2'" ref="form" :model="form" :rules="rules" label-position="left"  label-width="120px">
+          <div class="app-container">
+            <div>
+              <span style="font-size: 15px">规则基础信息</span>
+              <el-divider></el-divider>
+            </div>
+            <el-alert
+              title="根据规则,当客户在设定时间段内成为企业微信客户,将自动被打上标签"
+              type="warning"
+              style="font-size: 15px;margin-bottom: 2%;"
+              :closable="false"
+              show-icon>
+            </el-alert>
+            <el-form-item label="规则名称:" prop="ruleName" style="width: 400px">
+              <el-input v-model="form.ruleName" placeholder="请输入规则名称(内部可见)" />
+            </el-form-item>
+
+            <div style="margin-top: 5%">
+              <span style="font-size: 15px">设置打标签的规则</span>
+              <el-divider></el-divider>
+            </div>
+            <div style="background-color: #fbfbfb;padding: 10px;  border: 1px solid #e6e6e6; margin-bottom: 20px;">
+              <el-form ref="from"  :rules="rules" :model="form">
+                <div style="display: flex; gap: 10px;">
+                </div>
+              </el-form>
+            </div>
+
+          </div>
+        </el-form>
+        <el-form v-if="form.type==='3'" ref="form" :model="form" :rules="rules" label-width="80px">
+
+          <el-form-item label="规则名称" prop="ruleName">
+            <el-input v-model="form.ruleName" placeholder="请输入规则名称" />
+          </el-form-item>
+          <el-form-item label="生效成员:" prop="applyUsers">
+            <div>
+              <el-button
+                size="mini"
+                icon="el-icon-circle-plus-outline"
+                plain
+                @click="handlelistUser">请选择使用成员</el-button>
+            </div>
+            <div>
+              <el-tag
+                style="margin-left: 5px"
+                size="medium"
+                :key="list.id"
+                v-for="list in userSelectList"
+                closable
+                :disable-transitions="false"
+                @close="handleClosegroupUser(list)">
+                {{list.nickName}}
+              </el-tag>
+            </div>
+          </el-form-item>
+          <el-form-item label="打标签总数" prop="totalNumTags">
+            <el-input v-model="form.totalNumTags" placeholder="请输入打标签总数" />
+          </el-form-item>
+          <el-form-item label="今日打标签数" prop="numTagsTaday">
+            <el-input v-model="form.numTagsTaday" placeholder="请输入今日打标签数" />
+          </el-form-item>
+          <el-form-item label="是否运用规则状态 1启用 2停用" prop="isApply">
+            <el-input v-model="form.isApply" placeholder="请输入是否运用规则状态 1启用 2停用" />
+          </el-form-item>
+          <el-form-item label="公司id" prop="companyId">
+            <el-input v-model="form.companyId" placeholder="请输入公司id" />
+          </el-form-item>
+        </el-form>
+        <div slot="footer" class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </el-dialog>
+
+    <!-- 选择成员账号弹窗   -->
+    <el-dialog :title="listUser.title" :visible.sync="listUser.open" style="width: 1600px;height: 100%" append-to-body>
+      <qwUserList ref="QwUserList" @selectUserList="selectUserList"></qwUserList>
+    </el-dialog>
+  </div>
+
+</template>
+
+<script>
+import { listTags, getTags, delTags, addTags, updateTags, exportTags } from "@/api/qw/autoTags";
+import qwUserList from '@/views/qw/user/qwUserList.vue'
+
+export default {
+  name: "autoTags",
+  components: { qwUserList },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      activeName:'2',
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 自动打标签主表格数据
+      tagsList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+
+      //选择成员列表
+      listUser:{
+        title:"",
+        open:false
+      },
+      //选择成员列表
+      userSelectList:[],
+
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        type: null,
+        createName: null,
+        applyUsers: null,
+        ruleName: null,
+        rulesTags: null,
+        totalNumTags: null,
+        numTagsTaday: null,
+        isApply: null,
+        companyId: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        ruleName:[{ required: true, message: "规则名称不能为空", trigger: "blur" }],
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    //选择的标签页
+    handleClick(tab, event) {
+      this.queryParams.type=tab.name
+      this.getList();
+    },
+
+    //选择群发的企业成员账号
+    handlelistUser(){
+      this.listUser.title="选择企业成员"
+      this.listUser.open=true;
+    },
+    //选择的成员账号列表
+    selectUserList(list){
+
+      this.listUser.open=false;
+      //用于显示
+      this.userSelectList=list;
+
+    },
+    //删除一些选择了的账号
+    handleClosegroupUser(list){
+
+      // 假设 list 对象具有一个 id 属性
+      const index = this.userSelectList.findIndex(t => t.id === list.id);
+      if (index !== -1) {
+        this.userSelectList.splice(index, 1);
+      }
+    },
+
+    /** 查询自动打标签主列表 */
+    getList() {
+      this.loading = true;
+      listTags(this.queryParams).then(response => {
+        this.tagsList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        type: null,
+        createName: null,
+        applyUsers: null,
+        ruleName: null,
+        rulesTags: [{rules:[],tags:[]}],
+        totalNumTags: null,
+        numTagsTaday: null,
+        isApply: null,
+        createTime: null,
+        companyId: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd(row) {
+      this.reset();
+      this.form.type=row
+      this.open = true;
+      this.title = "添加规则";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getTags(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改自动打标签主";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateTags(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addTags(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除自动打标签主编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delTags(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+
+  }
+};
+</script>

+ 205 - 0
src/views/qw/friendWelcome/ImageUploadWeclome.vue

@@ -0,0 +1,205 @@
+<template>
+  <div class="component-upload-image">
+    <el-upload
+      :action="uploadUrl"
+      list-type="picture-card"
+      :on-success="handleUploadSuccess"
+      :before-upload="handleBeforeUpload"
+      :limit="limit"
+      :on-error="handleUploadError"
+      :on-exceed="handleExceed"
+      name="file"
+      :on-remove="handleRemove"
+      :show-file-list="true"
+      :file-list="fileList"
+      :on-preview="handlePictureCardPreview"
+      :class="{hide: this.fileList.length >= this.limit}"
+    >
+      <i class="el-icon-plus"></i>
+    </el-upload>
+
+    <el-dialog
+      :visible.sync="dialogVisible"
+      title="预览"
+      width="800"
+      append-to-body
+    >
+      <img
+        :src="dialogImageUrl"
+        style="display: block; max-width: 100%; margin: 0 auto"
+      />
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getToken } from "@/utils/auth";
+
+export default {
+  name: "ImageUpload",
+  props: {
+    value: [String, Object, Array],
+    // 图片数量限制
+    limit: {
+      type: Number,
+      default: 1,
+    },
+    // 大小限制(MB)
+    fileSize: {
+       type: Number,
+      default: 10,
+    },
+    // 文件类型, 例如['png', 'jpg', 'jpeg']
+    fileType: {
+      type: Array,
+      default: () => ["png", "jpg", "jpeg"],
+    },
+    // 是否显示提示
+    isShowTip: {
+      type: Boolean,
+      default: true
+    }
+  },
+  data() {
+    return {
+      dialogImageUrl: "",
+      dialogVisible: false,
+      hideUpload: false,
+      baseUrl:"",
+      uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
+      headers: {
+        Authorization: "Bearer " + getToken(),
+      },
+      fileList: []
+    };
+  },
+  watch: {
+    value: {
+      handler(val) {
+        if (val) {
+          // 首先将值转为数组
+          const list = Array.isArray(val) ? val : this.value.split(',');
+          // 然后将数组转为对象数组
+          this.fileList = list.map(item => {
+            if (typeof item === "string") {
+              if (item.indexOf(this.baseUrl) === -1) {
+                  item = { name: item, url: item };
+              } else {
+                  item = { name: item, url: item };
+              }
+            }
+            return item;
+          });
+        } else {
+          this.fileList = [];
+          return [];
+        }
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  computed: {
+    // 是否显示提示
+    showTip() {
+      return this.isShowTip && (this.fileType || this.fileSize);
+    },
+  },
+  methods: {
+    // 删除图片
+    handleRemove(file, fileList) {
+      const findex = this.fileList.map(f => f.name).indexOf(file.name);
+      if(findex > -1) {
+        this.fileList.splice(findex, 1);
+        this.$emit("input", this.listToString(this.fileList));
+      }
+    },
+    // 上传成功回调
+    handleUploadSuccess(res,file) {
+      this.fileList.push({ name: res.url, url: res.url });
+      this.$emit("input", this.listToString(this.fileList));
+      this.loading.close();
+    },
+    // 上传前loading加载
+    handleBeforeUpload(file) {
+      let isImg = false;
+      if (this.fileType.length) {
+        let fileExtension = "";
+        if (file.name.lastIndexOf(".") > -1) {
+          fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
+        }
+        isImg = this.fileType.some(type => {
+          if (file.type.indexOf(type) > -1) return true;
+          if (fileExtension && fileExtension.indexOf(type) > -1) return true;
+          return false;
+        });
+      } else {
+        isImg = file.type.indexOf("image") > -1;
+      }
+
+      if (!isImg) {
+        this.$message.error(
+          `文件格式不正确, 请上传${this.fileType.join("/")}图片格式文件!`
+        );
+        return false;
+      }
+      if (this.fileSize) {
+        const isLt = file.size / 1024 / 1024 < this.fileSize;
+        if (!isLt) {
+          this.$message.error(`上传头像图片大小不能超过 ${this.fileSize} MB!`);
+          return false;
+        }
+      }
+      this.loading = this.$loading({
+        lock: true,
+        text: "上传中",
+        background: "rgba(0, 0, 0, 0.7)",
+      });
+    },
+    // 文件个数超出
+    handleExceed() {
+      this.$message.error(`上传文件数量不能超过 ${this.limit} 个!`);
+    },
+    // 上传失败
+    handleUploadError() {
+      this.$message({
+        type: "error",
+        message: "上传失败",
+      });
+      this.loading.close();
+    },
+    // 预览
+    handlePictureCardPreview(file) {
+      console.log(file)
+      this.dialogImageUrl = file.url;
+      this.dialogVisible = true;
+    },
+    // 对象转成指定字符串分隔
+    listToString(list, separator) {
+      let strs = "";
+      separator = separator || ",";
+      for (let i in list) {
+        strs += list[i].url.replace(this.baseUrl, "") + separator;
+      }
+      return strs != '' ? strs.substr(0, strs.length - 1) : '';
+    }
+  }
+};
+</script>
+<style scoped lang="scss">
+// .el-upload--picture-card 控制加号部分
+::v-deep.hide .el-upload--picture-card {
+    display: none;
+}
+// 去掉动画效果
+::v-deep .el-list-enter-active,
+::v-deep .el-list-leave-active {
+    transition: all 0s;
+}
+
+::v-deep .el-list-enter, .el-list-leave-active {
+    opacity: 0;
+    transform: translateY(0);
+}
+</style>
+

+ 1418 - 0
src/views/qw/friendWelcome/indexNew.vue

@@ -0,0 +1,1418 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="120px">
+      <el-form-item label="企微公司" prop="corpId">
+          <el-select v-model="queryParams.corpId" placeholder="企微公司"  size="small" @change="updateCorpId()">
+            <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="companyId">
+          <el-select v-model="queryParams.companyId" placeholder="公司"  size="small" @change="updateCompanyId()">
+            <el-option
+              v-for="dict in myCompanyList"
+              :key="dict.companyId"
+              :label="dict.companyName"
+              :value="dict.companyId"
+            />
+          </el-select>
+      </el-form-item>
+      <el-form-item label="id" prop="id">
+        <el-input
+          v-model="queryParams.id"
+          placeholder="请输入ID"
+          clearable
+          size="small"
+        />
+      </el-form-item>
+      <el-form-item label="使用的成员" >
+        <el-select filterable v-model="queryParams.qwUserIds" filterable  clearable placeholder="公司员工"   size="small">
+          <el-option
+             v-for="dict in companyUserList"
+             :key="dict.id"
+             :label="dict.qwUserName+'('+dict.qwUserId+')'"
+             :value="dict.id">
+          </el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="是否开启分时段" prop="isDayparting">
+        <el-select v-model="queryParams.isDayparting" placeholder="请选择" clearable size="small">
+          <el-option v-for="dict in allowSelectOptions" :key="dict.dictValue" :label="dict.dictLabel"  :value="dict.dictValue"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createdTime">
+        <el-date-picker clearable size="small"
+          v-model="queryParams.createTime"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="选择创建时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="更新时间" prop="updateTieme">
+        <el-date-picker clearable size="small"
+          v-model="queryParams.updateTime"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="选择更新时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="是否发送欢迎语" prop="isSendMsg">
+        <el-select v-model="queryParams.isSendMsg" placeholder="请选择" clearable size="small" >
+          <el-option v-for="dict in allowSelectOptions" :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>
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          icon="el-icon-plus"
+          @click="handleAdd"
+          v-hasPermi="['qw:friendWelcome:add']"
+        >新增</el-button>
+      </el-form-item>
+    </el-form>
+    <el-row :gutter="10" class="mb8">
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+
+    <el-table v-loading="loading" :data="friendWelcomeList" @selection-change="handleSelectionChange" border>
+      <el-table-column label="id" align="center" prop="id" width="180"/>
+      <el-table-column label="标题" align="center" prop="welcomeTitle"/>
+      <el-table-column label="消息内容" align="left" prop="welcomeText"  width="400px" >
+        <template slot-scope="scope">
+          <span style="color:rgb(19, 154, 50);" v-if="scope.row.isDayparting==='1'">[共 {{JSON.parse(scope.row.daypartingItemlist).length+1}} 时段]</span>
+          <span style="color:rgb(19, 154, 50);" v-else >[默认时段]</span>
+          <el-tooltip class="item" effect="dark" :content="scope.row.welcomeText" placement="top">
+            <div style="display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; text-overflow: ellipsis;">
+              <span>{{ scope.row.welcomeText }}</span>
+            </div>
+          </el-tooltip>
+        </template>
+      </el-table-column>
+      <el-table-column label="使用成员" align="center" prop="qwUserIds">
+      <template slot-scope="scope">
+          <div v-for="id in JSON.parse(scope.row.qwUserIds)" :key="id" style="display: inline;" class="text-container">
+            <el-tag type="success" v-for="list in companyUserList" :key="list.qwUserId" style="margin: 3px;" v-if="list.id==id">{{list.qwUserName}}</el-tag>
+          </div>
+      </template>
+      </el-table-column>
+      <el-table-column label="是否开启分时段" align="center" prop="isDayparting">
+        <template slot-scope="scope">
+          <dict-tag :options="allowSelectOptions" :value="scope.row.isDayparting"></dict-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="是否发送欢迎语" align="center" prop="isSendMsg" >
+        <template slot-scope="scope">
+          <dict-tag :options="allowSelectOptions" :value="scope.row.isSendMsg"></dict-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180"/>
+      <el-table-column label="更新时间" align="center" prop="updateTime" width="180"/>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120px">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['qw:friendWelcome:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['qw:friendWelcome:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改好友欢迎语对话框 -->
+    <el-dialog :title="title" :visible.sync="open" v-loading="loading" width="1700px" append-to-body>
+      <div style="width: 1130px" class="app-container">
+        <div>
+          <span style="font-size: 15px">基础信息</span>
+          <el-divider></el-divider>
+          <el-alert
+            title="注意事项"
+            type="warning"
+            description="这是提示~根据特色还不知道写点啥"
+            :closable="false"
+            show-icon>
+          </el-alert>
+        </div>
+        <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+
+          <el-form-item label="选择使用成员:" prop="qwUserIds" style="margin-top: 2%">
+            <div>
+              <el-button
+                size="medium"
+                icon="el-icon-circle-plus-outline"
+                plain
+                @click="handlelistUser">请选择使用成员</el-button>
+            </div>
+            <div>
+              <el-tag
+                style="margin-left: 5px"
+                size="medium"
+                :key="list.id"
+                v-for="list in userSelectList"
+                closable
+                :disable-transitions="false"
+                @close="handleClosegroupUser(list)">
+                {{list.qwUserName}}({{list.nickName}})
+              </el-tag>
+            </div>
+          </el-form-item>
+          <!-- 新增整体标题 -->
+          <el-form-item label="标题:" prop="welcomeTitle">
+            <el-input v-model="form.welcomeTitle" placeholder="请输入欢迎语标题"/>
+            <el-alert style="margin-top: 8px;height: 30px"
+                      title="此标题仅用于欢迎语的用途区分"
+                      type="info"
+                      :closable="false"
+                      show-icon>
+            </el-alert>
+          </el-form-item>
+          <el-form-item label="是否发送欢迎语">
+            <el-switch
+              v-model="form.isSendMsg"
+              active-color="#13ce66"
+              inactive-color="#ff4949"
+              active-value="1"
+              inactive-value="2">
+            </el-switch>
+            <span v-if="form.isSendMsg == '1'" style="margin-left: 10px;color: #13ce66">允许</span>
+            <span v-if="form.isSendMsg == '2'" style="margin-left: 10px;color: #ff4949">不允许</span>
+
+          </el-form-item>
+          <div>
+            <span style="font-size: 15px">发送欢迎语</span>
+            <el-divider></el-divider>
+          </div>
+          <el-form-item label="默认欢迎语:" prop="welcomeText">
+              <el-input v-model="form.welcomeText" type="textarea"  :rows="12" maxlength="1300" show-word-limit placeholder="请输入消息内容"/>
+            <!-- 附件和链接列表 -->
+            <el-row>
+              <el-col>
+                <div v-for="(item, index) in form.attachments" :key="index" style="background-color: #f5f7fa;padding: 5px;border: 1px solid  #d9d9d9;">
+                  <div slot="header" style="display: flex;justify-content: space-between;align-items: center; ">
+                    <div style="flex: 1;">
+                    <span v-if="item.msgtype === 'image'">【图片】: {{ item.image.pic_url }}</span>
+                    <span v-if="item.msgtype === 'video'">【视频】: {{ item.video.url }}</span>
+                    <span v-if="item.msgtype === 'link'">【链接】: {{ item.link.title }}-{{item.link.desc}}</span>
+                    <span v-if="item.msgtype === 'miniprogram'">【小程序】: {{ item.miniprogram.title }}</span>
+                    </div>
+                    <div style="  display: flex;gap: 10px;">
+                      <el-button
+                        size="mini"
+                        type="text"
+                        icon="el-icon-edit"
+                        style="float: left;"
+                        @click="editFileItem(item,index,-1)"
+                      >修改</el-button>
+                      <el-button
+                        size="mini"
+                        type="text"
+                        icon="el-icon-delete"
+                        style="float: right;"
+                        @click="removeFileItem(item,index,-1)"
+                      >删除</el-button>
+                  </div>
+                  </div>
+                </div>
+              </el-col>
+            </el-row>
+
+            <el-dropdown @command="(command) => handleCommand(command, -1)" trigger="click" placement="top-start">
+              <el-dropdown-menu slot="dropdown" style="width: 120px;">
+                <el-dropdown-item command="image">
+                  <i class="el-icon-picture" style="margin-right: 10px;"></i>图片
+                </el-dropdown-item>
+                <el-dropdown-item command="video">
+                  <i class="el-icon-video-camera" style="margin-right: 10px;"></i>视频
+                </el-dropdown-item>
+                <el-dropdown-item command="link">
+                  <i class="el-icon-link" style="margin-right: 10px;"></i>链接
+                </el-dropdown-item>
+                <el-dropdown-item command="miniprogram">
+                  <i class="el-icon-link" style="margin-right: 10px;"></i>小程序
+                </el-dropdown-item>
+              </el-dropdown-menu>
+
+              <span class="el-dropdown-link">
+                <el-link icon="el-icon-paperclip" type="text" style="color: rgb(24, 144, 255)">
+                  添加附件(最多9个)
+                </el-link>
+              </span>
+            </el-dropdown>
+
+            </el-form-item>
+
+          <el-form-item label="分时段欢迎语">
+            <el-switch
+              v-model="form.isDayparting"
+              active-color="#13ce66"
+              inactive-color="#ff4949"
+              active-value="1"
+              inactive-value="2">
+            </el-switch>
+            <span v-if="form.isDayparting == '1'" style="margin-left: 10px;color: #13ce66">已启用</span>
+            <span v-if="form.isDayparting == '2'" style="margin-left: 10px;color: #ff4949">已禁用</span>
+          </el-form-item>
+
+          <el-form-item v-if="form.isDayparting == '1'" >
+            <div style="background-color:#ecf8fe;width: 100%;border: 1px solid #dcdfe6">
+              <span style="margin-left:20px;font-size: 15px;display: block" >注意:1、员工上下班不同时间段可设置不同欢迎语;</span>
+              <span style="margin-left:65px;font-size: 15px;display: block" >2、分时段之外的时间将发送已允许的默认欢迎语。</span>
+              <span style="margin-left:65px;font-size: 15px;display: block" >3、不设置分时段欢迎语则使用已允许的默认欢迎语</span>
+              <span style="margin-left:65px;font-size: 15px;display: block" >4、若员工没有设置过欢迎语则不会发送</span>
+            </div>
+          </el-form-item>
+          <el-form-item v-if="form.isDayparting == '2'">
+            <div style="background-color:#ecf8fe;width: 100%;border: 1px solid #dcdfe6">
+              <span style="margin-left:20px;font-size: 15px;display: block" >注意:1、新建欢迎语最多可发送1条文字消息和9个附件;</span>
+              <span style="margin-left:65px;font-size: 15px;display: block" >2、文字消息和附件不能同时为空,当两者均填写时用户会收到多条消息;</span>
+              <span style="margin-left:65px;font-size: 15px;display: block" >3、欢迎语将在客户加为好友后20秒内下发,因网络延迟可能造成发送不成功</span>
+            </div>
+          </el-form-item>
+          <div  v-if="form.isDayparting == '1'"  v-for="(item, index) in form.daypartingItemlist"    :key="index" >
+            <el-form-item :label="`时段 ${index + 1}:`">
+                <el-row>
+                  <el-col style="width: 965px">
+                    <div style="background-color: #fbfbfb;padding: 10px;  border: 1px solid #e6e6e6; margin-bottom: 20px;">
+                          <el-form ref="friendWelcomeItemForm"  :rules="itemRules" :model="item">
+                          <div style="display: flex; gap: 10px;">
+                            <el-form-item label="发起时间:" prop="week" style="flex: 8;">
+                              <el-select v-model="item.week" remote multiple placeholder="请选择" filterable style="width: 580px">
+                                <el-option
+                                  v-for="dict in weekOptions"
+                                  :key="dict.value"
+                                  :label="dict.label"
+                                  :value="dict.value">
+                                </el-option>
+                              </el-select>
+                            </el-form-item>
+                            <el-form-item prop="startTime" style="flex: 1;">
+                              <el-time-select style="width: 120px;"
+                                              placeholder="起始时间"
+                                              v-model="item.startTime"
+                                              :picker-options="{
+                                            start: '00:00',
+                                            step: '00:15',
+                                            end: '24:00'
+                                          }">
+                              </el-time-select>
+                            </el-form-item>
+                            <el-form-item prop="endTime" style="flex: 1;">
+                              <el-time-select style="width: 120px;"
+                                              placeholder="结束时间"
+                                              v-model="item.endTime"
+                                              :picker-options="{
+                                            start: '00:00',
+                                            step: '00:15',
+                                            end: '24:00',
+                                            minTime: item.startTime
+                                          }">
+                              </el-time-select>
+                            </el-form-item>
+                          </div>
+
+                        <el-form-item style="margin-top: 20px" prop="welcomeText">
+                          <el-input v-model="item.welcomeText" type="textarea" :rows="12" maxlength="1300" show-word-limit placeholder="请输入消息内容"/>
+                          <!-- 附件和链接列表 -->
+                          <el-row>
+                            <el-col>
+                              <div v-for="(attachment, attachIndex) in item.attachments" :key="attachIndex" style="background-color: #f5f7fa;padding: 5px;border: 1px solid  #d9d9d9;">
+                                <div slot="header" style="  display: flex;justify-content: space-between;align-items: center; ">
+                                  <div style="flex: 1;">
+                                    <span v-if="attachment.msgtype === 'image'">【图片】: {{ attachment.image.pic_url }}</span>
+                                    <span v-if="attachment.msgtype === 'video'">【视频】: {{ attachment.video.url }}</span>
+                                    <span v-if="attachment.msgtype === 'link'">【链接】: {{ attachment.link.title }}-{{attachment.link.desc}}</span>
+                                    <span v-if="attachment.msgtype === 'miniprogram'">【小程序】: {{ attachment.miniprogram.title }}</span>
+                                  </div>
+                                  <div style="  display: flex;gap: 10px;">
+                                    <el-button
+                                      size="mini"
+                                      type="text"
+                                      icon="el-icon-edit"
+                                      style="float: left;"
+                                      @click="editFileItem(attachment,attachIndex,index)"
+                                    >修改</el-button>
+                                    <el-button
+                                      size="mini"
+                                      type="text"
+                                      icon="el-icon-delete"
+                                      style="float: right;"
+                                      @click="removeFileItem(attachment,attachIndex,index)"
+                                    >删除</el-button>
+                                  </div>
+                                </div>
+                              </div>
+                            </el-col>
+                          </el-row>
+
+                          <el-dropdown @command="(command) => handleCommand(command, index)" trigger="click" placement="top-start">
+                            <el-dropdown-menu slot="dropdown" style="width: 120px;">
+                              <el-dropdown-item command="image">
+                                <i class="el-icon-picture" style="margin-right: 10px;"></i>图片
+                              </el-dropdown-item>
+                              <el-dropdown-item command="video">
+                                <i class="el-icon-video-camera" style="margin-right: 10px;"></i>视频
+                              </el-dropdown-item>
+                              <el-dropdown-item command="link">
+                                <i class="el-icon-link" style="margin-right: 10px;"></i>链接
+                              </el-dropdown-item>
+                              <el-dropdown-item command="miniprogram">
+                                <i class="el-icon-link" style="margin-right: 10px;"></i>小程序
+                              </el-dropdown-item>
+                            </el-dropdown-menu>
+
+                            <span class="el-dropdown-link">
+                            <el-link icon="el-icon-paperclip" type="text" style="color: rgb(24, 144, 255)">
+                              添加附件(最多9个)
+                            </el-link>
+                            </span>
+                          </el-dropdown>
+                        </el-form-item>
+                      </el-form>
+                    </div>
+                  </el-col>
+                  <el-col style="width: 15px;">
+                    <el-link v-if="form.daypartingItemlist.length>1" icon="el-icon-delete-solid" @click="delItemList(index)" type="text" style="color: rgb(24, 144, 255);margin-top: 350px" ></el-link>
+                  </el-col>
+                </el-row>
+            </el-form-item>
+          </div>
+          <div  v-if="form.isDayparting == '1'" style="margin-left: 10%">
+            <el-link type="primary" class="el-icon-plus" :underline="false" @click='addItemList()'>添加其他分时段欢迎语</el-link>
+          </div>
+
+        </el-form>
+      </div>
+
+      <div slot="footer" class="dialog-footer" style="text-align: center">
+        <el-button type="primary"  @click="submitForm">确定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 选择成员账号弹窗   -->
+    <el-dialog :title="listUser.title" :visible.sync="listUser.open" width="1600px" append-to-body>
+      <qwUserList ref="QwUserList" @selectUserList="selectUserList"></qwUserList>
+    </el-dialog>
+
+    <el-dialog :title="welcomeItem.title" :visible.sync="welcomeItem.open" width="1300px" append-to-body>
+      <el-form ref="fileFrom" :model="fileFrom" :rules="fuleRules" label-width="110px">
+        <div v-if="welcomeItem.type==='image'">
+          <el-form-item label="图片:" prop="imagePicUrl">
+            <ImageUpload v-model="fileFrom.imagePicUrl"  type="image" :num="10" :width="150" :height="150"  disabled/>
+          </el-form-item>
+        </div>
+        <div v-if="welcomeItem.type==='video'">
+          <el-form-item label="视频:" prop="videoUrl">
+
+            <el-upload
+              v-model="fileFrom.videoUrl"
+              class="avatar-uploader"
+              :action="uploadUrl"
+              :show-file-list="false"
+              :on-success="(res, file) => handleAvatarSuccessVideo(res, file, fileFrom)"
+              :before-upload="beforeAvatarUploadVideo">
+              <i class="el-icon-plus avatar-uploader-icon"></i>
+            </el-upload>
+            {{fileFrom.videoUrl}}
+            <video v-if="fileFrom.videoUrl"
+                   :src="fileFrom.videoUrl"
+                   controls style="width: 200px;height: 100px">
+            </video>
+          </el-form-item>
+        </div>
+        <div v-if="welcomeItem.type==='link'">
+
+          <el-form-item label="选择课程">
+            <el-select  v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini" filterable  @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
+              <el-option
+                v-for="dict in courseList"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="parseInt(dict.dictValue)"
+              />
+            </el-select>
+            <el-select  v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" filterable @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)" >
+              <el-option
+                v-for="dict in videoList"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="parseInt(dict.dictValue)"
+              />
+            </el-select>
+          </el-form-item>
+
+          <el-form-item label="图文标题:" prop="linkTitle">
+            <el-input v-model="fileFrom.linkTitle" :rows="2" maxlength="42"  show-word-limit placeholder="请输入图文消息标题,最长为42字" />
+          </el-form-item>
+          <el-form-item label="图文封面:" prop="linkPicUrl">
+            <ImageUpload v-model="fileFrom.linkPicUrl"  type="image" :num="10" :width="150" :height="150" />
+          </el-form-item>
+          <el-form-item label="图文的描述:" prop="linkDesc">
+            <el-input v-model="fileFrom.linkDesc" :rows="4" maxlength="170" show-word-limit type="textarea" placeholder="请输入内容,,最长为170字" />
+          </el-form-item>
+          <div v-if="fileFrom.videoId==null" style="margin-top: 1%">
+            <el-form-item label="图文链接:"  label-width="100px" >
+              <el-input v-model="fileFrom.linkUrl" placeholder="请输入链接地址" style="width: 90%;"/>
+            </el-form-item>
+          </div>
+          <div v-if="fileFrom.videoId!=null">
+            <el-form-item label="图文链接:"  label-width="100px" >
+              <el-tag type="warning" v-model="fileFrom.linkUrl='待生成'">选择的课程小节 即为卡片链接地址</el-tag>
+            </el-form-item>
+          </div>
+          <div v-if="fileFrom.videoId!=null">
+            <el-form-item label="课节过期时间" style="margin-top: 1%" required label-width="110px">
+              <el-row>
+                <el-input-number  v-model="fileFrom.expiresDays"  :min="1" :max="9999" ></el-input-number>
+                (天)
+              </el-row>
+              <el-row>
+                <span class="tip">默认为30天</span>
+              </el-row>
+            </el-form-item>
+          </div>
+<!--          <el-form-item label="图文链接:" prop="linkUrl">-->
+<!--            <el-input v-model="fileFrom.linkUrl" :rows="2"  placeholder="选择了课程小节会自动设置地址" />-->
+<!--          </el-form-item>-->
+        </div>
+        <div v-if="welcomeItem.type==='miniprogram'">
+
+          <el-form-item label="选择课程" prop="miniprogramCourseId">
+            <el-select  v-model="fileFrom.courseId" placeholder="请选择课程" style=" margin-right: 10px;" size="mini" filterable @change="courseChange(fileFrom,welcomeItem.index,welcomeItem.itemIndex)">
+              <el-option
+                v-for="dict in courseList"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="parseInt(dict.dictValue)"
+              />
+            </el-select>
+            <el-select  v-model="fileFrom.videoId" placeholder="请选择小节" size="mini" style=" margin-right: 10px;" filterable @change="videoIdChange(fileFrom, welcomeItem.index, welcomeItem.itemIndex,welcomeItem.type)" >
+              <el-option
+                v-for="dict in videoList"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="parseInt(dict.dictValue)"
+              />
+            </el-select>
+          </el-form-item>
+
+          <el-form-item label="小程序标题:" prop="miniprogramTitle">
+            <el-input v-model="fileFrom.miniprogramTitle" :rows="2" maxlength="64" placeholder="请输入小程序消息标题,最长为64字节" @input="checkByteLength(fileFrom)" />
+          </el-form-item>
+          <div v-if="fileFrom.videoId!=null">
+            <el-form-item label="小程序链接:"  label-width="100px" >
+              <el-tag type="warning" v-model="fileFrom.miniprogramPage='待生成'">选择的课程小节 即为卡片小程序链接地址</el-tag>
+            </el-form-item>
+          </div>
+          <el-form-item label="appid" prop="miniprogramAppid" v-show="false" >
+            <el-input v-model="fileFrom.miniprogramAppid='wx73f85f8d62769119' " disabled />
+          </el-form-item>
+
+          <div v-if="fileFrom.videoId!=null">
+            <el-form-item label="课节过期时间" style="margin-top: 1%" required label-width="110px">
+              <el-row>
+                <el-input-number  v-model="fileFrom.expiresDays"  :min="1" :max="9999" ></el-input-number>
+                (天)
+              </el-row>
+              <el-row>
+                <span class="tip">默认为30天</span>
+              </el-row>
+            </el-form-item>
+          </div>
+          <!--          <el-form-item label="图文链接:" prop="linkUrl">-->
+          <!--            <el-input v-model="fileFrom.linkUrl" :rows="2"  placeholder="选择了课程小节会自动设置地址" />-->
+          <!--          </el-form-item>-->
+        </div>
+      </el-form>
+      <div slot="footer" class="dialog-footer" style="text-align: center">
+        <el-button type="primary" @click="confirmUpload('fileFrom')">确定</el-button>
+        <el-button type="primary" @click="cancelUpload">取消</el-button>
+      </div>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+import { listFriendWelcome, getFriendWelcome, delFriendWelcome, addFriendWelcome, updateFriendWelcome, exportFriendWelcome } from "@/api/qw/friendWelcome";
+import qwUserList from '@/views/qw/user/qwUserList.vue'
+import ImageUploadWeclome from '@/views/qw/friendWelcome/ImageUploadWeclome.vue'
+import ImageUpload from '@/views/qw/material/ImageUpload.vue'
+import { getQwAllUserList,getCompanyListByCorpId } from '@/api/company/companyUser'
+import { getMyQwUserList,getMyQwCompanyListAll } from "@/api/qw/user";
+import {courseList, videoList} from "@/api/qw/sop";
+export default {
+  name: "FriendWelcome",
+  components: { ImageUpload, qwUserList,ImageUploadWeclome},
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      //公司列表
+      myQwCompanyList:[],
+      myCompanyList:[],
+      //选择成员列表
+      listUser:{
+        title:"",
+        open:false
+      },
+      //选择成员列表
+      userSelectList:[],
+      fileFrom:{
+        imagePicUrl:null,
+        linkTitle:null,
+        linkPicUrl:null,
+        linkDesc:null,
+        linkUrl:null,
+        videoId:null,
+        courseId:null,
+        expiresDays:30,
+        miniprogramTitle:null,
+        miniprogramPage:null,
+        miniprogramPicUrl:null,
+        miniprogramAppid:null,
+      },
+      uploadUrl: process.env.VUE_APP_BASE_API + "/common/uploadOSS2",
+      courseList:[],
+      videoList:[],
+      fuleRules:{
+        imagePicUrl:[ { required: true, message: "图片不能为空", trigger: "submit" }],
+        linkTitle:[ { required: true, message: "图文标题不能为空", trigger: "submit" }],
+        linkUrl:[ { required: true, message: "图文链接不能为空", trigger: "submit" }],
+        miniprogramTitle:[ { required: true, message: "图文链接不能为空", trigger: "submit" }],
+        miniprogramCourseId:[
+          {
+            required: true,
+            validator: (rule, value, callback) => {
+              // 检查id是否为空
+              if (!this.fileFrom.courseId) {
+                return callback(new Error('请选择课程'));
+              }
+              // 检查ddId是否为空
+              if (!this.fileFrom.videoId) {
+                return callback(new Error('请选择小节'));
+              }
+              // 校验通过
+              callback();
+            },
+            trigger: 'change' // 下拉选择变化时触发校验
+          }
+        ]
+      },
+
+
+      weekOptions: [{
+        value: 1,
+        label: '星期一'
+      }, {
+        value: 2,
+        label: '星期二'
+      }, {
+        value: 3,
+        label: '星期三'
+      }, {
+        value: 4,
+        label: '星期四'
+      }, {
+        value: 5,
+        label: '星期五'
+      }
+        , {
+          value: 6,
+          label: '星期六'
+        }
+        , {
+          value: 7,
+          label: '星期天'
+        }],
+
+      welcomeItem:{
+        open: false,
+        title: '',
+        type: '',
+        index: -1,
+        itemIndex: -1
+      },
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      //是否
+      allowSelectOptions:[],
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 好友欢迎语表格数据
+      friendWelcomeList: [],
+      //账号列表
+      companyUserList:[],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        id: null,
+        qwUserIds: [],
+        companyId: null,
+        welcomeText: null,
+        isDayparting: null,
+        createTime: null,
+        updateTime: null,
+        isSendMsg: null,
+        corpId: null,
+        companyId: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        qwUserIds: [
+          { required: true, message: "发送企业群发消息的成员账号不能为空", trigger: "submit" }
+        ],
+        welcomeText:[
+          { required: true, message: "消息内容不能为空噢", trigger: "submit" }
+        ],
+
+      },
+      itemRules: {
+        week: [
+          { required: true, message: '请选择发起时间的星期', trigger: 'submit' }
+        ],
+        startTime: [
+          { required: true, message: '请选择开始时间', trigger: 'submit' },
+        ],
+        endTime: [
+          { required: true, message: '请选择结束时间', trigger: 'submit' },
+
+        ],
+        welcomeText: [
+          { required: true, message: '消息内容不能为空噢', trigger: 'submit' }
+        ]
+      }
+
+    };
+  },
+  created() {
+    //账号列表
+
+
+    //是否允许发送
+    this.getDicts("sys_qw_allow_select").then(response => {
+      this.allowSelectOptions = response.data;
+    });
+    courseList().then(response => {
+      this.courseList = response.list;
+    });
+    getMyQwCompanyListAll().then(response => {
+
+            this.myQwCompanyList = response.data;
+            if(this.myQwCompanyList!=null){
+              getCompanyListByCorpId(this.myQwCompanyList[0].dictValue).then(response=>{
+                this.myCompanyList = response.data
+                this.queryParams.companyId = this.myCompanyList[0].companyId
+                this.queryParams.corpId=this.myQwCompanyList[0].dictValue
+                getQwAllUserList(this.myQwCompanyList[0].dictValue,this.myCompanyList[0].companyId).then(response => {
+                this.companyUserList = response.data;
+              });
+              this.getList();
+              })
+
+              
+            }
+    });
+  },
+  watch:{
+    userSelectList(newList) {
+      this.form.qwUserIds =newList.map(item =>item.id);
+    }
+  },
+  methods: {
+    updateCorpId(){
+        this.getList();
+        this.queryParams.companyId = "";
+        getCompanyListByCorpId(this.queryParams.corpId).then(response =>{
+          this.myCompanyList = response.data;
+        })
+      //   getQwAllUserList(this.queryParams.corpId).then(response => {
+      //   this.companyUserList = response.data;
+      // });
+     },
+     updateCompanyId(){
+        this.getList();
+        getQwAllUserList(this.queryParams.corpId,this.queryParams.companyId).then(response =>{
+          this.companyUserList = response.data;
+        })
+     },
+    /** 查询好友欢迎语列表 */
+    getList() {
+      this.loading = true;
+
+      listFriendWelcome(this.queryParams).then(response => {
+
+        // 将处理后的数据赋值给 friendWelcomeList
+        this.friendWelcomeList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // // 检查字节长度
+    checkByteLength(fileFrom) {
+      const text = fileFrom.miniprogramTitle;
+      const byteLength = this.getByteLength(text); // 获取当前字节数
+
+      // 如果字节数超过64,截断输入内容
+      if (byteLength > 64) {
+        this.$set(fileFrom, 'miniprogramTitle', this.truncateTextByByteLength(text,64));
+      }
+    },
+
+    // 计算字符串的字节数
+    getByteLength(text) {
+      return new Blob([text]).size; // 使用 Blob 计算字节数
+    },
+
+    // 根据字节数截断字符串
+    truncateTextByByteLength(text, maxByteLength) {
+      let byteLength = 0;
+      let result = "";
+
+      for (let i = 0; i < text.length; i++) {
+        const char = text[i];
+        const charByteLength = this.getByteLength(char); // 获取当前字符的字节数
+
+        // 如果加上当前字符的字节数后不超过限制,则添加到结果中
+        if (byteLength + charByteLength <= maxByteLength) {
+          result += char;
+          byteLength += charByteLength;
+        } else {
+          break; // 超过限制时停止
+        }
+      }
+
+      return result;
+    },
+
+    //选择群发的企业成员账号
+    handlelistUser(){
+      setTimeout(() => {
+        this.$refs.QwUserList.getDetails(this.queryParams.corpId);
+      }, 1);
+      this.listUser.title="选择企业成员"
+      this.listUser.open=true;
+    },
+    //选择的成员账号列表
+    selectUserList(list){
+
+      this.listUser.open=false;
+
+      // 3. 遍历要添加的 list,逐条判断是否存在重复
+      list.forEach(newItem => {
+        // some() 判断是否存在相同 id
+        const isExist = this.userSelectList.some(oldItem => oldItem.id === newItem.id);
+        if (!isExist) {
+          // 不存在重复的,才添加
+          this.userSelectList.push(newItem);
+        }
+      });
+      // //用于显示
+      // this.userSelectList=list;
+
+    },
+    //删除一些选择了的账号
+    handleClosegroupUser(list){
+
+      // 假设 list 对象具有一个 id 属性
+      const index = this.userSelectList.findIndex(t => t.id === list.id);
+      if (index !== -1) {
+        this.userSelectList.splice(index,1);
+      }
+    },
+    //附件选择
+    handleCommand(command,itemIndex){
+
+      if (this.form.attachments.length >=9 && itemIndex===-1) {
+        return this.$message.error('附件数量已达上限,无法添加更多附件');
+      }
+
+      if (this.isDayparting==='1' && this.form.daypartingItemlist[itemIndex].attachments.length>=9){
+        return this.$message.error('附件数量已达上限,无法添加更多附件');
+      }
+
+      this.welcomeItem = {
+        open: true,
+        title: this.getTitleByCommand(command),
+        type: command,
+        index: itemIndex === -1 ? this.form.attachments.length : this.form.daypartingItemlist[itemIndex].attachments.length,
+        itemIndex
+      };
+    },
+
+    getTitleByCommand(command) {
+      switch (command) {
+        case 'image':
+          return '添加图片';
+        case 'link':
+          return '添加链接';
+        case 'miniprogram':
+          return '添加小程序';
+      }
+    },
+
+
+    courseChange(fileFrom,index,itemIndex){
+
+      // 清空 videoId 选择
+      this.$set(fileFrom, 'videoId', null);
+      // 清空 videoList
+      this.videoList = [];
+
+      if (fileFrom.courseId != null) {
+        // 查找选中的课程对应的 label 和 dictImgUrl
+        const selectedCourse = this.courseList.find(course => parseInt(course.dictValue) === fileFrom.courseId);
+
+        if (selectedCourse) {
+          // 设置 linkTitle 和 linkImageUrl
+          this.$set(fileFrom, 'linkTitle', selectedCourse.dictLabel);
+          this.$set(fileFrom, 'linkPicUrl', selectedCourse.dictImgUrl);
+        }
+
+
+        // 获取新的 videoList
+        videoList(fileFrom.courseId).then(response => {
+          this.videoList = response.list;
+        });
+
+      }
+      //
+      // // 更新对应的数据层级
+      // if (itemIndex === -1) {
+      //   // 更新 form.attachments
+      //   this.$set(this.form.attachments, index, {
+      //     ...this.form.attachments[index],
+      //     courseId: fileFrom.courseId,
+      //     videoId: null, // 因为已清空
+      //     title: fileFrom.linkTitle,
+      //     picurl: fileFrom.linkPicUrl
+      //   });
+      // } else {
+      //
+      //   this.$set(this.form.daypartingItemlist[itemIndex].attachments, index, {
+      //     ...this.form.daypartingItemlist[itemIndex].attachments[index],
+      //     courseId: fileFrom.courseId,
+      //     videoId: null, // 因为已清空
+      //     title: fileFrom.linkTitle,
+      //     picurl: fileFrom.linkPicUrl
+      //   });
+      // }
+    },
+    videoIdChange(fileFrom,index, itemIndex,type){
+      //选择了课程小节则 默认绑上
+      if (fileFrom.videoId != null) {
+        // 根据 videoId 获取相关信息(假设有相关的 API 调用)
+        let  selectedVideo = this.videoList.find(course => parseInt(course.dictValue) === fileFrom.videoId);
+        if (selectedVideo && type==='link') {
+          this.$set(fileFrom, 'linkDesc', selectedVideo.dictLabel);
+          this.$set(fileFrom, 'expiresDays', 30);
+        }
+        if (selectedVideo && type==='miniprogram') {
+          this.$set(fileFrom, 'miniprogramTitle', this.truncateTextByByteLength(selectedVideo.dictLabel,64));
+          this.$set(fileFrom, 'expiresDays', 30);
+        }
+
+      }
+
+      // // 更新对应的数据层级
+      // if (itemIndex === -1) {
+      //   // 更新 form.attachments
+      //   this.$set(this.form.attachments, index, {
+      //     ...this.form.attachments[index],
+      //     videoId: fileFrom.videoId,
+      //     desc: fileFrom.linkDesc,
+      //   });
+      // } else {
+      //   // 更新 form.daypartingItemlist[itemIndex].attachments
+      //   this.$set(this.form.daypartingItemlist[itemIndex].attachments, index, {
+      //     ...this.form.daypartingItemlist[itemIndex].attachments[index],
+      //     videoId: fileFrom.videoId,
+      //     desc: fileFrom.linkDesc,
+      //   });
+      //
+      // }
+
+    },
+    //修改附件
+    editFileItem(item, index, itemIndex){
+
+      this.welcomeItem = {
+        open: true,
+        title: this.getEditTitleByMsgType(item.msgtype),
+        type: item.msgtype,
+        index,
+        itemIndex
+      };
+      if (item.msgtype === 'image') {
+        this.fileFrom.imagePicUrl = item.image.pic_url;
+      }else if (item.msgtype === 'video') {
+        this.fileFrom.videoUrl = item.video.url;
+      } else if (item.msgtype === 'link') {
+        this.fileFrom.linkTitle = item.link.title;
+        this.fileFrom.linkPicUrl = item.link.picurl;
+        this.fileFrom.linkDesc = item.link.desc;
+        this.fileFrom.linkUrl = item.link.url;
+        this.fileFrom.videoId = item.link.videoId;
+        this.fileFrom.courseId = item.link.courseId;
+        this.fileFrom.expiresDays = item.link.expiresDays;
+
+        videoList(item.link.courseId).then(response => {
+          this.videoList = response.list;
+        });
+
+
+      }else if (item.msgtype === 'miniprogram') {
+        this.fileFrom.miniprogramAppid = 'wx73f85f8d62769119';
+        this.fileFrom.miniprogramTitle = item.miniprogram.title;
+        this.fileFrom.miniprogramPicUrl = "待生成";
+        this.fileFrom.miniprogramPage = "待生成";
+        this.fileFrom.videoId = item.miniprogram.videoId;
+        this.fileFrom.courseId = item.miniprogram.courseId;
+        this.fileFrom.expiresDays = item.miniprogram.expiresDays;
+
+        videoList(item.miniprogram.courseId).then(response => {
+          this.videoList = response.list;
+        });
+
+      }
+
+
+    },
+
+
+
+    getEditTitleByMsgType(msgType) {
+      switch (msgType) {
+        case 'image':
+          return '编辑图片';
+        case 'link':
+          return '编辑链接';
+        case 'miniprogram':
+          return '编辑小程序';
+      }
+    },
+
+    //删除附件
+    removeFileItem(data,index, itemIndex) {
+
+      if (itemIndex === -1) {
+        this.form.attachments.splice(index, 1);
+      } else {
+        this.form.daypartingItemlist[itemIndex].attachments.splice(index, 1);
+      }
+    },
+
+    //添加分时段欢迎语
+    addItemList(){
+      this.form.daypartingItemlist.push({welcomeText:null,attachments:[],week:[1,2,3,4,5,6,7],startTime:null,endTime:null})
+    },
+
+
+    //删除某一个分时段欢迎语
+    delItemList(index){
+      this.form.daypartingItemlist.splice(index,1)
+    },
+
+    //提交附件
+    confirmUpload(fileFrom) {
+     this.$refs[fileFrom].validate((valid) => {
+          if (valid) {
+            const { type, index, itemIndex } = this.welcomeItem;
+            let attachment = {};
+            if (type === 'image') {
+              attachment = {
+                msgtype: 'image',
+                image: {
+                  pic_url: this.fileFrom.imagePicUrl
+                }
+              };
+            } else if (type === 'video') {
+              attachment = {
+                msgtype: 'video',
+                video: {
+                  url:this.fileFrom.videoUrl,
+                }
+              };
+            } else if (type === 'link') {
+              attachment = {
+                msgtype: 'link',
+                link: {
+                  title: this.fileFrom.linkTitle,
+                  picurl: this.fileFrom.linkPicUrl,
+                  desc: this.fileFrom.linkDesc,
+                  url: this.fileFrom.linkUrl,
+                  courseId:this.fileFrom.courseId,
+                  videoId:this.fileFrom.videoId,
+                  expiresDays:this.fileFrom.expiresDays,
+                }
+              };
+            }else if (type==='miniprogram'){
+              attachment = {
+                msgtype: 'miniprogram',
+                miniprogram: {
+                  title: this.fileFrom.miniprogramTitle,
+                  pic_media_id: "待查询",
+                  appid: "wx73f85f8d62769119",
+                  page: this.fileFrom.miniprogramPage,
+                  courseId:this.fileFrom.courseId,
+                  videoId:this.fileFrom.videoId,
+                  expiresDays:this.fileFrom.expiresDays,
+                }
+              };
+            }
+
+            if (itemIndex === -1) {
+              // 默认欢迎语附件处理
+              if (index < this.form.attachments.length) {
+                // 存在附件则更新
+                this.form.attachments.splice(index, 1, attachment);
+              } else {
+                // 不存在附件则插入
+                this.form.attachments.push(attachment);
+              }
+
+            } else {
+              // 分时段欢迎语附件处理
+              if (index < this.form.daypartingItemlist[itemIndex].attachments.length) {
+                // 存在附件则更新
+                this.form.daypartingItemlist[itemIndex].attachments.splice(index, 1, attachment);
+              } else {
+                // 不存在附件则插入
+                this.form.daypartingItemlist[itemIndex].attachments.push(attachment);
+              }
+            }
+            this.resetFileFrom();
+          } else {
+            console.log('error submit!!');
+            return false;
+          }
+        });
+
+    },
+
+    //取消附件
+    cancelUpload() {
+      this.resetFileFrom();
+      this.welcomeItem.open = false;
+    },
+
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+
+    //重置附件表单
+    resetFileFrom() {
+      this.fileFrom = {
+        imagePicUrl: null,
+        linkTitle: null,
+        linkPicUrl: null,
+        linkDesc: null,
+        linkUrl: null,
+        videoId:null,
+        courseId:null,
+        miniprogramTitle:null,
+        miniprogramPage:null,
+        miniprogramPicUrl:null,
+        miniprogramAppid:null,
+      };
+
+      this.welcomeItem={
+        open: false,
+        title: '',
+        type: '',
+        index: -1,
+        itemIndex: -1
+      } // 重置编辑索引
+
+      this.videoList=[];
+    },
+
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        qwUserIds: [],
+        companyId: null,
+        //默认欢迎语附件
+        attachments: [],
+        createdTime: null,
+        updateTieme: null,
+        isSendMsg:'1',
+        welcomeText: '',
+        isDayparting: '2',
+        //分时段欢迎语
+        daypartingItemlist:[{welcomeText:null,attachments:[],week:[1,2,3,4,5,6,7],startTime:null,endTime:null}],
+      };
+      this.userSelectList=[]
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.queryParams.createTime = null;
+      this.resetForm("queryForm");
+      this.queryParams.corpId= this.myQwCompanyList[0].dictValue
+      getQwAllUserList(this.queryParams.corpId).then(response => {
+        this.companyUserList = response.data;
+      });
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "新建好友欢迎语";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getFriendWelcome(id).then(response => {
+
+
+        let data = response.row;
+
+        // 转换 attachments
+        if (typeof data.attachments === 'string') {
+          data.attachments = JSON.parse(data.attachments);
+        }
+
+        // 转换 daypartingItemlist
+        if (typeof data.daypartingItemlist === 'string') {
+          data.daypartingItemlist = JSON.parse(data.daypartingItemlist);
+        }
+
+        // 转换 daypartingItemlist 中的每个项目的 attachments 和 week
+        if (Array.isArray(data.daypartingItemlist)) {
+          data.daypartingItemlist = data.daypartingItemlist.map(item => {
+            return {
+              ...item,
+              attachments: typeof item.attachments === 'string' ? JSON.parse(item.attachments) : item.attachments,
+              week: typeof item.week === 'string' ? JSON.parse(item.week) : item.week
+            };
+          });
+        }
+
+        // 赋值给表单
+        this.form = data;
+        this.userSelectList=this.form.userSelectList
+
+        this.open = true;
+        this.title = "修改好友欢迎语";
+      });
+    },
+    /** 提交按钮 验证 from表单*/
+    submitForm() {
+
+      this.loading=true;
+
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          this.form.corpId=this.queryParams.corpId;
+          //有分时段欢迎语 验证分时段表单
+          if (this.form.isDayparting==='1'){
+            const itemForms = this.$refs.friendWelcomeItemForm;
+            if (Array.isArray(itemForms)) {
+              let allValid = true;
+
+              itemForms.forEach((itemFormRef, index) => {
+                itemFormRef.validate((itemValid) => {
+                  if (!itemValid) {
+                    this.loading=false;
+                    allValid = false;
+                  } else {
+                    const { startTime, endTime } = itemFormRef.model;
+                    if (startTime && endTime && startTime > endTime) {
+                      this.$message.error(`时段 ${index + 1} 的开始时间不能大于结束时间`);
+                      allValid = false;
+                      this.loading=false;
+
+                    }
+                  }
+
+                  if (index === itemForms.length - 1 && allValid) {
+                    //全表单验证通过
+                    this.commitForm();
+                  }
+                });
+              });
+            }
+          }else {
+            //只有默认的
+            this.commitForm();
+
+          }
+
+        }
+        this.loading = false;
+      });
+    },
+
+    //提交form表单
+    commitForm(){
+
+      // 深拷贝表单数据
+      const requestData = { ...this.form };
+      // 将 `form.attachments` 转为 JSON 字符串
+      requestData.attachments = JSON.stringify(this.form.attachments);
+      requestData.qwUserIds = JSON.stringify(this.form.qwUserIds);
+
+      // 遍历 `daypartingItemlist`,将其中的 `attachments` 和 `week` 转为 JSON 字符串
+      requestData.daypartingItemlist = JSON.stringify(requestData.daypartingItemlist.map(item => ({
+          ...item,
+        }))
+      );
+
+
+      if (this.form.id != null) {
+        updateFriendWelcome(requestData).then(response => {
+          this.msgSuccess("修改成功");
+          this.loading=false;
+          this.open = false;
+          this.getList();
+        }).catch(error => {
+          this.open=false;
+          this.loading = false;
+        });
+      } else {
+        addFriendWelcome(requestData).then(response => {
+          this.msgSuccess("新增成功");
+          this.loading=false;
+          this.open = false;
+          this.getList();
+        }).catch(error => {
+          this.open=false;
+          this.loading = false;
+        });
+      }
+
+
+      // 重置表单 无论成功还是失败-都重置表单
+      this.reset();
+    },
+
+    //处理时间
+    // formatTime(date) {
+    //   const hours = date.getHours().toString().padStart(2, '0');
+    //   const minutes = date.getMinutes().toString().padStart(2, '0');
+    //   const seconds = date.getSeconds().toString().padStart(2, '0');
+    //   return `${hours}:${minutes}:${seconds}`;
+    // },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除好友欢迎语编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delFriendWelcome(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有好友欢迎语数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportFriendWelcome(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    },
+
+    handleAvatarSuccessVideo(res, file, content) {
+      if (res.code == 200) {
+        // 使用 $set 确保响应式更新
+        this.$set(content, 'videoUrl', res.url);
+      } else {
+        this.msgError(res.msg);
+      }
+
+    },
+    beforeAvatarUploadVideo(file) {
+      const isLt30M = file.size / 1024 / 1024 < 10;
+      const isMP4 = file.type === 'video/mp4';
+
+      if (!isMP4) {
+        this.$message.error('仅支持上传 MP4 格式的视频文件!');
+        return false;
+      }
+
+      if (!isLt30M) {
+        this.$message.error('上传大小不能超过 10MB!');
+        return false;
+      }
+
+      return true;
+    },
+  }
+};
+</script>
+
+<style>
+.text-container {
+  max-height: 7.5em; /* 设置最大高度为6行,根据字体大小调整 */
+  overflow-y: auto; /* 内容超出时显示滚动条 */
+  line-height: 1.5em; /* 行高设置,确保每行高度一致 */
+}
+</style>

+ 355 - 0
src/views/qw/groupMsg/customerGroupDetails.vue

@@ -0,0 +1,355 @@
+<template>
+  <div style="background-color: #fff;margin: 15px">
+    <el-card class="box-card">
+      <div  class="desct">
+        数据统计
+      </div>
+      <div class="statistics-container">
+        <el-row :gutter="20" type="flex" justify="space-between">
+          <el-col :span="6" v-for="(item, index) in CountGroupMsgUserList" :key="index">
+            <el-card style="height: 100px">
+              <div class="statistic-item">
+                <h2>{{ item.count }} </h2>
+                <p>{{ item.label }}</p>
+              </div>
+            </el-card>
+          </el-col>
+        </el-row>
+      </div>
+    </el-card>
+
+    <el-card class="box-card" style="margin-top: 10px">
+      <div style="margin-bottom: 2%">
+            <div class="desct">
+              发送接收详情
+            </div>
+            <el-alert
+              title="注意事项"
+              type="warning"
+              description="1、因企业微信接口限制,提醒成员完成群发任务,24小时内每个群发最多触发三次提醒,多点无效噢。2、成员选择客户发送之后,未选择的客户不能再次选择发送了"
+              :closable="false"
+              show-icon>
+            </el-alert>
+          </div>
+          <div>
+            <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="120px">
+              <el-form-item label="成员姓名" prop="nickName">
+                <el-input
+                  v-model="queryParams.nickName"
+                  placeholder="请输入想查询的成员姓名"
+                  clearable
+                  size="small"
+                  @keyup.enter.native="handleQuery"
+                />
+              </el-form-item>
+              <el-form-item label="客户名称" prop="name">
+                <el-input
+                  v-model="queryParams.name"
+                  placeholder="请输入想查询的客户姓名"
+                  clearable
+                  size="small"
+                  @keyup.enter.native="handleQuery"
+                />
+              </el-form-item>
+              <el-form-item label="成员发送状态" prop="status">
+                 <el-select v-model="queryParams.status" placeholder="请选择员工发送状态" >
+                   <el-option v-for="item in groupMsgStatusOptions"
+                              :key="item.dictValue"
+                              :label="item.dictLabel"
+                              :value="item.dictValue">
+                   </el-option>
+                 </el-select>
+              </el-form-item>
+
+              <el-form-item label="客户接收状态" prop="sendStatus">
+                  <el-select v-model="queryParams.sendStatus" placeholder="请选择客户接收状态">
+                    <el-option v-for="item in groupMsgSendStatusOptions"
+                               :key="item.dictValue"
+                               :label="item.dictLabel"
+                               :value="item.dictValue">
+
+                    </el-option>
+                  </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>
+                <el-button type="warning" icon="el-icon-message-solid" size="mini" @click="triggerRemindGroupMsg">提醒成员发送</el-button>
+                <el-button type="primary" icon="el-icon-refresh" size="mini" plain @click="refreshResults">刷新/获取企微结果</el-button>
+              </el-form-item>
+            </el-form>
+
+            <el-table v-loading="loading" :data="groupMsgUserDetailsList">
+              <el-table-column label="销售" align="center" prop="nickName" />
+              <el-table-column label="成员企微昵称" align="center" prop="qwUserName" />
+              <el-table-column label="成员发送状态" align="center" prop="status">
+                <template slot-scope="scope">
+                  <dict-tag :options="groupMsgStatusOptions" :value="scope.row.status"/>
+                </template>
+              </el-table-column>
+              <el-table-column label="客户" align="center" prop="name" >
+                <template slot-scope="scope">
+                  <el-image
+                    v-if="scope.row.avatar"
+                    style="width: 20px; height: 20px"
+                    :src="scope.row.avatar"
+                    fit="contain"
+                    @click="openImageViewer(scope.row.avatar)"
+                    />
+                  <span>{{scope.row.name}}</span>
+                </template>
+              </el-table-column>
+              <el-table-column label="客户接收状态" align="center" prop="sendStatus" >
+                <template slot-scope="scope">
+                  <dict-tag :options="groupMsgSendStatusOptions" :value="scope.row.sendStatus"/>
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+
+      <pagination
+        v-show="total>0"
+        :total="total"
+        :page.sync="queryParams.pageNum"
+        :limit.sync="queryParams.pageSize"
+        @pagination="getUserList"
+      />
+
+    </el-card>
+
+    <!-- 大图预览对话框 -->
+    <el-dialog
+      :visible.sync="dialogVisible"
+      :modal="false"
+      width="1200px"
+      append-to-body>
+      <img
+        :src="this.dialogImageUrl"
+        style="display: block; max-width: 100%; margin: 0 auto"
+      />
+    </el-dialog>
+  </div>
+</template>
+<script>
+
+import { countGroupMsgUser, CountGroupMsgUserDetails, remindGroupMsg } from '@/api/qw/groupMsg'
+import { refreshResultsMsgUser } from '@/api/qw/groupMsgUser'
+
+export default {
+  name: "Customer-group-details",
+  components:{},
+
+  props:{
+    rowDetailFrom:{},
+  },
+
+  watch:{
+    rowDetailFrom:{
+      handler(newVal){
+        // 当formData变化时重新查询
+        this.getUserList(newVal);
+        this.getCountGroupMsgUser(newVal.groupMsgId)
+      },
+      deep: true
+    }
+  },
+  data() {
+    return {
+      //数据统计
+      CountGroupMsgUserList: [],
+
+      //成员详情
+      groupMsgUserDetailsList:[],
+
+      //成员发送状态
+      groupMsgStatusOptions:[],
+
+      //客户接收状态
+      groupMsgSendStatusOptions:[],
+
+
+      //放大图片
+      dialogImageUrl:null,
+      dialogVisible:false,
+
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+
+
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        qwMsgId:null,
+        msgId:null,
+        nickName:null,
+        name:null,
+        status:null,
+        sendStatus:null,
+        chatType:"single",
+
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      },
+
+    };
+  },
+  created() {
+      this.getUserList(this.rowDetailFrom)
+      this.getCountGroupMsgUser(this.rowDetailFrom.id)
+
+    //成员发送状态
+    this.getDicts("sys_qw_groupMsg_status").then(response => {
+      this.groupMsgStatusOptions = response.data;
+    });
+
+    //客户接收状态
+    this.getDicts("sys_qw_groupMsg_SendStatus").then(response => {
+      this.groupMsgSendStatusOptions = response.data;
+    });
+
+
+  },
+
+
+  methods: {
+    //获取成员详细
+    getUserList(val){
+      this.queryParams.msgId = val.id || this.rowDetailFrom.id;
+
+      this.loading=false;
+      CountGroupMsgUserDetails(this.queryParams).then(res=>{
+            this.groupMsgUserDetailsList=res.rows
+            this.total = res.total;
+            this.loading = false;
+      })
+
+    },
+
+    /** 提醒成员群发 */
+    triggerRemindGroupMsg(){
+      this.queryParams.qwMsgId=this.rowDetailFrom.msgId
+      remindGroupMsg(this.queryParams).then(res=>{
+        if (res.code==200){
+
+          if (res.data.errcode==0){
+            return this.msgSuccess("提醒成员群发成功")
+          }else if (res.data.errcode==41094){
+            return this.msgWarning("此条记录的每日提醒次数超过限制了噢")
+          }else {
+            return this.msgError(res.data.errmsg)
+          }
+
+        }else {
+          return this.msgError(res.msg)
+        }
+
+      })
+    },
+
+    /** 刷新获取结果 */
+    refreshResults(){
+
+      let params = [];
+      this.loading = true;
+
+      //搞定定时任务导致的问题
+      let ResultsMsgUser={
+          id:this.rowDetailFrom.id,
+          msgId:this.rowDetailFrom.msgId,
+          chatType:this.rowDetailFrom.chatType,
+          timerResultType:1,
+          companyId:this.rowDetailFrom.companyId,
+          corpId:this.rowDetailFrom.corpId,
+      }
+
+      // 根据不同条件选择参数
+      if (this.groupMsgUserDetailsList == 0) {
+        params.push(ResultsMsgUser)
+      } else {
+        params = this.groupMsgUserDetailsList// 如果 `groupMsgUserDetailsList` 是一个对象
+      }
+
+      refreshResultsMsgUser(params).then(res=>{
+        this.loading=false;
+        if (res.code==200){
+          this.handleQuery();
+          return this.msgSuccess(res.msg)
+        }else {
+          this.handleQuery();
+          return this.msgError(res.msg)
+        }
+
+      })
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getUserList(this.rowDetailFrom);
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+
+    openImageViewer(url) {
+      // 打开大图预览对话框
+      this.dialogImageUrl=url
+      this.dialogVisible = true;
+    },
+    //数据详情
+    getCountGroupMsgUser(val){
+      countGroupMsgUser(val).then(res=>{
+        this.CountGroupMsgUserList=Object.keys(res.data).map(key=>{
+          return {label: key,count:res.data[key]}
+        })
+      })
+    },
+
+  }
+};
+</script>
+<style scoped>
+.desct{
+  padding-bottom: 20px;
+  color: #524b4a;
+  font-weight: bold;
+}
+.statistics-container {
+  padding: 20px;
+}
+.statistic-item {
+  text-align: center;
+}
+.statistic-item h2 {
+  font-size: 24px;
+  margin: 0;
+  font-weight: normal;
+}
+.statistic-item p {
+  margin: 5px 0 0;
+  color: #666;
+  font-weight: normal;
+}
+</style>

+ 205 - 0
src/views/qw/material/ImageUpload.vue

@@ -0,0 +1,205 @@
+<template>
+  <div class="component-upload-image">
+    <el-upload
+      :action="uploadUrl"
+      list-type="picture-card"
+      :on-success="handleUploadSuccess"
+      :before-upload="handleBeforeUpload"
+      :limit="limit"
+      :on-error="handleUploadError"
+      :on-exceed="handleExceed"
+      name="file"
+      :on-remove="handleRemove"
+      :show-file-list="true"
+      :file-list="fileList"
+      :on-preview="handlePictureCardPreview"
+      :class="{hide: this.fileList.length >= this.limit}"
+    >
+      <i class="el-icon-plus"></i>
+    </el-upload>
+
+    <el-dialog
+      :visible.sync="dialogVisible"
+      title="预览"
+      width="800"
+      append-to-body
+    >
+      <img
+        :src="dialogImageUrl"
+        style="display: block; max-width: 100%; margin: 0 auto"
+      />
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getToken } from "@/utils/auth";
+
+export default {
+  name: "ImageUpload",
+  props: {
+    value: [String, Object, Array],
+    // 图片数量限制
+    limit: {
+      type: Number,
+      default: 1,
+    },
+    // 大小限制(MB)
+    fileSize: {
+        type: Number,
+        default: 10,
+    },
+    // 文件类型, 例如['png', 'jpg', 'jpeg']
+    fileType: {
+      type: Array,
+      default: () => ["png", "jpg", "jpeg"],
+    },
+    // 是否显示提示
+    isShowTip: {
+      type: Boolean,
+      default: true
+    }
+  },
+  data() {
+    return {
+      dialogImageUrl: "",
+      dialogVisible: false,
+      hideUpload: false,
+      baseUrl:"",
+      uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
+      headers: {
+        Authorization: "Bearer " + getToken(),
+      },
+      fileList: []
+    };
+  },
+  watch: {
+    value: {
+      handler(val) {
+        if (val) {
+          // 首先将值转为数组
+          const list = Array.isArray(val) ? val : this.value.split(',');
+          // 然后将数组转为对象数组
+          this.fileList = list.map(item => {
+            if (typeof item === "string") {
+              if (item.indexOf(this.baseUrl) === -1) {
+                  item = { name: item, url: item };
+              } else {
+                  item = { name: item, url: item };
+              }
+            }
+            return item;
+          });
+        } else {
+          this.fileList = [];
+          return [];
+        }
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  computed: {
+    // 是否显示提示
+    showTip() {
+      return this.isShowTip && (this.fileType || this.fileSize);
+    },
+  },
+  methods: {
+    // 删除图片
+    handleRemove(file, fileList) {
+      const findex = this.fileList.map(f => f.name).indexOf(file.name);
+      if(findex > -1) {
+        this.fileList.splice(findex, 1);
+        this.$emit("input", this.listToString(this.fileList));
+      }
+    },
+    // 上传成功回调
+    handleUploadSuccess(res,file) {
+      this.fileList.push({ name: res.url, url: res.url });
+      this.$emit("input", this.listToString(this.fileList));
+      this.loading.close();
+    },
+    // 上传前loading加载
+    handleBeforeUpload(file) {
+      let isImg = false;
+      if (this.fileType.length) {
+        let fileExtension = "";
+        if (file.name.lastIndexOf(".") > -1) {
+          fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
+        }
+        isImg = this.fileType.some(type => {
+          if (file.type.indexOf(type) > -1) return true;
+          if (fileExtension && fileExtension.indexOf(type) > -1) return true;
+          return false;
+        });
+      } else {
+        isImg = file.type.indexOf("image") > -1;
+      }
+
+      if (!isImg) {
+        this.$message.error(
+          `文件格式不正确, 请上传${this.fileType.join("/")}图片格式文件!`
+        );
+        return false;
+      }
+      if (this.fileSize) {
+        const isLt = file.size / 1024 / 1024 < this.fileSize;
+        if (!isLt) {
+          this.$message.error(`上传头像图片大小不能超过 ${this.fileSize} MB!`);
+          return false;
+        }
+      }
+      this.loading = this.$loading({
+        lock: true,
+        text: "上传中",
+        background: "rgba(0, 0, 0, 0.7)",
+      });
+    },
+    // 文件个数超出
+    handleExceed() {
+      this.$message.error(`上传文件数量不能超过 ${this.limit} 个!`);
+    },
+    // 上传失败
+    handleUploadError() {
+      this.$message({
+        type: "error",
+        message: "上传失败",
+      });
+      this.loading.close();
+    },
+    // 预览
+    handlePictureCardPreview(file) {
+      console.log(file)
+      this.dialogImageUrl = file.url;
+      this.dialogVisible = true;
+    },
+    // 对象转成指定字符串分隔
+    listToString(list, separator) {
+      let strs = "";
+      separator = separator || ",";
+      for (let i in list) {
+        strs += list[i].url.replace(this.baseUrl, "") + separator;
+      }
+      return strs != '' ? strs.substr(0, strs.length - 1) : '';
+    }
+  }
+};
+</script>
+<style scoped lang="scss">
+// .el-upload--picture-card 控制加号部分
+::v-deep.hide .el-upload--picture-card {
+    display: none;
+}
+// 去掉动画效果
+::v-deep .el-list-enter-active,
+::v-deep .el-list-leave-active {
+    transition: all 0s;
+}
+
+::v-deep .el-list-enter, .el-list-leave-active {
+    opacity: 0;
+    transform: translateY(0);
+}
+</style>
+

+ 830 - 0
src/views/qw/qwUserVoiceLogTotal/index.vue

@@ -0,0 +1,830 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="148px">
+      <el-form-item label="部门" prop="type">
+        <treeselect
+          style="width: 220px"
+          :clearable="false"
+          v-model="queryParams.deptId"
+          :options="deptOptions"
+          clearable
+          :show-count="true"
+          placeholder="请选择归属部门"
+        />
+      </el-form-item>
+      <el-form-item label="所属客服" prop="companyUserId">
+        <el-select v-model="queryParams.companyUserId" clearable filterable remote
+                   placeholder="请输入关键词" :remote-method="loadCompanyUserOptions"
+                   v-select-load-more="loadMoreCompanyUserOptions"
+                   :loading="companyUserOptionsLoading">
+          <el-option
+            v-for="item in companyUserOptions"
+            :key="item.dictValue"
+            :label="item.dictLabel"
+            :value="item.dictValue">
+          </el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="企微用户名称" prop="qwUserName">
+        <el-input
+          v-model="queryParams.qwUserName"
+          placeholder="请输入企微用户名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <!--      <el-form-item label="标题" prop="title">
+              <el-input
+                v-model="queryParams.title"
+                placeholder="请输入标题"
+                clearable
+                size="small"
+                @keyup.enter.native="handleQuery"
+              />
+            </el-form-item>-->
+      <!--      <el-form-item label="通话状态" prop="status">
+              <el-select v-model="queryParams.status" placeholder="请选择通话状态" clearable size="small">
+                <el-option
+                  v-for="dict in statusOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="dict.dictValue"
+                />
+              </el-select>
+            </el-form-item>-->
+      <!--      <el-form-item label="企微id" prop="corpId">
+              <el-input
+                v-model="queryParams.corpId"
+                placeholder="请输入企微id"
+                clearable
+                size="small"
+                @keyup.enter.native="handleQuery"
+              />
+            </el-form-item>-->
+      <!--      <el-form-item label="公司名称" prop="companyName">
+              <el-input
+                v-model="queryParams.companyName"
+                placeholder="请输入公司名称"
+                clearable
+                size="small"
+                @keyup.enter.native="handleQuery"
+              />
+            </el-form-item>-->
+
+      <!--      <el-form-item label="时长秒" prop="duration">
+              <el-input
+                v-model="queryParams.duration"
+                placeholder="请输入时长秒"
+                clearable
+                size="small"
+                @keyup.enter.native="handleQuery"
+              />
+            </el-form-item>-->
+      <el-form-item label="标签" prop="tagIds">
+        <div @click="hangleChangeTags()" style="cursor: pointer; border: 1px solid #e6e6e6; background-color: white; overflow: hidden; flex-grow: 1;width: 250px">
+          <div style="min-height: 35px; max-height: 200px; overflow-y: auto;" :key="selectTags.length">
+            <el-tag type="success"
+                    closable
+                    :disable-transitions="false"
+                    v-for="list in this.selectTags"
+                    :key="list.tagId"
+                    @close="handleCloseTags(list)"
+                    style="margin: 3px;"
+            >{{list.name}}
+            </el-tag>
+          </div>
+        </div>
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker v-model="createTime" size="small" style="width: 220px"
+                        value-format="yyyy-MM-dd" type="daterange" range-separator="-"
+                        start-placeholder="开始日期" end-placeholder="结束日期"
+                        @change="changeTime"></el-date-picker>
+      </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>
+      </el-form-item>
+
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <!--      <el-col :span="1.5">
+              <el-button
+                type="primary"
+                plain
+                icon="el-icon-plus"
+                size="mini"
+                @click="handleAdd"
+                v-hasPermi="['qw:qwUserVoiceLog:add']"
+              >新增</el-button>
+            </el-col>
+            <el-col :span="1.5">
+              <el-button
+                type="success"
+                plain
+                icon="el-icon-edit"
+                size="mini"
+                :disabled="single"
+                @click="handleUpdate"
+                v-hasPermi="['qw:qwUserVoiceLog:edit']"
+              >修改</el-button>
+            </el-col>
+            <el-col :span="1.5">
+              <el-button
+                type="danger"
+                plain
+                icon="el-icon-delete"
+                size="mini"
+                :disabled="multiple"
+                @click="handleDelete"
+                v-hasPermi="['qw:qwUserVoiceLog:remove']"
+              >删除</el-button>
+            </el-col>-->
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['qw:qwUserVoiceLog:totalExport']"
+        >导出</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          @click="getSellList"
+        >切换到客服统计</el-button>
+      </el-col>
+
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          @click="getList"
+        >切回企微通话统计</el-button>
+      </el-col>
+
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="handlePagination"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="qwUserVoiceLogList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <!--      <el-table-column label="id" align="center" width="80" prop="id" />-->
+      <!--      <el-table-column label="外部联系人名称" align="center" prop="qwExternalContact.name" />-->
+      <el-table-column label="客服名称" align="center" prop="companyUserName" />
+      <el-table-column label="企微用户名称" align="center" prop="qwUser.qwUserName" />
+      <el-table-column label="企微主体名称" align="center" prop="corpName" />
+      <el-table-column label="企微用户id" align="center" prop="qwUser.qwUserId" />
+      <el-table-column label="时长秒" align="center"  prop="duration" />
+      <el-table-column label="标签" align="center" prop="tagIdsName" width="250px">
+        <template slot-scope="scope">
+          <div v-for="name in scope.row.tagIdsName" style="display: inline;">
+            <el-tag type="success">{{ name }}</el-tag>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="接通数量" align="center"  prop="connectCount" />
+      <el-table-column label="未接通数量" align="center"  prop="noConnectCount" />
+      <!--      <el-table-column label="标题" align="center" width="80" prop="title" />-->
+      <!--      <el-table-column label="通话状态" align="center" prop="status">
+              <template slot-scope="scope">
+                <dict-tag :options="statusOptions" :value="scope.row.status"/>
+              </template>
+            </el-table-column>-->
+      <!--<el-table-column label="公司名称" align="center" prop="company.companyName" />
+      <el-table-column label="客服用户名称" align="center" prop="companyUser.userName" />
+      <el-table-column label="创建时间" align="center" prop="createTime" />-->
+      <!--      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+              <template slot-scope="scope">
+                <el-button
+                  size="mini"
+                  type="text"
+                  icon="el-icon-edit"
+                  @click="handleUpdate(scope.row)"
+                  v-hasPermi="['qw:qwUserVoiceLog:edit']"
+                >修改</el-button>
+                <el-button
+                  size="mini"
+                  type="text"
+                  icon="el-icon-delete"
+                  @click="handleDelete(scope.row)"
+                  v-hasPermi="['qw:qwUserVoiceLog:remove']"
+                >删除</el-button>
+              </template>
+            </el-table-column>-->
+    </el-table>
+
+
+    <!--  搜索标签   -->
+    <el-dialog :title="changeTagDialog.title" :visible.sync="changeTagDialog.open" width="1000px"  append-to-body>
+
+      <div>搜索标签:
+        <el-input v-model="queryTagParams.name" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags(queryTagParams.name)">搜索</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
+      </div>
+      <div v-for="item in tagGroupList" :key="item.id"  >
+        <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
+          <span class="name-background">{{ item.name }}</span>
+        </div>
+        <!-- 添加外层滚动容器 -->
+        <div class="scroll-wrapper">
+          <div class="tag-container">
+            <a
+              v-for="tagItem in item.tag"
+              class="tag-box"
+              @click="tagSelection(tagItem)"
+              :class="{ 'tag-selected': tagItem.isSelected }"
+            >
+              {{ tagItem.name }}
+            </a>
+          </div>
+        </div>
+      </div>
+
+      <pagination
+        v-show="tagTotal>0"
+        :total="tagTotal"
+        :page.sync="queryTagParams.pageNum"
+        :limit.sync="queryTagParams.pageSize"
+        @pagination="getPageListTagGroup"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="tagSubmitForm()">确 定</el-button>
+        <el-button @click="tagCancel()">取消</el-button>
+      </div>
+    </el-dialog>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="handlePagination"
+    />
+  </div>
+</template>
+
+<script>
+// import { listQwUserVoiceLog, getQwUserVoiceLog, delQwUserVoiceLog, addQwUserVoiceLog, updateQwUserVoiceLog, exportQwUserVoiceLog } from "@/api/qw/qwUserVoiceLog";
+import {listQwUserVoiceLogTotal,exportQwUserVoiceLogTotal,listQwUserVoiceLogSellTotal,exportQwUserVoiceLogSellTotal} from "@/api/qw/qwUserVoiceLogTotal";
+import {getCompanyUserListLikeName} from "@/api/company/companyUser";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import {treeselect} from "../../../api/company/companyDept";
+import {allListTagGroup} from "@/api/qw/tagGroup";
+import {searchTags} from "@/api/qw/tag";
+
+export default {
+  name: "QwUserVoiceLog",
+  components: {Treeselect},
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      status: 0,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      //时间范围
+      createTime:null,
+      beginTime:null,
+      endTime:null,
+
+
+      selectTags:[],
+      queryTagParams:{
+        pageNum: 1,
+        pageSize: 5,
+        total:0,
+        name:null,
+        corpId:null,
+      },
+      //标签
+      changeTagDialog:{
+        title:"",
+        open:false,
+      },
+
+      tagTotal:0,
+
+      tagGroupList: [],
+
+      addTagForm:{
+        userIds:[],
+        tagIds:[]
+      },
+      // 总条数
+      total: 0,
+      // 企微用户通话记录表格数据
+      qwUserVoiceLogList: [],
+      deptOptions: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 1接听 2未接字典
+      statusOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        extId: null,
+        extName:null,
+        qwUserId: null,
+        qwUserName: null,
+        duration: null,
+        title: null,
+        status: null,
+        corpName: null,
+        companyId: null,
+        companyName: null,
+        companyUserId: null,
+        companyUserName: null,
+        createTime:null,
+        beginTime:null,
+        endTime:null,
+        tagIds: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      },
+      companyUserOptionsLoading: false,
+      companyUserOptions: [],
+      companyUserOptionsParams: {
+        name: undefined,
+        hasNextPage: false,
+        pageNum: 1,
+        pageSize: 10
+      },
+    };
+  },
+  created() {
+    this.getDeptTreeSelect();
+    this.handlePagination();
+    this.getDicts("sys_qw_user_voice_status").then(response => {
+      this.statusOptions = response.data;
+    });
+  },
+  methods: {
+    tagSubmitForm(){
+
+      for (let i = 0; i < this.tagGroupList.length; i++) {
+        for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+          if (this.tagGroupList[i].tag[x].isSelected === true) {
+
+            if (!this.selectTags) {
+              this.selectTags = [];
+            }
+
+            // 检查当前 tag 是否已经存在于 tagListFormIndex[index] 中
+            let tagExists = this.selectTags.some(
+              tag => tag.id === this.tagGroupList[i].tag[x].id
+            );
+
+            // 如果 tag 不存在于 tagListFormIndex[index] 中,则新增
+            if (!tagExists) {
+              this.selectTags.push(this.tagGroupList[i].tag[x]);
+            }
+          }
+        }
+      }
+      if (!this.selectTags || this.selectTags.length === 0) {
+        return this.$message('请选择标签');
+      }
+      this.changeTagDialog.open = false;
+    },
+
+    //取消选择标签
+    tagCancel(){
+      this.changeTagDialog.open = false;
+    },
+    tagSelection(row){
+
+      row.isSelected= !row.isSelected;
+      this.$forceUpdate();
+    },
+    handleSearchTags(name){
+
+      if (!name){
+        return this.$message.error("请输入要搜索的标签")
+      }
+      this.queryTagParams.name=name;
+      this.queryTagParams.corpId=this.queryParams.corpId;
+
+      searchTags(this.queryTagParams).then(response => {
+        this.tagGroupList = response.rows;
+        this.tagTotal = response.total;
+      });
+
+      // searchTags({name:name,corpId:this.queryParams.corpId}).then(response => {
+      //   this.tagGroupList = response.rows;
+      // });
+
+    },
+
+    cancelSearchTags(){
+      this.resetSearchQueryTag()
+
+      this.getPageListTagGroup();
+    },
+    //删除一些选择的标签
+    handleCloseTags(list){
+      const ls = this.selectTags.findIndex(t => t.tagId === list.tagId);
+      if (ls !== -1) {
+        this.selectTags.splice(ls, 1);
+        this.selectTags = [...this.selectTags];
+      }
+
+      if (this.selectTags!=null && this.selectTags.length>0){
+        // 确保 this.form.tags 是数组
+        if (!this.queryParams.tagIds) {
+          this.queryParams.tagIds = []; // 如果未定义,初始化
+        } else {
+          this.queryParams.tagIds = []; // 清空已有数据
+        }
+
+        // 遍历并添加 tagId
+        this.selectTags.forEach(tag => {
+          if (tag.tagId) { // 确保 tagId 存在
+            this.queryParams.tagIds.push(tag.tagId);
+          }
+        });
+        console.log(this.queryParams.tagIds)
+        this.queryParams.tagIds=this.queryParams.tagIds.join(",");
+      }else {
+        this.queryParams.tagIds=null;
+      }
+
+    },
+    getPageListTagGroup(){
+      this.queryTagParams.corpId=this.queryParams.corpId
+      allListTagGroup(this.queryTagParams).then(response => {
+        this.tagGroupList = response.rows;
+        this.tagTotal = response.total;
+      });
+    },
+    //搜索的标签
+    hangleChangeTags(){
+
+      this.changeTagDialog.title="搜索的标签"
+      this.changeTagDialog.open=true;
+
+      // 获取 tagListFormIndex 中的所有 tagId,用于快速查找
+      const selectedTagIds = new Set(
+        (this.selectTags || []).map(tagItem => tagItem?.tagId)
+      );
+
+      this.queryTagParams.name=null;
+
+      this.getPageListTagGroup();
+
+      setTimeout(() => {
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            this.tagGroupList[i].tag[x].isSelected = selectedTagIds.has(this.tagGroupList[i].tag[x].tagId);
+          }
+        }
+      }, 200);
+
+
+    },
+    /** 查询企微用户通话记录列表 */
+    getList() {
+      this.loading = true;
+      this.status = 0;
+      const { qwUserName, ...queryParams } = this.queryParams;
+      listQwUserVoiceLogTotal(queryParams).then(response => {
+        this.qwUserVoiceLogList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+
+    getDeptTreeSelect() {
+      treeselect().then((response) => {
+        this.deptOptions = response.data;
+      });
+    },
+    getSellList() {
+      this.loading = true;
+      this.status = 1;
+      listQwUserVoiceLogSellTotal(this.queryParams).then(response => {
+        this.qwUserVoiceLogList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 新增 handlePagination 方法
+    handlePagination() {
+      if (this.status === 0) {
+        this.getList();
+      } else {
+        this.getSellList();
+      }
+    },
+    /**
+     * 根据名称模糊查询用户列表
+     * @param query 参数
+     */
+    loadCompanyUserOptions(query) {
+      this.companyUserOptions = [];
+      if (query === '') {
+        return;
+      }
+
+      this.companyUserOptionsParams.pageNum = 1
+      this.companyUserOptionsParams.name = query
+      this.companyUserOptionsLoading = true;
+      this.getCompanyUserListLikeName()
+    },
+    getCompanyUserListLikeName() {
+      getCompanyUserListLikeName(this.companyUserOptionsParams).then(response => {
+        this.companyUserOptions = [...this.companyUserOptions, ...response.data.list]
+        this.companyUserOptionsParams.hasNextPage = response.data.hasNextPage
+        this.companyUserOptionsLoading = false;
+      });
+    },
+    /**
+     * 加载更多员工选项
+     */
+    loadMoreCompanyUserOptions() {
+      if (!this.companyUserOptionsParams.hasNextPage) {
+        return;
+      }
+
+      this.companyUserOptionsParams.pageNum += 1
+      this.getCompanyUserListLikeName()
+    },
+    changeTime(){
+      if(this.createTime!=null){
+        this.queryParams.beginTime=this.createTime[0];
+        this.queryParams.endTime=this.createTime[1];
+      }else{
+        this.queryParams.beginTime=null;
+        this.queryParams.endTime=null;
+      }
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        extId: null,
+        qwUserId: null,
+        duration: null,
+        title: null,
+        status: 0,
+        corpId: null,
+        companyId: null,
+        companyUserId: null,
+        createTime: null,
+        beginTime:null,
+        endTime:null,
+        deptOption:null,
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      if (this.selectTags!=null && this.selectTags.length>0){
+        // 确保 this.form.tags 是数组
+        if (!this.queryParams.tagIds) {
+          this.queryParams.tagIds = []; // 如果未定义,初始化
+        } else {
+          this.queryParams.tagIds = []; // 清空已有数据
+        }
+
+        // 遍历并添加 tagId
+        this.selectTags.forEach(tag => {
+          if (tag.tagId) { // 确保 tagId 存在
+            this.queryParams.tagIds.push(tag.tagId);
+          }
+        });
+        //this.queryParams.tagIds=this.queryParams.tagIds.join(",");
+      }else {
+        this.queryParams.tagIds=null;
+      }
+      this.queryParams.pageNum = 1;
+      this.handlePagination();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.createTime=null;
+      this.queryParams.beginTime = null;
+      this.queryParams.endTime = null;
+      this.queryParams.deptId = null;
+      if (this.myQwCompanyList && this.myQwCompanyList.length > 0) {
+        this.queryParams.corpId= this.myQwCompanyList[0].dictValue;
+      } else {
+        this.queryParams.corpId = null; // 或设置默认值
+      }
+      this.selectTags=[];
+      this.createTime=null;
+      this.queryParams.sTime=null;
+      this.queryParams.eTime=null;
+      this.queryParams.tagIds=null;
+      this.$forceUpdate();
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加企微用户通话记录";
+    },
+    /** 修改按钮操作 */
+    // handleUpdate(row) {
+    //   this.reset();
+    //   const id = row.id || this.ids
+    //   getQwUserVoiceLog(id).then(response => {
+    //     this.form = response.data;
+    //     this.open = true;
+    //     this.title = "修改企微用户通话记录";
+    //   });
+    // },
+    /** 提交按钮 */
+    // submitForm() {
+    //   this.$refs["form"].validate(valid => {
+    //     if (valid) {
+    //       if (this.form.id != null) {
+    //         updateQwUserVoiceLog(this.form).then(response => {
+    //           this.msgSuccess("修改成功");
+    //           this.open = false;
+    //           this.handlePagination();
+    //         });
+    //       } else {
+    //         addQwUserVoiceLog(this.form).then(response => {
+    //           this.msgSuccess("新增成功");
+    //           this.open = false;
+    //           this.handlePagination();
+    //         });
+    //       }
+    //     }
+    //   });
+    // },
+    // /** 删除按钮操作 */
+    // handleDelete(row) {
+    //   const ids = row.id || this.ids;
+    //   this.$confirm('是否确认删除企微用户通话记录编号为"' + ids + '"的数据项?', "警告", {
+    //     confirmButtonText: "确定",
+    //     cancelButtonText: "取消",
+    //     type: "warning"
+    //   }).then(function() {
+    //     return delQwUserVoiceLog(ids);
+    //   }).then(() => {
+    //     this.handlePagination();
+    //     this.msgSuccess("删除成功");
+    //   }).catch(() => {});
+    // },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有企微用户通话记录数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        if(this.status === 0){
+          return exportQwUserVoiceLogTotal(queryParams);
+        }else{
+          return exportQwUserVoiceLogSellTotal(queryParams);
+        }
+
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
+    }
+  }
+};
+</script>
+
+<style scoped>
+/* 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;
+}
+
+
+.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;
+}
+
+.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;
+}
+
+.feedback-dialog {
+  width: 100%;
+  max-width: 1000px;
+  max-height: 80vh; /* 限制最大高度为视窗高度的 80% */
+  overflow-y: auto; /* 超出时显示垂直滚动条 */
+  padding: 20px;
+  box-sizing: border-box; /* 确保 padding 不影响总宽度 */
+}
+/* 新增的滚动容器样式(不影响原有样式) */
+.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;
+}
+</style>

+ 432 - 0
src/views/qw/tagGroup/index.vue

@@ -0,0 +1,432 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="企微公司" prop="corpId">
+                      <el-select v-model="queryParams.corpId" placeholder="企微公司"  size="small" @change="updateCorpId()">
+                        <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="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入标签组名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </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>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          @click="handleSync"
+          v-hasPermi="['qw:tagGroup:sync']"
+        >同步</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['qw:tagGroup:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['qw:tagGroup:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['qw:tagGroup:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['qw:tagGroup:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="tagGroupList" @selection-change="handleSelectionChange" border>
+      <el-table-column type="selection" width="55" align="center" />
+
+      <el-table-column label="来源" align="center" prop="groupFrom">
+        <template slot-scope="scope">
+          <span v-if="scope.row.groupFrom==1">本应用创建</span>
+          <span v-else>其他创建</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="名称" align="center" prop="name" />
+      <el-table-column label="排序" align="center" prop="order" />
+      <el-table-column label="标签" align="center" prop="tag" >
+<!--        <template slot-scope="scope" >-->
+<!--            <el-tag type="success" v-for="i in scope.row.tag" :key="i.id" style="margin: 2px 5px 0 0;">{{i.name}}</el-tag>-->
+<!--        </template>-->
+        <template slot-scope="scope">
+          <div class="tag-container">
+            <div class="tag-list">
+              <el-tag type="success" v-for="i in scope.row.tag" :key="i.id" style="margin: 2px 5px 0 0;">{{i.name}}</el-tag>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['qw:tagGroup:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['qw:tagGroup:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改企微客户标签组对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+
+        <el-form-item label="名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入名称"  />
+        </el-form-item>
+        <el-form-item label="排序" prop="order">
+          <el-input-number v-model="form.order" placeholder="请输入排序" />
+        </el-form-item>
+        <el-row>
+           <el-col :span="3"><div style="margin-top: 9px;font-weight: bold;float: right; margin-right: 10px;">标签</div></el-col>
+          <el-col :span="21">
+            <el-table :data="form.tag"   >
+            <el-table-column label="来源" prop="tagFrom" align="center" width="90" >
+              <template slot-scope="scope">
+                  <span v-if="scope.row.tagFrom==1">本应用创建</span>
+                  <span v-if="!scope.row.tagFrom && scope.row.tagId">其他创建</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="名称" prop="name" align="center" >
+              <template slot-scope="scope">
+                <el-input v-model="scope.row.name"   ></el-input>
+              </template>
+            </el-table-column>
+            <el-table-column label="排序" prop="order" align="center" >
+              <template slot-scope="scope">
+                <el-input-number v-model="scope.row.order"  ></el-input-number>
+              </template>
+            </el-table-column>
+            <el-table-column label="操作" width="150px" align="center">
+              <template slot-scope="scope" >
+                  <el-button @click="addRow" size="mini" type="text" >新增</el-button>
+                  <el-button @click="deleteRow(scope.$index,scope.row)"   size="mini" type="text" v-if="form.tag.length>1"   >删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { syncTag,listTagGroup, getTagGroup, delTagGroup, addTagGroup, updateTagGroup, exportTagGroup } from "@/api/qw/tagGroup";
+import { getMyQwUserList,getMyQwCompanyListAll } from "@/api/qw/user";
+export default {
+  name: "TagGroup",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      myQwUserList: [],
+      myQwCompanyList:[],
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 企微客户标签组表格数据
+      tagGroupList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        groupId: null,
+        name: null,
+        order: null,
+        corpId: null,
+        companyId: null,
+      },
+      tagJson:[],
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+
+        name: [
+          { required: true, message: "名称不能为空", trigger: "blur" }
+        ],
+      }
+    };
+  },
+  created() {
+    getMyQwCompanyListAll().then(response => {
+            this.myQwCompanyList = response.data;
+            if(this.myQwCompanyList!=null){
+              this.queryParams.corpId=this.myQwCompanyList[0].dictValue
+              this.getList();
+            }
+    });
+  },
+  methods: {
+
+    updateCorpId(){
+           this.getList();
+     },
+    /** 查询企微客户标签组列表 */
+    getList() {
+      this.loading = true;
+      listTagGroup(this.queryParams).then(response => {
+        this.tagGroupList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        groupId: null,
+        name: null,
+        order: null,
+        corpId: null,
+        companyId: null,
+        createTime: null,
+        updateTime: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    addRow() {
+      this.form.tag.push({ name: "标签", order:0 ,tagFrom:1},);
+    },
+    deleteRow(index,row) {
+
+      if (row.tagFrom==1){
+        this.form.tag.splice(index, 1);
+      }else {
+        this.$message.error("不能删除非本应用创建的标签")
+      }
+    },
+
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.corpId= this.myQwCompanyList[0].dictValue;
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.form.tag= [
+        { name: "标签", order:0,tagFrom:1},
+      ];
+      this.title = "添加企微客户标签组";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getTagGroup(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改企微客户标签组";
+      });
+    },
+    handleSync(){
+      this.loading=true;
+      syncTag(this.queryParams.corpId).then(response => {
+        this.msgSuccess("同步成功");
+
+        this.getList();
+      }).finally(
+        () => {
+          this.loading=false;
+        }
+      );
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          this.form.corpId=this.queryParams.corpId
+          if (this.form.id != null) {
+            updateTagGroup(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addTagGroup(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除企微客户标签组名为"' + row.name + '"的数据项?【注意:仅能删除在本后台创建得标签组及标签】', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delTagGroup(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有企微客户标签组数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportTagGroup(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>
+<style scoped>
+
+.tag-container {
+  max-height: 300px;
+  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>

+ 218 - 0
src/views/qw/user/qwUserList.vue

@@ -0,0 +1,218 @@
+<template>
+  <div class="app-container">
+    <el-alert v-if="type==2 && (sendType==2||sendType==4||sendType==11)"
+      title="注意事项"
+      type="warning"
+      description="只显示含有【允许使用插件】的成员"
+      :closable="false"
+      center
+      show-icon>
+    </el-alert>
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px" @submit.prevent="handleQuery">
+
+      <el-form-item label="后台员工昵称" prop="nickName">
+        <el-input
+          v-model="queryParams.nickName"
+          placeholder="请输入后台员工昵称"
+          clearable
+          size="small"
+          @keydown.enter.native="handleQueryEnter"
+        />
+      </el-form-item>
+      <el-form-item label="企微员工部门" prop="deptName">
+        <el-input
+          v-model="queryParams.deptName"
+          placeholder="请输入企微员工部门"
+          clearable
+          size="small"
+          @keydown.enter.native="handleQueryEnter"
+        />
+      </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>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" :data="userList" ref="userList"  @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="企微员工账号" align="center" prop="qwUserId" />
+        <el-table-column label="企微员工昵称" align="center" prop="qwUserName"/>
+        <el-table-column label="企微员工部门" align="center" prop="departmentName"/>
+        <el-table-column label="后台员工昵称" align="center" prop="nickName"/>
+        <el-table-column label="后台员工用户名" align="center" prop="userName" />
+
+    </el-table>
+    <div style="margin-top: 30px;display: flex;justify-content: center">
+      <el-button type="warning" icon="el-icon-search" @click="confirmSelect">确定选择</el-button>
+    </div>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="handlePaginationChange"
+    />
+  </div>
+</template>
+
+<script>
+import { listUser, getUser, delUser, addUser, updateUser, exportUser } from "@/api/qw/user";
+
+
+export default {
+  name: "qwUserList",
+  data() {
+    return {
+      type:null,
+      sendType:null,
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      selectUsers: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 企微用户表格数据
+      userList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        qwUserId: null,
+        companyId: null,
+        companyUserId: null,
+        deptName: null,
+        corpId: null,
+        nickName: null
+      },
+      // 表单参数
+      form: {},
+
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+
+  },
+  methods: {
+
+    getDetails(corpId,type,sendType,isRemark){
+      this.type=type;
+      this.sendType=sendType;
+      if (type!=null&&sendType!=null){
+        this.queryParams.type=type;
+        this.queryParams.sendType=sendType;
+      }
+      this.queryParams.corpId=corpId;
+      this.queryParams.isRemark=isRemark;
+      this.getList();
+    },
+    /** 查询企微用户列表 */
+    getList() {
+      this.loading = true;
+      listUser(this.queryParams).then(response => {
+        // 如果 companyUserId 为 null,移除列
+
+        this.userList = response.rows;
+        this.total =   response.total;
+        this.loading = false;
+
+      });
+    },
+    handlePaginationChange(row) {
+      this.queryParams.pageNum = row.page;
+      this.queryParams.pageSize = row.limit;
+      this.getList();
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        qwUserId: null,
+        companyId: null,
+        companyUserId: null,
+        corpId: null
+      };
+      this.resetForm("form");
+    },
+    //确定选择
+    confirmSelect(){
+      this.$emit("selectUserList",this.selectUsers);
+      this.resetSelect();
+    },
+    //重置选择
+    resetSelect(){
+      this.$refs.userList.clearSelection();
+
+      this.selectUsers=[];
+      //重置
+      this.queryParams={
+        pageNum: 1,
+        pageSize: 5,
+        qwUserId: null,
+        companyId: null,
+        companyUserId: null,
+        corpId: null,
+        nickName: null
+      },
+        this.getList();
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    handleQueryEnter(event){
+      // 确保事件对象存在
+      if (event && event.preventDefault) {
+        event.preventDefault(); // 阻止默认提交行为
+      }
+      this.handleQuery();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+
+      // 保存当前页的选中项
+      const currentPageSelections = selection.map(item => item.id);
+
+      // 合并选中项
+      this.selectUsers = this.selectUsers.filter(item =>
+        this.userList.some(tag => tag.id === item.id) ? currentPageSelections.includes(item.id) : true
+      ).concat(selection.filter(item => !this.selectUsers.some(selected => selected.id === item.id)));
+
+      // 更新 single 和 multiple
+      this.single = this.selectUsers.length !== 1;
+      this.multiple = !this.selectUsers.length;
+
+    },
+
+  }
+};
+</script>