Browse Source

Merge remote-tracking branch 'company/master'

dongdong.xiang 3 tuần trước cách đây
mục cha
commit
99e612cb8f
69 tập tin đã thay đổi với 7987 bổ sung65 xóa
  1. 7 7
      .env.prod-fby
  2. 33 0
      .env.prod-test
  3. 1 0
      package.json
  4. 53 0
      src/api/ad/AdUploadLog.js
  5. 10 1
      src/api/ad/adSite.js
  6. 53 0
      src/api/aiob/AiobBaiduCallApi.js
  7. 53 0
      src/api/aiob/AiobBaiduEncryption.js
  8. 76 0
      src/api/aiob/AiobBaiduTask.js
  9. 53 0
      src/api/company/VoiceRoboticWx.js
  10. 70 0
      src/api/company/companyAccount.js
  11. 70 0
      src/api/company/companyClient.js
  12. 62 0
      src/api/company/companyVoiceDialog.js
  13. 24 14
      src/api/company/companyVoiceRobotic.js
  14. 61 0
      src/api/company/wxDialog.js
  15. 87 0
      src/api/wxUser/wxUser.js
  16. 61 0
      src/api/wxUser/wxUserGroup.js
  17. BIN
      src/assets/image/customer.png
  18. BIN
      src/assets/image/profile.jpg
  19. BIN
      src/assets/image/profile.png
  20. BIN
      src/assets/images/customer.png
  21. 39 0
      src/assets/images/dark.svg
  22. BIN
      src/assets/images/default - 副本.jpg
  23. BIN
      src/assets/images/default.jpg
  24. 39 0
      src/assets/images/light.svg
  25. BIN
      src/assets/images/login-background.jpg
  26. BIN
      src/assets/images/login_left.png
  27. BIN
      src/assets/images/profile.jpg
  28. BIN
      src/assets/images/profile.png
  29. BIN
      src/assets/images/watchApi/battery.png
  30. BIN
      src/assets/images/watchApi/bigicon.png
  31. BIN
      src/assets/images/watchApi/title-icon.png
  32. BIN
      src/assets/images/watchApi/watch_icon36.png
  33. BIN
      src/assets/images/watchApi/xl.png
  34. 130 0
      src/components/H5/FormWrapper.vue
  35. 87 0
      src/components/H5/config-item/common-config.vue
  36. 182 0
      src/components/H5/config-item/h5-chat-config-dialog.vue
  37. 317 0
      src/components/H5/config-item/h5-chat-config.vue
  38. 270 0
      src/components/H5/config-item/h5-countdown-config.vue
  39. 20 0
      src/components/H5/config-item/h5-image-config.vue
  40. 22 0
      src/components/H5/config-item/h5-sep-config.vue
  41. 127 0
      src/components/H5/config-item/h5-text-config.vue
  42. 13 0
      src/components/H5/css/base.css
  43. 27 0
      src/components/H5/h5-button.vue
  44. 239 0
      src/components/H5/h5-chat.vue
  45. 79 0
      src/components/H5/h5-countdown.vue
  46. 27 0
      src/components/H5/h5-image.vue
  47. 28 0
      src/components/H5/h5-sep.vue
  48. 27 0
      src/components/H5/h5-text.vue
  49. 419 0
      src/components/H5Editor/index.vue
  50. 3 0
      src/main.js
  51. 5 5
      src/router/index.js
  52. 1 1
      src/settings.js
  53. 346 0
      src/views/ad/AdUploadLog/index.vue
  54. 1 22
      src/views/ad/adSite/index.vue
  55. 313 0
      src/views/company/VoiceRoboticWx/index.vue
  56. 449 0
      src/views/company/companyClient/index.vue
  57. 296 0
      src/views/company/companyVoiceDialog/index.vue
  58. 814 0
      src/views/company/companyVoiceRobotic/index-old.vue
  59. 814 0
      src/views/company/companyVoiceRobotic/index.vue
  60. 308 0
      src/views/company/wxAccount/index.vue
  61. 266 0
      src/views/company/wxDialog/index.vue
  62. 551 0
      src/views/company/wxUser/index.vue
  63. 266 0
      src/views/company/wxUserGroup/wxUserGroup.vue
  64. 19 0
      src/views/components/course/userCourseCatalogDetails.vue
  65. 30 4
      src/views/course/userCoursePeriod/index.vue
  66. 475 0
      src/views/crm/components/CustomerSelect.vue
  67. 2 2
      src/views/qw/sopTemp/index.vue
  68. 155 2
      src/views/store/user/index.vue
  69. 7 7
      src/views/user/transfer/index.vue

+ 7 - 7
.env.prod-fby

@@ -9,19 +9,19 @@ ICP_URL =https://beian.miit.gov.cn
 # 网站LOG
 VUE_APP_LOG_URL =@/assets/logo/logo.png
 # 存储桶配置
-OSS_ACCESS_KEY_ID = K2UTJGIN7UTZJR2XMXYG
+VUE_APP_OBS_ACCESS_KEY_ID = K2UTJGIN7UTZJR2XMXYG
 # 存储桶配置
-OSS_SECRET_ACCESS_KEY = sbyeNJLbcYmH6copxeFP9pAoksM4NIT9Zw4x0SRX
+VUE_APP_OBS_SECRET_ACCESS_KEY = sbyeNJLbcYmH6copxeFP9pAoksM4NIT9Zw4x0SRX
 # 存储桶配置
-OSS_SERVER = https://obs.cn-north-4.myhuaweicloud.com
+VUE_APP_OBS_SERVER = https://obs.cn-north-4.myhuaweicloud.com
 # 存储桶配置
-OSS_BUCKET = hzyy-1323137866
+VUE_APP_OBS_BUCKET = hzyy-1323137866
 # 存储桶配置
-OSS_REGION = ap-chongqing
+VUE_APP_COS_BUCKET = ap-chongqing
 # 线路一地址
-OSS_LINE_1 = https://hzyytcpv.ylrzcloud.com
+VUE_APP_COS_REGION = https://hzyytcpv.ylrzcloud.com
 # 线路二地址
-OSS_LINE_2 = https://hzyyobs.ylrztop.com
+VUE_APP_VIDEO_LINE_1 = https://hzyyobs.ylrztop.com
 
 # 生产环境配置
 ENV = 'production'

+ 33 - 0
.env.prod-test

@@ -0,0 +1,33 @@
+# 页面标题
+VUE_APP_TITLE =互联网医院管理系统
+# 公司名称
+COMPANY_NAME =重庆云联融智科技有限公司
+# ICP备案号
+ICP_RECORD =蜀ICP备2023036719号
+# ICP网站访问地址
+ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/logo.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 = hzyy-1323137866
+# 存储桶配置
+VUE_APP_COS_BUCKET = ap-chongqing
+# 线路一地址
+VUE_APP_COS_REGION = https://hzyytcpv.ylrzcloud.com
+# 线路二地址
+VUE_APP_VIDEO_LINE_1 = https://hzyyobs.ylrztop.com
+
+# 生产环境配置
+ENV = 'production'
+
+#FS管理系统/生产环境
+VUE_APP_BASE_API = '/prod-api'
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 1 - 0
package.json

@@ -8,6 +8,7 @@
     "dev": "vue-cli-service serve",
     "build:prod": "vue-cli-service build",
     "build:stage": "vue-cli-service build --mode staging",
+    "build:prod-test": "vue-cli-service build --mode prod-test",
     "build:prod-jz": "vue-cli-service build --mode prod-jz",
     "build:prod-zkzh": "vue-cli-service build --mode prod-zkzh",
     "build:prod-fby": "vue-cli-service build --mode prod-fby",

+ 53 - 0
src/api/ad/AdUploadLog.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询百度回传日志列表
+export function listAdUploadLog(query) {
+  return request({
+    url: '/ad/AdUploadLog/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询百度回传日志详细
+export function getAdUploadLog(id) {
+  return request({
+    url: '/ad/AdUploadLog/' + id,
+    method: 'get'
+  })
+}
+
+// 新增百度回传日志
+export function addAdUploadLog(data) {
+  return request({
+    url: '/ad/AdUploadLog',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改百度回传日志
+export function updateAdUploadLog(data) {
+  return request({
+    url: '/ad/AdUploadLog',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除百度回传日志
+export function delAdUploadLog(id) {
+  return request({
+    url: '/ad/AdUploadLog/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出百度回传日志
+export function exportAdUploadLog(query) {
+  return request({
+    url: '/ad/AdUploadLog/export',
+    method: 'get',
+    params: query
+  })
+}

+ 10 - 1
src/api/ad/adSite.js

@@ -9,6 +9,15 @@ export function listAdSite(query) {
   })
 }
 
+// 查询站点管理列表
+export function listAll(query) {
+  return request({
+    url: '/ad/adSite/listAll',
+    method: 'get',
+    params: query
+  })
+}
+
 // 查询站点管理详细
 export function getAdSite(id) {
   return request({
@@ -50,4 +59,4 @@ export function exportAdSite(query) {
     method: 'get',
     params: query
   })
-}
+}

+ 53 - 0
src/api/aiob/AiobBaiduCallApi.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询百度外呼接口配置列表
+export function listAiobBaiduCallApi(query) {
+  return request({
+    url: '/aiob/AiobBaiduCallApi/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询百度外呼接口配置详细
+export function getAiobBaiduCallApi(id) {
+  return request({
+    url: '/aiob/AiobBaiduCallApi/' + id,
+    method: 'get'
+  })
+}
+
+// 新增百度外呼接口配置
+export function addAiobBaiduCallApi(data) {
+  return request({
+    url: '/aiob/AiobBaiduCallApi',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改百度外呼接口配置
+export function updateAiobBaiduCallApi(data) {
+  return request({
+    url: '/aiob/AiobBaiduCallApi',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除百度外呼接口配置
+export function delAiobBaiduCallApi(id) {
+  return request({
+    url: '/aiob/AiobBaiduCallApi/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出百度外呼接口配置
+export function exportAiobBaiduCallApi(query) {
+  return request({
+    url: '/aiob/AiobBaiduCallApi/export',
+    method: 'get',
+    params: query
+  })
+}

+ 53 - 0
src/api/aiob/AiobBaiduEncryption.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询百度AI外呼加密列表
+export function listAiobBaiduEncryption(query) {
+  return request({
+    url: '/aiob/AiobBaiduEncryption/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询百度AI外呼加密详细
+export function getAiobBaiduEncryption(id) {
+  return request({
+    url: '/aiob/AiobBaiduEncryption/' + id,
+    method: 'get'
+  })
+}
+
+// 新增百度AI外呼加密
+export function addAiobBaiduEncryption(data) {
+  return request({
+    url: '/aiob/AiobBaiduEncryption',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改百度AI外呼加密
+export function updateAiobBaiduEncryption(data) {
+  return request({
+    url: '/aiob/AiobBaiduEncryption',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除百度AI外呼加密
+export function delAiobBaiduEncryption(id) {
+  return request({
+    url: '/aiob/AiobBaiduEncryption/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出百度AI外呼加密
+export function exportAiobBaiduEncryption(query) {
+  return request({
+    url: '/aiob/AiobBaiduEncryption/export',
+    method: 'get',
+    params: query
+  })
+}

+ 76 - 0
src/api/aiob/AiobBaiduTask.js

@@ -0,0 +1,76 @@
+import request from '@/utils/request'
+
+// 查询百度AI外呼任务列表
+export function listAiobBaiduTask(query) {
+  return request({
+    url: '/aiob/AiobBaiduTask/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询百度AI外呼任务详细
+export function getAiobBaiduTask(id) {
+  return request({
+    url: '/aiob/AiobBaiduTask/' + id,
+    method: 'get'
+  })
+}
+
+// 新增百度AI外呼任务
+export function addAiobBaiduTask(data) {
+  return request({
+    url: '/aiob/AiobBaiduTask',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改百度AI外呼任务
+export function updateAiobBaiduTask(data) {
+  return request({
+    url: '/aiob/AiobBaiduTask',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除百度AI外呼任务
+export function delAiobBaiduTask(id) {
+  return request({
+    url: '/aiob/AiobBaiduTask/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出百度AI外呼任务
+export function exportAiobBaiduTask(query) {
+  return request({
+    url: '/aiob/AiobBaiduTask/export',
+    method: 'get',
+    params: query
+  })
+}
+// 导出百度AI外呼任务
+export function robotList() {
+  return request({
+    url: '/aiob/AiobBaiduTask/robotList',
+    method: 'get'
+  })
+}
+// 导出百度AI外呼任务
+export function startRobotic(taskId) {
+  return request({
+    url: '/aiob/AiobBaiduTask/startRobotic',
+    method: 'get',
+    params: {taskId}
+  })
+}
+// 导出百度AI外呼任务
+export function stopRobotic(taskId) {
+  return request({
+    url: '/aiob/AiobBaiduTask/stopRobotic',
+    method: 'get',
+    params: {taskId}
+  })
+}

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

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询AI外呼任务加微方式列表
+export function listVoiceRoboticWx(query) {
+  return request({
+    url: '/company/VoiceRoboticWx/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询AI外呼任务加微方式详细
+export function getVoiceRoboticWx(id) {
+  return request({
+    url: '/company/VoiceRoboticWx/' + id,
+    method: 'get'
+  })
+}
+
+// 新增AI外呼任务加微方式
+export function addVoiceRoboticWx(data) {
+  return request({
+    url: '/company/VoiceRoboticWx',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改AI外呼任务加微方式
+export function updateVoiceRoboticWx(data) {
+  return request({
+    url: '/company/VoiceRoboticWx',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除AI外呼任务加微方式
+export function delVoiceRoboticWx(id) {
+  return request({
+    url: '/company/VoiceRoboticWx/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出AI外呼任务加微方式
+export function exportVoiceRoboticWx(query) {
+  return request({
+    url: '/company/VoiceRoboticWx/export',
+    method: 'get',
+    params: query
+  })
+}

+ 70 - 0
src/api/company/companyAccount.js

@@ -0,0 +1,70 @@
+import request from '@/utils/request'
+
+// 查询个微账号列表
+export function listCompanyAccount(query) {
+  return request({
+    url: '/company/companyWx/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询个微账号列表
+export function companyListAll(query) {
+  return request({
+    url: '/company/companyWx/companyListAll',
+    method: 'get',
+    params: query
+  })
+}
+// 查询个微账号列表
+export function listAll(query) {
+  return request({
+    url: '/company/companyWx/listAll',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询个微账号详细
+export function getCompanyAccount(id) {
+  return request({
+    url: '/company/companyWx/' + id,
+    method: 'get'
+  })
+}
+
+// 新增个微账号
+export function addCompanyAccount(data) {
+  return request({
+    url: '/company/companyWx',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改个微账号
+export function updateCompanyAccount(data) {
+  return request({
+    url: '/company/companyWx',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除个微账号
+export function delCompanyAccount(id) {
+  return request({
+    url: '/company/companyWx/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出个微账号
+export function exportCompanyAccount(query) {
+  return request({
+    url: '/company/companyWx/export',
+    method: 'get',
+    params: query
+  })
+}

+ 70 - 0
src/api/company/companyClient.js

@@ -0,0 +1,70 @@
+import request from '@/utils/request'
+
+// 查询添加个微信账号列表
+export function listCompanyClient(query) {
+  return request({
+    url: '/company/companyClient/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询添加个微信账号列表
+export function addWxStatistics(query) {
+  return request({
+    url: '/company/companyClient/addWxStatistics',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询添加个微信账号详细
+export function getCompanyClient(id) {
+  return request({
+    url: '/company/companyClient/' + id,
+    method: 'get'
+  })
+}
+
+// 新增添加个微信账号
+export function addCompanyClient(data) {
+  return request({
+    url: '/company/companyClient',
+    method: 'post',
+    data: data
+  })
+}
+// 新增添加个微信账号
+export function addWxClient(data) {
+  return request({
+    url: '/company/companyClient/addWxClient',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改添加个微信账号
+export function updateCompanyClient(data) {
+  return request({
+    url: '/company/companyClient',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除添加个微信账号
+export function delCompanyClient(id) {
+  return request({
+    url: '/company/companyClient/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出添加个微信账号
+export function exportCompanyClient(query) {
+  return request({
+    url: '/company/companyClient/export',
+    method: 'get',
+    params: query
+  })
+}

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

@@ -0,0 +1,62 @@
+import request from '@/utils/request'
+
+// 查询AI外呼话术列表
+export function listDialog(query) {
+  return request({
+    url: '/company/companyVoiceDialog/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询AI外呼话术详细
+export function getConfigUrl(id) {
+  return request({
+    url: '/company/companyVoiceDialog/getConfigUrl',
+    method: 'get',
+    params: {id}
+  })
+}
+
+// 查询AI外呼话术详细
+export function getDialog(id) {
+  return request({
+    url: '/company/companyVoiceDialog/' + id,
+    method: 'get'
+  })
+}
+
+// 新增AI外呼话术
+export function addDialog(data) {
+  return request({
+    url: '/company/companyVoiceDialog',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改AI外呼话术
+export function updateDialog(data) {
+  return request({
+    url: '/company/companyVoiceDialog',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除AI外呼话术
+export function delDialog(id) {
+  return request({
+    url: '/company/companyVoiceDialog/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出AI外呼话术
+export function exportDialog(query) {
+  return request({
+    url: '/company/companyVoiceDialog/export',
+    method: 'get',
+    params: query
+  })
+}

+ 24 - 14
src/api/company/companyVoiceRobotic.js

@@ -3,7 +3,7 @@ import request from '@/utils/request'
 // 查询机器人外呼任务列表
 export function listRobotic(query) {
   return request({
-    url: 'company/companyVoiceRobotic/list',
+    url: '/company/companyVoiceRobotic/list',
     method: 'get',
     params: query
   })
@@ -11,7 +11,7 @@ export function listRobotic(query) {
 // 查询机器人外呼任务列表
 export function listAll(query) {
   return request({
-    url: 'company/companyVoiceRobotic/listAll',
+    url: '/company/companyVoiceRobotic/listAll',
     method: 'get',
     params: query
   })
@@ -19,7 +19,7 @@ export function listAll(query) {
 // 查询机器人外呼任务列表
 export function calleesList(query) {
   return request({
-    url: 'company/companyVoiceRobotic/calleesList',
+    url: '/company/companyVoiceRobotic/calleesList',
     method: 'get',
     params: query
   })
@@ -28,7 +28,7 @@ export function calleesList(query) {
 // 查询机器人外呼任务详细
 export function getRobotic(id) {
   return request({
-    url: 'company/companyVoiceRobotic/' + id,
+    url: '/company/companyVoiceRobotic/' + id,
     method: 'get'
   })
 }
@@ -36,7 +36,17 @@ export function getRobotic(id) {
 // 新增机器人外呼任务
 export function addRobotic(data) {
   return request({
-    url: 'company/companyVoiceRobotic',
+    url: '/company/companyVoiceRobotic',
+    method: 'post',
+    data: data
+  })
+}
+
+
+// 新增机器人外呼任务
+export function addScheme(data) {
+  return request({
+    url: '/company/companyVoiceRobotic/addScheme',
     method: 'post',
     data: data
   })
@@ -45,7 +55,7 @@ export function addRobotic(data) {
 // 修改机器人外呼任务
 export function updateRobotic(data) {
   return request({
-    url: 'company/companyVoiceRobotic',
+    url: '/company/companyVoiceRobotic',
     method: 'put',
     data: data
   })
@@ -54,7 +64,7 @@ export function updateRobotic(data) {
 // 删除机器人外呼任务
 export function delRobotic(id) {
   return request({
-    url: 'company/companyVoiceRobotic/' + id,
+    url: '/company/companyVoiceRobotic/' + id,
     method: 'delete'
   })
 }
@@ -62,7 +72,7 @@ export function delRobotic(id) {
 // 导出机器人外呼任务
 export function exportRobotic(query) {
   return request({
-    url: 'company/companyVoiceRobotic/export',
+    url: '/company/companyVoiceRobotic/export',
     method: 'get',
     params: query
   })
@@ -71,14 +81,14 @@ export function exportRobotic(query) {
 // 导出机器人外呼任务
 export function getTypes() {
   return request({
-    url: 'company/companyVoiceRobotic/getTypes',
+    url: '/company/companyVoiceRobotic/getTypes',
     method: 'get'
   })
 }
 // 导出机器人外呼任务
 export function statusList(ids) {
   return request({
-    url: 'company/companyVoiceRobotic/statusList',
+    url: '/company/companyVoiceRobotic/statusList',
     method: 'get',
     params: {ids}
   })
@@ -86,7 +96,7 @@ export function statusList(ids) {
 // 导出机器人外呼任务
 export function startRobotic(taskId) {
   return request({
-    url: 'company/companyVoiceRobotic/startRobotic',
+    url: '/company/companyVoiceRobotic/startRobotic',
     method: 'get',
     params: {taskId}
   })
@@ -94,7 +104,7 @@ export function startRobotic(taskId) {
 // 导出机器人外呼任务
 export function stopRobotic(taskId) {
   return request({
-    url: 'company/companyVoiceRobotic/stopRobotic',
+    url: '/company/companyVoiceRobotic/stopRobotic',
     method: 'get',
     params: {taskId}
   })
@@ -102,7 +112,7 @@ export function stopRobotic(taskId) {
 // 导出机器人外呼任务
 export function companyUserList(params) {
   return request({
-    url: 'company/companyVoiceRobotic/companyUserList',
+    url: '/company/companyVoiceRobotic/companyUserList',
     method: 'get',
     params
   })
@@ -111,7 +121,7 @@ export function companyUserList(params) {
 // 导出机器人外呼任务
 export function wxList(params) {
   return request({
-    url: 'company/companyVoiceRobotic/wxList',
+    url: '/company/companyVoiceRobotic/wxList',
     method: 'get',
     params
   })

+ 61 - 0
src/api/company/wxDialog.js

@@ -0,0 +1,61 @@
+import request from '@/utils/request'
+
+// 查询添加微信话术列表
+export function listWxDialog(query) {
+  return request({
+    url: '/company/wxDialog/list',
+    method: 'get',
+    params: query
+  })
+}
+// 查询添加微信话术列表
+export function listAll(query) {
+  return request({
+    url: '/company/wxDialog/listAll',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询添加微信话术详细
+export function getWxDialog(id) {
+  return request({
+    url: '/company/wxDialog/' + id,
+    method: 'get'
+  })
+}
+
+// 新增添加微信话术
+export function addWxDialog(data) {
+  return request({
+    url: '/company/wxDialog',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改添加微信话术
+export function updateWxDialog(data) {
+  return request({
+    url: '/company/wxDialog',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除添加微信话术
+export function delWxDialog(id) {
+  return request({
+    url: '/company/wxDialog/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出添加微信话术
+export function exportWxDialog(query) {
+  return request({
+    url: '/company/wxDialog/export',
+    method: 'get',
+    params: query
+  })
+}

+ 87 - 0
src/api/wxUser/wxUser.js

@@ -0,0 +1,87 @@
+import request from '@/utils/request'
+
+// 查询个微用户列表
+export function listWxUser(query) {
+  return request({
+    url: '/company/wxUser/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询个微用户列表
+export function listAll(query) {
+  return request({
+    url: '/company/wxUser/listAll',
+    method: 'get',
+    params: query
+  })
+}
+// 查询个微用户详细
+export function getWxUser(userId) {
+  return request({
+    url: '/company/wxUser/' + userId,
+    method: 'get'
+  })
+}
+
+// 新增个微用户
+export function addWxUser(data) {
+  return request({
+    url: '/company/wxUser',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改个微用户
+export function updateWxUser(data) {
+  return request({
+    url: '/company/wxUser',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除个微用户
+export function delWxUser(userId) {
+  return request({
+    url: '/company/wxUser/' + userId,
+    method: 'delete'
+  })
+}
+
+// 导出个微用户
+export function exportWxUser(query) {
+  return request({
+    url: '/company/wxUser/export',
+    method: 'get',
+    params: query
+  })
+}
+
+//绑定小程序id
+export function bindMiniUserId(data) {
+  return request({
+    url: '/company/wxUser/bindMiniUserId',
+    method: 'put',
+    data: data
+  })
+}
+
+//批量添加分组
+export function addGroup(data) {
+  return request({
+    url: '/company/wxUser/addGroup',
+    method: 'post',
+    data: data
+  })
+}
+//批量移除分组
+export function delGroup(data) {
+  return request({
+    url: '/company/wxUser/delGroup',
+    method: 'post',
+    data: data
+  })
+}

+ 61 - 0
src/api/wxUser/wxUserGroup.js

@@ -0,0 +1,61 @@
+import request from '@/utils/request'
+
+// 查询个微 分组列表
+export function listWxUserGroup(query) {
+  return request({
+    url: '/company/wxUserGroup/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询个微 分组列表 不要权限版
+export function sopListWxUserGroup(query) {
+  return request({
+    url: '/company/wxUserGroup/sopList',
+    method: 'get',
+    params: query
+  })
+}
+// 查询个微 分组详细
+export function getWxUserGroup(groupId) {
+  return request({
+    url: '/company/wxUserGroup/' + groupId,
+    method: 'get'
+  })
+}
+
+// 新增个微 分组
+export function addWxUserGroup(data) {
+  return request({
+    url: '/company/wxUserGroup',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改个微 分组
+export function updateWxUserGroup(data) {
+  return request({
+    url: '/company/wxUserGroup',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除个微 分组
+export function delWxUserGroup(groupId) {
+  return request({
+    url: '/company/wxUserGroup/' + groupId,
+    method: 'delete'
+  })
+}
+
+// 导出个微 分组
+export function exportWxUserGroup(query) {
+  return request({
+    url: '/company/wxUserGroup/export',
+    method: 'get',
+    params: query
+  })
+}

BIN
src/assets/image/customer.png


BIN
src/assets/image/profile.jpg


BIN
src/assets/image/profile.png


BIN
src/assets/images/customer.png


+ 39 - 0
src/assets/images/dark.svg

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1" 
+    xmlns="http://www.w3.org/2000/svg" 
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <defs>
+        <filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
+        <filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
+        </filter>
+    </defs>
+    <g id="配置面板" width="48" height="40" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="setting-copy-2" width="48" height="40" transform="translate(-1190.000000, -136.000000)">
+            <g id="Group-8" width="48" height="40" transform="translate(1167.000000, 0.000000)">
+                <g id="Group-5-Copy-5" filter="url(#filter-1)" transform="translate(25.000000, 137.000000)">
+                    <mask id="mask-3" fill="white">
+                        <use xlink:href="#path-2"></use>
+                    </mask>
+                    <g id="Rectangle-18">
+                        <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
+                        <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
+                    </g>
+                    <rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
+                    <rect id="Rectangle-18" fill="#303648" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

BIN
src/assets/images/default - 副本.jpg


BIN
src/assets/images/default.jpg


+ 39 - 0
src/assets/images/light.svg

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1" 
+    xmlns="http://www.w3.org/2000/svg" 
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <defs>
+        <filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
+        <filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
+        </filter>
+    </defs>
+    <g id="配置面板" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="setting-copy-2" transform="translate(-1254.000000, -136.000000)">
+            <g id="Group-8" transform="translate(1167.000000, 0.000000)">
+                <g id="Group-5" filter="url(#filter-1)" transform="translate(89.000000, 137.000000)">
+                    <mask id="mask-3" fill="white">
+                        <use xlink:href="#path-2"></use>
+                    </mask>
+                    <g id="Rectangle-18">
+                        <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
+                        <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
+                    </g>
+                    <rect id="Rectangle-18" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
+                    <rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

BIN
src/assets/images/login-background.jpg


BIN
src/assets/images/login_left.png


BIN
src/assets/images/profile.jpg


BIN
src/assets/images/profile.png


BIN
src/assets/images/watchApi/battery.png


BIN
src/assets/images/watchApi/bigicon.png


BIN
src/assets/images/watchApi/title-icon.png


BIN
src/assets/images/watchApi/watch_icon36.png


BIN
src/assets/images/watchApi/xl.png


+ 130 - 0
src/components/H5/FormWrapper.vue

@@ -0,0 +1,130 @@
+<template>
+  <el-form ref="form" :model="form" label-width="130px" v-if="form && form.type">
+    <!-- Text component form items -->
+    <text-form-items
+      v-if="form.type === 'h5-text'"
+      ref="items"
+      :config="form"
+      @update:config="updateFormConfig"
+    />
+
+    <!-- Image component form items -->
+    <image-form-items
+      v-if="form.type === 'h5-image'"
+      ref="items"
+      :config="form"
+    />
+
+    <!-- Sep component form items -->
+    <sep-form-items
+      v-if="form.type === 'h5-sep'"
+      ref="items"
+      :config="form"
+    />
+
+    <!-- Countdown component form items -->
+    <countdown-form-items
+      v-if="form.type === 'h5-countdown'"
+      ref="items"
+      :config="form"
+      @update:config="updateFormConfig"
+    />
+
+    <chat-form-items
+      v-if="form.type === 'h5-chat'"
+      ref="items"
+      :config="form"
+      @update:config="updateFormConfig"
+      />
+
+    <!-- Common form items for all components -->
+    <common-form-items
+      :config="form"
+      :index="index"
+      :list="list"
+      @bottom-change="handleBottomChange"
+      @delete="handleDelete"
+      @update:config="updateFormConfig"
+    />
+  </el-form>
+</template>
+
+<script>
+import TextFormItems from './config-item/h5-text-config.vue';
+import ImageFormItems from './config-item/h5-image-config.vue';
+import SepFormItems from './config-item/h5-sep-config.vue';
+import CommonFormItems from './config-item/common-config.vue';
+import CountdownFormItems from './config-item/h5-countdown-config.vue';
+import ChatFormItems from './config-item/h5-chat-config.vue'
+export default {
+  name: 'FormWrapper',
+  components: {
+    TextFormItems,
+    ImageFormItems,
+    SepFormItems,
+    CommonFormItems,
+    CountdownFormItems,
+    ChatFormItems
+  },
+  props: {
+    form: {
+      type: Object,
+      default: () => ({})
+    },
+    index: {
+      type: Number,
+      default: -1
+    },
+    list: {
+      type: Array,
+      default: () => []
+    }
+  },
+  methods: {
+    updateFormConfig(newConfig) {
+      console.log("更新表单配置...");
+      // Update form config
+      this.$emit('update:form', newConfig);
+      console.info(this.$refs.items)
+      this.$refs.items.updateCommonCofing({addWxFun: newConfig.addWxFun, fixe: newConfig.fixe});
+    },
+    handleBottomChange() {
+      // Check if another item is already fixed to bottom
+      let hasFooter = this.list.some((item, idx) =>
+        idx !== this.index && item.classText && item.classText.includes('footer')
+      );
+
+      if(hasFooter) {
+        alert('全局只能允许有一个在底部!');
+        this.form.fixe = false;
+        return;
+      }
+
+      // Update the class
+      let className = "footer";
+      if (this.form.fixe) {
+        this.addClassToItem(className);
+      } else {
+        this.removeClassFromItem(className);
+      }
+    },
+    addClassToItem(className) {
+      if (!this.form.classText.includes(className)) {
+        this.form.classText.push(className);
+      }
+    },
+    removeClassFromItem(className) {
+      this.form.classText = this.form.classText.filter(cls => cls !== className);
+    },
+    handleDelete() {
+      this.$emit('delete', this.index);
+    }
+  }
+}
+</script>
+
+<style>
+.el-form-item__label{
+  text-align: center !important;
+}
+</style>

+ 87 - 0
src/components/H5/config-item/common-config.vue

@@ -0,0 +1,87 @@
+// CommonFormItems.vue - Common form items shared across all components
+<template>
+  <div id="h5-config-common" ref="commonForm">
+    <el-form-item label="是否底部">
+      <el-switch v-model="config.fixe" @change="handleBottom"></el-switch>
+    </el-form-item>
+    <el-form-item label="点击是否加微">
+      <el-switch v-model="config.addWxFun" @change="val => updateConfig('addWxFun', val)" />
+    </el-form-item>
+    <el-form-item label="获客链接" v-if="config.addWxFun">
+      <el-select v-model="config.workUrl" filterable @change="val => updateConfig('workUrl', val)" placeholder="请选择">
+        <el-option
+          v-for="item in options"
+          :key="item.value"
+          :label="item.label"
+          :value="item.value">
+        </el-option>
+      </el-select>
+      <el-button type="primary" @click="copyLink">复制链接</el-button>
+    </el-form-item>
+    <el-form-item>
+      <el-button type="danger" @click="handleDelete">删 除</el-button>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+import {listAll} from '@/api/qw/workLink'
+
+export default {
+  name: 'CommonFormItems',
+  props: {
+    config: {
+      type: Object,
+      required: true
+    },
+    index: {
+      type: Number,
+      required: true
+    },
+    list: {
+      type: Array,
+      required: true
+    }
+  },
+  data(){
+    return {
+        options: []
+    }
+  },
+  mounted() {
+    this.loadQwAddr();
+  },
+  methods: {
+    async copyLink() {
+      try {
+        await navigator.clipboard.writeText(this.config.workUrl);
+        this.$message.success("链接已复制到剪贴板"); // 提示成功
+      } catch (err) {
+        console.error("复制失败:", err);
+        this.$message.error("复制失败,请手动复制"); // 提示失败
+      }
+    },
+    loadQwAddr(){
+      listAll({})
+        .then(res=>{
+          this.options = res.data.map(item=>{
+            return {
+              label: item.linkName,
+              value: item.url
+            }
+          })
+        })
+        .catch(err=>console.log(err));
+    },
+    updateConfig(key, value) {
+      this.$emit('update:config', { ...this.config, [key]: value });
+    },
+    handleBottom() {
+      this.$emit('bottom-change');
+    },
+    handleDelete() {
+      this.$emit('delete');
+    }
+  }
+}
+</script>

+ 182 - 0
src/components/H5/config-item/h5-chat-config-dialog.vue

@@ -0,0 +1,182 @@
+<template>
+  <div v-if="localDialog && localDialog.text " :class="visible?'dialog-config-active':'dialog-config'">
+    <div class="question-section">
+      <div class="section-label">提问</div>
+      <el-input v-model="localDialog.text" placeholder="选择问题" style="width: 100%">
+      </el-input>
+    </div>
+
+    <div class="answer-options" v-if="localDialog.options && localDialog.options.length > 0">
+      <div class="section-label">回复</div><el-button
+        type="text"
+        class="config-button"
+        @click="add">
+        新增
+      </el-button>
+
+      <draggable v-model="localDialog.options" @end="">
+        <div v-for="(option, index) in localDialog.options" :key="option.id || index" class="option-item">
+          <div class="option-label">选项{{ index + 1 }}: <el-input v-model="option.text" placeholder="对话" />
+            <br/>
+            <br/>
+            <el-input type="textarea" v-model="option.answer" placeholder="回复"></el-input>
+            <el-button
+              type="text"
+              class="config-button"
+              @click="del(index)">
+              删除
+            </el-button>
+          </div>
+        </div>
+      </draggable>
+    </div>
+    <div class="answer-options" v-else>
+      <el-button
+        type="text"
+        class="config-button"
+        @click="add">
+        新增
+      </el-button>
+    </div>
+
+    <div class="action-buttons">
+      <el-button type="primary" @click="saveAndReturn">保存并返回</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import draggable from 'vuedraggable'
+
+export default {
+  name: 'DialogConfig',
+  components: { draggable },
+  props: {
+    visible: {
+      type: Boolean,
+      default: false
+    },
+    dialog: {
+      type: Object,
+      required: false,
+      default: () => ({
+        id: 2,
+        sender: 'agent',
+        text: '您的年龄?',
+        options: [
+          { id: 1, text: '45-55岁' },
+          { id: 2, text: '55-60岁' },
+          { id: 3, text: '60-65岁' },
+          { id: 4, text: '65岁以上' }
+        ],
+        userSelection: null
+      })
+    },
+    dialogIndex: {
+      type: Number,
+      required: false
+    }
+  },
+  watch: {
+    dialog: {
+      immediate: true,
+      handler(newVal) {
+        this.localDialog = { ...newVal }
+        console.log('localDialog', this.localDialog)
+      }
+    },
+    visible: {
+      immediate: true,
+      handler(newVal) {
+        this.$nextTick(()=>{
+          // 隐藏通用表单
+          if (newVal) {
+            document.querySelector("#h5-config-common").style.display = "none";
+          } else {
+            document.querySelector("#h5-config-common").style.display = "block";
+          }
+        });
+      }
+    }
+  },
+  data() {
+    return {
+      localDialog: {
+        options:[],
+        ...this.dialog
+      }
+    }
+  },
+  methods: {
+    del(index) {
+      this.localDialog.options.splice(index, 1);
+    },
+    add() {
+      if (!this.localDialog.options) {
+        this.$set(this.localDialog, 'options', []);
+      }
+      this.localDialog.options.push({ text: '', answer: '' ,id: this.localDialog.options.length});
+      console.log(this.localDialog)
+    },
+    saveAndReturn() {
+      // this.$emit('update:dialog', this.localDialog);
+      this.$emit('update:dialog', { ...this.localDialog });
+      this.$emit('update:visible', false)
+    }
+  }
+}
+</script>
+
+<style scoped>
+.dialog-config {
+  padding: 100px;
+  visibility: hidden;
+  display: none;
+}
+
+.dialog-config-active {
+  position: absolute;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  z-index: 9999;
+  background-color: white;
+}
+
+.section-label {
+  font-size: 14px;
+  color: #606266;
+  margin-bottom: 10px;
+}
+
+.question-section, .answer-options {
+  margin-bottom: 25px;
+  z-index: 99999;
+  background-color: white;
+}
+
+.editor-content textarea {
+  width: 100%;
+  min-height: 100px;
+  border: none;
+  outline: none;
+  resize: vertical;
+}
+
+.option-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 10px 0;
+  border-bottom: 1px solid #ebeef5;
+}
+
+.config-button {
+  color: #409EFF;
+}
+
+.action-buttons {
+  margin-top: 30px;
+  text-align: center;
+}
+</style>

+ 317 - 0
src/components/H5/config-item/h5-chat-config.vue

@@ -0,0 +1,317 @@
+<template>
+  <div class="qa-dialog-config">
+    <!-- 互动问答内容设置 header -->
+    <div class="config-header">
+      <h3>互动问答内容设置</h3>
+    </div>
+
+    <!-- 问答对话设置 -->
+    <el-form-item label="问答对话">
+      <div
+        v-for="(msg, index) in localConfig.agentMsg"
+        :key="index"
+        class="dialog-item"
+      >
+        <div class="dialog-header">
+          <span>对话{{ msg.id }}</span>
+          <div class="dialog-actions">
+            <el-button type="text" @click="configDialog(msg.id)">设置</el-button>
+            <el-button type="text" class="delete-btn" @click="removeDialog(msg.id)">删除</el-button>
+          </div>
+        </div>
+        <div class="dialog-content">
+          <div class="question">提问: {{ msg.text }}</div>
+        </div>
+      </div>
+
+      <div class="add-dialog">
+        <el-button type="text" @click="addDialog">
+          <i class="el-icon-plus"></i>
+          添加对话(还可以添加{{ 6 - localConfig.agentMsg.length }}项)
+        </el-button>
+      </div>
+    </el-form-item>
+    <el-form-item label="按钮文案">
+        <div class="dialog-content">
+          <el-input v-for="item in localConfig.lastMsg" v-model="item.text" @input="buttonTextChange" />
+        </div>
+    </el-form-item>
+
+    <el-form-item label="客服头像">
+      <div class="avatar-setting">
+        <image-upload v-model="localConfig.style.avatar" :file-type='["png", "jpg", "jpeg", "gif"]' :limit="1"/>
+      </div>
+    </el-form-item>
+
+    <el-form-item label="按钮配色">
+      <el-color-picker v-model="localConfig.style.buttonColor"></el-color-picker>
+    </el-form-item>
+
+    <el-form-item label="按钮文字颜色">
+      <el-color-picker v-model="localConfig.style.btnTextColor"></el-color-picker>
+    </el-form-item>
+
+    <!-- 聊天配置对话框-->
+    <h5-chat-config-dialog :dialog-index="currentDialogIndex" :dialog="currentMsg" :visible="dialogConfigVisible" @update:visible="dialogConfigVisible=$event" @update:dialog="updateDialogData"/>
+
+    <el-form-item label="加微按钮" v-if="localConfig.addWxFun">
+      <image-upload v-model="localConfig.addWxButtonImg" :file-type='["png", "jpg", "jpeg", "gif"]' :limit="1"/>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+import H5ChatConfigDialog from '@/components/H5/config-item/h5-chat-config-dialog.vue'
+import draggable from 'vuedraggable'
+
+export default {
+  name: 'ChatConfigComponent',
+  components: {
+    draggable,
+    H5ChatConfigDialog
+  },
+  computed: {
+  },
+  props: {
+    config: {
+      type: Object,
+      default: () => ({
+        messages: [{
+          id: 1,
+          sender: 'agent',
+          text: '您好!欢迎报名【中老年健康养生大讲堂】,请仔细答一下问题,便于帮您分配专业的老师进行指导。',
+          welcome: true
+        },
+          {
+            id: 2,
+            sender: 'agent',
+            text: '您的年龄?',
+            options: [
+              { id: 1, text: '45-55岁', answer: '' },
+              { id: 2, text: '55-60岁', answer: '' },
+              { id: 3, text: '60-65岁', answer: '' },
+              { id: 4, text: '65岁以上', answer: '' }
+            ],
+            userSelection: null
+          },
+          {
+            id: 3,
+            sender: 'user',
+            text: '45-55岁',
+            userSelection: { id: 1, text: '45-55岁' }
+          },
+          {
+            id: 4,
+            sender: 'agent',
+            text: '更想通过课程学习到哪些知识?',
+            options: [
+              { id: 1, text: '食疗食补' },
+              { id: 2, text: '经络疏通' },
+              { id: 3, text: '脏腑调养' },
+              { id: 4, text: '启蒙养生' },
+              { id: 5, text: '以上所有' }
+            ],
+            userSelection: null
+          },
+          {
+            id: 5,
+            sender: 'user',
+            text: '食疗食补',
+            userSelection: { id: 1, text: '食疗食补' }
+          }],
+        agentMsg: [],
+        lastMsg:[
+          {type: 0, text: "好的,已经为您分配专业老师。"},
+          {type: 1, text: "【点击下方按钮】"},
+          {type: 0, text: "添加老师,获取免费上课链接。!"},
+        ],
+        style: {
+          avatar: '',
+          buttonColor: '#409EFF',
+          btnTextColor: ''
+        }
+      })
+    }
+  },
+  data() {
+    return {
+      localConfig: {agentMsg:[],...this.config},
+      currentMsg: null,
+      dialogConfigVisible: false,
+      currentDialogIndex: -1
+    }
+  },
+  watch: {
+    'localConfig.addWxButtonImg': {
+      handler(newVal) {
+        if (newVal) {
+          this.$emit('update:config', this.localConfig)
+        }
+      },
+      deep: true
+    },
+    'localConfig.style.avatar': {
+      handler(newVal) {
+        if (newVal) {
+          this.$emit('update:config', this.localConfig)
+        }
+      },
+      deep: true
+    },
+    'localConfig.agentMsg':{
+      handler(newVal) {
+        if (newVal) {
+          setTimeout(()=>{
+            // 根据agentMsg生成Message列表
+            let messages = []
+            let id = 0;
+            this.localConfig.agentMsg?.forEach((msg)=>{
+              id++;
+              if(!msg.options || msg.options.length === 0) {
+                messages.push({...msg,id: id})
+              } else {
+                messages.push({...msg,id: id})
+                messages.push({
+                  id: ++id,
+                  sender: 'user',
+                  text: msg.options[0].text
+                })
+              }
+            })
+            messages.push({
+              id: ++id,
+              sender: 'agent',
+              text: this.localConfig.lastMsg.map(e => {
+                if(e.type == 0) return e.text;
+                if(e.type == 1) return "<span style='color: red'>"+ e.text +"</span>";
+              }).join(""),
+              last: true
+            })
+            let config = JSON.parse(JSON.stringify(this.localConfig));
+            config.messages = messages;
+            this.$emit('update:config', config)
+          },100)
+        }
+      },
+      deep: true
+    }
+  },
+  methods: {
+    addDialog() {
+      if ((6 - this.localConfig.agentMsg.length) <= 0) {
+        alert('最多只能添加6条对话')
+        return
+      }
+      let maxId = Math.max(0,...this.localConfig.agentMsg.map(msg => msg.id));
+      if(!maxId){
+        maxId = 0;
+      }
+      this.localConfig.agentMsg.push({
+        id: maxId + 1,
+        sender: 'agent',
+        text: '新增对话',
+        welcome: true
+      })
+      this.$emit('update:config', this.localConfig)
+    },
+    removeDialog(id) {
+      let index = this.localConfig.agentMsg.findIndex(msg => msg.id === id)
+      this.localConfig.agentMsg.splice(index, 1)
+      this.$emit('update:config', this.localConfig)
+    },
+    configDialog(id) {
+      // 通过 id 找到对应的消息
+      let index = this.localConfig.agentMsg.findIndex(msg => msg.id === id)
+      if (index === -1) {
+        console.error(`Message with id ${id} not found.`)
+        return
+      }
+      this.currentDialogIndex = index
+      this.currentMsg = this.localConfig.agentMsg[index]
+      this.dialogConfigVisible = true
+      this.$set(this.$data, index, this.currentMsg)
+      console.log(this.currentMsg)
+    },
+    updateDialogData(data) {
+      this.localConfig.agentMsg[this.currentDialogIndex] = data
+      this.currentMsg = data
+      this.$emit('update:config', this.localConfig)
+    },
+    buttonTextChange(){
+      this.localConfig.agentMsg = JSON.parse(JSON.stringify(this.localConfig.agentMsg));
+    },
+    updateCommonCofing(data){
+      this.localConfig.addWxFun = data.addWxFun;
+      this.localConfig.fixe = data.fixe;
+    }
+  }
+}
+</script>
+
+<style scoped>
+.qa-dialog-config {
+  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
+  position: relative;
+}
+
+.config-header {
+  border-bottom: 1px solid #ebeef5;
+  padding-bottom: 10px;
+  margin-bottom: 20px;
+}
+
+.qa-section, .style-section {
+  margin-bottom: 20px;
+}
+
+h4 {
+  font-weight: 500;
+  margin-bottom: 15px;
+}
+
+
+.add-dialog {
+  color: #409EFF;
+  cursor: pointer;
+  margin-top: 5px;
+}
+
+.dialog-item {
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  margin-bottom: 10px;
+}
+
+.dialog-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 8px 12px;
+  border-bottom: 1px solid #ebeef5;
+}
+
+.dialog-actions {
+  display: flex;
+}
+
+.delete-btn {
+  color: #F56C6C;
+}
+
+.dialog-content {
+  padding: 12px;
+}
+
+.avatar-setting, .color-setting {
+  display: flex;
+  align-items: center;
+  margin-bottom: 15px;
+}
+
+.setting-label {
+  width: 80px;
+  font-size: 14px;
+}
+
+
+</style>

+ 270 - 0
src/components/H5/config-item/h5-countdown-config.vue

@@ -0,0 +1,270 @@
+<template>
+  <div class="countdown-config">
+    <div class="config-block">
+      <h3>倒计时配置</h3>
+
+      <el-form-item class="time-config" label="时间配置">
+        <div class="button-group">
+          <el-radio-group v-model="localConfig.countdownMode" @change="handleModeChange">
+            <el-radio-button :label="'1'" class="select-button"
+                             :class="{ 'selected': localConfig.countdownMode == '1' }"
+            >固定截止时间
+            </el-radio-button>
+            <el-radio-button :label="'2'" class="select-button"
+                             :class="{ 'selected': localConfig.countdownMode == '2' }"
+            >固定倒计时长
+            </el-radio-button>
+          </el-radio-group>
+        </div>
+
+        <!-- 固定截止时间模式 -->
+        <template v-if="localConfig.countdownMode == 1">
+          <div class="datetime-picker">
+            <el-date-picker
+              v-model="localConfig.endDateTime"
+              type="datetime"
+              placeholder="选择截止日期时间"
+              format="yyyy-MM-dd HH:mm:ss"
+              value-format="yyyy-MM-dd HH:mm:ss"
+              @change="handleEndTimeChange"
+            ></el-date-picker>
+          </div>
+          <div class="help-text">
+            * 设置一个截至日期固定的倒计时,例如,设置2021-03-04 12:00:00,访客进入页面,该倒计时将会倒计至2021-03-04
+            12:00:00结束。
+          </div>
+        </template>
+
+        <!-- 固定倒计时长模式 -->
+        <template v-else>
+          <div class="time-input">
+            <el-input v-model="localConfig.timeDisplay" @change="handleCountMinusChange" placeholder="分钟">
+              <template #append>
+                <i class="el-icon-time"></i>
+              </template>
+            </el-input>
+          </div>
+          <div class="help-text">
+            * 固定时长:设置一个固定时长的倒计时,例如,设置5分钟,访客每次进入页面,倒计时均倒计5分钟,若倒计时间结束,用户再次进入页面,倒计时重新开始计时。
+          </div>
+        </template>
+      </el-form-item>
+
+      <el-form-item class="color-config" label="颜色">
+        <el-color-picker
+          v-model="localConfig.mainColor"
+          show-alpha
+          @change="handleColorChange"
+        ></el-color-picker>
+      </el-form-item>
+
+      <el-form-item class="bg-image-config" label="倒计时底图">
+        <image-upload v-model="localConfig.bgImage" :file-type='["png", "jpg", "jpeg", "gif"]' :limit="1"/>
+      </el-form-item>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'CountdownConfigComponent',
+
+  props: {
+    config: {
+      type: Object,
+      required: false,
+      default: () => ({
+        hours: 0,
+        minutes: 10,
+        seconds: 0,
+        endDateTime: null,
+        timeDisplay: 0,
+        mainColor: '#FF5722',
+        bgImage: ''
+      })
+    }
+  },
+
+  data() {
+    return {
+      localConfig: { ...this.config }
+    }
+  },
+
+  methods: {
+    // 数字补零
+    padZero(num) {
+      return num.toString().padStart(2, '0')
+    },
+
+    // 格式化时间显示
+    formatTimeDisplay(hours, minutes, seconds) {
+      return `${this.padZero(hours)}时 ${this.padZero(minutes)}分 ${this.padZero(seconds)}秒`
+    },
+
+    // 处理倒计时模式变更
+    handleModeChange(value) {
+      this.localConfig.countdownMode = value
+      this.$emit('update:config', { ...this.localConfig })
+    },
+
+    // 处理倒计时长
+    handleCountMinusChange(value) {
+      this.localConfig.timeDisplay = value
+      this.$emit('update:config', { ...this.localConfig })
+    },
+    // 处理截止时间变更
+    handleEndTimeChange(value) {
+      this.localConfig.endDateTime = value
+      this.$emit('update:config', { ...this.localConfig })
+    },
+
+    // 处理颜色变更
+    handleColorChange(value) {
+      this.localConfig.mainColor = value
+      this.$emit('update:config', { ...this.localConfig })
+    }
+  },
+
+  // 监听属性变化
+  watch: {
+    'localConfig.bgImage': {
+      handler(newVal, oldVal) {
+        this.localConfig.bgImage = newVal
+        this.$emit('update:config', { ...this.localConfig })
+      },
+      deep: false
+    }
+  }
+}
+</script>
+
+<style scoped>
+.countdown-config {
+  width: 100%;
+  font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;
+}
+
+.config-block {
+  padding: 0px 15px;
+}
+
+h3, h4 {
+  font-weight: 500;
+  margin: 15px 0 10px 0;
+  color: #303133;
+}
+
+h3 {
+  font-size: 16px;
+  border-bottom: 1px solid #EBEEF5;
+  padding-bottom: 10px;
+}
+
+h4 {
+  font-size: 14px;
+  margin-top: 20px;
+}
+
+.button-group {
+  margin: 10px 0;
+}
+
+.select-button {
+  margin-right: -1px;
+}
+
+.selected {
+  color: #fff;
+  background-color: #409EFF;
+  border-color: #409EFF;
+}
+
+.datetime-picker, .time-input {
+  margin: 10px 0;
+}
+
+.help-text {
+  color: #909399;
+  font-size: 12px;
+  margin-top: 5px;
+  line-height: 1.5;
+}
+
+.color-config {
+  margin: 15px 0;
+}
+
+.color-preview {
+  height: 30px;
+  border-radius: 4px;
+  margin-top: 10px;
+}
+
+.image-upload-area {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  width: 100%;
+  height: 108px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  position: relative;
+  margin: 10px 0;
+  overflow: hidden;
+}
+
+.image-preview {
+  width: 100%;
+  height: 100%;
+  position: relative;
+}
+
+.image-preview img {
+  width: 100%;
+  height: 100%;
+  object-fit: contain;
+}
+
+.image-actions {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  background-color: rgba(0, 0, 0, 0.5);
+  display: flex;
+  justify-content: space-around;
+  padding: 5px 0;
+}
+
+.upload-tip {
+  text-align: center;
+  color: #909399;
+  font-size: 12px;
+}
+
+.upload-tip i {
+  font-size: 28px;
+  color: #C0C4CC;
+  margin-bottom: 5px;
+}
+
+.price-config {
+  margin-top: 15px;
+}
+
+.price-input {
+  display: flex;
+  align-items: center;
+  margin: 10px 0;
+}
+
+.color-label {
+  margin-right: 10px;
+  min-width: 40px;
+}
+
+.price-value {
+  margin: 10px 0 20px 0;
+}
+</style>

+ 20 - 0
src/components/H5/config-item/h5-image-config.vue

@@ -0,0 +1,20 @@
+// ImageFormItems.vue - Form items specific to the h5-image component
+<template>
+  <div>
+    <el-form-item label="图片">
+      <image-upload v-model="config.url" :file-type='["png", "jpg", "jpeg", "gif"]' :limit="1"/>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'ImageFormItems',
+  props: {
+    config: {
+      type: Object,
+      required: true
+    }
+  }
+}
+</script>

+ 22 - 0
src/components/H5/config-item/h5-sep-config.vue

@@ -0,0 +1,22 @@
+<template>
+  <div>
+    <el-form-item label="高度">
+      <el-input v-model="config.style.height" type="number"></el-input>
+    </el-form-item>
+    <el-form-item label="背景颜色">
+      <el-color-picker v-model="config.style.background"></el-color-picker>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'SepFormItems',
+  props: {
+    config: {
+      type: Object,
+      required: true
+    }
+  }
+}
+</script>

+ 127 - 0
src/components/H5/config-item/h5-text-config.vue

@@ -0,0 +1,127 @@
+<template>
+  <div>
+    <el-form-item label="内容">
+      <el-input type="textarea" :row="10" :value="config.content" @input="val => updateConfig('content', val)"/>
+    </el-form-item>
+    <el-form-item label="对齐方式">
+      <el-radio v-model="config.style.textAlign" label="left">右对齐</el-radio>
+      <el-radio v-model="config.style.textAlign" label="center">居中</el-radio>
+      <el-radio v-model="config.style.textAlign" label="right">左对齐</el-radio>
+    </el-form-item>
+    <el-form-item label="背景颜色">
+      <el-color-picker v-model="config.style.background"></el-color-picker>
+    </el-form-item>
+    <el-form-item label="文本颜色">
+      <el-color-picker v-model="config.style.color"></el-color-picker>
+    </el-form-item>
+    <el-form-item label="字号">
+      <el-input placeholder="请输入内容" v-model="style.fontSize"  @input="handleInput">
+        <template slot="append">px</template>
+      </el-input>
+    </el-form-item>
+    <el-form-item label="样式">
+      <el-tooltip class="icon-span" effect="dark" content="加粗" placement="top">
+        <svg @click="fontChange(config.style, 'fontWeight', 'bold')" class="icon svg"
+             viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="32"
+             height="32">
+          <path :fill="(config.style.fontWeight === 'bold' ? '#1296db' : '#515151')"
+                d="M768.96 575.072c-22.144-34.112-54.816-56.8-97.984-68.032v-2.176c22.88-10.88 42.112-23.04 57.696-36.48 15.616-12.704 27.584-26.144 35.936-40.288 16.32-29.76 24.128-60.96 23.392-93.632 0-63.872-19.776-115.232-59.328-154.08-39.2-38.464-97.824-58.048-175.84-58.784H215.232v793.728H579.52c62.432 0 114.496-20.864 156.256-62.624 42.112-39.936 63.52-94.176 64.224-162.752 0-41.376-10.336-79.68-31.04-114.88zM344.32 228.832h194.912c43.904 0.736 76.224 11.424 96.896 32.128 21.056 22.144 31.584 49.184 31.584 81.12s-10.528 58.432-31.584 79.488c-20.672 22.848-52.992 34.304-96.896 34.304H344.32V228.832z m304.352 536.256c-20.672 23.584-53.344 35.744-97.984 36.48H344.32v-238.432h206.336c44.64 0.704 77.312 12.512 97.984 35.392 20.672 23.232 31.04 51.168 31.04 83.84 0 31.904-10.336 59.488-31.008 82.72z"></path>
+        </svg>
+      </el-tooltip>
+      <el-tooltip class="icon-span" effect="dark" content="倾斜" placement="top">
+        <svg @click="fontChange(config.style, 'fontStyle', 'oblique')" class="icon svg"
+             viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="32"
+             height="32">
+          <path :fill="(config.style.fontStyle === 'oblique' ? '#1296db' : '#515151')"
+                d="M602.530909 162.909091l-87.458909 721.454545H616.727273a34.909091 34.909091 0 0 1 0 69.818182h-279.272728a34.909091 34.909091 0 0 1 0-69.818182h107.287273l87.458909-721.454545H430.545455a34.909091 34.909091 0 0 1 0-69.818182h279.272727a34.909091 34.909091 0 0 1 0 69.818182h-107.287273z"></path>
+        </svg>
+      </el-tooltip>
+      <el-tooltip class="icon-span" effect="dark" content="下划线" placement="top">
+        <svg @click="fontChange(config.style, 'textDecoration', 'underline')" class="icon svg"
+             viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="32"
+             height="32">
+          <path
+            :fill="(config.style.textDecoration && config.style.textDecoration === 'underline' ? '#1296db' : '#515151')"
+            d="M512 811.296a312 312 0 0 0 312-312V89.6h-112v409.696a200 200 0 1 1-400 0V89.6h-112v409.696a312 312 0 0 0 312 312zM864 885.792H160a32 32 0 0 0 0 64h704a32 32 0 0 0 0-64z"></path>
+        </svg>
+      </el-tooltip>
+      <el-tooltip class="icon-span" effect="dark" content="中划线" placement="top">
+        <svg @click="fontChange(config.style, 'textDecoration', 'line-through')"
+             class="icon svg" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
+             width="32" height="32">
+          <path
+            :fill="(config.style.textDecoration && config.style.textDecoration === 'line-through' ? '#1296db' : '#515151')"
+            d="M604.16 512H819.2v51.2h-117.76c30.72 25.6 46.08 61.44 46.08 102.4 0 51.2-20.48 92.16-61.44 122.88-40.96 30.72-97.28 40.96-163.84 40.96-66.56 0-122.88-15.36-163.84-46.08-46.08-35.84-71.68-87.04-76.8-158.72h66.56c5.12 51.2 25.6 87.04 51.2 112.64 25.6 20.48 66.56 30.72 117.76 30.72 46.08 0 87.04-10.24 117.76-25.6 30.72-20.48 46.08-40.96 46.08-71.68 0-35.84-20.48-66.56-56.32-87.04-10.24-5.12-25.6-10.24-51.2-20.48H204.8v-51.2h204.8c-20.48-5.12-35.84-15.36-46.08-20.48-46.08-25.6-66.56-61.44-66.56-112.64 0-51.2 20.48-92.16 66.56-117.76 35.84-25.6 87.04-35.84 148.48-35.84 66.56 0 117.76 15.36 153.6 46.08 40.96 30.72 61.44 76.8 66.56 138.24H665.6c-5.12-40.96-25.6-71.68-51.2-92.16-25.6-20.48-61.44-30.72-112.64-30.72-40.96 0-76.8 5.12-102.4 20.48-20.48 10.24-35.84 35.84-35.84 71.68 0 30.72 15.36 51.2 51.2 71.68 15.36 10.24 51.2 20.48 107.52 35.84 30.72 10.24 61.44 15.36 81.92 25.6z"></path>
+        </svg>
+      </el-tooltip>
+    </el-form-item>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'TextFormItems',
+  props: {
+    config: {
+      type: Object,
+      required: true
+    }
+  },
+  methods: {
+    handleInput(value) {
+      // 使用正则表达式过滤非数字字符
+      this.style.fontSize = value.replace(/[^\d]/g, '');
+    },
+    updateConfig(key, value) {
+      this.$emit('update:config', { ...this.config, [key]: value });
+    },
+    fontChange(data, name, value) {
+      // 根据属性类型设置回退值
+      const fallbackValue = {
+        fontWeight: 'normal',  // 加粗恢复为normal
+        fontStyle: 'normal',   // 倾斜恢复为normal
+        textDecoration: 'none' // 下划线/中划线恢复为none
+      }[name];
+
+      if (data[name] === value) {
+        this.$set(data, name, fallbackValue);
+      } else {
+        this.$set(data, name, value);
+      }
+      this.$emit('update:config', { ...this.config });
+    }
+  },
+  data(){
+    return {
+      style:{
+        fontSize: 12
+      },
+      rules: {
+        fontSize: [
+          {
+            validator: (rule, value, callback) => {
+              if (/^\d+$/.test(value)) {
+                callback();
+              } else {
+                callback(new Error('只能输入数字'));
+              }
+            },
+            trigger: 'blur',
+          },
+        ],
+      },
+    }
+  },
+  watch:{
+    'style.fontSize':{
+      handler(val){
+        if(val){
+          console.log(val)
+          this.$set(this.config.style,'fontSize',val+'px');
+        }
+      },
+      deep:true
+    }
+  }
+}
+</script>

+ 13 - 0
src/components/H5/css/base.css

@@ -0,0 +1,13 @@
+.parent-div{
+  border: 2px dashed transparent;
+  /*padding: 5px 0;*/
+}
+.parent-div.active{
+  border-color: #02ff9b;
+}
+.footer{
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  width: 100%;
+}

+ 27 - 0
src/components/H5/h5-button.vue

@@ -0,0 +1,27 @@
+<template>
+  <div :class="config.classText.join(' ')">
+    <button class="el-button">{{config.content}}</button>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "h5-button",
+  props: {
+    config: {
+      type: Object,
+      default: () => ({})
+    }
+  }
+};
+</script>
+<style src="./css/base.css"></style>
+<style lang="scss" scoped>
+img{
+  width: 100% !important;
+}
+.el-button{
+  width: 100%;
+}
+
+</style>

+ 239 - 0
src/components/H5/h5-chat.vue

@@ -0,0 +1,239 @@
+<template>
+  <div :class="config.classText.join(' ')">
+    <div class="chat-container" >
+      <div class="chat-messages">
+        <!-- Messages -->
+        <div v-for="(message, index) in messages" :key="index"
+             :class="['message-wrapper', message.sender === 'user' ? 'user-message' : 'agent-message']">
+          <div class="avatar">
+            <img :src="message.sender === 'user' ? userAvatar : getAgentAvatar" alt="Avatar" />
+          </div>
+          <div class="message-content">
+            <div v-if="message.text" class="message-text" v-html="message.text"></div>
+            <!-- Options buttons -->
+            <div v-if="message.options && message.options.length > 0" class="options-container">
+              <button
+                v-for="(option, optIndex) in message.options"
+                :key="optIndex"
+                :style="{color: config.style.btnTextColor,backgroundColor: config.style.buttonColor}"
+                class="option-button"
+                :class="{ 'selected': isOptionSelected(message.id, option) }">
+                {{ option.text }}
+              </button>
+            </div>
+          </div>
+        </div>
+        <div v-if="config.addWxFun" style="text-align: center">
+          <el-image :src="config.addWxButtonImg" v-if="config.addWxButtonImg" />
+          <p v-if="!config.addWxButtonImg">请上传图片</p>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import agentAvatar from '@/assets/images/customer.png'
+import userAvatar from '@/assets/images/profile.png'
+
+export default {
+  name: "h5-chat",
+  props: {
+    config: {
+      type: Object,
+      default: () => {
+        return {
+          style: {}
+        }
+      }
+    }
+  },
+  created() {
+    console.log("Messages:", this.messages);
+  },
+  data() {
+    return {
+      config: {},
+      messages: this.config.messages,
+      userInput: "",
+      userAvatar: userAvatar, // Placeholder for user avatar
+      agentAvatar: agentAvatar, // Placeholder for agent avatar
+      selectedOptions: {}
+    };
+  },
+  watch: {
+    config: {
+      handler(newVal) {
+        console.log("Messages updated:", newVal);
+        this.config = newVal;
+        this.messages = newVal.messages;
+      },
+      deep: true
+    }
+  },
+  computed: {
+    getAgentAvatar() {
+      if (this.config.style.avatar) {
+        return this.config.style.avatar;
+      }
+      return this.agentAvatar;
+    }
+  },
+  methods: {
+    isOptionSelected(messageId, option) {
+      const message = this.messages.find(m => m.id === messageId);
+      return message && message.userSelection && message.userSelection.id === option.id;
+    }
+  }
+};
+</script>
+<style src="./css/base.css"></style>
+<style lang="scss" scoped>
+p {
+  white-space: pre-line;
+}
+
+.active {
+  border-color: #02ff9b;
+}
+.chat-container {
+  width: 100%;
+  max-width: 500px;
+  display: flex;
+  flex-direction: column;
+  background-color: #f8f8f8;
+  font-family: Arial, sans-serif;
+}
+
+.chat-messages {
+  flex: 1;
+  overflow-y: auto;
+  padding: 16px;
+  display: flex;
+  flex-direction: column;
+}
+
+.message-wrapper {
+  display: flex;
+  margin-bottom: 16px;
+  max-width: 80%;
+}
+
+.agent-message {
+  align-self: flex-start;
+}
+
+.user-message {
+  align-self: flex-end;
+  flex-direction: row-reverse;
+}
+
+.avatar {
+  font-size: 14px;
+  display: flex;
+  padding-right: 5px;
+  padding-left: 0;
+  margin-bottom: 15px;
+}
+
+.avatar img {
+  width: 36px;
+  height: 36px;
+  border-radius: 50%;
+}
+
+.message-content {
+  display: flex;
+  flex-direction: column;
+}
+
+.message-text {
+  padding: 12px;
+  border-radius: 18px;
+  font-size: 14px;
+  line-height: 1.4;
+  word-break: break-word;
+}
+
+.agent-message .message-text {
+  background-color: white;
+  color: #333;
+  border-top-left-radius: 4px;
+}
+
+.user-message .message-text {
+  background-color: #4a90e2;
+  color: white;
+  border-top-right-radius: 4px;
+}
+
+.options-container {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+  margin-top: 8px;
+}
+
+.option-button {
+  background-color: #4a90e2;
+  color: white;
+  border: none;
+  border-radius: 18px;
+  padding: 8px 16px;
+  font-size: 14px;
+  cursor: pointer;
+  transition: background-color 0.2s;
+}
+
+.option-button:hover {
+  background-color: #3a80d2;
+}
+
+.option-button.selected {
+  background-color: #2a70c2;
+}
+
+.input-area {
+  display: flex;
+  padding: 12px;
+  border-top: 1px solid #e0e0e0;
+  background-color: white;
+}
+
+.message-input {
+  flex: 1;
+  padding: 10px;
+  border: 1px solid #e0e0e0;
+  border-radius: 20px;
+  margin-right: 8px;
+  font-size: 14px;
+}
+
+.send-button {
+  background-color: #4a90e2;
+  color: white;
+  border: none;
+  border-radius: 20px;
+  padding: 0 16px;
+  font-size: 14px;
+  cursor: pointer;
+}
+
+.send-button:hover {
+  background-color: #3a80d2;
+}
+
+/* For user selections displayed in chat */
+.user-message .message-content {
+  align-items: flex-end;
+}
+
+.user-selection {
+  background-color: #e6f3ff;
+  color: #4a90e2;
+  padding: 8px 16px;
+  border-radius: 18px;
+  font-size: 14px;
+  margin-top: 4px;
+}
+</style>

+ 79 - 0
src/components/H5/h5-countdown.vue

@@ -0,0 +1,79 @@
+<template>
+  <div :class="config.classText.join(' ')">
+      <div class="countdown2-box"
+           :style="{ backgroundImage: config.bgImage && config.bgImage !== '#' ? `url(${config.bgImage})` : '' }"
+      >
+        距结束<span id="days" :style="{background: config.mainColor}">{{ config.days }}</span>天
+        <span id="hours" :style="{background: config.mainColor}">{{ config.hours }}</span>时
+        <span id="minutes" :style="{background: config.mainColor}">{{ config.minutes }}</span>分
+        <span id="seconds" :style="{background: config.mainColor}">{{ config.seconds }}</span>秒
+      </div>
+  </div>
+</template>
+
+<script>
+
+export default {
+  name: 'h5-countdown',
+  props: {
+    config: {
+      type: Object,
+      default: () => {
+        return {
+          days: 'x',
+          hours: 'x',
+          minutes: 'x',
+          seconds: 'x',
+          classText: ['active'],
+          bgImage: '#',
+          mainColor:''
+        }
+      }
+    }
+  },
+  watch:{
+    'config.bgImage':{
+      handler(val){
+        console.info('bgImage change:',val)
+      },
+      deep:true
+    }
+  },
+  created() {
+    console.info('h5-text loaded:', this.config)
+  }
+}
+</script>
+<style src="./css/base.css"></style>
+<style lang="scss" scoped>
+p {
+  white-space: pre-line;
+}
+
+.active {
+  border-color: #02ff9b;
+}
+
+.countdown2-box {
+  background: url('#') no-repeat center;
+  background-size: 100%;
+  width: 100%;
+  height: 54px;
+  line-height: 54px;
+  color: #515A6E;
+  font-size: 14px;
+  text-align: center;
+}
+
+.countdown2-box span {
+  display: inline-block;
+  color: #fff;
+  width: 22px;
+  line-height: 20px;
+  text-align: center;
+  height: 20px;
+  border-radius: 3px;
+  margin: 7px;
+  background: #FF5A29;
+}
+</style>

+ 27 - 0
src/components/H5/h5-image.vue

@@ -0,0 +1,27 @@
+<template>
+  <div :class="config.classText.join(' ')">
+    <img :src="config.url || require('@/assets/images/default.jpg')" :style="config.style" />
+  </div>
+<!--  <img  src="@/assets/images/default.jpg" width="200" height="200" />-->
+</template>
+
+<script>
+export default {
+  name: "h5-image",
+  props: {
+    config: {
+      type: Object,
+      default: () => ({})
+    }
+  }
+};
+</script>
+<style src="./css/base.css"></style>
+<style lang="scss" scoped>
+img{
+  width: 100% !important;
+}
+.active{
+  border-color: #02ff9b;
+}
+</style>

+ 28 - 0
src/components/H5/h5-sep.vue

@@ -0,0 +1,28 @@
+<template>
+  <div :class="config.classText.join(' ')">
+  </div>
+</template>
+
+<script>
+export default {
+  name: "h5-sep",
+  props: {
+    config: {
+      type: Object,
+      default: () => ({})
+    }
+  },
+  created() {
+    console.info('h5-text loaded:', this.config);
+  }
+};
+</script>
+<style src="./css/base.css"></style>
+<style lang="scss" scoped>
+p{
+  white-space: pre-line;
+}
+.active{
+  border-color: #02ff9b;
+}
+</style>

+ 27 - 0
src/components/H5/h5-text.vue

@@ -0,0 +1,27 @@
+<template>
+    <p :class="config.classText.join(' ')" :style="config.style">{{ config.content }}</p>
+</template>
+
+<script>
+export default {
+  name: "h5-text",
+  props: {
+    config: {
+      type: Object,
+      default: () => ({})
+    }
+  },
+  created() {
+    console.info('h5-text loaded:', this.config);
+  }
+};
+</script>
+<style src="./css/base.css"></style>
+<style lang="scss" scoped>
+p{
+  white-space: pre-line;
+}
+.active{
+  border-color: #02ff9b;
+}
+</style>

+ 419 - 0
src/components/H5Editor/index.vue

@@ -0,0 +1,419 @@
+<template>
+  <div class="h5-editor-container">
+    <div class="h5-editor">
+    </div>
+    <el-row :gutter="24">
+      <el-col :span="2" class="button-body">
+        <div v-for="item in componentList">
+          <p/>
+          <div>
+            {{ item.groupName }}
+          </div>
+          <el-button class="button-tag" @click="add(item)" v-for="item in item.comps">
+            <!-- 添加图标和文字 -->
+            <i :class="item.icon" style="margin-right: 5px"></i>
+            {{ item.label }}
+          </el-button>
+        </div>
+      </el-col>
+      <el-col :span="12">
+        <div class="parent-container">
+          <div class="view-body">
+            <draggable v-model="list" @end="end">
+              <div v-for="(item, index) in list" :key="index" @click="select(index)" class="view-item">
+                <component :is="item.type" :config="item"/>
+              </div>
+            </draggable>
+          </div>
+        </div>
+      </el-col>
+      <el-col :span="10" style="overflow-y: auto;height:80vh;">
+        <form-wrapper
+          :form="form"
+          :index="index"
+          :list="list"
+          @update:form="updateForm"
+          @delete="del"
+        />
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import draggable from 'vuedraggable'
+import H5Text from '@/components/H5/h5-text.vue'
+import H5Image from '@/components/H5/h5-image.vue'
+import H5Button from '@/components/H5/h5-button.vue'
+import H5Sep from '@/components/H5/h5-sep.vue'
+import H5Countdown from '@/components/H5/h5-countdown.vue'
+import FormWrapper from '@/components/H5/FormWrapper.vue'
+import H5Chat from '@/components/H5/h5-chat.vue'
+import AgentAvatar from '@/assets/images/customer.png?inline'
+
+export default {
+  components: {
+    draggable, // 对应模板中的<h5-text>
+    H5Text, // 对应模板中的<h5-text>
+    H5Button, // 对应模板中的<h5-text>
+    H5Image,// 对应模板中的<h5-image>
+    H5Sep,// 对应模板中的<h5-sep>
+    H5Countdown,// 对应模板中的<h5-countdown>
+    FormWrapper,
+    H5Chat
+  },
+  mounted() {
+    this.initData(this.json)
+  },
+  props: {
+    json: {
+      type: String,
+      default: '[]'
+    }
+  },
+  data() {
+    return {
+      componentList: [{
+        groupName: '基础控件',
+        comps: [
+          {
+            type: 'h5-text',
+            label: '文本',
+            icon: 'el-icon-document'         // 文档图标更符合文本语义
+          },
+          {
+            type: 'h5-image',
+            label: '图片',
+            icon: 'el-icon-picture'          // 明确的图片图标
+          },
+          {
+            type: 'h5-sep',
+            label: '分割线',
+            icon: 'el-icon-minus'            // 减号图标模拟分割线效果
+          }
+        ]
+      }, {
+        groupName: '营销控件',
+        comps: [
+          {
+            type: 'h5-countdown',
+            label: '倒计时',
+            icon: 'el-icon-timer'            // 计时器图标表示倒计时
+          },
+          {
+            type: 'h5-chat',
+            label: '互动问答',
+            icon: 'el-icon-chat-square'     // 购物袋表示购买相关
+          }
+        ]
+      }],
+      list: [],
+      index: 0,
+      form: {}
+    }
+  },
+  methods: {
+    initData(json) {
+      this.list = JSON.parse(json)
+    },
+    end() {
+
+    },
+    add(item) {
+      let data = {
+        type: item.type,
+        active: false,
+        name: item.label,
+        fixe: false,
+        classText: ['parent-div'],
+        addWxFun: false,
+        workUrl: ''
+      }
+      if (item.type === 'h5-text') {
+        data.content = '默认文本'
+        data.style = {
+          textAlign: 'left',
+          fontSize: 20,
+          background: '#FFF',
+          color: '#000',
+          fontWeight: 'none',
+          fontStyle: 'none',
+          textDecoration: 'none'
+        }
+      } else if (item.type === 'h5-image') {
+        data.url = null
+      } else if (item.type === 'h5-button') {
+        data.content = '默认文本'
+      } else if (item.type === 'h5-sep') {
+        data.classText = [...data.classText, 'divider']
+        data.style = {
+          height: '10px',
+          background: 'rgb(228, 231, 237)'
+        }
+      } else if (item.type === 'h5-countdown') {
+        data.days = 0
+        data.hours = 0
+        data.minutes = 0
+        data.seconds = 0
+        data.countdownMode = 1
+      } else if (item.type === 'h5-chat') {
+        data = {
+          ...data,
+          ...{
+            messages: [
+              {
+                id: 1,
+                sender: "agent",
+                text: "您好!欢迎报名【中老年健康养生大讲堂】,请仔细答一下问题,便于帮您分配专业的老师进行指导。",
+                welcome: true
+              },
+              {
+                id: 2,
+                sender: "agent",
+                text: "您的年龄?",
+                options: [
+                  {id: 1, text: "45-55岁"},
+                  {id: 2, text: "55-60岁"},
+                  {id: 3, text: "60-65岁"},
+                  {id: 4, text: "65岁以上"}
+                ],
+                userSelection: null
+              },
+              {
+                id: 3,
+                sender: "user",
+                text: '45-55岁',
+                userSelection: {id: 1, text: "45-55岁"}
+              },
+              {
+                id: 4,
+                sender: "agent",
+                text: "更想通过课程学习到哪些知识?",
+                options: [
+                  {id: 1, text: "食疗食补"},
+                  {id: 2, text: "经络疏通"},
+                  {id: 3, text: "脏腑调养"},
+                  {id: 4, text: "启蒙养生"},
+                  {id: 5, text: "以上所有"}
+                ],
+                userSelection: null
+              },
+              {
+                id: 5,
+                sender: "user",
+                text: '食疗食补',
+                userSelection: {id: 1, text: "食疗食补"}
+              },
+              {
+                id: 6,
+                sender: "agent",
+                text: "好的,已经为您分配专业老师。<span style='color: red'>【点击下方按钮】</span>添加老师,获取免费上课链接。!",
+                userSelection: null
+              }
+            ],
+            agentMsg: [{
+              id: 1,
+              sender: "agent",
+              text: "您好!欢迎报名【中老年健康养生大讲堂】,请仔细答一下问题,便于帮您分配专业的老师进行指导。",
+              welcome: true
+            },
+              {
+                id: 2,
+                sender: "agent",
+                text: "您的年龄?",
+                options: [
+                  {id: 1, text: "45-55岁"},
+                  {id: 2, text: "55-60岁"},
+                  {id: 3, text: "60-65岁"},
+                  {id: 4, text: "65岁以上"}
+                ],
+                userSelection: null
+              },
+              {
+                id: 4,
+                sender: "agent",
+                text: "更想通过课程学习到哪些知识?",
+                options: [
+                  {id: 1, text: "食疗食补"},
+                  {id: 2, text: "经络疏通"},
+                  {id: 3, text: "脏腑调养"},
+                  {id: 4, text: "启蒙养生"},
+                  {id: 5, text: "以上所有"}
+                ],
+                userSelection: null
+              }
+            ],
+            lastMsg: [
+              {type: 0, text: "好的,已经为您分配专业老师。"},
+              {type: 1, text: "【点击下方按钮】"},
+              {type: 0, text: "添加老师,获取免费上课链接。!"},
+            ],
+            style: {
+              avatar: window.location.origin + AgentAvatar,
+              buttonColor: '#409EFF',
+              textColor: ''
+            }
+          }
+        }
+        console.log(data)
+        let h5chat = this.list.some(item => item.type && item.type.includes('h5-chat'))
+        if (h5chat) {
+          alert('全局只能允许有一个互动问答!')
+          return
+        }
+      }
+      console.log(this.list)
+
+      if (this.index !== null && this.index >= 0 && this.index < this.list.length) {
+        this.list.splice(this.index + 1, 0, data)
+      } else {
+        this.list.push(data)
+      }
+    },
+    select(index) {
+      this.index = index
+      let className = 'active'
+      this.clearClass(className)
+      this.addClass(className)
+      this.$set(this.list[index], 'active', true)  // 确保响应式更新
+      // 直接绑定list中的对象(关键修改)
+      this.form = this.list[index]
+    },
+    clearClass(classText) {
+      this.list.forEach(item => {
+        // 推荐使用 $set
+        this.$set(item, 'classText', item.classText.filter(c => c !== classText))
+      })
+    },
+    addClass(classText) {
+      this.list[this.index].classText.push(classText)
+    },
+
+    del() {
+      this.list.splice(this.index, 1)
+      this.form = {}
+    },
+    updateForm(newForm) {
+      // 更新表单数据
+      if (this.index === undefined || !this.list[this.index]) {
+        console.error('Invalid index or list item')
+        return
+      }
+
+      console.log('newForm:', newForm) // 检查 newForm 数据
+      Object.assign(this.form, newForm)
+
+      // 更新列表中的数据
+      for (const key in newForm) {
+        if (Object.hasOwnProperty.call(newForm, key)) {
+          // 如果是嵌套对象,递归更新
+          if (typeof newForm[key] === 'object' && newForm[key] !== null) {
+            for (const nestedKey in newForm[key]) {
+              this.$set(this.list[this.index][key], nestedKey, newForm[key][nestedKey])
+            }
+          } else {
+            this.$set(this.list[this.index], key, newForm[key])
+          }
+        }
+      }
+
+      console.log('Updated list:', this.list[this.index])
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.button-body {
+  text-align: center;
+  margin: 0 auto;
+
+  .button-tag:first-child {
+    margin-top: 0 !important;
+  }
+
+  .button-tag {
+    margin-left: 0;
+    margin-top: 10px;
+  }
+}
+
+/* 外层容器 (父级div) */
+.parent-container {
+  background: #eff3f5;
+  padding: 40px 0;
+  width: 100%;
+
+  /* 关键设置 */
+  height: 80vh;
+  overflow-y: auto; /* 滚动条出在这里 */
+  border: 1px solid #DCDEE2;
+}
+
+/* 定制滚动条样式 */
+.parent-container::-webkit-scrollbar {
+  width: 6px; /* 滚动条宽度 */
+}
+
+.parent-container::-webkit-scrollbar-track {
+  background: #f1f1f1; /* 滚动条轨道背景色 */
+  border-radius: 3px; /* 轨道圆角 */
+}
+
+.parent-container::-webkit-scrollbar-thumb {
+  background: #888; /* 滚动条滑块颜色 */
+  border-radius: 3px; /* 滑块圆角 */
+}
+
+.parent-container::-webkit-scrollbar-thumb:hover {
+  background: #555; /* 滑块悬停颜色 */
+}
+
+.view-body {
+  width: 375px; /* 明确具体值(会覆盖下面的width:100%) */
+  height: auto; /* 改掉height:100%,否则会根据父级高度计算*/
+
+  /* 清除非必须设置 */
+  overflow-y: visible; /* 保持默认 */
+
+  /* 其他属性 */
+  margin: 0 auto; /* 代替外层flex的justify-content */
+  background: #fff;
+  position: relative;
+  padding: 0;
+}
+
+.icon.svg {
+  cursor: pointer;
+  margin-left: 20px;
+  width: 20px;
+  height: 20px;
+}
+
+.icon.svg.active {
+  color: #02ff9b;
+}
+
+.icon-span {
+}
+
+.divider {
+  width: 100%;
+  background: #DCDEE2;
+  height: 10px;
+}
+
+.button-tag {
+  /* 新增图标样式 */
+  .el-icon {
+    margin-right: 6px; /* 图标与文本间距 */
+    font-size: 16px; /* 统一图标大小 */
+    vertical-align: -2px; /* 垂直居中补偿 */
+  }
+
+  &.is-plain .el-icon {
+    color: #666; /* 浅色主题下保持可视性 */
+  }
+}
+
+
+</style>

+ 3 - 0
src/main.js

@@ -93,6 +93,9 @@ Vue.component('RightToolbar', RightToolbar)
 Vue.component('Editor', Editor)
 Vue.component('FileUpload', FileUpload)
 Vue.component('ImageUpload', ImageUpload)
+import H5Editor from "@/components/H5Editor";
+Vue.component('H5Editor', H5Editor)
+
 
 Vue.use(permission)
 Vue.use(select)

+ 5 - 5
src/router/index.js

@@ -120,27 +120,27 @@ export const constantRoutes = [
     ]
   },
   {
-    path: '/qw/sopTempe',
+    path: '/course/sopTempe',
     component: Layout,
     hidden: true,
     children: [
       {
         path: 'updateSopTemp/:id/:type(\\d+)', // 确保 :type 的正则匹配数字
-        component: (resolve) => require(['@/views/qw/sopTemp/updateSopTemp'], resolve),
+        component: () => import('@/views/qw/sopTemp/updateSopTemp'),
         name: 'updateSopTemp',
-        meta: { title: '改动SOP模板', activeMenu: '/qw/addSopTemp' }
+        meta: { title: '改动SOP模板', activeMenu: '/course/addSopTemp' }
       },
       {
         path: 'updateTemp/:id/:type(\\d+)', // 确保 :type 的正则匹配数字
         component: () => import('@/views/qw/sopTemp/updateTemp'),
         name: 'updateTemp',
-        meta: { title: '改动SOP模板', activeMenu: '/qw/updateTemp' }
+        meta: { title: '改动SOP模板', activeMenu: '/course/updateTemp' }
       },
       {
         path: 'updateAiChatTemp/:id/:type(\\d+)', // 确保 :type 的正则匹配数字
         component: () => import('@/views/qw/sopTemp/updateAiChatTemp'),
         name: 'updateAiChatTemp',
-        meta: { title: '改动SOP模板', activeMenu: '/qw/addSopTemp' }
+        meta: { title: '改动SOP模板', activeMenu: '/course/addSopTemp' }
       }
     ]
   },

+ 1 - 1
src/settings.js

@@ -1,5 +1,5 @@
 module.exports = {
-  title: '果雨管理总后台',
+  title: 'SCRM管理总后台',
 
 
 

+ 346 - 0
src/views/ad/AdUploadLog/index.vue

@@ -0,0 +1,346 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+
+      <el-form-item label="媒体类型" prop="type">
+        <el-select v-model="queryParams.type" @change="typeChange" 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="accountId" v-if="queryParams.type != null">
+        <el-select v-model="queryParams.accountId" filterable v-loading="accountLoading" clearable size="small">
+          <el-option v-for="item in accountList" :value="item.id" :key="item.id" :label="item.name" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="站点" prop="siteId">
+        <el-select v-model="queryParams.siteId" filterable clearable size="small">
+          <el-option v-for="item in siteList" :value="item.id" :key="item.id" :label="item.name" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="广告ID" prop="vid">
+        <el-input
+          v-model="queryParams.vid"
+          placeholder="请输入广告ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="上传时间">
+        <el-date-picker
+          v-model="date"
+          type="daterange"
+          range-separator="至"
+          start-placeholder="开始日期"
+          value-format="yyyy-MM-dd"
+          end-placeholder="结束日期" />
+      </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="['ad:AdUploadLog:export']"-->
+<!--        >导出</el-button>-->
+<!--      </el-col>-->
+<!--      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>-->
+<!--    </el-row>-->
+
+    <el-table border v-loading="loading" :data="AdUploadLogList">
+      <el-table-column label="媒体类型" align="center" prop="type">
+        <template slot-scope="scope">
+          <el-tag prop="type" v-for="(item, index) in typeOptions" v-if="scope.row.type==item.dictValue">{{item.dictLabel}}</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="站点" align="center" prop="siteName" />
+<!--      <el-table-column label="模板ID" align="center" prop="templateId" />-->
+      <el-table-column label="账户" align="center" prop="accountName" />
+<!--      <el-table-column label="点击URL" align="center" prop="url">-->
+<!--        <template slot-scope="scope">-->
+<!--          <el-tooltip class="item" effect="dark" :content="scope.row.url" placement="top">-->
+<!--            <a>{{scope.row.url}}</a>-->
+<!--          </el-tooltip>-->
+<!--        </template>-->
+<!--      </el-table-column>-->
+      <el-table-column label="上传类型" align="center" prop="uploadType">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.uploadType.indexOf('ADD_WX') != -1" type="success">加微</el-tag>
+          <el-tag v-if="scope.row.uploadType.indexOf('REGISTERED') != -1" type="warning">注册</el-tag>
+          <el-tag v-if="scope.row.uploadType.indexOf('FINISH_THE_CLASS') != -1" type="danger">完课</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="广告ID" align="center" prop="vid" />
+      <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"
+    />
+
+    <!-- 添加或修改百度回传日志对话框 -->
+    <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="siteId">
+          <el-input v-model="form.siteId" placeholder="请输入站点ID" />
+        </el-form-item>
+        <el-form-item label="媒体类型" prop="type">
+          <el-select v-model="form.type" placeholder="请选择媒体类型">
+            <el-option label="请选择字典生成" value="" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="模板ID" prop="templateId">
+          <el-input v-model="form.templateId" placeholder="请输入模板ID" />
+        </el-form-item>
+        <el-form-item label="账户ID" prop="accountId">
+          <el-input v-model="form.accountId" placeholder="请输入账户ID" />
+        </el-form-item>
+        <el-form-item label="域名ID" prop="domainId">
+          <el-input v-model="form.domainId" placeholder="请输入域名ID" />
+        </el-form-item>
+        <el-form-item label="点击URL" prop="url">
+          <el-input v-model="form.url" placeholder="请输入点击URL" />
+        </el-form-item>
+        <el-form-item label="上传类型" prop="uploadType">
+          <el-select v-model="form.uploadType" placeholder="请选择上传类型">
+            <el-option label="请选择字典生成" value="" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="广告唯一ID" prop="vid">
+          <el-input v-model="form.vid" 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>
+  </div>
+</template>
+
+<script>
+import { listAdUploadLog, getAdUploadLog, delAdUploadLog, addAdUploadLog, updateAdUploadLog, exportAdUploadLog } from "@/api/ad/AdUploadLog";
+import {listAll as accountListAll} from "@/api/ad/adAccount";
+import {listAll as siteListAll} from "@/api/ad/adSite";
+
+export default {
+  name: "AdUploadLog",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 百度回传日志表格数据
+      AdUploadLogList: [],
+      accountList: [],
+      siteList: [],
+      accountAllList: [],
+      accountLoading: false,
+      typeOptions: [],
+      date: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        siteId: null,
+        type: null,
+        templateId: null,
+        accountId: null,
+        domainId: null,
+        url: null,
+        uploadType: null,
+        vid: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    accountListAll().then(e => {
+      this.accountAllList = e.data;
+    })
+    this.loadingSite();
+    this.getDicts("ad_type").then((response) => {
+      this.typeOptions = response.data;
+    });
+    this.getList();
+  },
+  methods: {
+    /** 查询百度回传日志列表 */
+    getList() {
+      this.loading = true;
+      if(this.date != null && this.date.length > 0){
+        this.queryParams.startDate = this.date[0];
+        this.queryParams.endDate = this.date[1];
+      }
+      listAdUploadLog(this.queryParams).then(response => {
+        this.AdUploadLogList = response.rows;
+        this.AdUploadLogList.forEach(item => {
+          item.uploadType = item.uploadType.split(",")
+        })
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    copyUrl(url){
+      navigator.clipboard.writeText(url)
+        .then(() => {
+          this.msgSuccess("复制成功");
+        })
+        .catch(err => {
+          this.msgError("复制失败");
+        });
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        siteId: null,
+        type: null,
+        templateId: null,
+        accountId: null,
+        domainId: null,
+        url: null,
+        uploadType: null,
+        vid: null,
+        createTime: 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() {
+      this.reset();
+      this.open = true;
+      this.title = "添加百度回传日志";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getAdUploadLog(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) {
+            updateAdUploadLog(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addAdUploadLog(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 delAdUploadLog(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有百度回传日志数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportAdUploadLog(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    },
+    typeChange(){
+      let type = this.queryParams.type;
+      this.queryParams.accountId = undefined;
+      this.accountList = this.accountAllList.filter(item => item.type == type);
+      this.queryParams.siteId = undefined;
+      this.loadingSite();
+    },
+    loadingSite(){
+      siteListAll({type:this.queryParams.type}).then(e => {
+        this.siteList = e.data;
+      })
+    },
+  }
+};
+</script>

+ 1 - 22
src/views/ad/adSite/index.vue

@@ -86,7 +86,7 @@
     <el-table border v-loading="loading" :data="adSiteList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="id" align="center" prop="id" />
-      <el-table-column label="模板" align="center" prop="templateName" />
+      <el-table-column label="获客连接" align="center" prop="linkName" />
       <el-table-column label="媒体类型" align="center" prop="type">
         <template slot-scope="scope">
           <el-tag prop="type" v-for="(item, index) in typeOptions" v-if="scope.row.type==item.dictValue">{{item.dictLabel}}</el-tag>
@@ -381,27 +381,6 @@ export default {
       let type = this.form.type;
       this.form.accountId = undefined;
       this.accountList = this.accountAllList.filter(item => item.type == type);
-      // if(type == 0){
-      //   this.accountLoading = true;
-      //   bdAccountListAll({}).then(res => {
-      //     this.accountLoading = false;
-      //     this.accountList = res.data;
-      //   })
-      // }
-      // if(type == 1){
-      //   this.accountLoading = true;
-      //   youkuAccountListAll().then(res => {
-      //     this.accountLoading = false;
-      //     this.accountList = res.data;
-      //   })
-      // }
-      // if(type == 2){
-      //   this.accountLoading = true;
-      //   iqiyiAccountListAll().then(res => {
-      //     this.accountLoading = false;
-      //     this.accountList = res.data;
-      //   })
-      // }
     },
   }
 };

+ 313 - 0
src/views/company/VoiceRoboticWx/index.vue

@@ -0,0 +1,313 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="意向" prop="intention">
+        <el-input
+          v-model="queryParams.intention"
+          placeholder="请输入意向"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="分配企微用户" prop="accountId">
+        <el-input
+          v-model="queryParams.accountId"
+          placeholder="请输入分配企微用户"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="加微话术" prop="wxDialogId">
+        <el-input
+          v-model="queryParams.wxDialogId"
+          placeholder="请输入加微话术"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="分配数量" prop="num">
+        <el-input
+          v-model="queryParams.num"
+          placeholder="请输入分配数量"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="添加数量" prop="addNum">
+        <el-input
+          v-model="queryParams.addNum"
+          placeholder="请输入添加数量"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" 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"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['company:VoiceRoboticWx:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['company:VoiceRoboticWx:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['company:VoiceRoboticWx:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['company:VoiceRoboticWx:export']"
+        >导出</el-button>
+      </el-col>
+	  <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="VoiceRoboticWxList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="id" align="center" prop="id" />
+      <el-table-column label="意向" align="center" prop="intention" />
+      <el-table-column label="分配企微用户" align="center" prop="accountId" />
+      <el-table-column label="加微话术" align="center" prop="wxDialogId" />
+      <el-table-column label="分配数量" align="center" prop="num" />
+      <el-table-column label="添加数量" align="center" prop="addNum" />
+      <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="['company:VoiceRoboticWx:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['company:VoiceRoboticWx: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"
+    />
+
+    <!-- 添加或修改AI外呼任务加微方式对话框 -->
+    <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="意向" prop="intention">
+          <el-input v-model="form.intention" placeholder="请输入意向" />
+        </el-form-item>
+        <el-form-item label="分配企微用户" prop="accountId">
+          <el-input v-model="form.accountId" placeholder="请输入分配企微用户" />
+        </el-form-item>
+        <el-form-item label="加微话术" prop="wxDialogId">
+          <el-input v-model="form.wxDialogId" 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>
+  </div>
+</template>
+
+<script>
+import { listVoiceRoboticWx, getVoiceRoboticWx, delVoiceRoboticWx, addVoiceRoboticWx, updateVoiceRoboticWx, exportVoiceRoboticWx } from "@/api/company/VoiceRoboticWx";
+
+export default {
+  name: "VoiceRoboticWx",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // AI外呼任务加微方式表格数据
+      VoiceRoboticWxList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        intention: null,
+        accountId: null,
+        wxDialogId: null,
+        num: null,
+        addNum: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询AI外呼任务加微方式列表 */
+    getList() {
+      this.loading = true;
+      listVoiceRoboticWx(this.queryParams).then(response => {
+        this.VoiceRoboticWxList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        intention: null,
+        accountId: null,
+        wxDialogId: null,
+        num: null,
+        addNum: null,
+        createTime: null,
+        createUser: 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() {
+      this.reset();
+      this.open = true;
+      this.title = "添加AI外呼任务加微方式";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getVoiceRoboticWx(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改AI外呼任务加微方式";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateVoiceRoboticWx(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          } else {
+            addVoiceRoboticWx(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除AI外呼任务加微方式编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delVoiceRoboticWx(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(function() {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有AI外呼任务加微方式数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportVoiceRoboticWx(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
+    }
+  }
+};
+</script>

+ 449 - 0
src/views/company/companyClient/index.vue

@@ -0,0 +1,449 @@
+<template>
+  <div class="app-container">
+    <el-row :gutter="24" class="baseInfo">
+      <el-col :xs="12" :sm="12" :lg="6" class="ivu-mb">
+        <el-card :bordered="false" dis-hover :padding="12">
+          <div slot="header" class="acea-row row-between-wrapper">
+            <span>总任务</span>
+          </div>
+          <div class="content" v-if="count">
+                        <span class="content-number spBlock mb15"><count-to :start-val="0" :end-val="count.totalNum"
+                                                                            :duration="2600"
+                                                                            class="card-panel-num"/></span>
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :xs="12" :sm="12" :lg="6" class="ivu-mb">
+        <el-card :bordered="false" dis-hover :padding="12">
+          <div slot="header" class="acea-row row-between-wrapper">
+            <span>今日加微数</span>
+          </div>
+          <div class="content" v-if="count">
+                        <span class="content-number spBlock mb15"><count-to :start-val="0" :end-val="count.toDayAddNum"
+                                                                            :duration="2600"
+                                                                            class="card-panel-num"/></span>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="外呼任务" prop="roboticId">
+        <el-select v-model="queryParams.roboticId" filterable clearable>
+          <el-option v-for="item in roboticList" :label="item.name" :value="item.id"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="话术" prop="dialogId">
+        <el-select v-model="queryParams.dialogId" filterable clearable>
+          <el-option v-for="item in diaLogList" :label="item.name" :value="item.id"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="销售" prop="roboticWxId">
+        <el-select v-model="queryParams.roboticWxId" filterable clearable>
+          <el-option v-for="item in accountList" :label="item.companyUserName + '-' + item.wxNickName"
+                     :value="item.userId"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="是否添加" prop="isAdd">
+        <el-select v-model="queryParams.isAdd" clearable>
+          <el-option label="否" :value="0"/>
+          <el-option label="是" :value="1"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="加微时间" prop="time">
+        <el-date-picker
+          v-model="queryParams.time"
+          type="daterange"
+          range-separator="至"
+          value-format="yyyy-MM-dd"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" 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"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['company:companyClient:add']"
+        >新增
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['company:companyClient:remove']"
+        >删除
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['company:companyClient:export']"
+        >导出
+        </el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="companyClientList">
+      <el-table-column label="外呼任务" align="center" prop="roboticName"/>
+      <el-table-column label="销售" align="center" prop="wxNickName"/>
+      <el-table-column label="个微昵称" align="center" prop="nickName"/>
+      <el-table-column label="手机号" align="center" prop="phone"/>
+      <el-table-column label="话术" align="center" prop="dialogName"/>
+      <el-table-column label="是否添加" align="center" prop="isAdd">
+        <template slot-scope="scope">
+          <el-tag type="danger" v-if="scope.row.isAdd == 0">否</el-tag>
+          <el-tag type="success" v-if="scope.row.isAdd == 1">是</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="添加时间" align="center" prop="addTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.addTime, '{y}-{m}-{d}') }}</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="['company:companyClient:edit']"-->
+          <!--          >修改</el-button>-->
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['company:companyClient: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"
+    />
+    <qw-user-select @success="selectQwUserFun" ref="qwUserSelect"/>
+    <!-- 添加或修改添加个微信账号对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="75%" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="外呼任务" prop="roboticId">
+          <el-select v-model="form.roboticId" filterable>
+            <el-option v-for="item in roboticList" :label="item.name" :value="item.id"/>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="分配账号">
+          <el-button @click="addQwUser">添加</el-button>
+          <el-row :gutter="24" v-for="(item, index) in form.qwUser" style="margin-top: 5px">
+            <el-col :span="5">
+              <el-select v-model="item.intention" placeholder="意向等级" filterable clearable>
+                <el-option v-for="item in levelList" :label="item.dictLabel" :value="item.dictValue"/>
+              </el-select>
+            </el-col>
+            <el-col :span="5">
+              <el-button @click="openQwUserSelect(index)">
+                选择企微({{ item.qwUserId ? item.qwUserId.length : 0 }})
+              </el-button>
+            </el-col>
+            <el-col :span="5">
+              <el-select v-model="item.wxDialogId" placeholder="话术" filterable>
+                <el-option v-for="item in diaLogList" :label="item.name" :value="item.id"/>
+              </el-select>
+            </el-col>
+            <el-col :span="3">
+              <el-button type="danger" icon="el-icon-delete" circle
+                         @click="removeQwUser(index)"></el-button>
+            </el-col>
+          </el-row>
+        </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>
+  </div>
+</template>
+
+<script>
+import {
+  listCompanyClient,
+  addWxClient,
+  addWxStatistics,
+  getCompanyClient,
+  delCompanyClient,
+  addCompanyClient,
+  updateCompanyClient,
+  exportCompanyClient
+} from "@/api/company/companyClient";
+import {listAll as roboticListAll} from "@/api/company/companyVoiceRobotic";
+import {listAll as dialogListAll} from '@/api/company/wxDialog';
+import {listAll as accountListAll} from "@/api/company/companyAccount";
+import {getDicts} from "@/api/system/dict/data";
+import qwUserSelect from "@/views/components/QwUserSelect.vue";
+import CountTo from "vue-count-to";
+
+export default {
+  name: "CompanyClient",
+  components: {qwUserSelect, CountTo},
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 添加个微信账号表格数据
+      companyClientList: [],
+      roboticList: [],
+      diaLogList: [],
+      accountList: [],
+      levelList: [],
+      thisQwUserIndex: 0,
+      selectQwUserList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        roboticWxId: null,
+        nickAnme: null,
+        avatar: null,
+        phone: null,
+        wxNo: null,
+        isAdd: null,
+        addTime: null,
+        createUser: null
+      },
+      // 表单参数
+      form: {},
+      count: {},
+      // 表单校验
+      rules: {
+        roboticId: [
+          {required: true, message: "请选择任务", trigger: "blur"}
+        ],
+      }
+    };
+  },
+  created() {
+    this.getList();
+    roboticListAll().then(e => {
+      this.roboticList = e.data;
+    })
+    dialogListAll().then(e => {
+      this.diaLogList = e.data;
+    })
+    accountListAll().then(e => {
+      this.accountList = e.data;
+    })
+    getDicts("customer_intention_level").then(e => {
+      this.levelList = e.data;
+    })
+    this.statis();
+  },
+  methods: {
+    /** 查询添加个微信账号列表 */
+    getList() {
+      this.loading = true;
+      listCompanyClient(this.getQueryData()).then(response => {
+        this.companyClientList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    statis() {
+      addWxStatistics(this.getQueryData()).then(e => {
+        this.count = e;
+      })
+    },
+    getQueryData() {
+      let form = JSON.parse(JSON.stringify(this.queryParams));
+      if (form.time && form.time.length === 2) {
+        form.beginTime = form.time[0];
+        form.endTime = form.time[1];
+      }
+      delete form.time;
+      return form;
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        roboticWxId: null,
+        nickAnme: null,
+        avatar: null,
+        phone: null,
+        qwUser: [],
+        wxNo: null,
+        isAdd: null,
+        addTime: null,
+        remark: null,
+        createTime: null,
+        createUser: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.statis();
+      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() {
+      this.reset();
+      this.open = true;
+      this.title = "添加添加个微信账号";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getCompanyClient(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改添加个微信账号";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          let list = [];
+          this.form.qwUser.forEach(l => {
+            list = list.concat(l.qwUserId.map(e => {
+              return {intention: l.intention, qwUserId: e, wxDialogId: l.wxDialogId}
+            }))
+          })
+          this.form.qwUserList = list;
+          if (!this.form.qwUserList || this.form.qwUserList.length === 0) {
+            this.msgError("请选者加微方案");
+            return;
+          }
+          addWxClient(this.form).then(response => {
+            if (response.code === 200) {
+              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 delCompanyClient(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(function () {
+      });
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有添加个微信账号数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function () {
+        return exportCompanyClient(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+      }).catch(function () {
+      });
+    },
+    addQwUser() {
+      this.form.qwUser.push({});
+    },
+    removeQwUser(index) {
+      this.form.qwUser.splice(index, 1)
+    },
+    openQwUserSelect(index) {
+      this.thisQwUserIndex = index;
+      this.$nextTick(() => {
+        this.$refs.qwUserSelect.setRows(this.selectQwUserList[index]);
+      })
+    },
+    selectQwUserFun(e) {
+      this.form.qwUser[this.thisQwUserIndex].qwUserId = e.ids;
+      this.selectQwUserList[this.thisQwUserIndex] = e.rows;
+      this.$forceUpdate()
+    },
+  }
+};
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+.baseInfo {
+  margin-bottom: 30px;
+}
+
+.content {
+  .card-panel-num {
+    display: inline-block;
+    font-size: 30px;
+  }
+
+  &-time {
+    font-size: 14px;
+    /*color: #8C8C8C;*/
+  }
+}
+</style>

+ 296 - 0
src/views/company/companyVoiceDialog/index.vue

@@ -0,0 +1,296 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="三方ID" prop="resultId">
+        <el-input
+          v-model="queryParams.resultId"
+          placeholder="请输入三方ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" 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"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['system:companyVoiceDialog:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['system:companyVoiceDialog:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['system:companyVoiceDialog:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['system:companyVoiceDialog:export']"
+        >导出</el-button>
+      </el-col>
+	  <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="dialogList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="名称" align="center" prop="name" />
+      <el-table-column label="三方ID" align="center" prop="resultId" />
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            @click="initUrl(scope.row.id)"
+            v-hasPermi="['system:companyVoiceDialog:list']"
+          >配置话术</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:companyVoiceDialog:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:companyVoiceDialog: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"
+    />
+
+    <!-- 添加或修改AI外呼话术对话框 -->
+    <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="名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入名称" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" 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>
+  </div>
+</template>
+
+<script>
+import { listDialog, getDialog, delDialog, addDialog, updateDialog, exportDialog, getConfigUrl } from "@/api/company/companyVoiceDialog";
+
+export default {
+  name: "Dialog",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // AI外呼话术表格数据
+      dialogList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        name: null,
+        resultName: null,
+        resultId: null,
+        callNum: null,
+        createUser: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询AI外呼话术列表 */
+    getList() {
+      this.loading = true;
+      listDialog(this.queryParams).then(response => {
+        this.dialogList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        name: null,
+        resultName: null,
+        resultId: null,
+        callNum: null,
+        remark: null,
+        dialogConfigUrl: null,
+        createTime: null,
+        createUser: 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() {
+      this.reset();
+      this.open = true;
+      this.title = "添加AI外呼话术";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getDialog(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改AI外呼话术";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateDialog(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          } else {
+            addDialog(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除AI外呼话术编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delDialog(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(function() {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有AI外呼话术数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportDialog(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
+    },
+    initUrl(id){
+      getConfigUrl(id).then(e => {
+        this.dialogConfigUrl = e.data;
+        this.openUrl();
+      })
+    },
+    openUrl(){
+      window.open(this.dialogConfigUrl, "_blank");
+    },
+  }
+};
+</script>

+ 814 - 0
src/views/company/companyVoiceRobotic/index-old.vue

@@ -0,0 +1,814 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="任务名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入任务名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="机器人" prop="robot">
+        <el-select v-model="queryParams.robot" filterable clearable>
+          <el-option v-for="item in robotList" :label="item.name + '('+item.num+')'" :value="item.id"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="话术" prop="dialogId">
+        <el-select v-model="queryParams.dialogId" filterable clearable>
+          <el-option v-for="item in dialogList" :label="item.name" :value="item.id"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" 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"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['system:companyVoiceRobotic:add']"
+        >新增
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['system:companyVoiceRobotic:edit']"
+        >修改
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['system:companyVoiceRobotic:remove']"
+        >删除
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['system:companyVoiceRobotic:export']"
+        >导出
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-refresh"
+          size="mini"
+          @click="updateStatusFun"
+          v-hasPermi="['system:companyVoiceRobotic:list']"
+        >更新状态
+        </el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="roboticList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center"/>
+      <el-table-column label="ID" align="center" prop="id"/>
+      <el-table-column label="任务名称" align="center" prop="name"/>
+      <el-table-column label="三方名称" align="center" prop="taskName"/>
+      <el-table-column label="三方ID" align="center" prop="taskId"/>
+      <el-table-column label="机器人" align="center" prop="robot">
+        <template slot-scope="scope">
+          <p v-for="(item, index) in robotList" v-if="scope.row.robot && scope.row.robot == item.id">{{ item.name }}</p>
+        </template>
+      </el-table-column>
+      <el-table-column label="话术" align="center" prop="dialogId">
+        <template slot-scope="scope">
+          <p v-for="(item, index) in dialogList" v-if="scope.row.dialogId && scope.row.dialogId == item.id">
+            {{ item.name }}</p>
+        </template>
+      </el-table-column>
+      <el-table-column label="加微方式" align="center" prop="dialogId">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.addType == 0">平均</el-tag>
+          <el-tag v-if="scope.row.addType == 1">意向</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="工作日" align="center" prop="weekDay1">
+        <template slot-scope="scope">
+          <el-tag v-for="(item, index) in weekList"
+                  v-if="scope.row.weekDay1 && scope.row.weekDay1.indexOf(item.value) != -1">{{ item.label }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="开始时间" align="center" prop="startTime1"/>
+      <el-table-column label="结束时间" align="center" prop="endTime1"/>
+      <el-table-column label="未分配数量" align="center">
+        <template slot-scope="scope">
+          <el-tag :type="Number(scope.row.num) > 0 ?'danger' : ''">{{scope.row.num}}个</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="当前状态" align="center">
+        <template slot-scope="scope">
+          <div v-loading="loadingStatus">
+            <p v-if="statusObj.hasOwnProperty(scope.row.taskId)">
+              <el-tag v-if="statusObj[scope.row.taskId].runningStatus == 0">未启动</el-tag>
+              <el-tag v-if="statusObj[scope.row.taskId].runningStatus == 1">运行中</el-tag>
+              <el-tag v-if="statusObj[scope.row.taskId].runningStatus == 2">已暂停</el-tag>
+              <el-tag v-if="statusObj[scope.row.taskId].runningStatus == 3">已停止</el-tag>
+            </p>
+            <p v-if="!statusObj.hasOwnProperty(scope.row.taskId)">
+              <el-tag>空</el-tag>
+            </p>
+          </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"
+            @click="calleesOpen(scope.row.id)"
+            v-hasPermi="['system:companyVoiceRobotic:list']"
+          >客户列表
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            @click="wxOpen(scope.row.id)"
+            v-hasPermi="['system:companyVoiceRobotic:list']"
+          >加微统计
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            v-if="statusObj.hasOwnProperty(scope.row.taskId) && (statusObj[scope.row.taskId].runningStatus == 0 || statusObj[scope.row.taskId].runningStatus == 3)"
+            @click="startRoboticFun(scope.row.taskId)"
+            v-hasPermi="['system:companyVoiceRobotic:list']"
+          >启动任务
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            v-if="statusObj.hasOwnProperty(scope.row.taskId) && (statusObj[scope.row.taskId].runningStatus == 1 || statusObj[scope.row.taskId].runningStatus == 2)"
+            @click="stopRoboticFun(scope.row.taskId)"
+            v-hasPermi="['system:companyVoiceRobotic:list']"
+          >停止任务
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            @click="addRoboticFun(scope.row)"
+            v-hasPermi="['system:companyVoiceRobotic:edit']"
+          >追加个微
+          </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:companyVoiceRobotic: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-drawer size="75%" :title="title" :visible.sync="open" width="500px" append-to-body>
+      <div class="app-container">
+        <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+          <el-form-item label="任务名称" prop="name">
+            <el-input v-model="form.name" placeholder="请输入任务名称"/>
+          </el-form-item>
+          <el-form-item label="机器人" prop="robot">
+            <el-select v-model="form.robot" filterable>
+              <el-option v-for="item in robotList" :label="item.name + '('+item.num+')'" :value="item.id"/>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="话术" prop="dialogId">
+            <el-select v-model="form.dialogId" filterable>
+              <el-option v-for="item in dialogList" :label="item.name" :value="item.id"/>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="拨打客户" prop="userIds">
+            <el-button @click="openSelect">选择客户({{ form.userIds ? form.userIds.length : 0 }})</el-button>
+          </el-form-item>
+          <el-form-item label="加微方式" prop="addType">
+            <el-radio v-model="form.addType" :label="0">平均</el-radio>
+            <el-radio v-model="form.addType" :label="1">意向</el-radio>
+          </el-form-item>
+          <el-form-item label="分配账号">
+            <el-button @click="addQwUser">添加</el-button>
+            <el-row :gutter="24" v-for="(item, index) in form.qwUser" style="margin-top: 5px">
+              <el-col :span="5">
+                <el-select v-model="item.intention" placeholder="意向等级" filterable clearable>
+                  <el-option v-for="item in levelList" :label="item.dictLabel" :value="item.dictLabel"/>
+                </el-select>
+              </el-col>
+              <el-col :span="4">
+                <el-button @click="openQwUserSelect(index)">
+                  选择个微({{ item.companyUserId ? item.companyUserId.length : 0 }})
+                </el-button>
+              </el-col>
+              <el-col :span="5">
+                <el-select v-model="item.wxDialogId" placeholder="话术" filterable>
+                  <el-option v-for="item in wxDialogList" :label="item.name" :value="item.id"/>
+                </el-select>
+              </el-col>
+              <el-col :span="3">
+                <el-button type="danger" icon="el-icon-delete" circle @click="removeQwUser(index)"></el-button>
+              </el-col>
+            </el-row>
+          </el-form-item>
+          <el-form-item label="模式" prop="mode">
+            <el-select v-model="form.mode">
+              <el-option label="呼叫机器人后挂断" :value="7"/>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="呼叫倍率" prop="multiplier">
+            <el-select v-model="form.multiplier">
+              <el-option :value="1"/>
+              <el-option :value="2"/>
+              <el-option :value="3"/>
+              <el-option :value="4"/>
+              <el-option :value="5"/>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="自动重呼" prop="autoRecall">
+            <el-radio v-model="form.autoRecall" label="0">否</el-radio>
+            <el-radio v-model="form.autoRecall" label="1">是</el-radio>
+          </el-form-item>
+          <el-form-item label="重呼次数" prop="recallTimes" v-if="form.autoRecall == 1">
+            <el-select v-model="form.recallTimes">
+              <el-option label="不自动重呼" :value="0"/>
+              <el-option :value="1"/>
+              <el-option :value="2"/>
+              <el-option :value="3"/>
+              <el-option :value="4"/>
+              <el-option :value="5"/>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="工作日" prop="weekDay">
+            <el-select v-model="form.weekDay" multiple style="width: 100%">
+              <el-option v-for="item in weekList" :label="item.label" :value="item.value"/>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="开始时间" prop="startTime1">
+            <el-time-select
+              v-model="form.startTime1"
+              format="HH:mm"
+              value-format="HH:mm:00"
+              :picker-options="{
+                  start: '00:00',
+                  end: '23:59',
+                  step: '00:30',
+                }"
+              placeholder="请选择开始时间">
+            </el-time-select>
+          </el-form-item>
+          <el-form-item label="结束时间" prop="endTime1">
+            <el-time-select
+              v-model="form.endTime1"
+              format="HH:mm"
+              value-format="HH:mm:00"
+              :picker-options="{
+                  start: '00:00',
+                  end: '23:59',
+                  step: '00:30',
+                  minTime: form.startTime1
+                }"
+              placeholder="请选择结束时间">
+            </el-time-select>
+          </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>
+      </div>
+    </el-drawer>
+    <customer-select @success="selectFun" ref="customer"/>
+    <qw-user-select @success="selectQwUserFun" ref="qwUserSelect"/>
+    <qw-user-select @success="selectQwUserFunTow" ref="qwUserSelectTow"/>
+
+    <el-drawer title="呼叫客户列表" size="60%" :visible.sync="callees.show" width="800px" append-to-body>
+      <el-table v-loading="callees.loading" :data="callees.list">
+        <el-table-column label="电话号码" align="center" prop="phone"/>
+        <el-table-column label="客户名称" align="center" prop="userName"/>
+        <el-table-column label="客户ID" align="center" prop="userId"/>
+        <el-table-column label="是否回调" align="center">
+          <template slot-scope="scope">
+            <el-tag v-if="scope.row.result == 0">否</el-tag>
+            <el-tag v-if="scope.row.result == 1">是</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="意向等级" align="center" prop="intention"/>
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template slot-scope="scope">
+            <el-button
+              size="mini"
+              type="text"
+              @click="openCustomer(scope.row.userId)"
+            >客户信息详情
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-show="callees.total>0"
+        :total="callees.total"
+        :page.sync="callees.queryParams.pageNum"
+        :limit.sync="callees.queryParams.pageSize"
+        @pagination="getCalleesList"
+      />
+    </el-drawer>
+    <el-drawer title="加微详情" size="60%" :visible.sync="wx.show" append-to-body>
+      <el-table v-loading="wx.loading" :data="wx.list">
+        <el-table-column label="意向等级" align="center" prop="intention"/>
+        <el-table-column label="微信昵称" align="center" prop="wxNickName"/>
+        <el-table-column label="微信号" align="center" prop="wxNo"/>
+        <el-table-column label="手机号" align="center" prop="phone"/>
+        <el-table-column label="员工名称" align="center" prop="companyUserName"/>
+        <el-table-column label="话术" align="center" prop="dialogName"/>
+        <el-table-column label="分配数量" align="center" prop="num"/>
+        <el-table-column label="添加数量" align="center" prop="addNum"/>
+      </el-table>
+
+      <pagination
+        v-show="wx.total>0"
+        :total="wx.total"
+        :page.sync="wx.queryParams.pageNum"
+        :limit.sync="wx.queryParams.pageSize"
+        @pagination="getWxList"
+      />
+    </el-drawer>
+    <el-drawer size="75%" title="客户详情" :visible.sync="customerDetailShow" append-to-body>
+      <customer-details ref="customerDetails"/>
+    </el-drawer>
+
+
+    <!-- 添加或修改添加个微信账号对话框 -->
+    <el-dialog title="追加个微" :visible.sync="openAdd" width="75%" append-to-body>
+      <el-form ref="form" :model="formOpen" label-width="80px">
+        <el-form-item label="分配账号">
+          <el-button @click="addQwUserTow">添加</el-button>
+          <el-row :gutter="24" v-for="(item, index) in formOpen.qwUser" style="margin-top: 5px">
+            <el-col :span="5">
+              <el-select v-model="item.intention" placeholder="意向等级" filterable clearable>
+                <el-option v-for="item in levelList" :label="item.dictLabel" :value="item.dictLabel"/>
+              </el-select>
+            </el-col>
+            <el-col :span="5">
+              <el-button @click="openQwUserSelectTow(index)">
+                选择企微({{ item.companyUserId ? item.companyUserId.length : 0 }})
+              </el-button>
+            </el-col>
+            <el-col :span="5">
+              <el-select v-model="item.wxDialogId" placeholder="话术" filterable>
+                <el-option v-for="item in wxDialogList" :label="item.name" :value="item.id"/>
+              </el-select>
+            </el-col>
+            <el-col :span="3">
+              <el-button type="danger" icon="el-icon-delete" circle
+                         @click="removeQwUser(index)"></el-button>
+            </el-col>
+          </el-row>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitFormTow">确 定</el-button>
+        <el-button @click="openAdd = false">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  listRobotic,
+  getRobotic,
+  delRobotic,
+  addRobotic,
+  updateRobotic,
+  exportRobotic,
+  calleesList,
+  statusList,
+  startRobotic,
+  stopRobotic,
+  addScheme,
+  companyUserList,
+  wxList,
+  getTypes
+} from "@/api/company/companyVoiceRobotic";
+import {listAll} from '@/api/company/wxDialog';
+import customerSelect from '@/views/crm/components/CustomerSelect.vue';
+import qwUserSelect from '@/views/components/QwUserSelect.vue';
+import customerDetails from "@/views/crm/components/customerDetails.vue";
+import {clearTime} from "element-ui";
+import {getDicts} from "@/api/system/dict/data";
+
+export default {
+  name: "Robotic",
+  components: {customerDetails, customerSelect, qwUserSelect},
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      weekList: [
+        {label: "星期一", value: 1},
+        {label: "星期二", value: 2},
+        {label: "星期三", value: 3},
+        {label: "星期四", value: 4},
+        {label: "星期五", value: 5},
+        {label: "星期六", value: 6},
+        {label: "星期日", value: 0},
+      ],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      loadingStatus: true,
+      // 总条数
+      total: 0,
+      // 机器人外呼任务表格数据
+      roboticList: [],
+      userTableList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      openAdd: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        name: null,
+        taskName: null,
+        taskId: null,
+        robot: null,
+        dialogId: null,
+        mode: null,
+        multiplier: null,
+        autoRecall: null,
+        recallTimes: null,
+        cidGroupId: null,
+        weekDay1: null,
+        startTime1: null,
+        endTime1: null,
+        weekDay2: null,
+        startTime2: null,
+        endTime2: null,
+        createUser: null
+      },
+      // 表单参数
+      form: {},
+      formOpen: {},
+      statusObj: {},
+      levelList: {},
+      robotList: [],
+      dialogList: [],
+      wxDialogList: [],
+      qwUserList: [],
+      selectQwUserList: [],
+      thisQwUserIndex: 0,
+      updateTime: null,
+      customer: {
+        show: false,
+      },
+      customerDetailShow: false,
+      callees: {
+        show: false,
+        list: [],
+        loading: false,
+        total: 0,
+        queryParams: {
+          id: null,
+          pageNum: 1,
+          pageSize: 10,
+        },
+      },
+      wx: {
+        show: false,
+        list: [],
+        loading: false,
+        total: 0,
+        queryParams: {
+          id: null,
+          pageNum: 1,
+          pageSize: 10,
+        },
+      },
+      // 表单校验
+      rules: {}
+    };
+  },
+  created() {
+    getTypes().then(e => {
+      this.robotList = e.robot;
+      this.dialogList = e.dialog;
+    })
+    listAll().then(e => {
+      this.wxDialogList = e.data;
+    })
+    companyUserList().then(e => {
+      this.qwUserList = e.data;
+    })
+    getDicts("customer_intention_level").then(e => {
+      this.levelList = e.data;
+    })
+    this.getList();
+  },
+  methods: {
+    /** 查询机器人外呼任务列表 */
+    getList() {
+      this.loading = true;
+      listRobotic(this.queryParams).then(response => {
+        this.roboticList = response.rows;
+        this.roboticList.forEach(e => {
+          if (e.weekDay1) {
+            e.weekDay = e.weekDay1.split(",")
+          }
+        })
+        this.total = response.total;
+        this.loading = false;
+        this.updateStatusFun();
+      });
+    },
+    updateStatusFun() {
+      if (!this.roboticList) {
+        return;
+      }
+      this.loadingStatus = true;
+      statusList(this.roboticList.map(e => e.taskId).join()).then(e => {
+        this.loadingStatus = false;
+        this.statusObj = e.data;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        name: null,
+        taskName: null,
+        taskId: null,
+        robot: null,
+        dialogId: null,
+        mode: null,
+        multiplier: null,
+        autoRecall: null,
+        recallTimes: null,
+        cidGroupId: null,
+        weekDay1: null,
+        startTime1: null,
+        addType: 0,
+        endTime1: null,
+        weekDay2: null,
+        startTime2: null,
+        endTime2: null,
+        createTime: null,
+        qwUser: [],
+        createUser: 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() {
+      this.reset();
+      this.open = true;
+      this.title = "添加机器人外呼任务";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getRobotic(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改机器人外呼任务";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.weekDay && this.form.weekDay.length > 0) {
+            this.form.weekDay1 = this.form.weekDay.join(",")
+          }
+          let list = [];
+          this.form.qwUser.forEach(l => {
+            list = list.concat(l.companyUserId.map(e => {
+              return {intention: l.intention, companyUserId: e, wxDialogId: l.wxDialogId}
+            }))
+          })
+          this.form.qwUserList = list;
+          if (!this.form.qwUserList || this.form.qwUserList.length == 0) {
+            this.msgError("请选者加微方案");
+            return;
+          }
+          if (this.form.id != null) {
+            updateRobotic(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          } else {
+            addRobotic(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 提交按钮 */
+    submitFormTow() {
+      let list = [];
+      this.formOpen.qwUser.forEach(l => {
+        list = list.concat(l.companyUserId.map(e => {
+          return {intention: l.intention, companyUserId: e, wxDialogId: l.wxDialogId}
+        }))
+      })
+      this.formOpen.qwUserList = list;
+      if (!this.formOpen.qwUserList || this.formOpen.qwUserList.length == 0) {
+        this.msgError("请选者加微方案");
+        return;
+      }
+      addScheme(this.formOpen).then(response => {
+        if (response.code === 200) {
+          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 delRobotic(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(function () {
+      });
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有机器人外呼任务数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function () {
+        return exportRobotic(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+      }).catch(function () {
+      });
+    },
+    openSelect() {
+      this.$refs.customer.setRows(this.form.userTableList);
+    },
+    openQwUserSelectTow(index) {
+      this.thisQwUserIndex = index;
+      this.$nextTick(() => {
+        this.$refs.qwUserSelectTow.setRows(this.selectQwUserList[index]);
+      })
+    },
+    openQwUserSelect(index) {
+      this.thisQwUserIndex = index;
+      this.$nextTick(() => {
+        this.$refs.qwUserSelect.setRows(this.selectQwUserList[index]);
+      })
+    },
+    selectFun(e) {
+      this.form.userIds = e.ids;
+      this.form.userNames = e.names;
+      this.form.userTableList = e.rows;
+      this.$forceUpdate()
+    },
+    selectQwUserFunTow(e) {
+      console.info(this.formOpen.qwUser[this.thisQwUserIndex])
+      this.formOpen.qwUser[this.thisQwUserIndex].companyUserId = e.ids;
+      console.info(this.formOpen)
+      this.selectQwUserList[this.thisQwUserIndex] = e.rows;
+      this.$forceUpdate()
+    },
+    selectQwUserFun(e) {
+      this.form.qwUser[this.thisQwUserIndex].companyUserId = e.ids;
+      this.selectQwUserList[this.thisQwUserIndex] = e.rows;
+      this.$forceUpdate()
+    },
+    calleesOpen(id) {
+      this.callees.show = true;
+      this.callees.queryParams.id = id;
+      this.getCalleesList();
+    },
+    getCalleesList() {
+      this.callees.loading = true;
+      calleesList(this.callees.queryParams).then(response => {
+        this.callees.list = response.rows;
+        this.callees.total = response.total;
+        this.callees.loading = false;
+      });
+    },
+    wxOpen(id) {
+      this.wx.show = true;
+      this.wx.queryParams.id = id;
+      this.getWxList();
+    },
+    getWxList() {
+      this.wx.loading = true;
+      wxList(this.wx.queryParams).then(response => {
+        this.wx.list = response.rows;
+        this.wx.total = response.total;
+        this.wx.loading = false;
+      });
+    },
+    openCustomer(id) {
+      this.customerDetailShow = true;
+      this.$nextTick(() => {
+        this.$refs.customerDetails.getDetails(id);
+      })
+    },
+    startRoboticFun(id) {
+      startRobotic(id).then(e => {
+        this.updateStatusFun();
+      })
+    },
+    stopRoboticFun(id) {
+      stopRobotic(id).then(e => {
+        this.updateStatusFun();
+      })
+    },
+    addQwUserTow(row) {
+      this.formOpen.qwUser.push({});
+    },
+    addRoboticFun(row) {
+      this.openAdd = true;
+      this.formOpen = {id: row.id, qwUser: []};
+    },
+    addQwUser() {
+      this.form.qwUser.push({});
+    },
+    removeQwUser(index) {
+      this.form.qwUser.splice(index, 1)
+    }
+  }
+};
+</script>

+ 814 - 0
src/views/company/companyVoiceRobotic/index.vue

@@ -0,0 +1,814 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="任务名称" prop="name">
+        <el-input
+            v-model="queryParams.name"
+            placeholder="请输入任务名称"
+            clearable
+            size="small"
+            @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="机器人" prop="robot">
+        <el-select v-model="queryParams.robot" filterable clearable>
+          <el-option v-for="item in robotList" :label="item.name + '('+item.num+')'" :value="item.id"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="话术" prop="dialogId">
+        <el-select v-model="queryParams.dialogId" filterable clearable>
+          <el-option v-for="item in dialogList" :label="item.name" :value="item.id"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" 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"
+            icon="el-icon-plus"
+            size="mini"
+            @click="handleAdd"
+            v-hasPermi="['system:companyVoiceRobotic:add']"
+        >新增
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+            type="success"
+            icon="el-icon-edit"
+            size="mini"
+            :disabled="single"
+            @click="handleUpdate"
+            v-hasPermi="['system:companyVoiceRobotic:edit']"
+        >修改
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+            type="danger"
+            icon="el-icon-delete"
+            size="mini"
+            :disabled="multiple"
+            @click="handleDelete"
+            v-hasPermi="['system:companyVoiceRobotic:remove']"
+        >删除
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+            type="warning"
+            icon="el-icon-download"
+            size="mini"
+            @click="handleExport"
+            v-hasPermi="['system:companyVoiceRobotic:export']"
+        >导出
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+            type="success"
+            icon="el-icon-refresh"
+            size="mini"
+            @click="updateStatusFun"
+            v-hasPermi="['system:companyVoiceRobotic:list']"
+        >更新状态
+        </el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="roboticList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center"/>
+      <el-table-column label="ID" align="center" prop="id"/>
+      <el-table-column label="任务名称" align="center" prop="name"/>
+      <el-table-column label="三方名称" align="center" prop="taskName"/>
+      <el-table-column label="三方ID" align="center" prop="taskId"/>
+      <el-table-column label="机器人" align="center" prop="robot">
+        <template slot-scope="scope">
+          <p v-for="(item, index) in robotList" v-if="scope.row.robot && scope.row.robot == item.id">{{ item.name }}</p>
+        </template>
+      </el-table-column>
+      <el-table-column label="话术" align="center" prop="dialogId">
+        <template slot-scope="scope">
+          <p v-for="(item, index) in dialogList" v-if="scope.row.dialogId && scope.row.dialogId == item.id">
+            {{ item.name }}</p>
+        </template>
+      </el-table-column>
+      <el-table-column label="加微方式" align="center" prop="dialogId">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.addType == 0">平均</el-tag>
+          <el-tag v-if="scope.row.addType == 1">意向</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="工作日" align="center" prop="weekDay1">
+        <template slot-scope="scope">
+          <el-tag v-for="(item, index) in weekList"
+                  v-if="scope.row.weekDay1 && scope.row.weekDay1.indexOf(item.value) != -1">{{ item.label }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="开始时间" align="center" prop="startTime1"/>
+      <el-table-column label="结束时间" align="center" prop="endTime1"/>
+      <el-table-column label="未分配数量" align="center">
+        <template slot-scope="scope">
+          <el-tag :type="Number(scope.row.num) > 0 ?'danger' : ''">{{scope.row.num}}个</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="当前状态" align="center">
+        <template slot-scope="scope">
+          <div v-loading="loadingStatus">
+            <p v-if="statusObj.hasOwnProperty(scope.row.taskId)">
+              <el-tag v-if="statusObj[scope.row.taskId].runningStatus == 0">未启动</el-tag>
+              <el-tag v-if="statusObj[scope.row.taskId].runningStatus == 1">运行中</el-tag>
+              <el-tag v-if="statusObj[scope.row.taskId].runningStatus == 2">已暂停</el-tag>
+              <el-tag v-if="statusObj[scope.row.taskId].runningStatus == 3">已停止</el-tag>
+            </p>
+            <p v-if="!statusObj.hasOwnProperty(scope.row.taskId)">
+              <el-tag>空</el-tag>
+            </p>
+          </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"
+              @click="calleesOpen(scope.row.id)"
+              v-hasPermi="['system:companyVoiceRobotic:list']"
+          >客户列表
+          </el-button>
+          <el-button
+              size="mini"
+              type="text"
+              @click="wxOpen(scope.row.id)"
+              v-hasPermi="['system:companyVoiceRobotic:list']"
+          >加微统计
+          </el-button>
+          <el-button
+              size="mini"
+              type="text"
+              v-if="statusObj.hasOwnProperty(scope.row.taskId) && (statusObj[scope.row.taskId].runningStatus == 0 || statusObj[scope.row.taskId].runningStatus == 3)"
+              @click="startRoboticFun(scope.row.taskId)"
+              v-hasPermi="['system:companyVoiceRobotic:list']"
+          >启动任务
+          </el-button>
+          <el-button
+              size="mini"
+              type="text"
+              v-if="statusObj.hasOwnProperty(scope.row.taskId) && (statusObj[scope.row.taskId].runningStatus == 1 || statusObj[scope.row.taskId].runningStatus == 2)"
+              @click="stopRoboticFun(scope.row.taskId)"
+              v-hasPermi="['system:companyVoiceRobotic:list']"
+          >停止任务
+          </el-button>
+          <el-button
+              size="mini"
+              type="text"
+              @click="addRoboticFun(scope.row)"
+              v-hasPermi="['system:companyVoiceRobotic:edit']"
+          >追加个微
+          </el-button>
+          <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-delete"
+              @click="handleDelete(scope.row)"
+              v-hasPermi="['system:companyVoiceRobotic: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-drawer size="75%" :title="title" :visible.sync="open" width="500px" append-to-body>
+      <div class="app-container">
+        <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+          <el-form-item label="任务名称" prop="name">
+            <el-input v-model="form.name" placeholder="请输入任务名称"/>
+          </el-form-item>
+          <el-form-item label="机器人" prop="robot">
+            <el-select v-model="form.robot" filterable>
+              <el-option v-for="item in robotList" :label="item.name + '('+item.num+')'" :value="item.id"/>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="话术" prop="dialogId">
+            <el-select v-model="form.dialogId" filterable>
+              <el-option v-for="item in dialogList" :label="item.name" :value="item.id"/>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="拨打客户" prop="userIds">
+            <el-button @click="openSelect">选择客户({{ form.userIds ? form.userIds.length : 0 }})</el-button>
+          </el-form-item>
+          <el-form-item label="加微方式" prop="addType">
+            <el-radio v-model="form.addType" :label="0">平均</el-radio>
+            <el-radio v-model="form.addType" :label="1">意向</el-radio>
+          </el-form-item>
+          <el-form-item label="分配账号">
+            <el-button @click="addQwUser">添加</el-button>
+            <el-row :gutter="24" v-for="(item, index) in form.qwUser" style="margin-top: 5px">
+              <el-col :span="5">
+                <el-select v-model="item.intention" placeholder="意向等级" filterable clearable>
+                  <el-option v-for="item in levelList" :label="item.dictLabel" :value="item.dictLabel"/>
+                </el-select>
+              </el-col>
+              <el-col :span="4">
+                <el-button @click="openQwUserSelect(index)">
+                  选择个微({{ item.companyUserId ? item.companyUserId.length : 0 }})
+                </el-button>
+              </el-col>
+              <el-col :span="5">
+                <el-select v-model="item.wxDialogId" placeholder="话术" filterable>
+                  <el-option v-for="item in wxDialogList" :label="item.name" :value="item.id"/>
+                </el-select>
+              </el-col>
+              <el-col :span="3">
+                <el-button type="danger" icon="el-icon-delete" circle @click="removeQwUser(index)"></el-button>
+              </el-col>
+            </el-row>
+          </el-form-item>
+          <el-form-item label="模式" prop="mode">
+            <el-select v-model="form.mode">
+              <el-option label="呼叫机器人后挂断" :value="7"/>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="呼叫倍率" prop="multiplier">
+            <el-select v-model="form.multiplier">
+              <el-option :value="1"/>
+              <el-option :value="2"/>
+              <el-option :value="3"/>
+              <el-option :value="4"/>
+              <el-option :value="5"/>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="自动重呼" prop="autoRecall">
+            <el-radio v-model="form.autoRecall" label="0">否</el-radio>
+            <el-radio v-model="form.autoRecall" label="1">是</el-radio>
+          </el-form-item>
+          <el-form-item label="重呼次数" prop="recallTimes" v-if="form.autoRecall == 1">
+            <el-select v-model="form.recallTimes">
+              <el-option label="不自动重呼" :value="0"/>
+              <el-option :value="1"/>
+              <el-option :value="2"/>
+              <el-option :value="3"/>
+              <el-option :value="4"/>
+              <el-option :value="5"/>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="工作日" prop="weekDay">
+            <el-select v-model="form.weekDay" multiple style="width: 100%">
+              <el-option v-for="item in weekList" :label="item.label" :value="item.value"/>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="开始时间" prop="startTime1">
+            <el-time-select
+                v-model="form.startTime1"
+                format="HH:mm"
+                value-format="HH:mm:00"
+                :picker-options="{
+                  start: '00:00',
+                  end: '23:59',
+                  step: '00:30',
+                }"
+                placeholder="请选择开始时间">
+            </el-time-select>
+          </el-form-item>
+          <el-form-item label="结束时间" prop="endTime1">
+            <el-time-select
+                v-model="form.endTime1"
+                format="HH:mm"
+                value-format="HH:mm:00"
+                :picker-options="{
+                  start: '00:00',
+                  end: '23:59',
+                  step: '00:30',
+                  minTime: form.startTime1
+                }"
+                placeholder="请选择结束时间">
+            </el-time-select>
+          </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>
+      </div>
+    </el-drawer>
+    <customer-select @success="selectFun" ref="customer"/>
+    <qw-user-select @success="selectQwUserFun" ref="qwUserSelect"/>
+    <qw-user-select @success="selectQwUserFunTow" ref="qwUserSelectTow"/>
+
+    <el-drawer title="呼叫客户列表" size="60%" :visible.sync="callees.show" width="800px" append-to-body>
+      <el-table v-loading="callees.loading" :data="callees.list">
+        <el-table-column label="电话号码" align="center" prop="phone"/>
+        <el-table-column label="客户名称" align="center" prop="userName"/>
+        <el-table-column label="客户ID" align="center" prop="userId"/>
+        <el-table-column label="是否回调" align="center">
+          <template slot-scope="scope">
+            <el-tag v-if="scope.row.result == 0">否</el-tag>
+            <el-tag v-if="scope.row.result == 1">是</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="意向等级" align="center" prop="intention"/>
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template slot-scope="scope">
+            <el-button
+                size="mini"
+                type="text"
+                @click="openCustomer(scope.row.userId)"
+            >客户信息详情
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+          v-show="callees.total>0"
+          :total="callees.total"
+          :page.sync="callees.queryParams.pageNum"
+          :limit.sync="callees.queryParams.pageSize"
+          @pagination="getCalleesList"
+      />
+    </el-drawer>
+    <el-drawer title="加微详情" size="60%" :visible.sync="wx.show" append-to-body>
+      <el-table v-loading="wx.loading" :data="wx.list">
+        <el-table-column label="意向等级" align="center" prop="intention"/>
+        <el-table-column label="微信昵称" align="center" prop="wxNickName"/>
+        <el-table-column label="微信号" align="center" prop="wxNo"/>
+        <el-table-column label="手机号" align="center" prop="phone"/>
+        <el-table-column label="员工名称" align="center" prop="companyUserName"/>
+        <el-table-column label="话术" align="center" prop="dialogName"/>
+        <el-table-column label="分配数量" align="center" prop="num"/>
+        <el-table-column label="添加数量" align="center" prop="addNum"/>
+      </el-table>
+
+      <pagination
+          v-show="wx.total>0"
+          :total="wx.total"
+          :page.sync="wx.queryParams.pageNum"
+          :limit.sync="wx.queryParams.pageSize"
+          @pagination="getWxList"
+      />
+    </el-drawer>
+    <el-drawer size="75%" title="客户详情" :visible.sync="customerDetailShow" append-to-body>
+      <customer-details ref="customerDetails"/>
+    </el-drawer>
+
+
+    <!-- 添加或修改添加个微信账号对话框 -->
+    <el-dialog title="追加个微" :visible.sync="openAdd" width="75%" append-to-body>
+      <el-form ref="form" :model="formOpen" label-width="80px">
+        <el-form-item label="分配账号">
+          <el-button @click="addQwUserTow">添加</el-button>
+          <el-row :gutter="24" v-for="(item, index) in formOpen.qwUser" style="margin-top: 5px">
+            <el-col :span="5">
+              <el-select v-model="item.intention" placeholder="意向等级" filterable clearable>
+                <el-option v-for="item in levelList" :label="item.dictLabel" :value="item.dictLabel"/>
+              </el-select>
+            </el-col>
+            <el-col :span="5">
+              <el-button @click="openQwUserSelectTow(index)">
+                选择企微({{ item.companyUserId ? item.companyUserId.length : 0 }})
+              </el-button>
+            </el-col>
+            <el-col :span="5">
+              <el-select v-model="item.wxDialogId" placeholder="话术" filterable>
+                <el-option v-for="item in wxDialogList" :label="item.name" :value="item.id"/>
+              </el-select>
+            </el-col>
+            <el-col :span="3">
+              <el-button type="danger" icon="el-icon-delete" circle
+                         @click="removeQwUser(index)"></el-button>
+            </el-col>
+          </el-row>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitFormTow">确 定</el-button>
+        <el-button @click="openAdd = false">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  listRobotic,
+  getRobotic,
+  delRobotic,
+  addRobotic,
+  updateRobotic,
+  exportRobotic,
+  calleesList,
+  statusList,
+  startRobotic,
+  stopRobotic,
+  addScheme,
+  companyUserList,
+  wxList,
+  getTypes
+} from "@/api/company/companyVoiceRobotic";
+import {listAll} from '@/api/company/wxDialog';
+import customerSelect from '@/views/crm/components/CustomerSelect.vue';
+import qwUserSelect from '@/views/components/QwUserSelect.vue';
+import customerDetails from "@/views/crm/components/customerDetails.vue";
+import {clearTime} from "element-ui";
+import {getDicts} from "@/api/system/dict/data";
+
+export default {
+  name: "Robotic",
+  components: {customerDetails, customerSelect, qwUserSelect},
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      weekList: [
+        {label: "星期一", value: 1},
+        {label: "星期二", value: 2},
+        {label: "星期三", value: 3},
+        {label: "星期四", value: 4},
+        {label: "星期五", value: 5},
+        {label: "星期六", value: 6},
+        {label: "星期日", value: 0},
+      ],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      loadingStatus: true,
+      // 总条数
+      total: 0,
+      // 机器人外呼任务表格数据
+      roboticList: [],
+      userTableList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      openAdd: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        name: null,
+        taskName: null,
+        taskId: null,
+        robot: null,
+        dialogId: null,
+        mode: null,
+        multiplier: null,
+        autoRecall: null,
+        recallTimes: null,
+        cidGroupId: null,
+        weekDay1: null,
+        startTime1: null,
+        endTime1: null,
+        weekDay2: null,
+        startTime2: null,
+        endTime2: null,
+        createUser: null
+      },
+      // 表单参数
+      form: {},
+      formOpen: {},
+      statusObj: {},
+      levelList: {},
+      robotList: [],
+      dialogList: [],
+      wxDialogList: [],
+      qwUserList: [],
+      selectQwUserList: [],
+      thisQwUserIndex: 0,
+      updateTime: null,
+      customer: {
+        show: false,
+      },
+      customerDetailShow: false,
+      callees: {
+        show: false,
+        list: [],
+        loading: false,
+        total: 0,
+        queryParams: {
+          id: null,
+          pageNum: 1,
+          pageSize: 10,
+        },
+      },
+      wx: {
+        show: false,
+        list: [],
+        loading: false,
+        total: 0,
+        queryParams: {
+          id: null,
+          pageNum: 1,
+          pageSize: 10,
+        },
+      },
+      // 表单校验
+      rules: {}
+    };
+  },
+  created() {
+    getTypes().then(e => {
+      this.robotList = e.robot;
+      this.dialogList = e.dialog;
+    })
+    listAll().then(e => {
+      this.wxDialogList = e.data;
+    })
+    companyUserList().then(e => {
+      this.qwUserList = e.data;
+    })
+    getDicts("customer_intention_level").then(e => {
+      this.levelList = e.data;
+    })
+    this.getList();
+  },
+  methods: {
+    /** 查询机器人外呼任务列表 */
+    getList() {
+      this.loading = true;
+      listRobotic(this.queryParams).then(response => {
+        this.roboticList = response.rows;
+        this.roboticList.forEach(e => {
+          if (e.weekDay1) {
+            e.weekDay = e.weekDay1.split(",")
+          }
+        })
+        this.total = response.total;
+        this.loading = false;
+        this.updateStatusFun();
+      });
+    },
+    updateStatusFun() {
+      if (!this.roboticList) {
+        return;
+      }
+      this.loadingStatus = true;
+      statusList(this.roboticList.map(e => e.taskId).join()).then(e => {
+        this.loadingStatus = false;
+        this.statusObj = e.data;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        name: null,
+        taskName: null,
+        taskId: null,
+        robot: null,
+        dialogId: null,
+        mode: null,
+        multiplier: null,
+        autoRecall: null,
+        recallTimes: null,
+        cidGroupId: null,
+        weekDay1: null,
+        startTime1: null,
+        addType: 0,
+        endTime1: null,
+        weekDay2: null,
+        startTime2: null,
+        endTime2: null,
+        createTime: null,
+        qwUser: [],
+        createUser: 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() {
+      this.reset();
+      this.open = true;
+      this.title = "添加机器人外呼任务";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getRobotic(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改机器人外呼任务";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.weekDay && this.form.weekDay.length > 0) {
+            this.form.weekDay1 = this.form.weekDay.join(",")
+          }
+          let list = [];
+          this.form.qwUser.forEach(l => {
+            list = list.concat(l.companyUserId.map(e => {
+              return {intention: l.intention, companyUserId: e, wxDialogId: l.wxDialogId}
+            }))
+          })
+          this.form.qwUserList = list;
+          if (!this.form.qwUserList || this.form.qwUserList.length == 0) {
+            this.msgError("请选者加微方案");
+            return;
+          }
+          if (this.form.id != null) {
+            updateRobotic(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          } else {
+            addRobotic(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 提交按钮 */
+    submitFormTow() {
+      let list = [];
+      this.formOpen.qwUser.forEach(l => {
+        list = list.concat(l.companyUserId.map(e => {
+          return {intention: l.intention, companyUserId: e, wxDialogId: l.wxDialogId}
+        }))
+      })
+      this.formOpen.qwUserList = list;
+      if (!this.formOpen.qwUserList || this.formOpen.qwUserList.length == 0) {
+        this.msgError("请选者加微方案");
+        return;
+      }
+      addScheme(this.formOpen).then(response => {
+        if (response.code === 200) {
+          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 delRobotic(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(function () {
+      });
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有机器人外呼任务数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function () {
+        return exportRobotic(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+      }).catch(function () {
+      });
+    },
+    openSelect() {
+      this.$refs.customer.setRows(this.form.userTableList);
+    },
+    openQwUserSelectTow(index) {
+      this.thisQwUserIndex = index;
+      this.$nextTick(() => {
+        this.$refs.qwUserSelectTow.setRows(this.selectQwUserList[index]);
+      })
+    },
+    openQwUserSelect(index) {
+      this.thisQwUserIndex = index;
+      this.$nextTick(() => {
+        this.$refs.qwUserSelect.setRows(this.selectQwUserList[index]);
+      })
+    },
+    selectFun(e) {
+      this.form.userIds = e.ids;
+      this.form.userNames = e.names;
+      this.form.userTableList = e.rows;
+      this.$forceUpdate()
+    },
+    selectQwUserFunTow(e) {
+      console.info(this.formOpen.qwUser[this.thisQwUserIndex])
+      this.formOpen.qwUser[this.thisQwUserIndex].companyUserId = e.ids;
+      console.info(this.formOpen)
+      this.selectQwUserList[this.thisQwUserIndex] = e.rows;
+      this.$forceUpdate()
+    },
+    selectQwUserFun(e) {
+      this.form.qwUser[this.thisQwUserIndex].companyUserId = e.ids;
+      this.selectQwUserList[this.thisQwUserIndex] = e.rows;
+      this.$forceUpdate()
+    },
+    calleesOpen(id) {
+      this.callees.show = true;
+      this.callees.queryParams.id = id;
+      this.getCalleesList();
+    },
+    getCalleesList() {
+      this.callees.loading = true;
+      calleesList(this.callees.queryParams).then(response => {
+        this.callees.list = response.rows;
+        this.callees.total = response.total;
+        this.callees.loading = false;
+      });
+    },
+    wxOpen(id) {
+      this.wx.show = true;
+      this.wx.queryParams.id = id;
+      this.getWxList();
+    },
+    getWxList() {
+      this.wx.loading = true;
+      wxList(this.wx.queryParams).then(response => {
+        this.wx.list = response.rows;
+        this.wx.total = response.total;
+        this.wx.loading = false;
+      });
+    },
+    openCustomer(id) {
+      this.customerDetailShow = true;
+      this.$nextTick(() => {
+        this.$refs.customerDetails.getDetails(id);
+      })
+    },
+    startRoboticFun(id) {
+      startRobotic(id).then(e => {
+        this.updateStatusFun();
+      })
+    },
+    stopRoboticFun(id) {
+      stopRobotic(id).then(e => {
+        this.updateStatusFun();
+      })
+    },
+    addQwUserTow(row) {
+      this.formOpen.qwUser.push({});
+    },
+    addRoboticFun(row) {
+      this.openAdd = true;
+      this.formOpen = {id: row.id, qwUser: []};
+    },
+    addQwUser() {
+      this.form.qwUser.push({});
+    },
+    removeQwUser(index) {
+      this.form.qwUser.splice(index, 1)
+    }
+  }
+};
+</script>

+ 308 - 0
src/views/company/wxAccount/index.vue

@@ -0,0 +1,308 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="微信昵称" prop="wxNickName">
+        <el-input
+          v-model="queryParams.wxNickName"
+          placeholder="请输入微信昵称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="微信号" prop="wxNo">
+        <el-input
+          v-model="queryParams.wxNo"
+          placeholder="请输入微信号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="手机号" prop="wxNo">
+        <el-input
+          :maxlength="11"
+          v-model="queryParams.phone"
+          placeholder="请输入手机号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="员工" prop="companyUserId">
+        <el-select v-model="queryParams.companyUserId" clearable>
+          <el-option v-for="item in qwUserList" :label="item.qwUserName" :value="item.id" />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" 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"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['company:companyWx:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['company:companyWx:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['company:companyWx:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['company:companyWx:export']"
+        >导出</el-button>
+      </el-col>
+	  <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="companyAccountList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="id" align="center" prop="id" />
+      <el-table-column label="微信昵称" align="center" prop="wxNickName" />
+      <el-table-column label="微信号" align="center" prop="wxNo" />
+      <el-table-column label="手机号" align="center" prop="phone" />
+      <el-table-column label="员工" align="center" prop="companyUserName" />
+      <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="['company:companyWx:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['company:companyWx: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="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="微信昵称" prop="wxNickName">
+          <el-input v-model="form.wxNickName" placeholder="请输入微信昵称" />
+        </el-form-item>
+        <el-form-item label="微信号" prop="wxNo">
+          <el-input v-model="form.wxNo" placeholder="请输入微信号" />
+        </el-form-item>
+        <el-form-item label="手机号" prop="phone">
+          <el-input v-model="form.phone" :maxlength="11" placeholder="请输入手机号" />
+        </el-form-item>
+        <el-form-item label="员工" prop="companyUserId">
+          <el-select v-model="form.companyUserId" filterable placeholder="请选择员工">
+            <el-option v-for="item in qwUserList" :label="item.nickName" :value="item.userId" />
+          </el-select>
+        </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>
+  </div>
+</template>
+
+<script>
+import { listCompanyAccount, getCompanyAccount, delCompanyAccount, addCompanyAccount, updateCompanyAccount, exportCompanyAccount, companyListAll } from "@/api/company/companyAccount";
+import {getAllUserlist} from "@/api/company/companyUser";
+
+
+export default {
+  name: "CompanyAccount",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 个微账号表格数据
+      companyAccountList: [],
+      qwUserList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        wxNickName: null,
+        wxNo: null,
+        companyUserId: null,
+        createUser: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+    companyListAll().then(e => {
+      this.qwUserList = e.data;
+    })
+  },
+  methods: {
+    /** 查询个微账号列表 */
+    getList() {
+      this.loading = true;
+      listCompanyAccount(this.queryParams).then(response => {
+        this.companyAccountList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        wxNickName: null,
+        wxNo: null,
+        companyUserId: null,
+        createTime: null,
+        createUser: 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() {
+      this.reset();
+      this.open = true;
+      this.title = "添加个微账号";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getCompanyAccount(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) {
+            updateCompanyAccount(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          } else {
+            addCompanyAccount(this.form).then(response => {
+              if (response.code === 200) {
+                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 delCompanyAccount(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(function() {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有个微账号数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportCompanyAccount(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
+    },
+  }
+};
+</script>

+ 266 - 0
src/views/company/wxDialog/index.vue

@@ -0,0 +1,266 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" 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"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['company:wxDialog:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['company:wxDialog:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['company:wxDialog:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['company:wxDialog:export']"
+        >导出</el-button>
+      </el-col>
+	  <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="wxDialogList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="id" align="center" prop="id" />
+      <el-table-column label="名称" align="center" prop="name" />
+      <el-table-column label="模板" align="center" prop="templateDetails" />
+      <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="['company:wxDialog:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['company:wxDialog: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="500px" 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="templateDetails">
+          <el-input v-model="form.templateDetails" type="textarea" 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>
+  </div>
+</template>
+
+<script>
+import { listWxDialog, getWxDialog, delWxDialog, addWxDialog, updateWxDialog, exportWxDialog } from "@/api/company/wxDialog";
+
+export default {
+  name: "WxDialog",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 添加微信话术表格数据
+      wxDialogList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        name: null,
+        templateDetails: null,
+        createUser: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询添加微信话术列表 */
+    getList() {
+      this.loading = true;
+      listWxDialog(this.queryParams).then(response => {
+        this.wxDialogList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        name: null,
+        templateDetails: null,
+        createTime: null,
+        createUser: 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() {
+      this.reset();
+      this.open = true;
+      this.title = "添加添加微信话术";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getWxDialog(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) {
+            updateWxDialog(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          } else {
+            addWxDialog(this.form).then(response => {
+              if (response.code === 200) {
+                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 delWxDialog(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(function() {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有添加微信话术数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportWxDialog(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
+    }
+  }
+};
+</script>

+ 551 - 0
src/views/company/wxUser/index.vue

@@ -0,0 +1,551 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="销售昵称" prop="companyUserId">
+        <el-input
+          v-model="queryParams.companyUserName"
+          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="weixinId">
+        <el-input
+          v-model="queryParams.weixinId"
+          placeholder="请输入微信号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="组别" prop="groupName">
+        <el-input
+          v-model="queryParams.groupName"
+          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"
+          size="mini"
+          icon="el-icon-s-flag"
+          @click="handleSendGroup()">
+          分组管理
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          @click="addUserGroup"
+          v-hasPermi="['company:wxUser:addGroup']"
+        >批量设置分组</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          @click="delUserGroup"
+          v-hasPermi="['company:wxUser:delGroup']"
+        >批量移除分组</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="['company:wxUser:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="wxUserList" @selection-change="handleSelectionChange" border>
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="所属销售" align="center" prop="companyUserName" />
+      <el-table-column label="微信昵称" align="center" prop="nickName" />
+      <el-table-column label="微信号" align="center" prop="weixinId" />
+      <el-table-column label="状态 1正常 0禁用" align="center" prop="status" />
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="头像" align="center" prop="avatar" />
+      <el-table-column label="组别" align="center" prop="groupId">
+        <template slot-scope="scope">
+          <div v-for="i in JSON.parse(scope.row.groupId)" :key="i" style="display: inline;">
+            <el-tag type="success" v-for="ii in wxUserGroupList" :key="ii.id" style="margin: 3px;" v-if="ii.groupId==i">{{ii.groupName}}</el-tag>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="是否绑定小程序用户" width="110px" fixed="right">
+        <template slot-scope="scope">
+          <el-button
+            v-if="scope.row.fsUserId"
+            type="success"
+            size="mini"
+            plain>
+            已绑定
+          </el-button>
+          <el-button
+            v-else
+            type="danger"
+            size="mini"
+            plain>
+            未绑定
+          </el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120px" fixed="right">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit-outline"
+            @click="handleUpdateUser(scope.row)"
+          >
+            <span v-if="scope.row.fsUserId">换绑小程序</span>
+            <span v-else>绑定小程序用户</span>
+          </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="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="所属销售ID" prop="companyUserId">
+          <el-input v-model="form.companyUserId" placeholder="请输入所属销售ID" />
+        </el-form-item>
+        <el-form-item label="微信昵称" prop="nickName">
+          <el-input v-model="form.nickName" placeholder="请输入微信昵称" />
+        </el-form-item>
+        <el-form-item label="微信号" prop="weixinId">
+          <el-input v-model="form.weixinId" placeholder="请输入微信号" />
+        </el-form-item>
+        <el-form-item label="状态 1正常 0禁用">
+          <el-radio-group v-model="form.status">
+            <el-radio label="1">请选择字典生成</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" 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-dialog :title="userBind.title" :visible.sync="userBind.open" width="800px" append-to-body>
+      <selectUser ref="selectUser" @bindMiniCustomerId="bindMiniCustomerId"></selectUser>
+    </el-dialog>
+
+    <el-dialog :title="sendGroup.title" :visible.sync="sendGroup.open" width="800px" append-to-body>
+      <wx-user-group ref="wxUserGroup" ></wx-user-group>
+    </el-dialog>
+
+    <el-dialog title="批量添加分组" :visible.sync="groupOpen" width="600px" append-to-body>
+      <el-form ref="form" :model="addGroupForm"  label-width="100px">
+        <div style="margin: 10px">
+          <a v-for="item in wxUserGroupList" :key="item.groupId" class="tag-box"
+             @click="groupSelection(item)" :class="{'tag-selectd': item.isSelected==true}" >{{item.groupName}}</a>
+        </div>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="addGroupSubmitForm()">确 定</el-button>
+        <el-button @click="groupCancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog title="批量移除分组" :visible.sync="groupDelOpen" width="500px" append-to-body>
+      <el-form ref="form" :model="addGroupForm"  label-width="80px">
+        <div style="margin: 10px">
+          <a v-for="item in wxUserGroupList" :key="item.groupId" class="tag-box"
+             @click="groupSelection(item)" :class="{'tag-selectd': item.isSelected==true}" >{{item.groupName}}</a>
+        </div>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="delGroupSubmitForm()">确 定</el-button>
+        <el-button @click="delGroupCancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listWxUser, getWxUser, delWxUser, addWxUser, updateWxUser, exportWxUser,bindMiniUserId,addGroup,delGroup } from "@/api/wxUser/wxUser";
+import wxUserGroup from "@/views/company/wxUserGroup/wxUserGroup.vue";
+import {listWxUserGroup} from "@/api/wxUser/wxUserGroup";
+
+
+export default {
+  name: "WxUser",
+  components: {wxUserGroup},
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 个微用户表格数据
+      wxUserList: [],
+      // 弹出层标题
+      title: "",
+      //小程序绑定个微
+      userForm:{
+        userId:null,
+        fsUserId:null,
+      },
+
+      //批量添加分组的数据
+      addGroupForm:{
+        userIds:[],
+        groupIds:[]
+      },
+      //分组弹窗
+      groupOpen:false,
+
+      // 查询参数取消分组的弹窗
+      groupDelOpen:false,
+
+      //绑定小程序
+      userBind:{
+        open:false,
+        title:"绑定小程序"
+      },
+      //设置分组
+      sendGroup:{
+        open:false,
+        title:"分组管理"
+      },
+      // 个微 分组表格数据
+      wxUserGroupList: [],
+
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        companyId: null,
+        companyUserName: null,
+        nickName: null,
+        weixinId: null,
+        status: null,
+        avatar: null,
+        groupName:null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询个微用户列表 */
+    getList() {
+      this.loading = true;
+      listWxUser(this.queryParams).then(response => {
+        this.wxUserList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+
+      listWxUserGroup().then(response => {
+        this.wxUserGroupList = response.rows;
+        for (let i = 0; i < this.wxUserGroupList.length; i++) {
+          this.wxUserGroupList[i].isSelected=false;
+        }
+
+      });
+
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        userId: null,
+        companyId: null,
+        companyUserId: null,
+        nickName: null,
+        weixinId: null,
+        status: 0,
+        remark: null,
+        createTime: null,
+        avatar: null
+      };
+      this.resetForm("form");
+    },
+
+    //绑定小程序客户
+    handleUpdateUser(row){
+      this.userBind.title="小程序客户"
+      this.userBind.open=true;
+      this.userForm.userId=row.userId;
+    },
+
+    //分组选择
+    groupSelection(row){
+      row.isSelected= !row.isSelected;
+      this.$forceUpdate();
+    },
+
+    //绑定小程序id
+    bindMiniCustomerId(row){
+
+      this.userForm.fsUserId=row;
+      bindMiniUserId(this.userForm).then(res=>{
+        if (res.code==200){
+          this.$message.success('绑定成功')
+        }else {
+          this.$message.error('绑定失败:',res.msg)
+        }
+        this.getList()
+        this.userBind.open=false;
+      })
+    },
+
+    //设置分组
+    handleSendGroup(){
+      this.sendGroup.open=true;
+    },
+
+    //批量设置分组
+    addUserGroup(){
+
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要添加标签的客户');
+      }
+
+      this.groupOpen = true;
+
+    },
+    //批量添加分组
+    addGroupSubmitForm(){
+
+      for (let i = 0; i < this.wxUserGroupList.length; i++) {
+          if(this.wxUserGroupList[i].isSelected==true){
+            this.addGroupForm.groupIds.push(this.wxUserGroupList[i].groupId)
+          }
+      }
+
+      if(this.addGroupForm.groupIds==[]||this.addGroupForm.groupIds==null||this.addGroupForm.groupIds==""){
+        return  this.$message('请选择分组');
+      }
+
+      this.addGroupForm.userIds=this.ids;
+
+      addGroup(this.addGroupForm).then(response => {
+        this.msgSuccess(response.msg);
+        this.groupOpen = false;
+        this.addGroupForm={
+          userIds:[],
+          groupIds:[]
+        };
+        this.getList()
+      });
+    },
+
+
+    //批量移除分组
+    delGroupSubmitForm(){
+      for (let i = 0; i < this.wxUserGroupList.length; i++) {
+          if(this.wxUserGroupList[i].isSelected==true){
+            this.addGroupForm.groupIds.push(this.wxUserGroupList[i].groupId)
+          }
+      }
+
+      if(this.addGroupForm.groupIds==[]||this.addGroupForm.groupIds==null||this.addGroupForm.groupIds==""){
+        return  this.$message('请选择分组');
+      }
+
+      this.addGroupForm.userIds=this.ids;
+
+      delGroup(this.addGroupForm).then(response => {
+        this.msgSuccess(response.msg);
+        this.groupDelOpen = false;
+        this.addGroupForm={
+          userIds:[],
+          groupIds:[]
+        };
+        this.getList()
+      });
+    },
+
+    //取消
+    groupCancel(){
+      this.groupOpen = false;
+      this.addGroupForm={
+        userIds:[],
+        groupIds:[]
+      };
+    },
+
+    //取消批量
+    delGroupCancel(){
+      this.groupDelOpen = false;
+      this.addGroupForm={
+        userIds:[],
+        groupIds:[]
+      };
+    },
+
+    //批量删除分组
+    delUserGroup(){
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要移除分组的客户');
+      }
+      this.groupDelOpen = true;
+    },
+
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.userId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加个微用户";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const userId = row.userId || this.ids
+      getWxUser(userId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改个微用户";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.userId != null) {
+            updateWxUser(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addWxUser(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const userIds = row.userId || this.ids;
+      this.$confirm('是否确认删除个微用户编号为"' + userIds + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delWxUser(userIds);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有个微用户数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportWxUser(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>
+<style scoped>
+.tag-box{
+  margin: 10px;
+  padding: 5px;
+  background-color: #f0f0f0 ;
+  border-radius: 4px;
+}
+.tag-selectd{
+  background-color: rgb(231, 244, 255) ;
+  border: 1px solid rgb(24, 144, 255) ;
+}
+</style>

+ 266 - 0
src/views/company/wxUserGroup/wxUserGroup.vue

@@ -0,0 +1,266 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="分组名" prop="groupName">
+        <el-input
+          v-model="queryParams.groupName"
+          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
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['company:wxUserGroup: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="['company:wxUserGroup: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="['company:wxUserGroup: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="['company:wxUserGroup:export']"
+        >导出</el-button>
+      </el-col>
+
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="wxUserGroupList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="分组id" align="center" prop="groupId" />
+      <el-table-column label="分组名" align="center" prop="groupName" />
+      <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="['company:wxUserGroup:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['company:wxUserGroup: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="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="分组名" prop="groupName">
+          <el-input v-model="form.groupName" 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>
+  </div>
+</template>
+
+<script>
+import { listWxUserGroup, getWxUserGroup, delWxUserGroup, addWxUserGroup, updateWxUserGroup, exportWxUserGroup } from "@/api/wxUser/wxUserGroup";
+
+export default {
+  name: "WxUserGroup",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 个微 分组表格数据
+      wxUserGroupList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        groupName: null,
+        companyId: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询个微 分组列表 */
+    getList() {
+      this.loading = true;
+      listWxUserGroup(this.queryParams).then(response => {
+        this.wxUserGroupList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        groupId: null,
+        groupName: 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.groupId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加个微 分组";
+    },
+
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const groupId = row.groupId || this.ids
+      getWxUserGroup(groupId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改个微 分组";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.groupId != null) {
+            updateWxUserGroup(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addWxUserGroup(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const groupIds = row.groupId || this.ids;
+      this.$confirm('是否确认删除个微 分组编号为"' + groupIds + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delWxUserGroup(groupIds);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有个微 分组数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportWxUserGroup(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 19 - 0
src/views/components/course/userCourseCatalogDetails.vue

@@ -78,6 +78,24 @@
               {{ formatDuration(row.duration) }}
           </template>
       </el-table-column>
+      <el-table-column label="看课开始时间" align="center" prop="duration">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.viewStartTime">{{row.viewStartTime}}</el-tag>
+          <el-tag type="danger" v-if="!row.viewStartTime">无</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="看课结束时间" align="center" prop="duration">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.viewEndTime">{{row.viewEndTime}}</el-tag>
+          <el-tag type="danger" v-if="!row.viewEndTime">无</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="领取红包时间" align="center" prop="duration">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.lastJoinTime">{{ row.lastJoinTime }}</el-tag>
+          <el-tag type="danger" v-if="!row.lastJoinTime">无</el-tag>
+        </template>
+      </el-table-column>
       <el-table-column label="红包金额" align="center" prop="redPacketMoney" v-if="isPrivate === 1"/>
       <el-table-column label="排序" align="center" prop="courseSort" />
       <el-table-column label="上传时间" align="center" prop="createTime" />
@@ -804,6 +822,7 @@ export default {
       batchRedSave(){
         batchUpdateRed(this.redData.list).then(response => {
           this.redData.open = false;
+          this.getList();
         })
       },
     }

+ 30 - 4
src/views/course/userCoursePeriod/index.vue

@@ -257,7 +257,7 @@
             <el-radio :label="2" >单课程</el-radio>
           </el-radio-group>
         </el-form-item>
-        <el-form-item label="销售可查看天数" prop="periodType">
+        <el-form-item label="销售可查看天数" prop="maxViewNum">
           <el-input-number :min="0" v-model="form.maxViewNum" style="width: 200px" />
         </el-form-item>
         <el-form-item label="开营日期" prop="periodStartingTime">
@@ -270,7 +270,9 @@
             range-separator="至"
             start-placeholder="开始日期"
             end-placeholder="结束日期"
-            value-format="yyyy-MM-dd">
+            value-format="yyyy-MM-dd"
+            :picker-options="{disabledDate}"
+          >
           </el-date-picker>
           <el-date-picker
             :style="{display: form.periodType == 2 ? '' : 'none !important'}"
@@ -278,7 +280,9 @@
             v-model="form.date"
             type="date"
             value-format="yyyy-MM-dd"
-            placeholder="选择日期">
+            placeholder="选择日期"
+            :picker-options="{disabledDate}"
+          >
           </el-date-picker>
         </el-form-item>
 
@@ -456,7 +460,7 @@
     title="营期相关设置"
     :visible.sync="periodSettingsVisible"
     direction="rtl"
-    size="70%"
+    size="74%"
     :destroy-on-close="true"
     append-to-body
     custom-class="period-settings-drawer"
@@ -489,6 +493,7 @@
             <el-table-column type="selection" width="55" align="center" />
             <el-table-column label="课程" align="center" prop="courseName" width="180" />
             <el-table-column label="小节" align="center" prop="videoName" />
+            <el-table-column label="开课状态" align="center" prop="status" width="100" :formatter="courseStatusFormatter" />
             <el-table-column label="营期时间" align="center" prop="dayDate" />
             <el-table-column label="开始时间" align="center" prop="startDateTime" width="100">
               <template slot-scope="scope">
@@ -641,6 +646,24 @@ export default {
       },
       // 表单校验
       rules: {
+        periodName: [
+          { required: true, message: '营期名称不能为空', trigger: 'blur' }
+        ],
+        companyId: [
+          { required: true, message: '公司不能为空', trigger: 'change' }
+        ],
+        redPacketGrantMethod: [
+          { required: true, message: '红包发放方式不能为空', trigger: 'change' }
+        ],
+        periodType: [
+          { required: true, message: '营期类型不能为空', trigger: 'change' }
+        ],
+        maxViewNum: [
+          { required: true, message: '销售可查看天数不能为空', trigger: 'blur' }
+        ],
+        periodStartingTime: [
+          { required: true, message: '开营日期不能为空', trigger: 'change' }
+        ]
       },
       // 公司选项
       companyOptions: [],
@@ -1448,6 +1471,9 @@ export default {
       this.form = {id: row.id, dayDate: row.dayDate};
       this.updateDateOpen = true;
     },
+    disabledDate(time) {
+      return time.getTime() < new Date(new Date().setHours(0,0,0,0));
+    },
   },
 };
 </script>

+ 475 - 0
src/views/crm/components/CustomerSelect.vue

@@ -0,0 +1,475 @@
+<template>
+  <el-drawer size="75%" title="客户选择" :visible.sync="shows" append-to-body>
+    <div class="app-container">
+      <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+        <el-form-item label="公司名" prop="companyId">
+          <el-select filterable  v-model="queryParams.companyId" placeholder="请选择公司名"  @change="companyChange" clearable size="small">
+            <el-option
+              v-for="item in companys"
+              :key="item.companyId"
+              :label="item.companyName"
+              :value="item.companyId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item >
+          <treeselect style="width: 220px" :clearable="false"  v-model="queryParams.deptId"  :options="deptOptions" :show-count="true" placeholder="请选择归属部门" />
+        </el-form-item>
+        <el-form-item label="认领人" prop="companyUserNickName">
+          <el-input
+            v-model="queryParams.companyUserNickName"
+            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 statusOptions"
+              :key="'status'+item.dictValue"
+              :label="item.dictLabel"
+              :value="item.dictValue"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="客户类型" prop="customerType">
+          <el-select multiple v-model="ctsTypeArr" placeholder="请选择客户类型" clearable size="small">
+            <el-option
+              v-for="(item, index) in typeOptions"
+              :key="`${item.dictValue}-${index}`"
+              :label="item.dictLabel"
+              :value="item.dictValue"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="创建时间" prop="createTime">
+          <el-date-picker clearable size="small" style="width: 205.4px"
+                          v-model="dateRange"
+                          type="daterange"
+                          value-format="yyyy-MM-dd"
+                          start-placeholder="开始日期" end-placeholder="结束日期">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="领取时间" prop="receiveTimeRange">
+          <el-date-picker
+            style="width:205.4px"
+            clearable size="small"
+            v-model="receiveTimeRange"
+            type="daterange"
+            value-format="yyyy-MM-dd"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="客户来源" prop="source">
+          <el-select multiple v-model="sourceArr" placeholder="请选择客户来源" clearable size="small">
+            <el-option
+              v-for="item in sourceOptions"
+              :key="'source'+item.dictValue"
+              :label="item.dictLabel"
+              :value="item.dictValue"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="客户标签" prop="tags">
+          <el-select multiple v-model="tagIds" placeholder="请选择客户标签" clearable size="small">
+            <el-option
+              v-for="(item, index) in tagsOptions"
+              :key="`${item.dictValue}-${index}`"
+              :label="item.dictLabel"
+              :value="item.dictLabel"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="cyan" 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 border v-loading="loading" :data="customerList" :row-key="getRowKeys" @selection-change="handleSelectionChange" size="mini" ref="table" height="460">
+        <el-table-column type="selection" width="55" align="center" :reserve-selection="true" />
+        <el-table-column label="ID" align="center" prop="customerId" />
+        <el-table-column label="所属公司" align="center" prop="companyName" width="300"/>
+        <el-table-column label="客户编码" align="center" prop="customerCode" width="150"/>
+        <el-table-column label="客户名称" align="center" prop="customerName" />
+        <el-table-column label="手机" align="center" prop="mobile" width="90"/>
+        <el-table-column  label="性别" align="center" prop="sex" width="55">
+          <template slot-scope="scope">
+            <el-tag prop="sex" v-for="(item, index) in sexOptions" :key="'sex'+index"   v-if="scope.row.sex==item.dictValue">{{item.dictLabel}}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="微信号" align="center" prop="weixin" width="95"/>
+        <el-table-column label="所在地" align="center" prop="address" />
+        <el-table-column label="标签" align="center" prop="tags" width="100" show-overflow-tooltip="true"/>
+        <el-table-column  label="客户来源" align="center" prop="source">
+          <template slot-scope="scope">
+            <el-tag prop="source" v-for="(item, index) in sourceOptions"  :key="'source'+index"    v-if="scope.row.source==item.dictValue">{{item.dictLabel}}</el-tag>
+          </template>
+        </el-table-column>
+
+        <el-table-column  label="客户类型" align="center" prop="customerType">
+          <template slot-scope="scope">
+            <el-tag prop="customerType" v-for="(item, index) in typeOptions" :key="'customerType'+index"   v-if="scope.row.customerType==item.dictValue">{{item.dictLabel}}</el-tag>
+          </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 statusOptions"  :key="'status'+index"  v-if="scope.row.status==item.dictValue">{{item.dictLabel}}</el-tag>
+          </template>
+        </el-table-column>
+
+        <el-table-column label="认领人" align="center" prop="companyUserNickName" />
+        <el-table-column label="领取时间" align="center" prop="receiveTime"  width="135"/>
+        <el-table-column label="创建时间" align="center" prop="createTime" width="135"/>
+        <el-table-column label="最后一次跟进时间" align="center" prop="lastTime" width="180">
+        </el-table-column>
+        <el-table-column label="入公海时间" align="center" prop="poolTime" width="180" />
+        <el-table-column label="操作" fixed="right" width="180px" align="center" class-name="small-padding fixed-width">
+          <template slot-scope="scope">
+            <el-button
+              size="mini"
+              type="text"
+              @click="handleShow(scope.row)"
+              v-hasPermi="['crm:customer:query']"
+            >查看</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div slot="footer" class="dialog-footer" style="width: 100%;display: flex;flex-direction: row-reverse;margin-top: 20px;z-index: 9898989;padding-top: 5px">
+        <el-button type="primary" @click="submitForm" style="margin-bottom: 5px">确 定</el-button>
+      </div>
+      <el-drawer
+        size="75%"
+        :title="show.title" :visible.sync="show.open" append-to-body>
+        <customer-details  ref="customerDetails" />
+      </el-drawer>
+    </div>
+  </el-drawer>
+</template>
+
+<script>
+import { listCustomerAll  } from "@/api/crm/customer";
+import { getCompanyList } from "@/api/company/company";
+import customerDetails from '@/views/crm/components/customerDetails.vue';
+import editCustomerSource from '@/views/crm/components/editCustomerSource.vue';
+import {getCitys} from "@/api/store/city";
+import { throwStatement } from "@babel/types";
+
+import { treeselect } from "@/api/company/companyDept";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "CustomerSelect",
+  components: { customerDetails,editCustomerSource,Treeselect },
+  data() {
+    return {
+      source:{
+        title:"修改客户来源",
+        open:false,
+      },
+      shows:false,
+      deptOptions:[],
+      receiveTimeRange:[],
+      tagId:null,
+      deptId:undefined,
+      companyId:undefined,
+      tagsOptions:[],
+      ctsTypeArr:[],
+      sourceArr:[],
+      dateRange:[],
+      cityIds:[],
+      citys:[],
+      tags:[],
+      tagIds:[],
+      inputVisible: false,
+      inputValue: '',
+      statusOptions:[],
+      typeOptions:[],
+      sourceOptions:[],
+      sexOptions:[],
+      pageSizes: [10, 20, 30, 50,100,500 ],
+      show:{
+        title:"客户详情",
+        open:false,
+      },
+      companys:[],
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      names: [],
+      userIds: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 客户表格数据
+      customerList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        customerCode: null,
+        customerName: null,
+        mobile: null,
+        sex: null,
+        weixin: null,
+        userId: null,
+        createUserId: null,
+        receiveUserId: null,
+        customerUserId: null,
+        address: null,
+        location: null,
+        detailAddress: null,
+        lng: null,
+        lat: null,
+        status: null,
+        isReceive: null,
+        deptId: null,
+        isDel: null,
+        customerType: null,
+        receiveTime: null,
+        poolTime: null,
+        companyId: null,
+        isLine: null,
+        source: null,
+        tags: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        // customerName: [
+        //   { required: true, message: "客户名称不能为空", trigger: "blur" }
+        // ],
+        mobile: [
+          { required: true, message: "手机号不能为空", trigger: "blur" }
+        ],
+        // sex: [
+        //   { required: true, message: "性别不能为空", trigger: "blur" }
+        // ],
+        source: [
+          { required: true, message: "客户来源不能为空", trigger: "blur" }
+        ],
+      }
+    };
+  },
+  created() {
+    this.getDicts("crm_customer_tag").then((response) => {
+      this.tagsOptions = response.data;
+    });
+    this.getDicts("crm_customer_source").then((response) => {
+      this.sourceOptions = response.data;
+    });
+    this.getDicts("common_sex").then((response) => {
+      this.sexOptions = response.data;
+    });
+    this.getDicts("crm_customer_status").then((response) => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("crm_customer_type").then((response) => {
+      this.typeOptions = response.data;
+    });
+    getCompanyList().then(response => {
+      this.companys = response.data;
+    });
+    this.getCitys();
+    // this.getList();
+  },
+  methods: {
+    setRows(rows){
+      this.shows = true;
+      this.rows = rows;
+      this.initSelect();
+    },
+    initSelect(){
+      if(this.rows && this.rows.length > 0){
+        this.rows.forEach(row => {
+          this.$refs.table.toggleRowSelection(row);
+        })
+      }
+    },
+    getRowKeys(item){
+      return item.customerId;
+    },
+    handleEditSource(){
+      this.source.open=true;
+      var that=this;
+      setTimeout(() => {
+        that.$refs.editSource.handleEdit(that.ids);
+      }, 200);
+
+    },
+    closeSource(){
+      this.source.open=false;
+      this.getList();
+    },
+    tagsChange(e){
+      var item=this.tagsOptions.find(val => val.dictValue === e);
+      console.log(item);
+      this.tags.push(item.dictLabel);
+      this.form.tags=this.tags.toString();
+    },
+    handleCityChange(value) {
+      console.log(value);
+      var nodes=this.$refs.citySelect.getCheckedNodes();
+      this.form.address=nodes[0].pathLabels[0]+"-"+nodes[0].pathLabels[1]+"-"+nodes[0].pathLabels[2];
+      this.form.cityIds=value.toString();
+    },
+    getCitys(){
+        getCitys().then(res => {
+          this.loading = false;
+          this.citys=res.data;
+        })
+    },
+    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.$refs.input.focus();
+      });
+    },
+    handleInputConfirm() {
+      let inputValue = this.inputValue;
+      if (inputValue) {
+        this.tags.push(inputValue);
+      }
+      this.inputVisible = false;
+      this.inputValue = '';
+      this.form.tags=this.tags.toString();
+    },
+    handleShow(row){
+      var that=this;
+      that.show.open=true;
+      setTimeout(() => {
+          that.$refs.customerDetails.getDetails(row.customerId);
+      }, 200);
+    },
+    /** 查询客户列表 */
+    getList() {
+      this.loading = true;
+      if(this.receiveTimeRange!=null&&this.receiveTimeRange.length==2){
+        this.queryParams.receiveTimeRange=this.receiveTimeRange[0]+"--"+this.receiveTimeRange[1]
+      }
+      else{
+        this.queryParams.receiveTimeRange=null;
+      }
+      if(this.ctsTypeArr.length>0){
+        this.queryParams.customerType=this.ctsTypeArr.toString();
+      }
+      else{
+        this.queryParams.customerType=null
+      }
+
+      if(this.sourceArr.length>0){
+        this.queryParams.source=this.sourceArr.toString();
+      }
+      else{
+        this.queryParams.source=null
+      }
+      if(this.tagIds.length>0){
+        this.queryParams.tags=this.tagIds.toString();
+      }
+      else{
+        this.queryParams.tags=null
+      }
+      listCustomerAll(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+        this.customerList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+        this.initSelect();
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.rows = selection;
+      this.ids = selection.map(item => item.customerId)
+      this.names = selection.map(item => item.customerName)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    getTreeselect() {
+        var that=this;
+        var param={companyId:this.companyId}
+        treeselect(param).then((response) => {
+          this.deptOptions = response.data;
+          console.log(this.deptOptions)
+          if(response.data!=null&&response.data.length>0){
+            //this.queryParams.deptId=response.data[0].id;
+          }
+        });
+    },
+    companyChange(val){
+      console.log(val);
+      this.companyId=val;
+      this.getTreeselect();
+    },
+     currDeptChange(val){
+          this.queryParams.deptId=val;
+          this.getList();
+    },
+    submitForm(){
+      this.$nextTick(() => {
+        this.$emit("success", {ids: this.ids, names: this.names, rows: this.rows})
+        this.shows = false;
+        this.$refs.table.clearSelection();
+      })
+    },
+  }
+};
+</script>
+<style scoped>
+  .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;
+  }
+  .el-dialog__wrapper{
+    z-index: 100000;
+  }
+  .app-container{padding: 0}
+  .dialog-footer{
+    position: absolute;
+    bottom: 0;
+    right: 20px;
+    background: #FFF;
+  }
+</style>

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

@@ -504,7 +504,7 @@ export default {
       // if (row.sendType==4) {
       //   this.$router.push(`/qw/sopTemp/updateAiChatTemp/${row.id}/3`)
       // }else{
-      this.$router.push(`/qw/sopTempe/updateSopTemp/${row.id}/3`)
+      this.$router.push(`/course/sopTempe/updateSopTemp/${row.id}/3`)
       // }
     },
     /** 修改按钮操作 */
@@ -522,7 +522,7 @@ export default {
       // if (row.sendType==4) {
       //   this.$router.push(`/qw/sopTemp/updateAiChatTemp/${row.id}/1`)
       // }else{
-      let url = `/qw/sopTempe/updateSopTemp/${row.id}/1`;
+      let url = `/course/sopTempe/updateSopTemp/${row.id}/1`;
       console.info(url)
       this.$router.push(url)
       // }

+ 155 - 2
src/views/store/user/index.vue

@@ -78,7 +78,15 @@
     </el-form>
 
     <el-row :gutter="10" class="mb8">
-
+      <el-col :span="3">
+      <el-button
+        type="primary"
+        icon="el-icon-user"
+        size="mini"
+        @click="handleChangeCompanyUser"
+        :disabled="multiple"
+      >更换会员归属</el-button>
+      </el-col>
       <el-col :span="1.5">
         <el-button
           type="warning"
@@ -140,6 +148,14 @@
       <el-table-column label="可提现佣金" align="center" prop="registerCode" />
       <el-table-column label="冻结佣金" align="center" prop="source" />
       <el-table-column label="已提现佣金" align="center" prop="remark" />
+      <el-table-column label="看课数量" align="center" prop="watchCourseCount" />
+      <el-table-column label="参与营期数" align="center" prop="partCourseCount" />
+      <el-table-column label="所属销售" align="center" prop="companyUserNickName" />
+      <el-table-column label="最后看课时间" align="center" prop="lastWatchDate" width="160">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.lastWatchDate) }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="操作" align="center" fixed="right" width="150px" class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button
@@ -263,11 +279,41 @@
          <store-user-details ref="storeUserDetails"></store-user-details>
     </el-drawer>
 
+    <!-- 更换会员归属对话框 -->
+    <el-dialog title="更换会员归属" :visible.sync="changeCompanyUserOpen" width="500px" append-to-body>
+      <el-form ref="changeCompanyUserForm" :model="changeCompanyUserForm" :rules="changeCompanyUserRules" label-width="100px">
+        <el-form-item label="选择公司" prop="companyId">
+          <el-select v-model="changeCompanyUserForm.companyId" placeholder="请选择公司" style="width: 100%" @change="handleCompanyChange">
+            <el-option
+              v-for="item in companyOptions"
+              :key="item.companyId"
+              :label="item.companyName"
+              :value="item.companyId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="选择销售" prop="companyUserId">
+          <el-select v-model="changeCompanyUserForm.companyUserId" placeholder="请选择销售" style="width: 100%" @change="handleCompanyUserChange">
+            <el-option
+              v-for="item in companyUserOptions"
+              :key="item.userId"
+              :label="item.nickName + '_' + item.userName"
+              :value="item.userId"
+            />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitChangeCompanyUserForm">确 定</el-button>
+        <el-button @click="cancelChangeCompanyUser">取 消</el-button>
+      </div>
+    </el-dialog>
   </div>
 </template>
 
 <script>
 import { listUser, getUser, delUser, addUser, updateUser, exportUser } from "@/api/store/user";
+import { getCompanyUserList, changeCompanyUser, getCompanyList } from '@/api/company/companyUser';
 import storeUserDetails from './components/storeUserDetails.vue';
 export default {
   components: { storeUserDetails },
@@ -341,7 +387,27 @@ export default {
           { required: true, message: "等级不能为空", trigger: "blur" }
         ],
 
-      }
+      },
+      // 更换会员归属对话框
+      changeCompanyUserOpen: false,
+      // 更换会员归属表单
+      changeCompanyUserForm: {
+        companyId: null,
+        companyUserId: null,
+        userIds: []
+      },
+      // 更换会员归属表单校验
+      changeCompanyUserRules: {
+        companyId: [
+          { required: true, message: '请选择公司', trigger: 'change' }
+        ],
+        companyUserId: [
+          { required: true, message: '请选择销售', trigger: 'change' }
+        ]
+      },
+      // 销售选项
+      companyUserOptions: [],
+      companyOptions: []
     };
   },
   created() {
@@ -505,6 +571,93 @@ export default {
           that.$refs.storeUserDetails.getDetails(row.userId);
       }, 200);
     },
+    /** 更换会员归属按钮操作 */
+    handleChangeCompanyUser() {
+      // 获取公司下拉列表
+      getCompanyList().then(response => {
+        if (response.code === 200) {
+          this.companyOptions = response.data;
+          // 重置表单和销售列表
+          this.resetCompanyUserForm();
+          this.companyUserOptions = [];
+          this.changeCompanyUserOpen = true;
+        } else {
+          this.$message.error(response.msg || '获取公司列表失败');
+        }
+      }).catch(() => {
+        this.$message.error('获取公司列表失败');
+      });
+    },
+    /** 销售选择变化 */
+    handleCompanyUserChange(userId) {
+      if (!this.changeCompanyUserForm.companyId) {
+        this.$message.warning('请先选择公司');
+        this.changeCompanyUserForm.companyUserId = null;
+        return;
+      }
+    },
+    /** 重置更换会员归属表单 */
+    resetCompanyUserForm() {
+      this.changeCompanyUserForm = {
+        companyId: null,
+        companyUserId: null,
+        userIds: []
+      };
+      this.resetForm("changeCompanyUserForm");
+    },
+    handleCompanyChange(companyId) {
+      // 清空已选择的销售
+      this.changeCompanyUserForm.companyUserId = null;
+      // 根据公司ID获取对应的销售列表
+      if (companyId) {
+        getCompanyUserList({ companyId: companyId }).then(response => {
+          if (response.code === 200) {
+            this.companyUserOptions = response.data;
+          } else {
+            this.$message.error(response.msg || '获取销售列表失败');
+            this.companyUserOptions = [];
+          }
+        }).catch(() => {
+          this.$message.error('获取销售列表失败');
+          this.companyUserOptions = [];
+        });
+      } else {
+        this.companyUserOptions = [];
+      }
+    },
+    /** 取消更换会员归属 */
+    cancelChangeCompanyUser() {
+      this.changeCompanyUserOpen = false;
+      this.resetCompanyUserForm();
+    },
+    /** 提交更换会员归属 */
+    submitChangeCompanyUserForm() {
+      this.$refs["changeCompanyUserForm"].validate(valid => {
+        if (valid) {
+          // 调用更换会员归属接口
+          // 检查companyId是否已设置
+          if (!this.changeCompanyUserForm.companyId) {
+            this.$message.error('请选择公司');
+            return;
+          }
+
+          changeCompanyUser(this.ids, {
+            companyUserId: this.changeCompanyUserForm.companyUserId,
+            companyId: this.changeCompanyUserForm.companyId
+          }).then(response => {
+            if (response.code === 200) {
+              this.msgSuccess("操作成功");
+              this.changeCompanyUserOpen = false;
+              this.getList();
+            } else {
+              this.$message.error(response.msg || '操作失败');
+            }
+          }).catch(() => {
+            this.$message.error('操作失败');
+          });
+        }
+      });
+    }
   }
 };
 </script>

+ 7 - 7
src/views/user/transfer/index.vue

@@ -103,7 +103,7 @@
       <el-table-column label="所属公司" align="center" prop="companyName" />
       <el-table-column label="转移类型" align="center" prop="transferTypeText" />
       <el-table-column label="目标销售" align="center" prop="targetUserName" />
-      <el-table-column label="发起转移用户" align="center" prop="initiatorUserName" />
+      <el-table-column label="发起用户" align="center" prop="initiatorUserName" />
       <el-table-column label="转移内容/原因" align="center" prop="content" />
       <el-table-column label="审批状态" align="center" prop="approvalStatus" >
         <template slot-scope="scope">
@@ -111,12 +111,12 @@
         </template>
       </el-table-column>
       <el-table-column label="审批意见/备注" align="center" prop="approvalRemark" />
-      <el-table-column label="记录创建时间" align="center" prop="createdAt" width="180">
+      <el-table-column label="创建时间" align="center" prop="createdAt" width="180">
         <template slot-scope="scope">
           <span>{{ parseTime(scope.row.createdAt, '{y}-{m}-{d}') }}</span>
         </template>
       </el-table-column>
-      <el-table-column label="记录最后更新时间" align="center" prop="updatedAt" width="180">
+      <el-table-column label="更新时间" align="center" prop="updatedAt" width="180">
         <template slot-scope="scope">
           <span>{{ parseTime(scope.row.updatedAt, '{y}-{m}-{d}') }}</span>
         </template>
@@ -167,13 +167,13 @@
             <el-table-column label="转移后销售" align="center" prop="afterCompanyUserName" />
           </el-table>
         </el-form-item>
-        <el-form-item label="目标接收销售用户" prop="targetUserId">
+        <el-form-item label="接收销售" prop="targetUserId">
           <el-input v-model="form.targetUserName" placeholder="请输入目标接收销售用户 ID" disabled="disabled"/>
         </el-form-item>
-        <el-form-item label="发起此转移请求用户" prop="initiatorUserId">
+        <el-form-item label="请求用户" prop="initiatorUserId">
           <el-input v-model="form.initiatorUserName" placeholder="请输入发起此转移请求的用户 ID" disabled="disabled"/>
         </el-form-item>
-        <el-form-item label="转移提示内容/原因">
+        <el-form-item label="转移提示内容">
           <el-input v-model="form.content" :min-height="192" disabled="disabled"/>
         </el-form-item>
         <el-form-item label="审批状态">
@@ -181,7 +181,7 @@
             <el-tag>{{form.approvalStatusText}}</el-tag>
           </el-radio-group>
         </el-form-item>
-        <el-form-item label="审批意见/备注" prop="approvalRemark">
+        <el-form-item label="审批意见" prop="approvalRemark">
           <el-input v-model="form.approvalRemark" type="textarea" placeholder="请输入内容"  disabled="disabled"/>
         </el-form-item>
       </el-form>