瀏覽代碼

Merge remote-tracking branch 'origin/master' into bjcz_his_scrm

# Conflicts:
#	src/api/hisStore/city.js
#	src/api/hisStore/store.js
#	src/views/hisStore/store/audit.vue
#	src/views/hisStore/store/index.vue
#	src/views/hisStore/storeProduct/index.vue
yjwang 2 天之前
父節點
當前提交
01238ffb53
共有 54 個文件被更改,包括 7557 次插入2075 次删除
  1. 1 1
      .env.prod-jnmy
  2. 1 1
      .env.prod-myhk
  3. 12 1
      src/api/company/statistics.js
  4. 18 0
      src/api/company/traffic.js
  5. 19 0
      src/api/company/trafficLog.js
  6. 7 0
      src/api/course/coursePlaySourceConfig.js
  7. 18 0
      src/api/course/courseWatchComment.js
  8. 53 0
      src/api/fastGpt/fastGptChatReplaceText.js
  9. 62 0
      src/api/fastGpt/fastGptKeywordSend.js
  10. 70 0
      src/api/fastGpt/fastgptEventLogTotal.js
  11. 106 0
      src/api/his/complaint.js
  12. 53 0
      src/api/his/fsFirstDiagnosis.js
  13. 53 0
      src/api/his/hfpayConfig.js
  14. 9 1
      src/api/his/patient.js
  15. 8 8
      src/api/hisStore/city.js
  16. 54 0
      src/api/hisStore/recommend.js
  17. 10 9
      src/api/hisStore/store.js
  18. 8 0
      src/api/hisStore/storeProduct.js
  19. 9 0
      src/api/qw/externalContact.js
  20. 0 1
      src/components/Material/index.vue
  21. 0 1
      src/components/Material/single.vue
  22. 92 87
      src/utils/cos.js
  23. 69 52
      src/utils/obs.js
  24. 350 0
      src/views/company/companyTraffic/index.vue
  25. 276 0
      src/views/company/companyTrafficLog/index.vue
  26. 0 1
      src/views/components/his/inquiryOrderDetails.vue
  27. 9 1
      src/views/components/his/userPatietDetails.vue
  28. 82 1
      src/views/course/coursePlaySourceConfig/index.vue
  29. 228 95
      src/views/course/courseWatchComment/index.vue
  30. 447 245
      src/views/course/videoResource/index.vue
  31. 340 0
      src/views/fastGpt/fastGptChatReplaceText/index.vue
  32. 113 0
      src/views/fastGpt/fastGptKeywordSend/fastGptKeyWordDetails.vue
  33. 529 0
      src/views/fastGpt/fastGptKeywordSend/index.vue
  34. 333 0
      src/views/fastGpt/fastgptEventLogTotal/index.vue
  35. 442 361
      src/views/his/company/index.vue
  36. 838 0
      src/views/his/complaint/index.vue
  37. 369 0
      src/views/his/fsFirstDiagnosis/index.vue
  38. 326 0
      src/views/his/hfpayConfig/index.vue
  39. 252 0
      src/views/his/statistics/tokenStatic.vue
  40. 2 1
      src/views/his/storeOrder/order1.vue
  41. 2 2
      src/views/his/user/indexProject.vue
  42. 2 2
      src/views/his/user/userDetails.vue
  43. 96 0
      src/views/hisStore/components/storeDetails.vue
  44. 158 161
      src/views/hisStore/store/audit.vue
  45. 630 246
      src/views/hisStore/store/index.vue
  46. 0 770
      src/views/hisStore/store/index1.vue
  47. 401 0
      src/views/hisStore/store/recommend.vue
  48. 10 10
      src/views/hisStore/storeProduct/index.vue
  49. 17 8
      src/views/hisStore/storeProductAudit/index.vue
  50. 65 1
      src/views/index.vue
  51. 36 2
      src/views/qw/externalContact/index.vue
  52. 6 3
      src/views/qw/qwCompany/index.vue
  53. 3 0
      src/views/qw/sopTemp/index.vue
  54. 463 3
      src/views/system/config/config.vue

+ 1 - 1
.env.prod-jnmy

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

+ 1 - 1
.env.prod-myhk

@@ -1,7 +1,7 @@
 # 页面标题
 VUE_APP_TITLE =木易华康互联网医院管理系统
 # 首页菜单标题
-VUE_APP_TITLE_INDEX =木易华康互联网医院
+VUE_APP_TITLE_INDEX =康复e站
 # 公司名称
 VUE_APP_COMPANY_NAME =福州市木易华康医药有限公司
 # ICP备案号

+ 12 - 1
src/api/company/statistics.js

@@ -128,5 +128,16 @@ export function exportIpadStaticByTime(dateTime) {
     method: 'get'
   })
 }
-
+export function tokenStaticTotal(dateTime) {
+  return request({
+    url: '/company/statistics/tokenStaticTotal/' + dateTime,
+    method: 'get'
+  })
+}
+export function exportTokenStaticByTime(dateTime) {
+  return request({
+    url: '/company/statistics/exportTokenStaticByTime/' + dateTime,
+    method: 'get'
+  })
+}
 

+ 18 - 0
src/api/company/traffic.js

@@ -0,0 +1,18 @@
+import request from '@/utils/request'
+
+export function rechargeTraffic(data) {
+  return request({
+    url: '/company/traffic/rechargeTraffic',
+    method: 'post',
+    data: data
+  })
+}
+
+export function listTrafficRecords(query) {
+  return request({
+    url: '/company/traffic/list',
+    method: 'get',
+    params: query
+  })
+}
+

+ 19 - 0
src/api/company/trafficLog.js

@@ -0,0 +1,19 @@
+import request from '@/utils/request'
+
+
+export function listTrafficLogExport(query) {
+  return request({
+    url: '/company/trafficLog/export',
+    method: 'get',
+    params: query
+  })
+}
+
+export function listTrafficLog(query) {
+  return request({
+    url: '/company/trafficLog/list',
+    method: 'get',
+    params: query
+  })
+}
+

+ 7 - 0
src/api/course/coursePlaySourceConfig.js

@@ -37,3 +37,10 @@ export function del(id) {
     method: 'delete'
   })
 }
+
+export function listAll() {
+  return request({
+    url: '/course/playSourceConfig/listAll',
+    method: 'get'
+  })
+}

+ 18 - 0
src/api/course/courseWatchComment.js

@@ -35,6 +35,15 @@ export function listCourseWatchComment(query) {
 //   })
 // }
 //
+
+// 修改弹幕状态
+export function updateBarrageStatus(data) {
+  return request({
+    url: '/course/courseWatchComment/updateBarrageStatus',
+    method: 'put',
+    data: data
+  })
+}
 // 删除看课评论
 export function delCourseWatchComment(commentId) {
   return request({
@@ -60,3 +69,12 @@ export function addBlack(query) {
     params: query
   })
 }
+
+// 解除拉黑外部联系人
+export function clearBlack(query) {
+  return request({
+    url: '/course/courseWatchComment/clearBlack',
+    method: 'put',
+    params: query
+  })
+}

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

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询违规词语列表
+export function listFastGptChatReplaceText(query) {
+  return request({
+    url: '/fastGpt/fastGptChatReplaceText/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询违规词语详细
+export function getFastGptChatReplaceText(id) {
+  return request({
+    url: '/fastGpt/fastGptChatReplaceText/' + id,
+    method: 'get'
+  })
+}
+
+// 新增违规词语
+export function addFastGptChatReplaceText(data) {
+  return request({
+    url: '/fastGpt/fastGptChatReplaceText',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改违规词语
+export function updateFastGptChatReplaceText(data) {
+  return request({
+    url: '/fastGpt/fastGptChatReplaceText',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除违规词语
+export function delFastGptChatReplaceText(id) {
+  return request({
+    url: '/fastGpt/fastGptChatReplaceText/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出违规词语
+export function exportFastGptChatReplaceText(query) {
+  return request({
+    url: '/fastGpt/fastGptChatReplaceText/export',
+    method: 'get',
+    params: query
+  })
+}

+ 62 - 0
src/api/fastGpt/fastGptKeywordSend.js

@@ -0,0 +1,62 @@
+import request from '@/utils/request'
+
+// 查询Ai指令关键字列表
+export function keywordList(query) {
+  return request({
+    url: '/fastGpt/fastGptKeywordSend/keywordList',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询Ai指令列表
+export function listFastGptKeywordSend(query) {
+  return request({
+    url: '/fastGpt/fastGptKeywordSend/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询Ai指令详细
+export function getFastGptKeywordSend(id) {
+  return request({
+    url: '/fastGpt/fastGptKeywordSend/' + id,
+    method: 'get'
+  })
+}
+
+// 新增Ai指令
+export function addFastGptKeywordSend(data) {
+  return request({
+    url: '/fastGpt/fastGptKeywordSend',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改Ai指令
+export function updateFastGptKeywordSend(data) {
+  return request({
+    url: '/fastGpt/fastGptKeywordSend',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除Ai指令
+export function delFastGptKeywordSend(id) {
+  return request({
+    url: '/fastGpt/fastGptKeywordSend/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出Ai指令
+export function exportFastGptKeywordSend(query) {
+  return request({
+    url: '/fastGpt/fastGptKeywordSend/export',
+    method: 'get',
+    params: query
+  })
+}

+ 70 - 0
src/api/fastGpt/fastgptEventLogTotal.js

@@ -0,0 +1,70 @@
+import request from '@/utils/request'
+
+// 查询ai事件埋点统计列表
+/*export function listFastgptEventLogTotal(query) {
+  return request({
+    url: '/fastGpt/fastgptEventLogTotal/list',
+    method: 'get',
+    params: query
+  })
+}*/
+
+export function listFastgptEventLogTotal(data) {
+  return request({
+    url: '/fastGpt/fastgptEventLogTotal/list',
+    method: 'post',
+    data: data
+  })
+}
+
+
+// 查询ai事件埋点统计详细
+export function getFastgptEventLogTotal(id) {
+  return request({
+    url: '/fastGpt/fastgptEventLogTotal/' + id,
+    method: 'get'
+  })
+}
+
+// 新增ai事件埋点统计
+export function addFastgptEventLogTotal(data) {
+  return request({
+    url: '/fastGpt/fastgptEventLogTotal',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改ai事件埋点统计
+export function updateFastgptEventLogTotal(data) {
+  return request({
+    url: '/fastGpt/fastgptEventLogTotal',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除ai事件埋点统计
+export function delFastgptEventLogTotal(id) {
+  return request({
+    url: '/fastGpt/fastgptEventLogTotal/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出ai事件埋点统计
+export function exportFastgptEventLogTotal(query) {
+  return request({
+    url: '/fastGpt/fastgptEventLogTotal/export',
+    method: 'get',
+    params: query
+  })
+}
+
+
+export function getFastGptRoleAppKeyList() {
+  return request({
+    url: '/fastGpt/fastgptEventLogTotal/getFastGptRoleAppKeyList',
+    method: 'get'
+  })
+}

+ 106 - 0
src/api/his/complaint.js

@@ -0,0 +1,106 @@
+import request from '@/utils/request'
+
+
+// 查询用户投诉列表
+export function listComplaint(data) {
+  return request({
+    url: '/user/complaint/list',
+    method: 'post',
+    data: data
+  })
+}
+
+// 查询用户投诉详细
+export function getComplaint(id) {
+  return request({
+    url: '/user/complaint/' + id,
+    method: 'get'
+  })
+}
+
+// 新增用户投诉
+export function addComplaint(data) {
+  return request({
+    url: '/user/complaint',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改用户投诉
+export function updateComplaint(data) {
+  return request({
+    url: '/user/complaint',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除用户投诉
+export function delComplaint(id) {
+  return request({
+    url: '/user/complaint/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出用户投诉
+export function exportComplaint(query) {
+  return request({
+    url: '/user/complaint/export',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询投诉消息记录列表
+export function listMsg(query) {
+  return request({
+    url: '/user/msg/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询投诉消息记录详细
+export function getMsg(id) {
+  return request({
+    url: '/user/msg/' + id,
+    method: 'get'
+  })
+}
+
+// 新增投诉消息记录
+export function addMsg(data) {
+  return request({
+    url: '/user/msg',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改投诉消息记录
+export function updateMsg(data) {
+  return request({
+    url: '/user/msg',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除投诉消息记录
+export function delMsg(id) {
+  return request({
+    url: '/user/msg/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出投诉消息记录
+export function exportMsg(query) {
+  return request({
+    url: '/user/msg/export',
+    method: 'get',
+    params: query
+  })
+}

+ 53 - 0
src/api/his/fsFirstDiagnosis.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询初诊单列表
+export function listFsFirstDiagnosis(query) {
+  return request({
+    url: '/his/fsFirstDiagnosis/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询初诊单详细
+export function getFsFirstDiagnosis(id) {
+  return request({
+    url: '/his/fsFirstDiagnosis/' + id,
+    method: 'get'
+  })
+}
+
+// 新增初诊单
+export function addFsFirstDiagnosis(data) {
+  return request({
+    url: '/his/fsFirstDiagnosis',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改初诊单
+export function updateFsFirstDiagnosis(data) {
+  return request({
+    url: '/his/fsFirstDiagnosis',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除初诊单
+export function delFsFirstDiagnosis(id) {
+  return request({
+    url: '/his/fsFirstDiagnosis/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出初诊单
+export function exportFsFirstDiagnosis(query) {
+  return request({
+    url: '/his/fsFirstDiagnosis/export',
+    method: 'get',
+    params: query
+  })
+}

+ 53 - 0
src/api/his/hfpayConfig.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询汇付多支付配置列表
+export function listHfpayConfig(query) {
+  return request({
+    url: '/his/hfpayConfig/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询汇付多支付配置详细
+export function getHfpayConfig(id) {
+  return request({
+    url: '/his/hfpayConfig/' + id,
+    method: 'get'
+  })
+}
+
+// 新增汇付多支付配置
+export function addHfpayConfig(data) {
+  return request({
+    url: '/his/hfpayConfig',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改汇付多支付配置
+export function updateHfpayConfig(data) {
+  return request({
+    url: '/his/hfpayConfig',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除汇付多支付配置
+export function delHfpayConfig(id) {
+  return request({
+    url: '/his/hfpayConfig/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出汇付多支付配置
+export function exportHfpayConfig(query) {
+  return request({
+    url: '/his/hfpayConfig/export',
+    method: 'get',
+    params: query
+  })
+}

+ 9 - 1
src/api/his/patient.js

@@ -9,6 +9,14 @@ export function listPatient(query) {
   })
 }
 
+export function listPatientList(query) {
+  return request({
+    url: '/his/patient/userList',
+    method: 'get',
+    params: query
+  })
+}
+
 // 查询病人详细
 export function getPatient(patientId) {
   return request({
@@ -57,4 +65,4 @@ export function exportPatient(query) {
     method: 'get',
     params: query
   })
-}
+}

+ 8 - 8
src/api/hisStore/city.js

@@ -3,14 +3,14 @@ import request from '@/utils/request'
 // 查询城市列表
 export function listCity(query) {
   return request({
-    url: '/his/city/list',
+    url: '/store/store/city/list',
     method: 'get',
     params: query
   })
 }
 export function getAllList(query) {
   return request({
-    url: '/his/city/getAllList',
+    url: '/store/store/city/getAllList',
     method: 'get',
     params: query
   })
@@ -18,7 +18,7 @@ export function getAllList(query) {
 
 export function getCitys() {
   return request({
-    url: '/his/city/getCitys',
+    url: '/store/store/city/getCitys',
     method: 'get'
   })
 }
@@ -28,7 +28,7 @@ export function getCitys() {
 // 查询城市详细
 export function getCity(id) {
   return request({
-    url: '/his/city/' + id,
+    url: '/store/store/city/' + id,
     method: 'get'
   })
 }
@@ -36,7 +36,7 @@ export function getCity(id) {
 // 新增城市
 export function addCity(data) {
   return request({
-    url: '/his/city',
+    url: '/store/store/city',
     method: 'post',
     data: data
   })
@@ -45,7 +45,7 @@ export function addCity(data) {
 // 修改城市
 export function updateCity(data) {
   return request({
-    url: '/his/city',
+    url: '/store/store/city',
     method: 'put',
     data: data
   })
@@ -54,7 +54,7 @@ export function updateCity(data) {
 // 删除城市
 export function delCity(id) {
   return request({
-    url: '/his/city/' + id,
+    url: '/store/store/city/' + id,
     method: 'delete'
   })
 }
@@ -62,7 +62,7 @@ export function delCity(id) {
 // 导出城市
 export function exportCity(query) {
   return request({
-    url: '/his/city/export',
+    url: '/store/store/city/export',
     method: 'get',
     params: query
   })

+ 54 - 0
src/api/hisStore/recommend.js

@@ -0,0 +1,54 @@
+// src/api/hisStore/storeRecommendScrm.js
+import request from '@/utils/request'
+
+// 查询推荐店铺列表
+export function listRecommendScrm(query) {
+  return request({
+    url: '/store/recommend/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询推荐店铺详细
+export function getRecommendScrm(id) {
+  return request({
+    url: '/store/recommend/' + id,
+    method: 'get'
+  })
+}
+
+// 新增推荐店铺
+export function addRecommendScrm(data) {
+  return request({
+    url: '/store/recommend',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改推荐店铺
+export function updateRecommendScrm(data) {
+  return request({
+    url: '/store/recommend',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除推荐店铺
+export function delRecommendScrm(id) {
+  return request({
+    url: '/store/recommend/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出推荐店铺
+export function exportRecommendScrm(query) {
+  return request({
+    url: '/store/recommend/export',
+    method: 'get',
+    params: query
+  })
+}

+ 10 - 9
src/api/hisStore/store.js

@@ -3,7 +3,7 @@ import request from '@/utils/request'
 // 查询店铺管理列表
 export function listStore(query) {
   return request({
-    url: '/store/store/list',
+    url: '/store/his/store/list',
     method: 'get',
     params: query
   })
@@ -12,7 +12,7 @@ export function listStore(query) {
 // 查询店铺管理详细
 export function getStore(storeId) {
   return request({
-    url: '/store/store/' + storeId,
+    url: '/store/his/store/' + storeId,
     method: 'get'
   })
 }
@@ -21,7 +21,7 @@ export function getStore(storeId) {
 // 新增店铺管理
 export function addStore(data) {
   return request({
-    url: '/his/store',
+    url: '/store/his/store',
     method: 'post',
     data: data
   })
@@ -30,7 +30,7 @@ export function addStore(data) {
 // 修改店铺管理
 export function updateStore(data) {
   return request({
-    url: '/his/store',
+    url: '/store/his/store',
     method: 'put',
     data: data
   })
@@ -38,7 +38,7 @@ export function updateStore(data) {
 // 修改店铺管理
 export function audit(data) {
   return request({
-    url: '/store/store/audit',
+    url: '/store/his/store/audit',
     method: 'put',
     data: data
   })
@@ -46,7 +46,7 @@ export function audit(data) {
 // 删除店铺管理
 export function delStore(storeId) {
   return request({
-    url: '/store/store/' + storeId,
+    url: '/store/his/store/' + storeId,
     method: 'delete'
   })
 }
@@ -61,15 +61,16 @@ export function refreshPasWod(storeId) {
 // 导出店铺管理
 export function exportStore(query) {
   return request({
-    url: '/store/store/export',
+    url: '/store/his/store/export',
     method: 'get',
     params: query
   })
 }
 
-export function getAllStore() {
+//getStoreAuditLog
+export function getStoreAuditLog(storeId) {
   return request({
-    url: '/store/store/storeList',
+    url: '/store/his/store/auditLog/'+ storeId,
     method: 'get'
   })
 }

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

@@ -17,6 +17,14 @@ export function batchModify(param) {
   })
 }
 
+export function batchAudit(param) {
+  return request({
+    url: '/store/store/storeProduct/batchAudit',
+    method: 'post',
+    data: param
+  })
+}
+
 // 查询商品详细
 export function getStoreProduct(productId) {
   return request({

+ 9 - 0
src/api/qw/externalContact.js

@@ -51,3 +51,12 @@ export function exportExternalContact(query) {
     params: query
   })
 }
+
+// 导出企业微信客户unionId
+export function exportUnionId(query) {
+  return request({
+    url: '/qw/externalContact/exportUnionId',
+    method: 'get',
+    params: query
+  })
+}

+ 0 - 1
src/components/Material/index.vue

@@ -270,7 +270,6 @@ export default {
       this.materialGroupLoading = true;
       getAllMaterialGroup({}).then(response => {
         this.materialGroupList = response.data
-        console.log(this.materialGroupList)
         this.materialGroupLoading = false;
       });
     },

+ 0 - 1
src/components/Material/single.vue

@@ -261,7 +261,6 @@ export default {
       this.materialGroupLoading = true;
       getAllMaterialGroup({}).then(response => {
         this.materialGroupList = response.data
-        console.log(this.materialGroupList)
         this.materialGroupLoading = false;
       });
     },

+ 92 - 87
src/utils/cos.js

@@ -1,97 +1,102 @@
-import COS from 'cos-js-sdk-v5';
-import { Message } from 'element-ui';
-import { getTmpSecretKey } from '@/api/common';
+import COS from "cos-js-sdk-v5"
+import { getTmpSecretKey } from "@/api/common"
 
-console.log('环境变量:', process.env);
-console.log('NODE_ENV:', process.env.NODE_ENV);
-console.log('VUE_APP_COS_BUCKET:', process.env.VUE_APP_COS_BUCKET);
-console.log('VUE_APP_COS_REGION:', process.env.VUE_APP_COS_REGION);
+console.log("环境变量:", process.env)
+console.log("NODE_ENV:", process.env.NODE_ENV)
+console.log("VUE_APP_COS_BUCKET:", process.env.VUE_APP_COS_BUCKET)
+console.log("VUE_APP_COS_REGION:", process.env.VUE_APP_COS_REGION)
 
 const config = {
   Bucket: process.env.VUE_APP_COS_BUCKET,
   Region: process.env.VUE_APP_COS_REGION,
-};
-console.log('COS配置:', config);
+}
+console.log("COS配置:", config)
 
-// 上传到腾讯云cos
-export const uploadObject = async (file,onProgress,type,callBackUp) => {
-    try {
-        console.log(type);
-        const response = await getTmpSecretKey(); // 后台接口返回 密钥相关信息
-        console.log("Key  ",response);
-        const data = response.data;
-        const credentials = data && data.credentials;
+export const uploadObject = async (file, onProgress, type, callBackUp) => {
+  try {
+    console.log(type)
+    const response = await getTmpSecretKey()
+    console.log("Key  ", response)
+    const data = response.data
+    const credentials = data && data.credentials
 
-        if (!data || !credentials) {
-            console.error('未获取到参数');
-            return;
-        }
+    if (!data || !credentials) {
+      console.error("未获取到参数")
+      return
+    }
+
+    const cos = new COS({
+      Timeout: 1200 * 1000,
+      getAuthorization: (options, callback) => {
+        callback({
+          TmpSecretId: credentials.tmpSecretId,
+          TmpSecretKey: credentials.tmpSecretKey,
+          XCosSecurityToken: credentials.sessionToken,
+          StartTime: data.startTime,
+          ExpiredTime: data.expiredTime,
+        })
+      },
+    })
 
-        // 初始化
-        const cos = new COS({
-            Timeout: 1200 * 1000,
-            getAuthorization: (options, callback) => {
-                callback({
-                    TmpSecretId: credentials.tmpSecretId,
-                    TmpSecretKey: credentials.tmpSecretKey,
-                    XCosSecurityToken: credentials.sessionToken,
-                    StartTime: data.startTime,
-                    ExpiredTime: data.expiredTime,
-                });
-            },
-        });
+    console.log("初始化成功")
+    const fileName = file.name || ""
+    const upload_file_name = new Date().getTime() + "." + fileName.split(".")[fileName.split(".").length - 1]
+    const date = new Date()
+    const year = date.getFullYear()
+    const month = date.getMonth() + 1
+    const strDate = date.getDate()
+    const uploadDay = `${year}${month}${strDate}`
+    const videoKey = `/userVideo/${uploadDay}/${upload_file_name}`
+    const courseKey = `/course/${uploadDay}/${upload_file_name}`
+    const key = type === 1 ? courseKey : videoKey
+    console.log("开始上传")
 
-        console.log("初始化成功")
-        let fileName = file.name || ""
-        const upload_file_name = new Date().getTime() + '.' + fileName.split(".")[fileName.split(".").length - 1];
-        let date =  new Date()
-        let year = date.getFullYear()
-        let month = date.getMonth() + 1
-        let strDate = date.getDate()
-        let uploadDay = `${year}${month}${strDate}`
-        let videoKey = `/userVideo/${uploadDay}/${upload_file_name}`
-        let courseKey = `/course/${uploadDay}/${upload_file_name}`
-        let key = type ===1 ? courseKey : videoKey;
-        console.log("开始上传")
-        return new Promise((resolve, reject) => {
-            console.log("uploadFile")
-            cos.uploadFile(
-                {
-                    Bucket: config.Bucket, /* 必须 */
-                    Region: config.Region, /* 存储桶所在地域,必须字段 */
-                    Key: key, // 文件名
-                    StorageClass: 'STANDARD', // 上传类型,可选
-                    Body: file, // 上传文件对象
-                    // onTaskReady: function (taskId) {
-                    //     // 用于中断分片上传回调
-                    //     console.log('Task ready:', taskId);
-                    //     callBackUp && callBackUp({cos,taskId})
-                    // },
-                    onProgress: function (progressData) {
-                        console.log('COS上传进度=======>:', JSON.stringify(progressData));
-                        onProgress(progressData);
-                    },
-                    // onFileFinish: function (err, data, options) {
-                    //     console.log(options.Key + '上传' + (err ? '失败' : '完成'));
-                    // },
+    return new Promise((resolve, reject) => {
+      console.log("uploadFile")
+      let taskId = null
+
+      const uploadTask = cos.uploadFile(
+        {
+          Bucket: config.Bucket,
+          Region: config.Region,
+          Key: key,
+          StorageClass: "STANDARD",
+          Body: file,
+          onTaskReady: (id) => {
+            taskId = id
+            console.log("Task ready:", taskId)
+            if (callBackUp) {
+              callBackUp({
+                cos,
+                taskId,
+                cancel: () => {
+                  console.log("Cancelling COS upload:", taskId)
+                  cos.cancelTask(taskId)
+                  reject(new Error("Upload cancelled by user"))
                 },
-                (err, data) => {
-                    if (err) {
-                        reject(err);
-                    } else {
-                        // 将上传的key包含在返回的数据中
-                        const result = {
-                            ...data,
-                            urlPath: key
-                        };
-                        console.log('上传成功', result);
-                        resolve(result);
-                    }
-                }
-            );
-        });
-    } catch (error) {
-        console.error('Error during upload:', error);
-        throw error;
-    }
-};
+              })
+            }
+          },
+          onProgress: (progressData) => {
+            onProgress(progressData)
+          },
+        },
+        (err, data) => {
+          if (err) {
+            reject(err)
+          } else {
+            const result = {
+              ...data,
+              urlPath: key,
+            }
+            console.log("上传成功", result)
+            resolve(result)
+          }
+        },
+      )
+    })
+  } catch (error) {
+    console.error("Error during upload:", error)
+    throw error
+  }
+}

+ 69 - 52
src/utils/obs.js

@@ -1,56 +1,73 @@
-import ObsClient from "esdk-obs-browserjs/src/obs";
+import ObsClient from "esdk-obs-browserjs/src/obs"
 
+export const uploadToOBS = async (file, progressCallback, type, cancelCallback) => {
+  try {
+    const obsClient = new ObsClient({
+      access_key_id: process.env.VUE_APP_OBS_ACCESS_KEY_ID,
+      secret_access_key: process.env.VUE_APP_OBS_SECRET_ACCESS_KEY,
+      server: process.env.VUE_APP_OBS_SERVER,
+      timeout: 1200,
+    })
 
-export const uploadToOBS = async(file,progressCallback,type) =>  {
-    try {
-        const obsClient = new ObsClient({
-          access_key_id: process.env.VUE_APP_OBS_ACCESS_KEY_ID,
-          secret_access_key: process.env.VUE_APP_OBS_SECRET_ACCESS_KEY,
-          server: process.env.VUE_APP_OBS_SERVER,
-          timeout: 1200,
-        });
-        let fileName = file.name || ""
-        const upload_file_name = new Date().getTime() + '.' + fileName.split(".")[fileName.split(".").length - 1];
-        let date =  new Date()
-        let year = date.getFullYear()
-        let month = date.getMonth() + 1
-        let strDate = date.getDate()
-        let uploadDay = `${year}${month}${strDate}`
-        let videoKey = `userVideo/${uploadDay}/${upload_file_name}`
-        let courseKey = `course/${uploadDay}/${upload_file_name}`
-        let key = type ===1 ? courseKey : videoKey;
-        var callback = function (transferredAmount, totalAmount, totalSeconds) {
-            // 获取上传进度百分比
-            const progress = parseInt(transferredAmount * 100.0 / totalAmount);
-            console.log("OBS上传进度=========>",progress);
-            if (progressCallback) {
-              progressCallback(progress);
-            }
-          };
-        return new Promise((resolve, reject) => {
-            //上传对象
-            obsClient.putObject({
-                Bucket: process.env.VUE_APP_OBS_BUCKET,//桶名称
-                Key: key,//文件名
-                Body: file,
-                ProgressCallback: callback,//进度回调
-            }, (err, result) => {
-                if(err){
-                    reject(err);
-                    console.error('Error-->' + err);
-                }else{
-                  // 将上传的key包含在返回的数据中
-                  const a = {
-                    ...result,
-                    urlPath: key
-                  };
-                  console.log('上传成功', a);
-                  resolve(a);
-                }
-            });
-        });
-    } catch (error) {
-        console.error('Error during upload:', error);
-        throw error;
+    const fileName = file.name || ""
+    const upload_file_name = new Date().getTime() + "." + fileName.split(".")[fileName.split(".").length - 1]
+    const date = new Date()
+    const year = date.getFullYear()
+    const month = date.getMonth() + 1
+    const strDate = date.getDate()
+    const uploadDay = `${year}${month}${strDate}`
+    const videoKey = `userVideo/${uploadDay}/${upload_file_name}`
+    const courseKey = `course/${uploadDay}/${upload_file_name}`
+    const key = type === 1 ? courseKey : videoKey
+
+    var callback = (transferredAmount, totalAmount, totalSeconds) => {
+      const progress = Number.parseInt((transferredAmount * 100.0) / totalAmount)
+      if (progressCallback) {
+        progressCallback(progress)
+      }
     }
+
+    return new Promise((resolve, reject) => {
+      let isCancelled = false
+
+      if (cancelCallback) {
+        cancelCallback({
+          cancel: () => {
+            console.log("Cancelling OBS upload")
+            isCancelled = true
+            reject(new Error("Upload cancelled by user"))
+          },
+        })
+      }
+
+      obsClient.putObject(
+        {
+          Bucket: process.env.VUE_APP_OBS_BUCKET,
+          Key: key,
+          Body: file,
+          ProgressCallback: callback,
+        },
+        (err, result) => {
+          if (isCancelled) {
+            return // Don't process result if cancelled
+          }
+
+          if (err) {
+            reject(err)
+            console.error("Error-->" + err)
+          } else {
+            const a = {
+              ...result,
+              urlPath: key,
+            }
+            console.log("上传成功", a)
+            resolve(a)
+          }
+        },
+      )
+    })
+  } catch (error) {
+    console.error("Error during upload:", error)
+    throw error
+  }
 }

+ 350 - 0
src/views/company/companyTraffic/index.vue

@@ -0,0 +1,350 @@
+<template>
+  <div class="app-container">
+    <!-- 查询条件 -->
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+      <el-form-item label="公司名称">
+        <!-- 修改为多选搜索框 -->
+        <el-select
+          v-model="queryParams.companyIds"
+          multiple
+          filterable
+          remote
+          reserve-keyword
+          placeholder="请输入公司名称搜索"
+          :remote-method="searchCompanies"
+          :loading="companySearchLoading"
+          style="width: 220px"
+          clearable
+          size="small"
+        >
+          <el-option
+            v-for="item in companyOptions"
+            :key="item.dictValue"
+            :label="item.dictLabel"
+            :value="item.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-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="handleRecharge"
+          v-hasPermi="['company:traffic:charge']"
+        >流量充值</el-button>
+      </el-col>
+
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <!-- 数据表格 -->
+    <el-table v-loading="loading" :data="trafficRecordList" @selection-change="handleSelectionChange">
+
+      <el-table-column label="公司名称" align="center" prop="companyName" :show-overflow-tooltip="true" />
+
+      <el-table-column label="流量余额" align="center" prop="balance" :formatter="formatBalance"/>
+
+<!--      <el-table-column label="操作人员" align="center" prop="createBy" />
+
+      <el-table-column label="操作时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</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-money"
+            @click="handleRechargeCompany(scope.row)"
+            v-hasPermi="['company:traffic:charge']"
+          >充值</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="rechargeTitle" :visible.sync="rechargeOpen" width="500px" append-to-body :before-close="resetOption">
+      <el-form ref="rechargeForm" :model="rechargeForm" :rules="rechargeRules" label-width="100px">
+
+        <el-form-item label="公司ID" prop="companyId" v-show="!isCompanyRecharge">
+          <el-select
+            v-model="rechargeForm.companyId"
+            filterable
+            remote
+            placeholder="请输入公司名称搜索"
+            :remote-method="searchCompanies"
+            :loading="companySearchLoading"
+            @change="syncCompanyName"
+            style="width: 220px"
+            clearable
+            size="small"
+          >
+            <el-option
+              v-for="item in companyOptions"
+              :key="item.dictValue"
+              :label="item.dictValue"
+              :value="item.dictValue"
+            >
+            <span style="float: left">{{ item.dictValue }}</span>
+            <span style="margin-left: 30px">{{ item.dictLabel }}</span>
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="公司名称" prop="companyName">
+          <el-input v-model="rechargeForm.companyName" placeholder="请输入公司名称" size="small" disabled/>
+        </el-form-item>
+
+
+        <el-form-item label="充值金额" prop="chargeAmount">
+          <el-input-number
+            v-model="rechargeForm.chargeAmount"
+            :min="1"
+            :max="999999999"
+            placeholder="请输入充值金额(元)"
+            controls-position="right"
+            style="width: 100%"
+          />
+        </el-form-item>
+
+        <el-form-item label="备注" prop="remark">
+          <el-input
+            v-model="rechargeForm.remark"
+            type="textarea"
+            placeholder="请输入备注"
+            :rows="3"
+          />
+        </el-form-item>
+      </el-form>
+
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitRechargeForm">确 定</el-button>
+        <el-button @click="cancelRecharge">取 消</el-button>
+      </div>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+import { listTrafficRecords, rechargeTraffic } from "@/api/company/traffic";
+import { allList } from '@/api/company/company'
+import { resetForm } from '@/utils/common'
+import { delAdIqiyiAccount } from '@/api/ad/AdIqiyiAccount'
+
+export default {
+  name: "CompanyTraffic",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 流量记录表格数据
+      trafficRecordList: [],
+      // 弹出层标题
+      rechargeTitle: "",
+      // 是否显示充值弹出层
+      rechargeOpen: false,
+      // 公司搜索相关
+      companySearchLoading: false,
+      companyOptions: [],
+      isCompanyRecharge: false,
+
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        companyName: null,
+        companyIds: [], // 修改为数组
+        createTimeStart: null,
+        createTimeEnd: null
+      },
+      // 流量充值表单参数(保持不变)
+      rechargeForm: {
+        companyId: null,
+        companyName: null,
+        chargeAmount: null,
+        remark: null
+      },
+      // 流量详情数据
+      detailData: {},
+      // 表单校验(保持不变)
+      rechargeRules: {
+        companyId: [
+          { required: true, message: "公司ID不能为空", trigger: "blur" }
+        ],
+        chargeAmount: [
+          { required: true, message: "充值金额不能为空", trigger: "blur" },
+          { type: "number", min: 1, message: "充值金额必须大于0", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    resetForm,
+    resetOption(){
+      this.rechargeOpen = false;
+      this.companyOptions = [];
+      this.rechargeForm = {};
+    },
+    /** 查询流量记录列表 */
+    getList() {
+      this.loading = true;
+
+      listTrafficRecords(this.queryParams).then(response => {
+        this.trafficRecordList = response.rows;
+        console.log(this.trafficRecordList)
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    /** 搜索公司 */
+    searchCompanies( query) {
+      allList().then(response => {
+        this.companyOptions = response.rows.filter(item => item.dictLabel.includes(query));
+        this.companySearchLoading = false;
+      }).catch(()=>{
+        this.companySearchLoading = false;
+      });
+    },
+    syncCompanyName(){
+      if(!this.rechargeForm.companyId){
+        this.rechargeForm.companyName = null;
+      }
+      this.rechargeForm.companyName = this.companyOptions.filter(item => item.dictValue === this.rechargeForm.companyId)[0].dictLabel;
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.rechargeForm = {};
+      this.handleQuery();
+    },
+
+    formatBalance(row){
+      //对流量值进行判断,换算成GB或TB
+      if(!row.balance){
+        return "0KB";
+      }
+      if(row.balance < 1024){
+        return row.balance + "KB";
+      }
+      else if(row.balance < 1024 * 1024){
+        return (row.balance / 1024).toFixed(2) + "MB";
+      }
+      else if(row.balance < 1024 * 1024 * 1024){
+        return (row.balance / (1024 * 1024)).toFixed(2) + "GB";
+      }
+      else{
+        return (row.balance / (1024 * 1024 * 1024)).toFixed(2) + "TB";
+      }
+    },
+
+    /** 多选框选中数据 */
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+
+    /** 流量充值按钮操作 */
+    handleRecharge() {
+      this.rechargeTitle = "流量充值";
+      this.resetForm("rechargeForm");
+      this.rechargeForm = {};
+      this.companyOptions = [];
+      this.isCompanyRecharge = false;
+      this.rechargeForm.operationType = 1; // 默认充值
+      this.rechargeOpen = true;
+    },/** 流量充值按钮操作 */
+    handleRechargeCompany(row) {
+      this.rechargeTitle = "流量充值";
+      this.resetForm("rechargeForm");
+      this.rechargeForm = {};
+      this.companyOptions = [];
+      this.isCompanyRecharge = true;
+      this.rechargeForm.companyId = row.companyId;
+      this.rechargeForm.companyName = row.companyName;
+      this.rechargeForm.operationType = 1; // 默认充值
+      this.rechargeOpen = true;
+    },
+
+    /** 提交流量充值 */
+    submitRechargeForm() {
+      this.$refs["rechargeForm"].validate(valid => {
+        if (valid) {
+          //添加confirm提示
+          this.$confirm('确定要为 '+this.rechargeForm.companyName+' 充值 '+this.rechargeForm.chargeAmount+' 元吗?', '提示', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning'
+          }).then(() => {
+            return rechargeTraffic(this.rechargeForm);
+          }).then(response => {
+            if(response.code === 200){
+              this.msgSuccess("充值成功");
+            }else{
+              this.msgError(response.msg);
+            }
+            this.rechargeOpen = false;
+            this.getList();
+          }).catch(() => {});
+        }
+      });
+    },
+
+    /** 取消充值 */
+    cancelRecharge() {
+      this.rechargeOpen = false;
+      this.resetForm("rechargeForm");
+      this.rechargeForm = {};
+    }
+  }
+};
+</script>
+
+<style scoped>
+
+.mb8 {
+  margin-bottom: 8px;
+}
+</style>

+ 276 - 0
src/views/company/companyTrafficLog/index.vue

@@ -0,0 +1,276 @@
+<template>
+  <div class="app-container">
+    <!-- 查询条件 -->
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+      <el-form-item label="公司名称">
+        <el-select
+          v-model="queryParams.companyIds"
+          multiple
+          filterable
+          remote
+          reserve-keyword
+          placeholder="请输入公司名称搜索"
+          :remote-method="searchCompanies"
+          :loading="companySearchLoading"
+          style="width: 220px"
+          clearable
+          size="small"
+        >
+          <el-option
+            v-for="item in companyOptions"
+            :key="item.dictValue"
+            :label="item.dictLabel"
+            :value="item.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="操作类型">
+        <el-select v-model="queryParams.operationType" placeholder="请选择操作类型" clearable size="small">
+          <el-option label="充值" :value="1"></el-option>
+          <el-option label="扣费" :value="2"></el-option>
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="操作人员">
+        <el-input
+          v-model="queryParams.userName"
+          placeholder="请输入操作人员"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="操作时间">
+        <el-date-picker
+          v-model="dateRange"
+          size="small"
+          style="width: 240px"
+          value-format="yyyy-MM-dd HH:mm:ss"
+          type="datetimerange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+        ></el-date-picker>
+      </el-form-item>
+
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 操作按钮区域 -->
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['company:trafficLog:export']"
+        >导出</el-button>
+      </el-col>
+
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <!-- 数据表格 -->
+    <el-table v-loading="loading" :data="trafficRecordList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+
+      <el-table-column label="公司名称" align="center" prop="companyName" :show-overflow-tooltip="true" :formatter="companyNameFormatter"/>
+
+      <el-table-column label="操作类型" align="center" prop="operationType">
+        <template slot-scope="scope">
+          <el-tag :type="scope.row.operationType === 1 ? 'success' : 'danger'">
+            {{ scope.row.operationType === 1 ? '充值' : '扣费' }}
+          </el-tag>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="流量数量(KB)" align="center" prop="trafficAmount">
+        <template slot-scope="scope">
+          <span :class="scope.row.operationType === 1 ? 'recharge' : 'deduction'">
+            {{ scope.row.operationType === 1 ? '+' : '-' }}{{ scope.row.trafficAmount }}
+          </span>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="操作后余额(KB)" align="center" prop="balance" />
+
+      <el-table-column label="操作人员" align="center" prop="userName" />
+
+      <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
+
+      <el-table-column label="操作时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页 -->
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { listTrafficLog, listTrafficLogExport } from "@/api/company/trafficLog";
+import { allList } from '@/api/company/company'
+
+export default {
+  name: "CompanyTrafficLog",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 流量记录表格数据
+      trafficRecordList: [],
+      // 日期范围
+      dateRange: [],
+      // 公司搜索相关
+      companySearchLoading: false,
+      companyOptions: [],
+      formatterCompanyOptions: [],
+
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        companyName: null,
+        companyId: null,
+        companyIds: [], // 多选公司ID
+        operationType: null,
+        userName: null,
+        createTime: null,
+        createTimeStart: null,
+        createTimeEnd: null
+      }
+    };
+  },
+  created() {
+    this.getList();
+    //初始化formatterCompanyOptions
+    allList().then(e => {
+      this.formatterCompanyOptions = e.rows;
+    });
+  },
+  methods: {
+    /** 查询流量记录列表 */
+    getList() {
+      this.loading = true;
+      // 处理日期范围
+      if (this.dateRange && this.dateRange.length === 2) {
+        this.queryParams.createTimeStart = this.dateRange[0];
+        this.queryParams.createTimeEnd = this.dateRange[1];
+      } else {
+        this.queryParams.createTimeStart = null;
+        this.queryParams.createTimeEnd = null;
+      }
+
+      listTrafficLog(this.queryParams).then(response => {
+        this.trafficRecordList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+
+    /** 搜索公司 */
+    searchCompanies(query) {
+      this.companySearchLoading = true;
+      allList().then(response => {
+        this.companyOptions = response.rows;
+        if (query) {
+          this.companyOptions = this.companyOptions.filter(item =>
+            item.dictLabel.includes(query)
+          );
+        }
+        this.companySearchLoading = false;
+      }).catch(()=>{
+        this.companySearchLoading = false;
+      });
+    },
+
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+
+    /** 多选框选中数据 */
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+
+    companyNameFormatter(row){
+      return this.formatterCompanyOptions.filter(item => item.dictValue === row.companyId)[0].dictLabel
+    },
+
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = {...this.queryParams};
+      // 处理日期范围
+      if (this.dateRange && this.dateRange.length === 2) {
+        queryParams.createTimeStart = this.dateRange[0];
+        queryParams.createTimeEnd = this.dateRange[1];
+      }
+      this.$confirm('是否确认导出所有流量充值记录数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return listTrafficLogExport(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
+
+    }
+  }
+};
+</script>
+
+<style scoped>
+.recharge {
+  color: #67C23A;
+  font-weight: bold;
+}
+
+.deduction {
+  color: #F56C6C;
+  font-weight: bold;
+}
+
+.mb8 {
+  margin-bottom: 8px;
+}
+</style>

+ 0 - 1
src/views/components/his/inquiryOrderDetails.vue

@@ -556,7 +556,6 @@ import { js } from "js-beautify";
           content:'',
           advice:'',
         })
-        let ak = this.patientForm.doctorAdviceJson.treatmentAdvice.filter(obj => obj.content != '');
       },
       delItem(item,index){
         this.patientForm.doctorAdviceJson.treatmentAdvice.splice(index,1)

+ 9 - 1
src/views/components/his/userPatietDetails.vue

@@ -170,7 +170,15 @@
 </template>
 
 <script>
-import { listPatient, getPatient, delPatient, addPatient, updatePatient, exportPatient } from "@/api/his/patient";
+import {
+  listPatient,
+  getPatient,
+  delPatient,
+  addPatient,
+  updatePatient,
+  exportPatient,
+  listPatientList
+} from '@/api/his/patient'
 import {getUserList} from "@/api/his/doctor";
 export default {
   name: "Patient",

+ 82 - 1
src/views/course/coursePlaySourceConfig/index.vue

@@ -10,6 +10,27 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
+      <el-form-item label="所属公司" prop="companyId">
+        <el-select
+          v-model="queryParams.companyId"
+          filterable
+          remote
+          reserve-keyword
+          placeholder="请输入公司名称搜索"
+          :remote-method="searchCompanies"
+          :loading="companySearchLoading"
+          style="width: 220px"
+          clearable
+          size="small"
+        >
+          <el-option
+            v-for="item in companyOptions"
+            :key="item.dictValue"
+            :label="item.dictLabel"
+            :value="item.dictValue"
+          />
+        </el-select>
+      </el-form-item>
       <el-form-item label="appid" prop="appid">
         <el-input
           v-model="queryParams.appid"
@@ -95,6 +116,7 @@
       <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="companyId" :formatter="companyNameFormatter"/>
       <el-table-column label="图标" align="center" prop="img">
         <template slot-scope="scope">
           <el-image
@@ -152,11 +174,32 @@
     />
 
     <!-- 添加或修改点播配置对话框 -->
-    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
+    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body :before-close="resetOption">
       <el-form ref="form" :model="form" :rules="rules" label-width="130px">
         <el-form-item label="名称" prop="name">
           <el-input v-model="form.name" placeholder="请输入名称" />
         </el-form-item>
+        <el-form-item label="所属公司" prop="companyId">
+          <el-select
+            v-model="form.companyId"
+            filterable
+            remote
+            reserve-keyword
+            placeholder="请输入公司名称搜索"
+            :remote-method="searchCompanies"
+            :loading="companySearchLoading"
+            style="width: 220px"
+            clearable
+            size="small"
+          >
+            <el-option
+              v-for="item in companyOptions"
+              :key="item.dictValue"
+              :label="item.dictLabel"
+              :value="item.dictValue"
+            />
+          </el-select>
+        </el-form-item>
         <el-form-item label="图标" prop="img">
           <image-upload v-model="form.img" :file-type='["png", "jpg", "jpeg"]' :limit="1"/>
         </el-form-item>
@@ -203,12 +246,18 @@
 <script>
 import {list, get, update, add, del} from '@/api/course/coursePlaySourceConfig'
 import {updateIsTownOn} from "@/api/system/config";
+import { allList } from '@/api/company/company'
+import { resetForm } from '@/utils/common'
 
 export default {
   name: 'CoursePlaySourceConfig',
   data() {
     return {
       switchDialogVisible: false,
+      // 公司搜索相关
+      companySearchLoading: false,
+      companyOptions: [],
+      formatterCompanyOptions: [],
       switchForm: {
         appId: '',
         switchStatus: '001',
@@ -234,6 +283,9 @@ export default {
         name: [
           { required: true, message: "名称不能为空", trigger: "blur" }
         ],
+        companyId: [
+          { required: true, message: "所属公司不能为空", trigger: "blur" }
+        ],
         appid: [
           { required: true, message: "appid不能为空", trigger: "blur" }
         ],
@@ -269,9 +321,19 @@ export default {
         listClass: 'primary'}
       })
     });
+    //初始化formatterCompanyOptions
+    allList().then(e => {
+      this.formatterCompanyOptions = e.rows;
+    });
     this.getList();
   },
   methods: {
+    resetForm,
+    resetOption(){
+      console.log(1)
+      this.companyOptions = [];
+      this.open = false;
+    },
 
 
     // 处理开关配置
@@ -283,6 +345,25 @@ export default {
       this.getSwitchConfig(row.appid);
       this.switchDialogVisible = true;
     },
+    /** 搜索公司 */
+    searchCompanies(query) {
+      this.companySearchLoading = true;
+      allList().then(response => {
+        this.companyOptions = response.rows;
+        if (query) {
+          this.companyOptions = this.companyOptions.filter(item =>
+            item.dictLabel.includes(query)
+          );
+        }
+        this.companySearchLoading = false;
+      }).catch(()=>{
+        this.companySearchLoading = false;
+      });
+    },
+    companyNameFormatter(row){
+      let company = this.formatterCompanyOptions.filter(item => item.dictValue === row.companyId)[0];
+      return company ? company.dictLabel : '';
+    },
 
     // 获取开关配置
     getSwitchConfig(appId) {

+ 228 - 95
src/views/course/courseWatchComment/index.vue

@@ -11,6 +11,22 @@
           style="width: 280px"
         />
       </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="操作状态"
+          clearable
+          size="small"
+          style="width: 240px"
+        >
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
         <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
@@ -18,27 +34,27 @@
     </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="['course:courseWatchComment: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="['course:courseWatchComment:edit']"-->
-<!--        >修改</el-button>-->
-<!--      </el-col>-->
+      <!--      <el-col :span="1.5">-->
+      <!--        <el-button-->
+      <!--          type="primary"-->
+      <!--          plain-->
+      <!--          icon="el-icon-plus"-->
+      <!--          size="mini"-->
+      <!--          @click="handleAdd"-->
+      <!--          v-hasPermi="['course:courseWatchComment: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="['course:courseWatchComment:edit']"-->
+      <!--        >修改</el-button>-->
+      <!--      </el-col>-->
       <el-col :span="1.5">
         <el-button
           type="danger"
@@ -66,26 +82,39 @@
 
     <el-table border v-loading="loading" :data="courseWatchCommentList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
-<!--      <el-table-column label="评论id" align="center" prop="commentId" />-->
-<!--      <el-table-column label="用户id" align="center" prop="userId" />-->
+      <!--      <el-table-column label="评论id" align="center" prop="commentId" />-->
+      <!--      <el-table-column label="用户id" align="center" prop="userId" />-->
       <el-table-column label="用户昵称" align="center" prop="nickName" width="130px" />
-<!--      <el-table-column label="用户类型,1-管理员,2-用户" align="center" prop="userType" />-->
-<!--      <el-table-column label="评论类型 1:评论,2:回复" align="center" prop="type" />-->
-<!--      <el-table-column label="父评论id" align="center" prop="parentId" />-->
+      <!--      <el-table-column label="用户类型,1-管理员,2-用户" align="center" prop="userType" />-->
+      <!--      <el-table-column label="评论类型 1:评论,2:回复" align="center" prop="type" />-->
+      <!--      <el-table-column label="父评论id" align="center" prop="parentId" />-->
       <el-table-column label="评论内容" align="center" prop="content" />
       <el-table-column label="所属课程" align="center" prop="courseName" />
       <el-table-column label="所属小节" align="center" prop="title" />
+      <el-table-column label="弹幕状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <el-tag :type="getStatusTagType(scope.row.status)">
+            {{ formatBarrageStatus(scope.row.status) }}
+          </el-tag>
+        </template>
+      </el-table-column>
       <el-table-column label="评论时间" align="center" prop="createTime" width="160px"/>
-<!--      <el-table-column label="是否是撤回的消息,1-是,0-否" align="center" prop="isRevoke" />-->
+      <!--      <el-table-column label="是否是撤回的消息,1-是,0-否" align="center" prop="isRevoke" />-->
       <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="['course:courseWatchComment:edit']"-->
-<!--          >修改</el-button>-->
+          <!--          <el-button-->
+          <!--            size="mini"-->
+          <!--            type="text"-->
+          <!--            icon="el-icon-edit"-->
+          <!--            @click="handleUpdate(scope.row)"-->
+          <!--            v-hasPermi="['course:courseWatchComment:edit']"-->
+          <!--          >修改</el-button>-->
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdateStatus(scope.row)"
+          >修改弹幕状态</el-button>
           <el-button
             size="mini"
             type="text"
@@ -93,11 +122,19 @@
             @click="handleAddKeyWords(scope.row)"
           >添加关键字</el-button>
           <el-button
+            v-if="scope.row.userStatus === 1 "
             size="mini"
             type="text"
             icon="el-icon-edit"
             @click="handleAddBlack(scope.row)"
           >拉黑</el-button>
+          <el-button
+            v-if="scope.row.userStatus === 0 "
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleClearBlack(scope.row)"
+          >解除拉黑</el-button>
           <el-button
             size="mini"
             type="text"
@@ -126,57 +163,86 @@
         <el-button type="primary" @click="submitForm">确 定</el-button>
         <el-button @click="cancel">取 消</el-button>
       </div>
-  </el-dialog>
-<!--    &lt;!&ndash; 添加或修改看课评论对话框 &ndash;&gt;-->
-<!--    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>-->
-<!--      <el-form ref="form" :model="form" :rules="rules" label-width="80px">-->
-<!--        <el-form-item label="用户id" prop="userId">-->
-<!--          <el-input v-model="form.userId" placeholder="请输入用户id" />-->
-<!--        </el-form-item>-->
-<!--        <el-form-item label="用户类型,1-管理员,2-用户" prop="userType">-->
-<!--          <el-select v-model="form.userType" placeholder="请选择用户类型,1-管理员,2-用户">-->
-<!--            <el-option label="请选择字典生成" value="" />-->
-<!--          </el-select>-->
-<!--        </el-form-item>-->
-<!--        <el-form-item label="课程id" prop="courseId">-->
-<!--          <el-input v-model="form.courseId" placeholder="请输入课程id" />-->
-<!--        </el-form-item>-->
-<!--        <el-form-item label="视频id" prop="videoId">-->
-<!--          <el-input v-model="form.videoId" placeholder="请输入视频id" />-->
-<!--        </el-form-item>-->
-<!--        <el-form-item label="评论类型 1:评论,2:回复" prop="type">-->
-<!--          <el-select v-model="form.type" placeholder="请选择评论类型 1:评论,2:回复">-->
-<!--            <el-option label="请选择字典生成" value="" />-->
-<!--          </el-select>-->
-<!--        </el-form-item>-->
-<!--        <el-form-item label="父评论id" prop="parentId">-->
-<!--          <el-input v-model="form.parentId" placeholder="请输入父评论id" />-->
-<!--        </el-form-item>-->
-<!--        <el-form-item label="评论内容" prop="content">-->
-<!--          <el-input v-model="form.content" type="textarea" placeholder="请输入内容" />-->
-<!--        </el-form-item>-->
-<!--        <el-form-item label="是否是撤回的消息,1-是,0-否" prop="isRevoke">-->
-<!--          <el-select v-model="form.isRevoke" placeholder="请选择是否是撤回的消息,1-是,0-否">-->
-<!--            <el-option label="请选择字典生成" value="" />-->
-<!--          </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>-->
+    </el-dialog>
+
+    <el-dialog :title="title" :visible.sync="updateStatus" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="弹幕状态" prop="barrageStatus">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in barrageStatusOptions"
+              :key="dict.dictValue"
+              :label="dict.dictValue"
+              v-if="dict.dictValue !== 2"
+            >
+              <el-tag :type="getStatusTagType(dict.dictValue)" size="small">
+                {{dict.dictLabel}}
+              </el-tag>
+            </el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="updateForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+    <!--    &lt;!&ndash; 添加或修改看课评论对话框 &ndash;&gt;-->
+    <!--    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>-->
+    <!--      <el-form ref="form" :model="form" :rules="rules" label-width="80px">-->
+    <!--        <el-form-item label="用户id" prop="userId">-->
+    <!--          <el-input v-model="form.userId" placeholder="请输入用户id" />-->
+    <!--        </el-form-item>-->
+    <!--        <el-form-item label="用户类型,1-管理员,2-用户" prop="userType">-->
+    <!--          <el-select v-model="form.userType" placeholder="请选择用户类型,1-管理员,2-用户">-->
+    <!--            <el-option label="请选择字典生成" value="" />-->
+    <!--          </el-select>-->
+    <!--        </el-form-item>-->
+    <!--        <el-form-item label="课程id" prop="courseId">-->
+    <!--          <el-input v-model="form.courseId" placeholder="请输入课程id" />-->
+    <!--        </el-form-item>-->
+    <!--        <el-form-item label="视频id" prop="videoId">-->
+    <!--          <el-input v-model="form.videoId" placeholder="请输入视频id" />-->
+    <!--        </el-form-item>-->
+    <!--        <el-form-item label="评论类型 1:评论,2:回复" prop="type">-->
+    <!--          <el-select v-model="form.type" placeholder="请选择评论类型 1:评论,2:回复">-->
+    <!--            <el-option label="请选择字典生成" value="" />-->
+    <!--          </el-select>-->
+    <!--        </el-form-item>-->
+    <!--        <el-form-item label="父评论id" prop="parentId">-->
+    <!--          <el-input v-model="form.parentId" placeholder="请输入父评论id" />-->
+    <!--        </el-form-item>-->
+    <!--        <el-form-item label="评论内容" prop="content">-->
+    <!--          <el-input v-model="form.content" type="textarea" placeholder="请输入内容" />-->
+    <!--        </el-form-item>-->
+    <!--        <el-form-item label="是否是撤回的消息,1-是,0-否" prop="isRevoke">-->
+    <!--          <el-select v-model="form.isRevoke" placeholder="请选择是否是撤回的消息,1-是,0-否">-->
+    <!--            <el-option label="请选择字典生成" value="" />-->
+    <!--          </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 { listCourseWatchComment, delCourseWatchComment, exportCourseWatchComment, addBlack } from "@/api/course/courseWatchComment";
+import { listCourseWatchComment, delCourseWatchComment, exportCourseWatchComment, addBlack,clearBlack,updateBarrageStatus } from "@/api/course/courseWatchComment";
 import { addKeyword } from "@/api/system/keyword";
 
 export default {
   name: "CourseWatchComment",
   data() {
     return {
+      // 弹幕状态选项
+      barrageStatusOptions: [
+        { dictValue: 0, dictLabel: "正常" },
+        { dictValue: 1, dictLabel: "屏蔽" },
+        { dictValue: 2, dictLabel: "人工" }
+      ],
       // 遮罩层
       loading: true,
       // 导出遮罩层
@@ -193,16 +259,21 @@ export default {
       total: 0,
       // 看课评论表格数据
       courseWatchCommentList: [],
+      //下拉状态
+      statusOptions:[],
       // 弹出层标题
       title: "",
       // 是否显示弹出层
       open: false,
+      updateStatus: false,
       // 查询参数
       queryParams: {
         pageNum: 1,
         pageSize: 10,
         keywords: null,
         isAll: true, //判断是否属于全局查询
+        status: '',
+        userStatus: '',
         // userId: null,
         // userType: null,
         // courseId: null,
@@ -223,6 +294,9 @@ export default {
     };
   },
   created() {
+    this.getDicts("sys_barrage_clean_type").then((response) => {
+      this.statusOptions = response.data;
+    });
     this.getList();
   },
   methods: {
@@ -235,9 +309,24 @@ export default {
         this.loading = false;
       });
     },
+    // 获取状态标签类型
+    getStatusTagType(status) {
+      switch(status) {
+        case 0: return 'success';
+        case 1: return 'danger';
+        case 2: return 'primary';
+        default: return 'info';
+      }
+    },
+    // 格式化状态显示
+    formatBarrageStatus(status) {
+      const dict = this.barrageStatusOptions.find(item => item.dictValue === status);
+      return dict ? dict.dictLabel : status;
+    },
     // 取消按钮
     cancel() {
       this.open = false;
+      this.updateStatus = false;
       this.reset();
     },
     // 表单重置
@@ -254,7 +343,9 @@ export default {
         createTime: null,
         updateTime: null,
         isRevoke: null,
-        keyword: null
+        keyword: null,
+        status: '',
+        userStatus: ''
       };
       this.resetForm("form");
     },
@@ -281,6 +372,34 @@ export default {
       this.open = true;
       this.title = "添加到关键字";
     },
+    handleUpdateStatus(row) {
+      this.reset();
+      this.form.status = row.status;
+      this.form.commentId = row.commentId;
+      this.updateStatus = true;
+      this.title = "修改弹幕状态";
+    },
+    /** 解除拉黑用户按钮操作 */
+    handleClearBlack(row) {
+      this.$confirm(`谨慎操作,确定要解除"${row.nickName}"用户拉黑吗`, "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        const data = {
+          fsUserId: row.userId,
+          commentStatus: 0
+        };
+        clearBlack(data).then(response => {
+          this.msgSuccess("操作成功");
+          this.getList(); // 重新加载列表
+        }).catch(() => {
+          this.msgError("操作失败");
+        });
+      }).catch(() => {
+        // 用户取消操作
+      });
+    },
     /** 拉黑用户按钮操作 */
     handleAddBlack(row) {
       this.$confirm(`谨慎操作,确定要拉黑用户"${row.nickName}"吗`, "警告", {
@@ -302,6 +421,20 @@ export default {
         // 用户取消操作
       });
     },
+    updateForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          console.log(this.form)
+          updateBarrageStatus(this.form).then(response => {
+            this.msgSuccess("修改成功");
+            this.updateStatus = false;
+            this.getList();
+          }).catch(() => {
+            this.msgError("修改失败");
+          });
+        }
+      })
+    },
     /** 提交按钮 */
     submitForm() {
       this.$refs["form"].validate(valid => {
@@ -339,30 +472,30 @@ export default {
     handleDelete(row) {
       const commentIds = row.commentId || this.ids;
       this.$confirm('是否确认删除此看课评论?删除后不可恢复', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delCourseWatchComment(commentIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return delCourseWatchComment(commentIds);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
       this.$confirm('是否确认导出当前看课评论数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportCourseWatchComment(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportCourseWatchComment(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     }
   }
 };

文件差異過大導致無法顯示
+ 447 - 245
src/views/course/videoResource/index.vue


+ 340 - 0
src/views/fastGpt/fastGptChatReplaceText/index.vue

@@ -0,0 +1,340 @@
+<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" placeholder="请选择类型" clearable size="small">
+          <el-option
+            v-for="dict in typeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="易错词" prop="content">
+        <el-input
+          v-model="queryParams.content"
+          placeholder="请输入原来的文本"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['fastGpt:fastGptChatReplaceText:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['fastGpt:fastGptChatReplaceText:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['fastGpt:fastGptChatReplaceText:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['fastGpt:fastGptChatReplaceText:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="fastGptChatReplaceTextList" @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="type">
+        <template slot-scope="scope">
+          <dict-tag :options="typeOptions" :value="scope.row.type"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="易错词" align="center" prop="content" />
+      <el-table-column label="替换文本" align="center" prop="changeCount" />
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="排序" align="center" prop="sort" />
+      <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="['fastGpt:fastGptChatReplaceText:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['fastGpt:fastGptChatReplaceText: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="type">
+          <el-select v-model="form.type" placeholder="请选择类型">
+            <el-option
+              v-for="dict in typeOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="parseInt(dict.dictValue)"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="易错词" prop="content">
+          <el-input v-model="form.content" placeholder="请输入易错词" />
+        </el-form-item>
+        <el-form-item label="替换文本" prop="changeCount">
+          <el-input v-model="form.changeCount" placeholder="替换文本" />
+        </el-form-item>
+        <el-form-item label="状态">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="parseInt(dict.dictValue)"
+            >{{dict.dictLabel}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="排序" prop="sort">
+            <el-input-number v-model="form.sort"  :min="0" label="请输入排序"></el-input-number>
+        </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 { listFastGptChatReplaceText, getFastGptChatReplaceText, delFastGptChatReplaceText, addFastGptChatReplaceText, updateFastGptChatReplaceText, exportFastGptChatReplaceText } from "@/api/fastGpt/fastGptChatReplaceText";
+
+export default {
+  name: "FastGptChatReplaceText",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 易错词语表格数据
+      fastGptChatReplaceTextList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 类型字典
+      typeOptions: [],
+      // 状态字典
+      statusOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        type: null,
+        content: null,
+        changeCount: null,
+        status: null,
+        sort: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_fastgpt_chat_replace_words_type").then(response => {
+      this.typeOptions = response.data;
+    });
+    this.getDicts("sys_company_status").then(response => {
+      this.statusOptions = response.data;
+    });
+  },
+  methods: {
+    /** 查询易错词语列表 */
+    getList() {
+      this.loading = true;
+      listFastGptChatReplaceText(this.queryParams).then(response => {
+        this.fastGptChatReplaceTextList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        type: null,
+        content: null,
+        changeCount: null,
+        status: 0,
+        sort: 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
+      getFastGptChatReplaceText(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) {
+            updateFastGptChatReplaceText(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addFastGptChatReplaceText(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 delFastGptChatReplaceText(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有易错词语数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportFastGptChatReplaceText(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 113 - 0
src/views/fastGpt/fastGptKeywordSend/fastGptKeyWordDetails.vue

@@ -0,0 +1,113 @@
+<template>
+    <div style="background-color: #f0f2f5; padding-bottom: 20px; min-height: 100%; " >
+      <div style="padding: 20px; background-color: #fff;">
+        营销指令内容
+      </div>
+      <!-- 使用 el-form 包裹表单项 -->
+      <el-form label-width="120px" style="padding: 20px;">
+        <!-- 发送文字内容 -->
+        <el-form-item label="发送文字内容" >
+          <div class="el-form-item__content readonly-field" style="line-height: 28px;">
+            {{ form.content || '-' }}
+          </div>
+        </el-form-item>
+
+        <!-- 图片访问地址 -->
+        <el-form-item label="图片访问地址">
+          <div class="el-form-item__content readonly-field">
+            <div v-if="form.contentType !== 0 && form.imgUrl && form.imgUrl.trim()">
+              <el-image
+                v-for="(url, index) in form.imgUrl.split(',')"
+                :key="index"
+                :src="url"              style="width: 100px; height: 100px; margin-right: 10px;"
+                fit="cover"
+              >
+                <div slot="error" class="image-slot">
+                  <i class="el-icon-picture-outline"></i>
+                </div>
+              </el-image>
+            </div>
+            <div v-else class="el-form-item__content" style="line-height: 28px;">-</div>
+          </div>
+        </el-form-item>
+      </el-form>
+    </div>
+</template>
+
+<script>
+
+import {getFastGptKeywordSend} from "@/api/fastGpt/fastGptKeywordSend";
+
+  export default {
+    name: "fastGptChatMsgDetails",
+    data() {
+      return {
+        open:false,
+        logsOpen:false,
+        roles:[],
+        msgList:[],
+        item:null,
+        form: {
+          content: '',
+          imgUrl: ''
+        },
+        queryParams: {
+          pageNum: 1,
+          pageSize: 10,
+          keyword: null,
+          content: null,
+          contentType: null,
+          imgUrl: null,
+          status: null,
+          roleId: null,
+          createTime: null,
+        }
+      }
+    },
+
+    methods: {
+      getDetails(id) {
+        getFastGptKeywordSend(id).then(response => {
+          console.log(response);
+          this.form = response.data;
+        });
+      },
+
+      cancel(){
+          this.open = false;
+      }
+    }
+  }
+</script>
+<style>
+  .readonly-field {
+    background-color: #fafafa;
+    padding: 10px;
+    border-radius: 4px;
+  }
+  .contentx{
+      height: 100%;
+      background-color: #fff;
+      padding: 0px 20px 20px;
+
+
+      margin: 20px;
+  }
+  .el-descriptions-item__label.is-bordered-label{
+    font-weight: normal;
+  }
+  .el-descriptions-item__content {
+    max-width: 150px;
+    min-width: 100px;
+  }
+  .desct{
+      padding-top: 20px;
+      padding-bottom: 20px;
+      color: #524b4a;
+      font-weight: bold;
+    }
+  .padding-a{
+    padding-right: 10px;
+
+  }
+</style>

+ 529 - 0
src/views/fastGpt/fastGptKeywordSend/index.vue

@@ -0,0 +1,529 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="88px">
+<!--      <el-form-item label="营销关键字" prop="keyword" style="white-space: nowrap;">
+        <el-input
+          v-model="queryParams.keyword"
+          placeholder="请输入营销关键字"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>-->
+      <el-form-item label="营销关键字" prop="keyword"  style="white-space: nowrap;">
+        <el-select v-model="queryParams.keyword" clearable placeholder="请选择营销关键字">
+          <el-option
+            v-for="dict in keywordOptions"
+            :key="dict.keyword"
+            :label="dict.keyword"
+            :value="dict.keyword"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+     <el-form-item label="发送文字内容" prop="content" style="white-space: nowrap;">
+        <el-input
+          v-model="queryParams.content"
+          placeholder="请输入发送文字内容"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="内容类型" prop="contentType">
+        <el-select v-model="queryParams.contentType" placeholder="请选择内容类型" clearable size="small">
+          <el-option
+            v-for="dict in contentTypeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+<!--      <el-form-item label="客服角色" prop="roleIds">
+        <el-select v-model="queryParams.roleIds" placeholder="请选择客服角色" clearable size="small">
+          <el-option
+            v-for="item in roles"
+            :key="item.roleId"
+            :label="item.roleName"
+            :value="item.roleId"
+          />
+        </el-select>
+      </el-form-item>-->
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['fastGpt:fastGptKeywordSend:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['fastGpt:fastGptKeywordSend:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['fastGpt:fastGptKeywordSend:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['fastGpt:fastGptKeywordSend:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="fastGptKeywordSendList" @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="keyword"/>
+      <el-table-column label="内容类型" align="center" prop="contentType">
+        <template slot-scope="scope">
+          <dict-tag :options="contentTypeOptions" :value="scope.row.contentType"/>
+        </template>
+      </el-table-column>
+<!--      <el-table-column label="图片访问地址" align="center" prop="imgUrl" />-->
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+<!--      <el-table-column label="客服角色" align="center" prop="roleIds">
+        <template slot-scope="scope">
+          {{ getRoleNameById(scope.row.roleIds) }}
+        </template>
+      </el-table-column>-->
+
+      <el-table-column label="创建时间" align="center" prop="createTime" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            @click="handleDetails(scope.row)"
+          >查看</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['fastGpt:fastGptKeywordSend:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['fastGpt:fastGptKeywordSend: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="100px">
+
+        <el-form-item label="营销关键字" prop="keyword">
+          <el-select v-model="form.keyword" placeholder="请选择营销关键字">
+            <el-option
+              v-for="dict in keywordOptions"
+              :key="dict.keyword"
+              :label="dict.keyword"
+              :value="dict.keyword"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="发送内容" prop="content">
+          <el-input
+            type="textarea"
+            :autosize="{ minRows: 2, maxRows: 4}"
+            placeholder="请输入发送内容"
+            v-model="form.content">
+          </el-input>
+        </el-form-item>
+        <el-form-item label="内容类型" prop="contentType">
+          <el-select v-model="form.contentType" placeholder="请选择内容类型">
+            <el-option
+              v-for="dict in contentTypeOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="parseInt(dict.dictValue)"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="图片" prop="imgUrl" v-if="this.form.contentType !== 0">
+          <ImageUpload v-model="form.imgUrl"  type="image" :limit="1" :width="100" :height="100" />
+        </el-form-item>
+        <el-form-item label="状态">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="parseInt(dict.dictValue)"
+            >{{dict.dictLabel}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+<!--        <el-form-item label="客服角色" prop="roleIds">
+          <el-select
+            v-model="form.roleIds"
+            placeholder="请选择客服角色"
+            size="small"
+            multiple
+            filterable
+            clearable
+            :filter-method="filterRoles"
+          >
+            <el-option
+              v-for="item in filteredRoles"
+              :key="item.roleId"
+              :label="item.roleName"
+              :value="item.roleId"/>
+          </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>
+
+    <el-drawer
+      :with-header="false"
+      size="75%"  @close="handleDrawerClose"
+      :title="show.title" :visible.sync="show.open">
+      <fastGptKeyWordDetails  ref="Details" />
+    </el-drawer>
+  </div>
+</template>
+
+<script>
+import {
+  listFastGptKeywordSend,
+  getFastGptKeywordSend,
+  delFastGptKeywordSend,
+  addFastGptKeywordSend,
+  updateFastGptKeywordSend,
+  exportFastGptKeywordSend,
+  keywordList
+} from "@/api/fastGpt/fastGptKeywordSend";
+import ImageUpload from "@/components/ImageUpload/index.vue";
+import fastGptKeyWordDetails from "@/views/fastGpt/fastGptKeywordSend/fastGptKeyWordDetails.vue";
+import { getAllRoleList } from "@/api/fastGpt/fastGptRole";
+
+export default {
+  name: "FastGptKeywordSend",
+  components: {fastGptKeyWordDetails, ImageUpload},
+  data() {
+    return {
+      show:{
+        title:"指令内容",
+        open:false,
+      },
+      roleMap:{},
+      roles:[],
+      filteredRoles: [], // 过滤后的角色数据
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // Ai指令表格数据
+      fastGptKeywordSendList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 关键字内容字典
+      keywordOptions: [],
+      // 内容类型字典
+      contentTypeOptions: [],
+      // 状态字典
+      statusOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        keyword: null,
+        content: null,
+        contentType: null,
+        imgUrl: null,
+        status: null,
+        roleIds: [],
+        createTime: null,
+      },
+      // 表单参数
+      form: {roleIds: [],},
+      // 表单校验
+      rules: {
+        keyword: [
+          { required: true, message: "营销关键字不能为空", trigger: "change" }
+        ],
+        content: [
+          // 如果 contentType 不是纯文本类型(比如图文混合),可以动态设置校验规则
+          // 这里假设纯文本内容不需要上传图片
+          { validator: (rule, value, callback) => {
+              const { contentType } = this.form;
+              if (contentType === 0 && !value) {
+                callback(new Error("发送文字内容不能为空"));
+              } else {
+                callback();
+              }
+            },
+            trigger: "blur"
+          }
+        ],
+        imgUrl: [
+          { validator: (rule, value, callback) => {
+              const { contentType } = this.form;
+              if (contentType !== 0 && !value) {
+                callback(new Error("图片不能为空"));
+              } else {
+                callback();
+              }
+            },
+            trigger: "change"
+          }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+    Promise.all([
+      keywordList().then(response => {
+        this.keywordOptions = response.data;
+      }),
+    this.getDicts("sys_fastgpt_keyword_file_type").then(response => {
+      this.contentTypeOptions = response.data;
+    }),
+    this.getDicts("sys_fastgpt_keyword_send_status").then(response => {
+      this.statusOptions = response.data;
+    }),
+      getAllRoleList().then(response => {
+        this.roles = response.data;
+        this.filteredRoles = response.data;
+        // 生成角色映射表
+        this.roleMap = response.data.reduce((map, role) => {
+          map[role.roleId] = role.roleName;
+          return map;
+        }, {});
+      })
+    ])
+  },
+  methods: {
+    /** 查询Ai指令列表 */
+    getList() {
+      this.loading = true;
+      listFastGptKeywordSend(this.queryParams).then(response => {
+        this.fastGptKeywordSendList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 添加过滤方法
+    filterRoles(query) {
+      this.filteredRoles = this.roles.filter(item =>
+        item.roleName.toLowerCase().includes(query.toLowerCase())
+      );
+    },
+    // 获取角色名
+    getRoleNameById(roleIds) {
+      if (!roleIds) return '-';
+
+      // 确保 roleIds 是数组
+      const idArray = Array.isArray(roleIds) ? roleIds : roleIds.split(',').map(id => id.trim());
+      return idArray
+        .map(id => this.roleMap[id])
+        .filter(name => name)
+        .join('、');
+    },
+    //查看按钮
+    handleDetails(row){
+      this.show.open=true;
+      setTimeout(() => {
+        this.$refs.Details.getDetails(row.id);
+      }, 500);
+    },
+
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      getAllRoleList().then(response => {
+        this.roles = response.data;
+        this.filteredRoles = response.data;
+      });
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        keyword: null,
+        content: null,
+        contentType: null,
+        imgUrl: null,
+        status: 0,
+        roleIds: [],
+        createTime: null
+      };
+      this.resetForm("form");
+
+    },
+    //关闭
+    handleDrawerClose(){
+      this.getList();
+    },
+    /** 搜索按钮操作 */
+    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;
+      getFastGptKeywordSend(id).then(response => {
+        const data = response.data;
+        this.form = {
+          ...data,
+          roleIds: data.roleIds ? data.roleIds.split(',').map(Number) : [] // 确保转为 number[]
+        };
+        this.open = true;
+        this.title = "修改Ai指令";
+        this.$nextTick(() => {
+          this.$forceUpdate(); // 强制更新 el-select 的绑定
+        });
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          // 提取 roleIds 数组中的 roleId 字段组成字符串
+          this.form.roleIds = this.form.roleIds.join(',');
+          if (this.form.id != null) {
+            updateFastGptKeywordSend(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addFastGptKeywordSend(this.form).then(response => {
+              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 delFastGptKeywordSend(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有Ai指令数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportFastGptKeywordSend(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
+    }
+  }
+};
+</script>
+<style scoped>.el-form-item__content {
+  white-space: nowrap;
+}
+</style>

+ 333 - 0
src/views/fastGpt/fastgptEventLogTotal/index.vue

@@ -0,0 +1,333 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="公司名" prop="companyId">
+        <select-tree
+          v-model="selectedCompanyList"
+          :raw-data="deptList"
+          placeholder="请选择销售"
+          :parentSelectable="true"
+          :multiple="true"
+          component-width="300px"
+          :max-display-tags="3"
+          :check-strictly="false"
+          :return-leaf-only="false"
+          @change="handleMultiChange"
+        ></select-tree>
+      </el-form-item>
+      <el-form-item label="销售" prop="nickName" v-if="queryParams.companyId">
+        <el-select v-model="queryParams.companyUserId" remote
+                   placeholder="请选择"
+                   filterable clearable
+                   style="width: 100%;"
+                   @keyup.enter.native="handleQuery"
+                   @change="handleCompanyUserId"
+        >
+          <el-option
+            v-for="dict in companyUserList"
+            :key="`${dict.nickName} - ${dict.userName}`"
+            :label="`${dict.nickName} - ${dict.userName}`"
+            :value="dict.userId">
+          </el-option>
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="AppKey" prop="appKey">
+        <div style="display: flex; align-items: center;">
+          <tree-select
+            v-model="selectedAppKey"
+            :options="appKeyOptions"
+            :normalizer="normalizer"
+            :disable-branch-nodes="false"
+            placeholder="请选择 AppKey"      style="width: 300px;"
+            @input="handleAppKeyChange"
+          />
+        </div>
+      </el-form-item>
+
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker v-model="createTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"  @change="changeTime"></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="fastgptEventLogTotalList" :row-class-name="() => 'fixed-bottom-row'"
+              @selection-change="handleSelectionChange" :max-height="600">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="角色名称" align="center" prop="roleName" />
+      <el-table-column label="时间" align="center" prop="statTime" />
+      <el-table-column
+        v-for="dict in typeOptions"
+        :key="dict.dictValue"
+        :label="dict.dictLabel"
+        align="center">
+        <template slot-scope="scope">
+          <span>{{ scope.row.typeCountMap ? scope.row.typeCountMap[dict.dictValue] : '' }}</span>
+          <span v-if="dict.dictValue !== '11'"
+                :style="{ fontSize: '12px', marginLeft: '5px',
+                color: getPercentageColor((scope.row.typeCountMap[dict.dictValue] / scope.row.typeCountMap[2]) * 100) }">
+            ({{ ((scope.row.typeCountMap[dict.dictValue] / scope.row.typeCountMap[2]) * 100).toFixed(2) }}%)
+          </span>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { listFastgptEventLogTotal, getFastgptEventLogTotal, delFastgptEventLogTotal, addFastgptEventLogTotal, updateFastgptEventLogTotal, exportFastgptEventLogTotal, getFastGptRoleAppKeyList} from "@/api/fastGpt/fastgptEventLogTotal";
+import SelectTree from "@/components/TreeSelect/index.vue";
+import {getDeptData} from "@/api/system/employeeStats";
+import TreeSelect from '@riophae/vue-treeselect'
+import '@riophae/vue-treeselect/dist/vue-treeselect.css'
+
+
+
+export default {
+  name: "FastgptEventLogTotal",
+  components: {SelectTree,TreeSelect},
+  data() {
+    return {
+      createTime:null,
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      selectedCompanyList: [],
+      deptList: [],
+      companyUserList: [],
+      selectedAppKey: null,
+      selectedAppKeyLabel: '',
+      appKeyOptions: [],
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // ai事件埋点统计表格数据
+      fastgptEventLogTotalList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      typeCountMap: null,
+      // 日志类型字典
+      typeOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        roleId: null,
+        count: null,
+        type: null,
+        companyId: null,
+        companyUserId: null,
+        qwUserId: null,
+        typeCountMap: null,
+        beginTime:null,
+        endTime:null,
+        appKey:null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_fastgpt_event_log_type").then(response => {
+      this.typeOptions = response.data;
+    });
+
+    getDeptData().then(response => {
+      this.deptList = response.data;
+    });
+    getFastGptRoleAppKeyList().then(res => {
+      this.appKeyOptions = res.data.map(item => ({
+        id: `p_${item.roleId}`,
+        label: item.roleName,
+        children: (item.roleList || []).map(child => ({
+          id: `c_${child.roleId}`,
+          label: child.roleName,
+          parentId: `p_${item.roleId}`, // 记录父节点 ID
+          parentLabel: item.roleName,   // 记录父节点 label
+          disabled: true
+        }))
+      }));
+    });
+
+  },
+  methods: {
+    /** 查询ai事件埋点统计列表 */
+    getList() {
+      this.loading = true;
+      if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
+        this.queryParams.userIds = this.selectedCompanyList;
+      }else {
+        this.queryParams.userIds = [];
+      }
+
+      listFastgptEventLogTotal(this.queryParams).then(response => {
+        console.log(response)
+        this.fastgptEventLogTotalList = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    normalizer(node) {
+      return {
+        id: node.id,
+        label: node.label,
+        children: node.children,
+        disabled: node.disabled
+      }
+    },
+    handleAppKeyChange(value) {
+      const node = this.findNodeById(this.appKeyOptions, value);
+      if (!node) {
+        this.selectedAppKeyLabel = '';
+        return;
+      }
+
+      // 如果是子节点,则找父节点 label
+      if (node.parentLabel) {
+        this.queryParams.appKey = node.parentLabel;
+        this.selectedAppKeyLabel = node.parentLabel;
+        this.selectedAppKey = this.selectedAppKeyLabel;
+      } else {
+        this.queryParams.appKey = node.label;
+        this.selectedAppKeyLabel = node.label;
+        this.selectedAppKey = this.selectedAppKeyLabel;
+      }
+    },
+    findNodeById(nodes, id) {
+      for (const node of nodes) {
+        if (node.id === id) return node;
+        if (node.children) {
+          const found = this.findNodeById(node.children, id);
+          if (found) return found;
+        }
+      }
+      return null;
+    },
+    changeTime(){
+      console.log(this.createTime);
+      if(this.createTime!=null){
+        this.queryParams.beginTime=this.createTime[0];
+        this.queryParams.endTime=this.createTime[1];
+      }else{
+        this.queryParams.beginTime=null;
+        this.queryParams.endTime=null;
+      }
+      console.log(this.queryParams.beginTime);
+      console.log(this.queryParams.endTime);
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    handleMultiChange(e){
+
+    },
+    handleCompanyUserId(val){
+      if(val == null || val === '') {
+        this.queryParams.companyUserId = null;
+        this.queryParams.userIds = [];
+      }
+      console.log(val);
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        roleId: null,
+        count: null,
+        type: null,
+        companyId: null,
+        companyUserId: null,
+        qwUserId: null,
+        statTime: null
+      };
+      this.resetForm("form");
+    },
+    getPercentageColor(percentage) {
+      // HSL模式从黄色(60度)渐变到红色(0度)
+      const percent = Math.min(100, Math.max(0, parseFloat(percentage)));
+
+      // 调整色相范围:从深黄色(40°)渐变到红色(0°)
+      const hue = 40 - 40 * (percent / 100); // 初始 hue=40(深黄),终点 hue=0(红)
+
+      // 提高饱和度(100%),亮度保持 50%(鲜艳但不刺眼)
+      return `hsl(${hue}, 100%, 50%)`;
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      console.log(this.selectedAppKey)
+      if(this.selectedAppKey === null || typeof this.selectedAppKey === 'undefined'){
+        this.queryParams.appKey = null;
+      }
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.selectedAppKey = null;
+      this.selectedAppKeyLabel = '';
+      this.selectedCompanyList = [];
+      this.queryParams.appKey = null;
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+
+      if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
+        this.queryParams.userIds = this.selectedCompanyList;
+      }else {
+        this.queryParams.userIds = [];
+      }
+      this.$confirm('是否确认导出所有ai事件埋点统计数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportFastgptEventLogTotal(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

文件差異過大導致無法顯示
+ 442 - 361
src/views/his/company/index.vue


+ 838 - 0
src/views/his/complaint/index.vue

@@ -0,0 +1,838 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="用户" prop="userId">
+        <el-input
+          v-model="queryParams.userId"
+          placeholder="请输入用户id"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="联系方式" prop="phone">
+        <el-input
+          v-model="queryParams.phone"
+          placeholder="请输入联系方式"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="处理状态" prop="isHandle">
+        <el-select
+          v-model="queryParams.isHandle"
+          placeholder="请选择处理状态"
+          clearable
+          size="small"
+        >
+          <el-option label="未处理" value="0"></el-option>
+          <el-option label="已处理" value="1"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="投诉时间" prop="complaintTime">
+        <el-date-picker v-model="complaintTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="changeTime"></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['his:complaint:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="complaintList" @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="nickName" />
+      <el-table-column label="投诉方式" align="center" prop="complaintType" >
+        <template slot-scope="scope">
+          <template v-for="item in complaintTypeOptions">
+            <el-tag v-if="item.dictValue === scope.row.complaintType" :key="item.dictValue">
+              {{ item.dictLabel }}
+            </el-tag>
+          </template>
+        </template>
+      </el-table-column>
+      <el-table-column label="投诉类型" align="center" prop="type" >
+        <template slot-scope="scope">
+            <dict-tag :options="typeOptions" :value="scope.row.type"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="投诉时间" align="center" prop="createTime" />
+      <el-table-column
+        label="是否处理"
+        align="center"
+        prop="isHandlePlatform"
+        :render-header="renderHandleHeader"
+      >
+        <template slot-scope="scope">
+          <el-tag
+            :type="scope.row.isHandlePlatform == 1 ? 'success' : 'warning'"
+            disable-transitions
+          >
+            {{ formatHandleStatus(scope.row.isHandle) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column 
+        label="店铺是否处理"
+        align="center"
+        prop="isHandlePlatform"
+        :render-header="renderHandleHeader"
+      >
+        <template slot-scope="scope">
+          <el-tag
+            :type="(scope.row.isHandleStore == 1)? 'success' : 'warning'"
+            disable-transitions
+          >
+            {{ formatHandleStatus(scope.row.isHandle) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注" align="center" prop="remarks" />
+      <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"
+            v-hasPermi="['his:complaint:edit']"
+            @click="handleUpdate(scope.row)"
+          >投诉详情</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['his:complaint: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="900px" append-to-body>
+      <!-- 修改tab-click事件处理器名称 -->
+      <el-tabs v-model="activeTab" type="card" @tab-click="handleClick">
+        <!-- 投诉详情标签页 -->
+        <el-tab-pane label="投诉详情" name="complaint">
+          <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+            <el-form-item label="投诉内容" prop="name">
+              <el-input v-model="form.name" :disabled="true" />
+            </el-form-item>
+            <el-form-item label="详细内容" v-if="form.content && form.content!=''">
+              <el-input type="textarea" v-model="form.content" :disabled="true"/>
+            </el-form-item>
+            <el-form-item label="联系方式" prop="phone" v-if="form.phone && form.phone!=''">
+              <el-input v-model="form.phone" :disabled="true"/>
+            </el-form-item>
+            <el-form-item label="图片" v-if="form.images && form.images!=''">
+              <div v-for="(url, index) in imageUrls(form.images)" :key="index" class="image-container">
+                <el-image :src="url" :preview-src-list="[url]" style="width: 100px; height: 100px;"></el-image>
+              </div>
+            </el-form-item>
+            <!-- <el-form-item label="交易截图" v-if="form.tradeImage && form.tradeImage!=''">
+              <div v-for="(url, index) in imageUrls(form.tradeImage)" :key="index" class="image-container">
+                <el-image :src="url" :preview-src-list="[url]" style="width: 100px; height: 100px;"></el-image>
+              </div>
+            </el-form-item> -->
+            <el-form-item label="用户" prop="nickName">
+              <el-input v-model="form.nickName" :disabled="true"/>
+            </el-form-item>
+            <el-form-item label="是否处理" prop="isHandle">
+              <el-select v-model="form.isHandlePlatform" placeholder="请选择处理状态" :disabled="true">
+                <el-option label="未处理" :value="0"></el-option>
+                <el-option label="已处理" :value="1"></el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item label="备注" prop="remarks" >
+              <el-input type="textarea" v-model="form.remarks" :maxlength="250" :disabled="true"/>
+            </el-form-item>
+          </el-form>
+        </el-tab-pane>
+
+        <!-- 回复详情标签页 -->
+        <el-tab-pane label="回复详情" name="replies">
+          <div class="reply-section">
+            <!-- 添加回复表单 -->
+            <el-card class="add-reply-card" shadow="never">
+              <div slot="header">
+                <span>添加回复</span>
+              </div>
+              <el-form :model="replyForm" ref="replyForm" label-width="80px">
+                <el-form-item label="回复内容" prop="content" :rules="[{ required: true, message: '请输入回复内容', trigger: 'blur' }]">
+                  <el-input
+                    type="textarea"
+                    v-model="replyForm.content"
+                    placeholder="请输入回复内容"
+                    :rows="3"
+                    maxlength="500"
+                    show-word-limit
+                  />
+                </el-form-item>
+                
+                <!-- 添加图片上传功能 -->
+                <el-form-item label="上传图片" prop="images">
+                  <!-- <div class="image-upload-container">
+                     <el-upload
+                      ref="imageUpload"
+                      :action="uploadUrl"
+                      :show-file-list="false"
+                      :file-list="replyImageList"
+                      :on-success="handleSuccess"
+                      :before-upload="beforeUpload"
+                      :limit="4"
+                      list-type="picture-card"
+                      accept="image/*"
+                    >
+                      <i class="el-icon-plus"></i>
+                      <div slot="tip" class="el-upload__tip">
+                        最多上传4张图片,单张图片不超过2MB
+                      </div>
+                    </el-upload>
+                  </div> -->
+                  <ImageUpload v-model="replyForm.images" type="image" :num="4" :width="150" :height="150"/>  
+
+                </el-form-item>
+
+                <el-form-item>
+                  <el-button type="primary" size="small" @click="submitReply" :loading="replyLoading">
+                    <i class="el-icon-s-promotion"></i> 发送回复
+                  </el-button>
+                </el-form-item>
+              </el-form>
+            </el-card>
+
+            <!-- 回复列表 -->
+            <el-card class="reply-list-card" shadow="never">
+              <div slot="header">
+                <span>回复记录 ({{ replyTotal }}条)</span>
+              </div>
+              
+              <div v-loading="replyLoading" class="reply-list">
+                <div v-if="replyList.length === 0" class="empty-replies">
+                  <el-empty description="暂无回复记录" :image-size="100"></el-empty>
+                </div>
+                
+                <div v-else>
+                  <div v-for="reply in replyList" :key="reply.id" class="reply-item">
+                    <div class="reply-header">
+                      <div class="reply-user">
+                        <el-avatar :size="32" :src="reply.avatar || '/default-avatar.png'">
+                          {{ reply.userName ? reply.userName.charAt(0) : 'U' }}
+                        </el-avatar>
+                        <!-- <span class="user-name">{{ reply.userName || '系统管理员' }}</span> -->
+                        <el-tag size="mini" :type="reply.sendType != 1 ? 'success' : 'info'">
+                          {{ reply.sendType === 1 ? '用户' : reply.sendType === 2 ? '系统平台':'店铺平台' }}
+                        </el-tag>
+                      </div>
+                      <div class="reply-time">
+                        {{ reply.createTime }}
+                      </div>
+                    </div>
+                    <div class="reply-content">
+                      {{ reply.content }}
+                    </div>
+                    
+                    <!-- 显示回复中的图片 -->
+                    <div class="reply-images" v-if="reply.images && reply.images !== ''">
+                      <div v-for="(url, index) in imageUrls(reply.images)" :key="index" class="reply-image-container">
+                        <el-image 
+                          :src="url" 
+                          :preview-src-list="imageUrls(reply.images)" 
+                          style="width: 80px; height: 80px;"
+                          fit="cover"
+                        ></el-image>
+                      </div>
+                    </div>
+
+                    <div class="reply-actions" v-if="reply.userType === 'admin'">
+                      <el-button type="text" size="mini" @click="editReply(reply)">
+                        <i class="el-icon-edit"></i> 编辑
+                      </el-button>
+                      <el-button type="text" size="mini" @click="deleteReply(reply)" style="color: #f56c6c;">
+                        <i class="el-icon-delete"></i> 删除
+                      </el-button>
+                    </div>
+                  </div>
+                </div>
+              </div>
+
+              <!-- 回复分页 -->
+              <div class="reply-pagination" v-if="replyTotal > 0">
+                <el-pagination
+                  @size-change="handleReplySizeChange"
+                  @current-change="handleReplyCurrentChange"
+                  :current-page="replyQueryParams.pageNum"
+                  :page-sizes="[5, 10, 20]"
+                  :page-size="replyQueryParams.pageSize"
+                  layout="total, sizes, prev, pager, next, jumper"
+                  :total="replyTotal"
+                  small
+                />
+              </div>
+            </el-card>
+          </div>
+        </el-tab-pane>
+      </el-tabs>
+
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm" v-if="activeTab === 'complaint' && form.id==null">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+
+    <!-- 编辑回复对话框 -->
+    <el-dialog title="编辑回复" :visible.sync="editReplyVisible" width="500px" append-to-body>
+      <el-form :model="editReplyForm" ref="editReplyForm" label-width="80px">
+        <el-form-item label="回复内容" prop="content" :rules="[{ required: true, message: '请输入回复内容', trigger: 'blur' }]">
+          <el-input
+            type="textarea"
+            v-model="editReplyForm.content"
+            placeholder="请输入回复内容"
+            :rows="4"
+            maxlength="500"
+            show-word-limit
+          />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="updateReply" :loading="replyLoading">确 定</el-button>
+        <el-button @click="editReplyVisible = false">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listComplaint, getComplaint, delComplaint, addComplaint, updateComplaint, exportComplaint,listMsg,addMsg } from "@/api/his/complaint";
+import ImageUpload from '@/components/ImageUpload/index';
+export default {
+  name: "Complaint",
+  components: {
+     ImageUpload
+  },
+  data() {
+    return {
+      replyImageList: [],
+      uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
+      complaintId:null,
+      activeName:"0",
+      typeOptions:[
+        {
+          dictValue:'0',
+          dictLabel:'默认'
+        },
+        {
+          dictValue:'1',
+          dictLabel:'店铺'
+        },
+        {
+          dictValue:'2',
+          dictLabel:'商品'
+        },
+      ],
+      complaintTypeOptions:[
+        {
+          dictValue:1,
+          dictLabel:'咨询'
+        },
+        {
+          dictValue:2,
+          dictLabel:'投诉/举报'
+        },
+      ],
+      complaintTime:null,
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 用户投诉表格数据
+      complaintList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 当前激活的标签页
+      activeTab: 'complaint',
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: null,
+        userName: null,
+        templateId: null,
+        content: null,
+        phone: null,
+        urls: null,
+        account: null,
+        isHandle: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        userId: [
+          { required: true, message: "用户id不能为空", trigger: "blur" }
+        ],
+        templateId: [
+          { required: true, message: "投诉模板id不能为空", trigger: "blur" }
+        ],
+      },
+      // 回复相关数据
+      replyList: [],
+      replyTotal: 0,
+      replyLoading: false,
+      replyQueryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        complaintId: null
+      },
+      replyForm: {
+        content: '',
+        complaintId: null
+      },
+      // 编辑回复
+      editReplyVisible: false,
+      editReplyForm: {
+        id: null,
+        content: ''
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    handleClick(tab) {
+      if (tab.name === 'replies') {
+        this.getReplyList();
+      }
+    },
+    renderHandleHeader(h, { column }) {
+      if (column.label === '是否处理') {
+        return h('div', [
+          '是否处理',
+          h('el-tooltip', {
+            props: {
+              content: '仅需要处理投诉/举报类',
+              placement: 'top'
+            }
+          }, [
+            h('i', {
+              class: 'el-icon-question',
+              style: 'margin-left: 5px; cursor: pointer; color: #909399;'
+            })
+          ])
+        ]);
+      } else if (column.label === '店铺是否处理') {
+        return h('div', [
+          '店铺是否处理',
+          h('el-tooltip', {
+            props: {
+              content: '仅需要处理咨询类',
+              placement: 'top'
+            }
+          }, [
+            h('i', {
+              class: 'el-icon-question',
+              style: 'margin-left: 5px; cursor: pointer; color: #909399;'
+            })
+          ])
+        ]);
+      }
+      return column.label;
+    },
+    imageUrls(urls) {
+      return String(urls).split(",");
+    },
+    formatHandleStatus(status) {
+      return status == 1 ? '已处理' : '未处理';
+    },
+    /** 查询用户投诉列表 */
+    getList() {
+      this.loading = true;
+      listComplaint(this.queryParams).then(response => {
+        this.complaintList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+      this.resetReplyData();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        userId: null,
+        templateId: null,
+        content: null,
+        phone: null,
+        urls: null,
+        account: null,
+        createTime: null,
+        isHandle: 0,
+        remarks:null
+      };
+      this.resetForm("form");
+    },
+    // 重置回复数据
+    resetReplyData() {
+      this.activeTab = 'complaint';
+      this.replyList = [];
+      this.replyTotal = 0;
+      this.replyQueryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        complaintId: null
+      };
+      this.replyForm = {
+        content: '',
+        complaintId: null,
+        images: '' // 重置图片字段
+      };
+      this.replyImageList = [];
+      this.editReplyImageList = [];
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.complaintTime = null;
+      this.queryParams.complaintsTime=null;
+      this.queryParams.complainteTime=null;
+      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();
+      this.resetReplyData();
+      // const id = row.id || this.ids
+      const complaintId = row.id || this.complaintId
+      this.complaintId = complaintId;
+      getComplaint(complaintId).then(response => {
+        this.form = response.data;
+        this.replyForm.complaintId = complaintId;
+        this.replyQueryParams.complaintId = complaintId;
+        this.open = true;
+        this.title = "投诉详情";
+        // 加载回复列表
+        this.getReplyList();
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateComplaint(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addComplaint(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 delComplaint(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有用户投诉数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportComplaint(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    },
+    changeTime(){
+      if(this.complaintTime!=null){
+        this.queryParams.complaintsTime=this.complaintTime[0];
+        this.queryParams.complainteTime=this.complaintTime[1];
+      }else{
+        this.queryParams.complaintsTime=null;
+        this.queryParams.complainteTime=null;
+      }
+    },
+    // 获取回复列表
+    getReplyList() {
+      this.replyLoading = true;
+      // 模拟API调用 - 你需要替换为实际的API
+      setTimeout(() => {
+        // 模拟数据
+        listMsg(this.replyQueryParams).then(response => {
+              this.replyList = response.rows;
+              this.replyTotal = response.total;
+              this.replyLoading = false;
+            });
+      }, 500);
+    },
+    // 提交回复
+    submitReply() {
+      this.$refs.replyForm.validate(valid => {
+        if (valid) {
+          this.replyLoading = true;
+          // const imageUrls = this.replyImageList.map(file => file.url || file.response?.url).filter(url => url);
+          // this.replyForm.images = imageUrls.join(',');
+          // 模拟API调用
+          setTimeout(() => {
+            const newReply = {
+              content: this.replyForm.content,
+              complaintId:this.replyForm.complaintId,
+              images: this.replyForm.images, // 包含图片数据
+              sendType: 2
+            };
+            addMsg(newReply).then(response => {
+              this.replyLoading = false;
+              this.$message.success('回复发送成功');
+              this.replyForm.content = '';
+              this.replyForm.images = ''; // 重置图片字段
+              this.replyImageList = []; // 重置图片列表
+              this.getReplyList()
+            });
+            
+          }, 500);
+        }
+      });
+    },
+    // 编辑回复
+    editReply(reply) {
+      this.editReplyForm = {
+        id: reply.id,
+        content: reply.content,
+        images: reply.images || '' // 包含图片数据
+      };
+      this.editReplyImageList = reply.images ? 
+        reply.images.split(',').map((url, index) => ({
+          uid: index,
+          name: `image-${index}`,
+          url: url
+        })) : [];
+      this.editReplyVisible = true;
+    },
+    
+    // 更新回复
+    updateReply() {
+      this.$refs.editReplyForm.validate(valid => {
+        if (valid) {
+          this.replyLoading = true;
+          // const imageUrls = this.editReplyImageList.map(file => file.url || file.response?.url).filter(url => url);
+          // this.editReplyForm.images = imageUrls.join(',');
+          
+          // 模拟API调用
+          setTimeout(() => {
+            const index = this.replyList.findIndex(item => item.id === this.editReplyForm.id);
+            if (index !== -1) {
+              this.replyList[index].content = this.editReplyForm.content;
+              this.replyList[index].images = this.editReplyForm.images; // 更新图片
+            }
+            this.editReplyVisible = false;
+            this.replyLoading = false;
+            this.$message.success('回复更新成功');
+          }, 500);
+        }
+      });
+    },
+    // 删除回复
+    deleteReply(reply) {
+      this.$confirm('确定要删除这条回复吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        const index = this.replyList.findIndex(item => item.id === reply.id);
+        if (index !== -1) {
+          this.replyList.splice(index, 1);
+          this.replyTotal--;
+          this.$message.success('删除成功');
+        }
+      });
+    },
+    // 回复分页大小改变
+    handleReplySizeChange(val) {
+      this.replyQueryParams.pageSize = val;
+      this.getReplyList();
+    },
+    // 回复当前页改变
+    handleReplyCurrentChange(val) {
+      this.replyQueryParams.pageNum = val;
+      this.getReplyList();
+    },
+    handleSuccess(res, file) {
+        if(res.code==200){
+          this.form.licenseImages=res.url;
+          this.$forceUpdate()
+        }
+        else{
+          this.msgError(res.msg);
+        }
+    },
+    
+    beforeUpload(file) {
+      const isLt1M = file.size / 1024 / 1024 < 1;
+      if (!isLt1M) {
+        this.$message.error('上传图片大小不能超过 1MB!');
+      }
+      return   isLt1M;
+    },
+  }
+};
+</script>
+
+<style scoped>
+.reply-section {
+  margin-top: 10px;
+}
+
+.add-reply-card {
+  margin-bottom: 20px;
+}
+
+.reply-list-card {
+  min-height: 400px;
+}
+
+.reply-list {
+  min-height: 300px;
+}
+
+.empty-replies {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 200px;
+}
+
+.reply-item {
+  border-bottom: 1px solid #f0f0f0;
+  padding: 15px 0;
+}
+
+.reply-item:last-child {
+  border-bottom: none;
+}
+
+.reply-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 10px;
+}
+
+.reply-user {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+.user-name {
+  font-weight: 500;
+  color: #303133;
+}
+
+.reply-time {
+  color: #909399;
+  font-size: 12px;
+}
+
+.reply-content {
+  background-color: #f8f9fa;
+  padding: 12px;
+  border-radius: 6px;
+  margin-bottom: 8px;
+  line-height: 1.5;
+  color: #606266;
+}
+
+.reply-actions {
+  text-align: right;
+}
+
+.reply-pagination {
+  margin-top: 20px;
+  text-align: center;
+}
+
+.image-container {
+  display: inline-block;
+  margin-right: 10px;
+  margin-bottom: 10px;
+}
+</style>

+ 369 - 0
src/views/his/fsFirstDiagnosis/index.vue

@@ -0,0 +1,369 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="患者姓名" prop="patientName">
+        <el-input v-model="queryParams.patientName" placeholder="请输入患者姓名" clearable size="small"
+          @keyup.enter.native="handleQuery" />
+      </el-form-item>
+      <el-form-item label="电话" prop="phone">
+        <el-input v-model="queryParams.phone" placeholder="请输入电话" clearable size="small"
+          @keyup.enter.native="handleQuery" />
+      </el-form-item>
+      <el-form-item label="医生名称" prop="doctorName">
+        <el-input v-model="queryParams.doctorName" placeholder="请输入医生名称" clearable size="small"
+          @keyup.enter.native="handleQuery" />
+      </el-form-item>
+      <el-form-item label="用户姓名" prop="userName">
+        <el-input v-model="queryParams.userName" placeholder="请输入用户姓名" clearable size="small"
+          @keyup.enter.native="handleQuery" />
+      </el-form-item>
+      <el-form-item label="销售名称" prop="qwUserName">
+        <el-input v-model="queryParams.qwUserName" placeholder="请输入销售名称" clearable size="small"
+          @keyup.enter.native="handleQuery" />
+      </el-form-item>
+      <el-form-item label="医生证号" prop="doctorCertificate">
+        <el-input v-model="queryParams.doctorCertificate" placeholder="请输入医生证号" clearable size="small"
+          @keyup.enter.native="handleQuery" />
+      </el-form-item>
+      <el-form-item label="医生填写" prop="doctorStatus">
+        <el-select clearable v-model="queryParams.doctorStatus">
+          <el-option label="未填写" value="0"></el-option>
+          <el-option label="已填写" value="1"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="用户答复" prop="userStatus">
+        <el-select clearable v-model="queryParams.userStatus">
+          <el-option label="未答复" value="0"></el-option>
+          <el-option label="已答复" value="1"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-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="['his:fsFirstDiagnosis: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="['his:fsFirstDiagnosis: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="['his:fsFirstDiagnosis: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="['his:fsFirstDiagnosis:export']">导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="fsFirstDiagnosisList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <!-- <el-table-column label="医生证号" align="center" prop="id" /> -->
+      <el-table-column label="患者姓名" align="center" prop="patientName" />
+      <el-table-column label="年龄" align="center" prop="age" />
+      <el-table-column label="性别" align="center" prop="gender">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.gender == 0">未知</el-tag>
+          <el-tag v-if="scope.row.gender == 1">男</el-tag>
+          <el-tag v-if="scope.row.gender == 2">女</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="电话" align="center" prop="phone" />
+      <el-table-column label="身体状况" align="center" prop="physicalCondition" :show-overflow-tooltip="true" />
+      <el-table-column label="日期" align="center" prop="dateTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.dateTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="初步诊断" align="center" prop="firstDiagnosis" :show-overflow-tooltip="true" />
+      <el-table-column label="医生名称" align="center" prop="doctorName" />
+      <el-table-column label="医生职称" align="center" prop="doctorDep" />
+      <el-table-column label="医生证号" align="center" prop="doctorCertificate" />
+      <el-table-column label="用户姓名" align="center" prop="userName" />
+      <el-table-column label="销售名称" align="center" prop="qwUserName" />
+      <el-table-column label="用户答复" align="center" prop="userStatus" width="120px">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.userStatus == 0">未答复</el-tag>
+          <el-tag type="success" v-if="scope.row.userStatus == 1">已答复</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="医生填写" align="center" prop="doctorStatus" width="120px">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.doctorStatus == 0">未填写</el-tag>
+          <el-tag type="success" v-if="scope.row.doctorStatus == 1">已填写</el-tag>
+        </template>
+      </el-table-column>
+      <!-- <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['his:fsFirstDiagnosis:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['his:fsFirstDiagnosis: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="patientName">
+          <el-input v-model="form.patientName" placeholder="请输入患者姓名" />
+        </el-form-item>
+        <el-form-item label="年龄" prop="age">
+          <el-input v-model="form.age" placeholder="请输入年龄" />
+        </el-form-item>
+        <el-form-item label="0-未知 1-男性 2-女性" prop="gender">
+          <el-input v-model="form.gender" placeholder="请输入0-未知 1-男性 2-女性" />
+        </el-form-item>
+        <el-form-item label="电话" prop="phone">
+          <el-input v-model="form.phone" placeholder="请输入电话" />
+        </el-form-item>
+        <el-form-item label="身体状况" prop="physicalCondition">
+          <el-input v-model="form.physicalCondition" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="日期" prop="dateTime">
+          <el-date-picker clearable size="small" v-model="form.dateTime" type="date" value-format="yyyy-MM-dd"
+            placeholder="选择日期">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="出版诊断" prop="firstDiagnosis">
+          <el-input v-model="form.firstDiagnosis" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="医生id" prop="doctoId">
+          <el-input v-model="form.doctoId" placeholder="请输入医生id" />
+        </el-form-item>
+        <el-form-item label="医生名称" prop="doctorName">
+          <el-input v-model="form.doctorName" placeholder="请输入医生名称" />
+        </el-form-item>
+        <el-form-item label="职称" prop="doctorDep">
+          <el-input v-model="form.doctorDep" placeholder="请输入职称" />
+        </el-form-item>
+        <el-form-item label="用户id" prop="userId">
+          <el-input v-model="form.userId" placeholder="请输入用户id" />
+        </el-form-item>
+        <el-form-item label="医生证号" prop="doctorCertificate">
+          <el-input v-model="form.doctorCertificate" 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 { listFsFirstDiagnosis, getFsFirstDiagnosis, delFsFirstDiagnosis, addFsFirstDiagnosis, updateFsFirstDiagnosis, exportFsFirstDiagnosis } from "@/api/his/fsFirstDiagnosis";
+
+export default {
+  name: "FsFirstDiagnosis",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 初诊单表格数据
+      fsFirstDiagnosisList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        patientName: null,
+        age: null,
+        gender: null,
+        phone: null,
+        physicalCondition: null,
+        dateTime: null,
+        firstDiagnosis: null,
+        doctoId: null,
+        doctorName: null,
+        doctorDep: null,
+        userId: null,
+        doctorCertificate: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询初诊单列表 */
+    getList() {
+      this.loading = true;
+      listFsFirstDiagnosis(this.queryParams).then(response => {
+        this.fsFirstDiagnosisList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        patientName: null,
+        age: null,
+        gender: null,
+        phone: null,
+        physicalCondition: null,
+        dateTime: null,
+        firstDiagnosis: null,
+        doctoId: null,
+        doctorName: null,
+        doctorDep: null,
+        createTime: null,
+        updateTime: null,
+        userId: null,
+        doctorCertificate: 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
+      getFsFirstDiagnosis(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) {
+            updateFsFirstDiagnosis(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addFsFirstDiagnosis(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 delFsFirstDiagnosis(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => { });
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有初诊单数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportFsFirstDiagnosis(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => { });
+    }
+  }
+};
+</script>

+ 326 - 0
src/views/his/hfpayConfig/index.vue

@@ -0,0 +1,326 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="85px">
+      <el-form-item label="appId" prop="appId">
+        <el-input
+          v-model="queryParams.appId"
+          placeholder="请输入appId"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="汇付产品号" prop="hfProductId">
+        <el-input
+          v-model="queryParams.hfProductId"
+          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="['his:hfpayConfig: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="['his:hfpayConfig: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="['his:hfpayConfig: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="['his:hfpayConfig:export']"
+        >导出</el-button>
+      </el-col> -->
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="hfpayConfigList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="appId" align="center" prop="appId" />
+      <el-table-column label="汇付产品号" align="center" prop="hfProductId" />
+      <el-table-column label="系统号" align="center" prop="hfSysId" />
+      <el-table-column label="商户号" align="center" prop="huifuId" />
+      <el-table-column label="支付回调地址" align="center" :show-overflow-tooltip="true" prop="hfPayNotifyUrl" />
+      <el-table-column label="大额支付回调地址" align="center" :show-overflow-tooltip="true" prop="hfPayOnlineNotifyUrl" />
+      <el-table-column label="退款回调地址" align="center" :show-overflow-tooltip="true" prop="hfRefundNotifyUrl" />
+      <el-table-column label="大额退款回调地址" align="center" :show-overflow-tooltip="true" prop="hfOnlineRefundNotifyUrl" />
+      <el-table-column label="商户私钥" align="center" :show-overflow-tooltip="true" prop="hfRsaPrivateKey" />
+      <el-table-column label="汇付公钥" align="center" :show-overflow-tooltip="true" prop="hfRsaPublicKey" />
+      <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="['his:hfpayConfig:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['his:hfpayConfig:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改汇付多支付配置对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="125px">
+        <el-form-item label="appId" prop="appId">
+          <el-input v-model="form.appId" placeholder="请输入appId" />
+        </el-form-item>
+        <el-form-item label="汇付产品号" prop="hfProductId">
+          <el-input v-model="form.hfProductId" placeholder="请输入汇付产品号" />
+        </el-form-item>
+        <el-form-item label="系统号" prop="hfSysId">
+          <el-input v-model="form.hfSysId" placeholder="请输入系统号" />
+        </el-form-item>
+        <el-form-item label="商户号" prop="huifuId">
+          <el-input v-model="form.huifuId" placeholder="请输入商户号" />
+        </el-form-item>
+        <el-form-item label="支付回调地址" prop="hfPayNotifyUrl">
+          <el-input v-model="form.hfPayNotifyUrl" placeholder="请输入支付回调地址" />
+        </el-form-item>
+        <el-form-item label="大额支付回调地址" prop="hfPayOnlineNotifyUrl">
+          <el-input v-model="form.hfPayOnlineNotifyUrl" placeholder="请输入大额支付回调地址" />
+        </el-form-item>
+        <el-form-item label="退款回调地址" prop="hfRefundNotifyUrl">
+          <el-input v-model="form.hfRefundNotifyUrl" placeholder="请输入退款回调地址" />
+        </el-form-item>
+        <el-form-item label="大额退款回调地址" prop="hfOnlineRefundNotifyUrl">
+          <el-input v-model="form.hfOnlineRefundNotifyUrl" placeholder="请输入大额退款回调地址" />
+        </el-form-item>
+        <el-form-item label="商户私钥" prop="hfRsaPrivateKey">
+          <el-input v-model="form.hfRsaPrivateKey" type="textarea" placeholder="请输入商户私钥" />
+        </el-form-item>
+        <el-form-item label="汇付公钥" prop="hfRsaPublicKey">
+          <el-input v-model="form.hfRsaPublicKey" 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 { listHfpayConfig, getHfpayConfig, delHfpayConfig, addHfpayConfig, updateHfpayConfig, exportHfpayConfig } from "@/api/his/hfpayConfig";
+
+export default {
+  name: "HfpayConfig",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 汇付多支付配置表格数据
+      hfpayConfigList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        appId: null,
+        hfProductId: null,
+        hfSysId: null,
+        huifuId: null,
+        hfPayNotifyUrl: null,
+        hfPayOnlineNotifyUrl: null,
+        hfRefundNotifyUrl: null,
+        hfOnlineRefundNotifyUrl: null,
+        hfRsaPrivateKey: null,
+        hfRsaPublicKey: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询汇付多支付配置列表 */
+    getList() {
+      this.loading = true;
+      listHfpayConfig(this.queryParams).then(response => {
+        this.hfpayConfigList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        appId: null,
+        hfProductId: null,
+        hfSysId: null,
+        huifuId: null,
+        hfPayNotifyUrl: null,
+        hfPayOnlineNotifyUrl: null,
+        hfRefundNotifyUrl: null,
+        hfOnlineRefundNotifyUrl: null,
+        hfRsaPrivateKey: null,
+        hfRsaPublicKey: null,
+        createTime: null,
+        updateTime: 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
+      getHfpayConfig(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) {
+            updateHfpayConfig(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addHfpayConfig(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 delHfpayConfig(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有汇付多支付配置数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportHfpayConfig(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 252 - 0
src/views/his/statistics/tokenStatic.vue

@@ -0,0 +1,252 @@
+<template>
+    <div class="app-container">
+      <el-card>
+        <div slot="header" class="clearfix">
+          <span>token消耗统计</span>
+        </div>
+
+        <el-tabs v-model="activeTab" @tab-click="handleTabClick">
+          <el-tab-pane label="按天统计" name="daily">
+            <el-form :inline="true" class="demo-form-inline">
+              <el-form-item label="日期">
+                <el-date-picker
+                  v-model="dailyDate"
+                  type="date"
+                  placeholder="选择日期"
+                  value-format="yyyy-MM-dd"
+                  @change="handleDailyDateChange"
+                ></el-date-picker>
+              </el-form-item>
+
+              <el-form-item>
+                <el-button type="primary" @click="searchDaily">查询</el-button>
+                <el-button @click="resetDaily">重置</el-button>
+                <el-button type="success" @click="exportDaily">导出</el-button>
+              </el-form-item>
+            </el-form>
+
+            <el-table
+              v-loading="dailyLoading"
+              border
+              :data="companyList"
+              style="width: 100%"
+            >
+              <el-table-column prop="statTime" label="日期" width="180" />
+              <el-table-column prop="companyName" label="公司名称" />
+              <el-table-column prop="count" label="消耗token数" />
+            </el-table>
+
+            <div class="chart-container" style="margin-top: 20px; height: 400px">
+              <div ref="dailyChart" style="height: 100%; width: 100%"></div>
+            </div>
+          </el-tab-pane>
+
+          <el-tab-pane label="按月统计" name="monthly">
+            <el-form :inline="true" class="demo-form-inline">
+              <el-form-item label="月份">
+                <el-date-picker
+                  v-model="monthlyDate"
+                  type="month"
+                  placeholder="选择月份"
+                  value-format="yyyy-MM"
+                  @change="handleMonthlyDateChange"
+                ></el-date-picker>
+              </el-form-item>
+
+              <el-form-item>
+                <el-button type="primary" @click="searchMonthly">查询</el-button>
+                <el-button @click="resetMonthly">重置</el-button>
+                <el-button type="success" @click="exportMonthly">导出</el-button>
+              </el-form-item>
+            </el-form>
+
+            <el-table
+              v-loading="monthlyLoading"
+              border
+              :data="companyList"
+              style="width: 100%"
+            >
+              <el-table-column prop="date" label="月份" width="180" />
+              <el-table-column prop="companyName" label="公司名称" />
+              <el-table-column prop="count" label="消耗token数" />
+            </el-table>
+
+            <div class="chart-container" style="margin-top: 20px; height: 400px">
+              <div ref="monthlyChart" style="height: 100%; width: 100%"></div>
+            </div>
+          </el-tab-pane>
+        </el-tabs>
+      </el-card>
+    </div>
+  </template>
+
+  <script>
+  import { tokenStaticTotal,exportTokenStaticByTime} from "@/api/company/statistics";
+
+  export default {
+    name: 'tokenStatic',
+    data() {
+      const today = this.parseTime(new Date(), '{y}-{m}-{d}')
+      const yesterday = this.parseTime(new Date(new Date().getTime() - 24 * 60 * 60 * 1000), '{y}-{m}-{d}')
+      return {
+        // 激活的标签页
+        activeTab: 'daily',
+        // 按天统计数据
+        dailyLoading: false,
+        dailyDate: yesterday, // 默认当天
+        // 按月统计数据
+        monthlyLoading: false,
+        monthlyDate: this.parseTime(new Date(), '{y}-{m}'), // 默认当月
+        companyList: [],
+      }
+    },
+    created() {
+      // 获取当天数据
+      this.getList()
+    },
+    methods: {
+      // 标签页切换
+      handleTabClick(tab) {
+        if (tab.name === 'daily') {
+          this.getList()
+        } else if (tab.name === 'monthly') {
+          this.getMonthlyList()
+        }
+      },
+
+      // 按天统计相关方法
+      handleDailyDateChange(val) {
+        if (val) {
+          this.dailyDate = val
+        }
+      },
+      searchDaily() {
+        this.getList()
+      },
+      resetDaily() {
+        const today = this.parseTime(new Date(), '{y}-{m}-{d}')
+        const yesterday = this.parseTime(new Date(new Date().getTime() - 24 * 60 * 60 * 1000), '{y}-{m}-{d}')
+        this.dailyDate = yesterday
+        this.getList()
+      },
+
+      // 导出
+      exportDaily() {
+        this.$confirm("是否确认导出数据项?", "警告", {
+            confirmButtonText: "确定",
+            cancelButtonText: "取消",
+            type: "warning",
+        })
+            .then(() => {
+            this.exportLoading = true;
+            return exportTokenStaticByTime(this.dailyDate);
+            })
+            .then((response) => {
+            this.download(response.msg);
+            this.exportLoading = false;
+            })
+            .catch(() => { });
+      },
+      getList() {
+        this.dailyLoading = true
+        tokenStaticTotal(this.dailyDate).then(response => {
+          // 处理返回数据,添加日期字段用于表格和图表显示
+          this.companyList = response.list;
+          this.dailyLoading = false;
+        }).catch(() => {
+          this.dailyLoading = false;
+        });
+      },
+
+      // 按月统计相关方法
+      handleMonthlyDateChange(val) {
+        if (val) {
+          this.monthlyDate = val
+        }
+      },
+      searchMonthly() {
+        this.getMonthlyList()
+      },
+      resetMonthly() {
+        this.monthlyDate = this.parseTime(new Date(), '{y}-{m}')
+        this.getMonthlyList()
+      },
+      exportMonthly() {
+        this.$confirm("是否确认导出数据项?", "警告", {
+            confirmButtonText: "确定",
+            cancelButtonText: "取消",
+            type: "warning",
+        })
+            .then(() => {
+            this.exportLoading = true;
+            return exportTokenStaticByTime(this.monthlyDate);
+            })
+            .then((response) => {
+            this.download(response.msg);
+            this.exportLoading = false;
+            })
+            .catch(() => { });
+      },
+      getMonthlyList() {
+        this.monthlyLoading = true
+        tokenStaticTotal(this.monthlyDate).then(response => {
+          // 处理返回数据,添加月份字段用于表格和图表显示
+          this.companyList = response.list;
+          this.monthlyLoading = false;
+        }).catch(() => {
+          this.monthlyLoading = false;
+          this.monthlyTotal = 0;
+        });
+      },
+
+      // 日期格式化
+      parseTime(time, pattern) {
+        let date;
+        if (arguments.length === 0 || !time) {
+          return null
+        }
+        const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
+
+        if (typeof time === 'object') {
+          date = time
+        } else {
+          if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
+            time = parseInt(time)
+          } else if (typeof time === 'string') {
+            time = time.replace(new RegExp(/-/gm), '/')
+          }
+          if ((typeof time === 'number') && (time.toString().length === 10)) {
+            time = time * 1000
+          }
+          date = new Date(time)
+        }
+        const formatObj = {
+          y: date.getFullYear(),
+          m: date.getMonth() + 1,
+          d: date.getDate(),
+          h: date.getHours(),
+          i: date.getMinutes(),
+          s: date.getSeconds(),
+          a: date.getDay()
+        }
+        const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
+          let value = formatObj[key]
+          // Note: getDay() returns 0 on Sunday
+          if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
+          if (result.length > 0 && value < 10) {
+            value = '0' + value
+          }
+          return value || 0
+        })
+        return time_str
+      }
+    }
+  }
+  </script>
+
+  <style scoped>
+  .chart-container {
+    position: relative;
+    padding: 20px 0;
+  }
+  </style>

+ 2 - 1
src/views/his/storeOrder/order1.vue

@@ -1386,7 +1386,7 @@ export default {
           this.executeCreateErpOrder();
         });
       }
-      
+      this.getList();
     },
 
     async executSetErpOrder() {
@@ -1685,6 +1685,7 @@ export default {
         } else {
           this.$message.error(response.msg || '保存失败');
         }
+        this.getList();
       }).catch(() => {
         this.$message.error('保存失败');
       });

+ 2 - 2
src/views/his/user/indexProject.vue

@@ -64,7 +64,7 @@
       <el-form-item label="所属销售" prop="companyUserNickName">
 
         <el-select
-          v-model="queryParams.companyUserNickName"
+          v-model="queryParams.companyUserId"
           placeholder="请选择所属销售"
           clearable
           filterable
@@ -74,7 +74,7 @@
             v-for="item in companyQueryUserOptions"
             :key="item.userId"
             :label="item.nickName"
-            :value="item.nickName">
+            :value="item.userId">
           </el-option>
         </el-select>
       </el-form-item>

+ 2 - 2
src/views/his/user/userDetails.vue

@@ -1,9 +1,9 @@
 <template>
   <div>
     <div style="background-color: #f0f2f5; padding-bottom: 20px; min-height: 100%; " >
-      <div style="padding: 20px; background-color: #fff;">
+      <!-- <div style="padding: 20px; background-color: #fff;">
         会员详情
-      </div>
+      </div> -->
     </div>
     <template>
       <el-tabs v-model="activeName"  :tab-position="tabPosition" style="height: 200px;margin: 40px">

+ 96 - 0
src/views/hisStore/components/storeDetails.vue

@@ -63,6 +63,102 @@
           <span v-if="item!=null">{{item.updateTime}}</span>
         </el-descriptions-item>
 
+        <!--  // 重置证书相关字段
+        businessLicense: null,                    // 营业执照文件
+        businessLicenseExpireStart: null,              // 营业执照失效日期
+        businessLicenseExpireEnd: null,              // 营业执照失效日期
+        drugLicense: null,             // 药品经营许可证有效期
+        drugLicenseExpiryStart: null,               // 药品经营许可证文件
+        drugLicenseExpiryEnd: null,               // 药品经营许可证文件
+        // 医疗器械相关证书
+        medicalDevice1: null,          // 一类医疗器械备案证书
+        medicalDevice1ExpiryStart: null,        // 二类医疗器械备案有效期
+        medicalDevice1ExpiryEnd: null,        // 二类医疗器械备案有效期
+        medicalDevice2: null,          // 二类器械生产备案文件
+        medicalDevice2ExpiryStart: null,        // 一类生产备案有效期
+        medicalDevice2ExpiryEnd: null,        // 一类生产备案有效期
+        medicalDevice3: null,         // 三类器械经营许可证文件
+        medicalDevice3ExpiryStart: null,       // 三类器械经营许可证有效期
+        medicalDevice3ExpiryEnd: null,       // 三类器械经营许可证有效期
+        // 其他许可证相关字段
+        foodLicense: null,               // 食品经营许可证文件
+        foodLicenseExpiryStart: null,             // 食品经营许可证有效期
+        foodLicenseExpiryEnd: null,             // 食品经营许可证有效期
+        medicalLicense: null,  // 医疗机构执业许可证文件
+        medicalLicenseExpiryStart: null // 医疗机构执业许可证有效期
+        medicalLicenseExpiryEnd: null // 医疗机构执业许可证有效期
+        -->
+        <el-descriptions-item label="营业执照" >
+          <el-image
+            style="width: 100px"
+            :src="item.businessLicense"
+            :preview-src-list="[item.businessLicense]">
+          </el-image>
+        </el-descriptions-item>
+        <el-descriptions-item label="营业执照有效期" >
+          <span v-if="item!=null">{{item.businessLicenseExpireStart}} - {{item.businessLicenseExpireEnd}}</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="药品经营许可证" >
+          <el-image
+            style="width: 100px"
+            :src="item.drugLicense"
+            :preview-src-list="[item.drugLicense]">
+          </el-image>
+        </el-descriptions-item>
+        <el-descriptions-item label="药品经营许可证有效期" >
+          <span v-if="item!=null">{{item.drugLicenseExpiryStart}} - {{item.drugLicenseExpiryEnd}}</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="1类器械生产" >
+          <el-image
+            style="width: 100px"
+            :src="item.medicalDevice1"
+            :preview-src-list="[item.medicalDevice1]">
+          </el-image>
+        </el-descriptions-item>
+        <el-descriptions-item label="1类器械生产有效期" >
+          <span v-if="item!=null">{{item.medicalDevice1ExpiryStart}} - {{item.medicalDevice1ExpiryEnd}}</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="2类器械备案" >
+          <el-image
+            style="width: 100px"
+            :src="item.medicalDevice2"
+            :preview-src-list="[item.medicalDevice2]">
+          </el-image>
+        </el-descriptions-item>
+        <el-descriptions-item label="2类器械备案有效期" >
+          <span v-if="item!=null">{{item.medicalDevice2ExpiryStart}} - {{item.medicalDevice2ExpiryEnd}}</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="3类器械营业许可证" >
+          <el-image
+            style="width: 100px"
+            :src="item.medicalDevice3"
+            :preview-src-list="[item.medicalDevice3]">
+          </el-image>
+        </el-descriptions-item>
+        <el-descriptions-item label="3类器械营业许可证有效期" >
+          <span v-if="item!=null">{{item.medicalDevice3ExpiryStart}} - {{item.medicalDevice3ExpiryEnd}}</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="食品许可证" >
+          <el-image
+            style="width: 100px"
+            :src="item.foodLicense"
+            :preview-src-list="[item.foodLicense]">
+          </el-image>
+        </el-descriptions-item>
+        <el-descriptions-item label="食品许可证有效期" >
+          <span v-if="item!=null">{{item.foodLicenseExpiryStart}} - {{item.foodLicenseExpiryEnd}}</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="药品许可证" >
+          <el-image
+            style="width: 100px"
+            :src="item.medicalLicense"
+            :preview-src-list="[item.medicalLicense]">
+          </el-image>
+        </el-descriptions-item>
+        <el-descriptions-item label="药品许可证有效期" >
+          <span v-if="item!=null">{{item.medicalLicenseExpiryStart}} - {{item.medicalLicenseExpiryEnd}}</span>
+        </el-descriptions-item>
+
 
 
       </el-descriptions>

+ 158 - 161
src/views/hisStore/store/audit.vue

@@ -76,29 +76,29 @@
       <el-table-column label="店铺id" align="center" prop="storeId" width="120px"/>
       <el-table-column label="店铺名称" align="center" prop="storeName" width="120px"/>
       <el-table-column label="店铺LOGO" align="center" prop="logoUrl" width="100px">
-          <template slot-scope="scope">
-             <el-popover
-               placement="right"
-               title=""
-               trigger="hover">
-               <img slot="reference" :src="scope.row.logoUrl" width="80px">
-               <img :src="scope.row.logoUrl" style="max-width: 150px;">
-             </el-popover>
-          </template>
+        <template slot-scope="scope">
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover">
+            <img slot="reference" :src="scope.row.logoUrl" width="80px">
+            <img :src="scope.row.logoUrl" style="max-width: 150px;">
+          </el-popover>
+        </template>
       </el-table-column>
       <el-table-column label="地址" align="center" prop="address" width="200px"/>
       <el-table-column label="店铺电话" align="center" prop="phone" width="120px"/>
-      <el-table-column label="资质证书" align="center" prop="licenseImages" width="100px">
+<!--      <el-table-column label="资质证书" align="center" prop="licenseImages" width="100px">
         <template slot-scope="scope">
-                <el-popover
-                  placement="right"
-                  title=""
-                  trigger="hover">
-                  <img slot="reference" :src="scope.row.licenseImages" width="80px">
-                  <img :src="scope.row.licenseImages" style="max-width: 150px;">
-                </el-popover>
-              </template>
-      </el-table-column>
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover">
+            <img slot="reference" :src="scope.row.licenseImages" width="80px">
+            <img :src="scope.row.licenseImages" style="max-width: 150px;">
+          </el-popover>
+        </template>
+      </el-table-column>-->
       <el-table-column label="审核状态" align="center" prop="isAudit">
         <template slot-scope="scope">
           <dict-tag :options="isAuditOptions" :value="scope.row.isAudit"/>
@@ -115,21 +115,17 @@
       <el-table-column label="累计金额" align="center" prop="totalMoney" />
 
       <el-table-column label="登录帐号" align="center" prop="account" width="150px" />
-        <el-table-column label="创建时间" align="center" prop="createTime"  width="150px"/>
+      <el-table-column label="创建时间" align="center" prop="createTime"  width="150px"/>
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="130px">
         <template slot-scope="scope">
-          <el-button v-if="scope.row.isAudit==0"
+          <el-button
             size="mini"
             type="text"
-            icon="el-icon-edit"
-            @click="handleUpdate(scope.row)"
-            v-hasPermi="['his:store:audit']"
-          >审核</el-button>
-           <el-button
-                      size="mini"
-                      type="text"
-                      @click="handledetails(scope.row)"
-           >详情
+            icon="el-icon-s-promotion"
+            @click="handledetails(scope.row)"
+          >
+            <span v-if="scope.row.isAudit===0">审核</span>
+            <span v-else>详情</span>
           </el-button>
         </template>
       </el-table-column>
@@ -144,20 +140,21 @@
     />
 
 
-      <el-drawer
-            :with-header="false"
-            size="75%"
-             :title="show.title" :visible.sync="show.open">
-         <storeDetails  ref="Details" />
-       </el-drawer>
-
+    <el-drawer
+      :with-header="false"
+      size="75%"
+      :title="show.title" :visible.sync="show.open" >
+      <storeDetails  ref="Details" @fresh="getList" @showClose="this.show.open = false"/>
+    </el-drawer>
 
   </div>
+
+
 </template>
 
 <script>
-import { audit,listStore, getStore, delStore, addStore, updateStore, exportStore } from "@/api/hisStore/store";
-import storeDetails from '../../components/his/storeDetails.vue';
+import { audit,listStore, exportStore } from "@/api/hisStore/store";
+import storeDetails from '../components/storeDetails.vue';
 import {getCitys} from "@/api/store/city";
 export default {
   name: "adutstore",
@@ -165,14 +162,14 @@ export default {
   data() {
     return {
       show:{
-              title:"店铺详情",
-              open:false,
-            },
+        title:"店铺详情",
+        open:false,
+      },
 
       citys:[],
       licenseuploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
-            uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
-            baseUrl: process.env.VUE_APP_BASE_API,
+      uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
+      baseUrl: process.env.VUE_APP_BASE_API,
       shippingTypeOptions: [{
         "label": "配送",
         "value": "1"
@@ -218,36 +215,38 @@ export default {
         isAudit: 0,
         account: null,
       },
+
+
       // 表单参数
       form: {},
       // 表单校验
       rules: {
         storeName: [
-         { required: true, message: "店铺名称不能为空", trigger: "blur" }
-       ],
-       logoUrl: [
-         { required: true, message: "店铺LOGO不能为空", trigger: "blur" }
-       ],
-       cityIds: [
-         { required: true, message: "所属城市不能为空", trigger: "blur" }
-       ],
-      address: [
-        { required: true, message: "地址不能为空", trigger: "blur" }
-      ],
-      licenseImages: [
-        { required: true, message: "资质证书不能为空", trigger: "blur" }
-      ],
-      shippingType: [
-        { required: true, message: "配送方式不能为空", trigger: "blur" }
-      ],
-      phone: [
-        { required: true, message: "店铺电话不能为空", trigger: "blur" }
-      ],
+          { required: true, message: "店铺名称不能为空", trigger: "blur" }
+        ],
+        logoUrl: [
+          { required: true, message: "店铺LOGO不能为空", trigger: "blur" }
+        ],
+        cityIds: [
+          { required: true, message: "所属城市不能为空", trigger: "blur" }
+        ],
+        address: [
+          { required: true, message: "地址不能为空", trigger: "blur" }
+        ],
+        licenseImages: [
+          { required: true, message: "资质证书不能为空", trigger: "blur" }
+        ],
+        shippingType: [
+          { required: true, message: "配送方式不能为空", trigger: "blur" }
+        ],
+        phone: [
+          { required: true, message: "店铺电话不能为空", trigger: "blur" }
+        ],
       }
     };
   },
   created() {
-      this.getCitys();
+    this.getCitys();
     this.getList();
     this.getDicts("sys_company_status").then(response => {
       this.statusOptions = response.data;
@@ -257,88 +256,86 @@ export default {
     });
   },
   methods: {
-
-
     handleUpdate(row){
-        var that=this;
-        var the=null;
-         this.$confirm('是否确认审核?', "审核", {
-           distinguishCancelAndClose: true,
-           confirmButtonText: "确定",
-           cancelButtonText: "驳回",
-           type: "warning"
-         }).then(function() {
-           var data={
+      var that=this;
+      var the=null;
+      this.$confirm('是否确认审核?', "审核", {
+        distinguishCancelAndClose: true,
+        confirmButtonText: "确定",
+        cancelButtonText: "驳回",
+        type: "warning"
+      }).then(function() {
+        var data={
           storeId:row.storeId,
           isAudit:1
-              }
-           return audit(data);
-         }).then(() => {
-           this.msgSuccess("操作成功");
-              this.getList();
-         }).catch(function(action) {
-           if (action === 'cancel') {
-           var data={
-           storeId:row.storeId,
-           isAudit:-1
-               }
+        }
+        return audit(data);
+      }).then(() => {
+        this.msgSuccess("操作成功");
+        this.getList();
+      }).catch(function(action) {
+        if (action === 'cancel') {
+          var data={
+            storeId:row.storeId,
+            isAudit:-1
+          }
           the='cancel';
-            return audit(data);
-            }
-         }).then(() => {
-           if(the==='cancel'){
-             this.msgSuccess("操作成功");
-                this.getList();
-           }
+          return audit(data);
+        }
+      }).then(() => {
+        if(the==='cancel'){
+          this.msgSuccess("操作成功");
+          this.getList();
+        }
 
-         });
-},
+      });
+    },
     handledetails(row){
-            this.show.open=true;
-            setTimeout(() => {
-                 this.$refs.Details.getDetails(row.storeId);
-            }, 1);
-        },
+      this.show.open=true;
+      setTimeout(() => {
+        this.$refs.Details.getDetails(row.storeId);
+      }, 1);
+    },
 
     handleCityChange(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;
-            })
-        },
+      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;
+      })
+    },
 
     licensehandleAvatarSuccess(res, file) {
-        if(res.code==200){
-          this.form.licenseImages=res.url;
-          this.$forceUpdate()
-        }
-        else{
-          this.msgError(res.msg);
-        }
+      if(res.code==200){
+        this.form.licenseImages=res.url;
+        this.$forceUpdate()
+      }
+      else{
+        this.msgError(res.msg);
+      }
     },
     handleAvatarSuccess(res, file) {
-            if(res.code==200){
-              this.form.logoUrl=res.url;
-              this.$forceUpdate()
-            }
-            else{
-              this.msgError(res.msg);
-            }
-      },
+      if(res.code==200){
+        this.form.logoUrl=res.url;
+        this.$forceUpdate()
+      }
+      else{
+        this.msgError(res.msg);
+      }
+    },
     beforeAvatarUpload(file) {
-          const isLt1M = file.size / 1024 / 1024 < 1;
-          if (!isLt1M) {
-            this.$message.error('上传图片大小不能超过 1MB!');
-          }
-          return   isLt1M;
-        },
+      const isLt1M = file.size / 1024 / 1024 < 1;
+      if (!isLt1M) {
+        this.$message.error('上传图片大小不能超过 1MB!');
+      }
+      return   isLt1M;
+    },
     handleClickX(){
-        this.getList()
+      this.getList()
     },
     /** 查询店铺管理列表 */
     getList() {
@@ -403,39 +400,39 @@ export default {
     handleExport() {
       const queryParams = this.queryParams;
       this.$confirm('是否确认导出所有店铺管理数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportStore(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportStore(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     }
   }
 };
 </script>
 <style>
 
-    .avatar-uploader .el-upload {
-       border: 1px dashed #d9d9d9;
-       border-radius: 6px;
-       cursor: pointer;
-       position: relative;
-       overflow: hidden;
-     }
-     .avatar-uploader .el-upload:hover {
-       border-color: #409EFF;
-     }
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.avatar-uploader .el-upload:hover {
+  border-color: #409EFF;
+}
 
-     .avatar-uploader-icon {
-       font-size: 28px;
-       color: #8c939d;
-       width: 150px;
-       height: 150px;
-       line-height: 150px;
-       text-align: center;
-     }
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 150px;
+  height: 150px;
+  line-height: 150px;
+  text-align: center;
+}
 </style>

文件差異過大導致無法顯示
+ 630 - 246
src/views/hisStore/store/index.vue


+ 0 - 770
src/views/hisStore/store/index1.vue

@@ -1,770 +0,0 @@
-<template>
-  <div class="app-container">
-    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="店铺名称" prop="storeName">
-        <el-input
-          v-model="queryParams.storeName"
-          placeholder="请输入店铺名称"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="地址" prop="address">
-        <el-input
-          v-model="queryParams.address"
-          placeholder="请输入地址"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="店铺电话" prop="phone">
-        <el-input
-          v-model="queryParams.phone"
-          placeholder="请输入店铺电话"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="状态" prop="status">
-        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
-          <el-option
-            v-for="dict in statusOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="审核状态" prop="isAudit">
-        <el-select v-model="queryParams.isAudit" placeholder="请选择审核状态" clearable size="small">
-          <el-option
-            v-for="dict in isAuditOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="登录帐号" prop="account">
-        <el-input
-          v-model="queryParams.account"
-          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="['his:store: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="['his:store: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="['his:store: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="['his:store:export']"
-        >导出</el-button>
-      </el-col>
-      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
-    </el-row>
-
-    <el-table v-loading="loading" border :data="storeList" @selection-change="handleSelectionChange">
-      <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="店铺id" align="center" prop="storeId" width="120px"/>
-      <el-table-column label="店铺名称" align="center" prop="storeName" width="120px"/>
-      <el-table-column label="机构全称" align="center" prop="fullName" width="120px"/>
-      <el-table-column label="店铺LOGO" align="center" prop="logoUrl" width="100px">
-          <template slot-scope="scope">
-             <el-popover
-               placement="right"
-               title=""
-               trigger="hover">
-               <img slot="reference" :src="scope.row.logoUrl" width="80px">
-               <img :src="scope.row.logoUrl" style="max-width: 150px;">
-             </el-popover>
-          </template>
-      </el-table-column>
-      <el-table-column label="地址" align="center" prop="address" width="200px"/>
-      <el-table-column label="店铺电话" align="center" prop="phone" width="120px"/>
-<!--      <el-table-column label="资质证书" align="center" prop="licenseImages" width="100px">
-        <template slot-scope="scope">
-          <el-popover
-            placement="right"
-            title=""
-            trigger="hover">
-            <img slot="reference" :src="scope.row.licenseImages" width="80px">
-            <img :src="scope.row.licenseImages" style="max-width: 150px;">
-          </el-popover>
-        </template>
-      </el-table-column>
-      <el-table-column label="营业执照" align="center" prop="bizLicense" width="100px">
-        <template slot-scope="scope">
-          <el-popover
-            placement="right"
-            title=""
-            trigger="hover">
-            <img slot="reference" :src="scope.row.bizLicense" width="80px">
-            <img :src="scope.row.bizLicense" style="max-width: 150px;">
-          </el-popover>
-        </template>
-      </el-table-column>-->
-      <el-table-column label="审核状态" align="center" prop="isAudit">
-        <template slot-scope="scope">
-          <dict-tag :options="isAuditOptions" :value="scope.row.isAudit"/>
-        </template>
-      </el-table-column>
-      <el-table-column label="商品总数" align="center" prop="productCount" />
-      <el-table-column label="状态" align="center" prop="status">
-        <template slot-scope="scope">
-          <dict-tag :options="statusOptions" :value="scope.row.status"/>
-        </template>
-      </el-table-column>
-      <el-table-column label="销量" align="center" prop="salesCount" />
-      <el-table-column label="余额" align="center" prop="balance" />
-      <el-table-column label="累计金额" align="center" prop="totalMoney" />
-      <el-table-column label="登录帐号" align="center" prop="account" width="150px" />
-      <el-table-column label="创建时间" align="center" prop="createTime"  width="150px"/>
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="150px">
-        <template slot-scope="scope">
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-edit"
-            @click="handleUpdate(scope.row)"
-            v-hasPermi="['his:store:edit']"
-          >修改</el-button>
-           <el-button
-             size="mini"
-               type="text"
-               @click="handledetails(scope.row)"
-             >详情
-          </el-button>
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-delete"
-            @click="handleDelete(scope.row)"
-            v-hasPermi="['his:store:remove']"
-          >删除</el-button>
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-refresh"
-            @click="handleRefresh(scope.row)"
-            v-hasPermi="['his:store:refresh']"
-          >重置密码</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-    <pagination
-      v-show="total>0"
-      :total="total"
-      :page.sync="queryParams.pageNum"
-      :limit.sync="queryParams.pageSize"
-      @pagination="getList"
-    />
-    <!-- 添加或修改店铺管理对话框 -->
-    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
-      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
-        <el-row>
-          <el-col :span="12">
-              <el-form-item label="店铺名称" prop="storeName">
-                <el-input v-model="form.storeName" placeholder="请输入店铺名称" />
-              </el-form-item>
-          </el-col>
-          <el-col :span="12">
-              <el-form-item label="店铺电话" prop="phone">
-                <el-input v-model="form.phone" placeholder="请输入店铺电话" />
-              </el-form-item>
-          </el-col>
-        </el-row>
-              <el-form-item label="机构全称" prop="fullName">
-                <el-input v-model="form.fullName" placeholder="请输入机构全称" />
-              </el-form-item>
-        <el-row>
-            <el-col :span="12">
-              <el-form-item label="店铺LOGO" prop="logoUrl">
-               <el-upload
-                 v-model="form.logoUrl"
-                 class="avatar-uploader"
-                 :action="uploadUrl"
-                 :show-file-list="false"
-                 :on-success="handleAvatarSuccess"
-                 :before-upload="beforeAvatarUpload">
-                 <img v-if="form.logoUrl" :src="form.logoUrl" class="avatar" width="200px">
-                 <i v-else class="el-icon-plus avatar-uploader-icon"></i>
-               </el-upload>
-              </el-form-item>
-            </el-col>
-            <el-col :span="12">
-        	</el-col>
-        </el-row>
-<!--        <el-form-item label="资质证书" prop="licenseImages">
-          <ImageUpload
-            v-model="form.licenseImages"
-            class="avatar-uploader"
-            :action="licenseuploadUrl"
-            :show-file-list="false"
-            :on-success="licensehandleAvatarSuccess"
-            :before-upload="beforeAvatarUpload">
-            <img v-if="form.licenseImages" :src="form.licenseImages" class="avatar" width="200px">
-            <i v-else class="el-icon-plus avatar-uploader-icon"></i>
-          </ImageUpload>
-        </el-form-item>-->
-<!--        <el-row>
-          <el-col :span="12">
-            <el-form-item label="营业执照" prop="bizLicense">
-              <el-upload
-                v-model="form.bizLicense"
-                class="avatar-uploader"
-                :action="uploadUrl"
-                :show-file-list="false"
-                :on-success="handleBizLicenseSuccess"
-                :before-upload="beforeBizLicenseUpload">
-                <img v-if="form.bizLicense" :src="form.bizLicense" class="avatar" width="200px">
-                <i v-else class="el-icon-plus avatar-uploader-icon"></i>
-              </el-upload>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="营业执照失效日期" prop="bizLicenseExpireTime">
-              <el-input v-model="form.bizLicenseExpireTime" placeholder="请输入营业执照失效日期" />
-            </el-form-item>
-          </el-col>
-        </el-row>-->
-        <el-form-item label="店铺介绍" prop="descs" >
-          <el-input v-model="form.descs" placeholder="请输入店铺介绍" type="textarea"/>
-        </el-form-item>
-         <el-row>
-          <el-col :span="12">
-            <el-form-item label="所属城市" prop="cityIds">
-            <el-cascader
-              ref="citySelect"
-              v-model="form.cityIds"
-              :options="citys"
-              @change="handleCityChange">
-              </el-cascader>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-              <el-form-item label="地址" prop="address">
-                <el-input v-model="form.address" placeholder="请输入地址" />
-              </el-form-item>
-          </el-col>
-        </el-row>
-        <el-form-item label="退货地址" prop="refundAddress">
-          <el-input v-model="form.refundAddress" placeholder="请输入退货地址" />
-        </el-form-item>
-        <el-row>
-          <el-col :span="12">
-          <el-form-item label="退货电话" prop="refundPhone">
-            <el-input v-model="form.refundPhone" placeholder="请输入退货电话" />
-          </el-form-item>
-          </el-col>
-           <el-col :span="12">
-            <el-form-item label="退货收货人" prop="refundConsignee">
-              <el-input v-model="form.refundConsignee" placeholder="请输入退货收货人" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-form-item label="寄件人电话" prop="sendPhone">
-          <el-input v-model="form.sendPhone" placeholder="请输入寄件人电话" />
-        </el-form-item>
-          <el-row>
-          <el-col :span="12">
-            <el-form-item label="商品总数" prop="productCount">
-               <el-input-number v-model="form.productCount"  :min="0" label="描述文字"></el-input-number>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="销量" prop="salesCount">
-               <el-input-number v-model="form.salesCount"  :min="0" label="描述文字"></el-input-number>
-            </el-form-item>
-          </el-col>
-        </el-row>
-          <el-row>
-            <el-col :span="12">
-              <el-form-item label="累计金额" prop="totalMoney">
-                 <el-input-number v-model="form.totalMoney" :precision="2" :step="0.1"></el-input-number>
-              </el-form-item>
-            </el-col>
-            <el-col :span="12">
-             <!-- <el-form-item label="分佣比例%" prop="shippingType">
-                    <el-input-number v-model="form.brokerageRate" :min="0" :max="100"></el-input-number>
-               </el-form-item> -->
-            </el-col>
-          </el-row>
-          <el-row>
-            <el-col :span="12">
-              <el-form-item label="状态">
-                <el-radio-group v-model="form.status">
-                  <el-radio
-                    v-for="dict in statusOptions"
-                    :key="dict.dictValue"
-                    :label="parseInt(dict.dictValue)"
-                  >{{dict.dictLabel}}</el-radio>
-                </el-radio-group>
-              </el-form-item>
-            </el-col>
-            <el-col :span="12">
-              <el-form-item label="分佣方式" prop="brokerageType" >
-                 <el-radio v-model="form.brokerageType" label="1">每盒</el-radio>
-                 <el-radio v-model="form.brokerageType" label="2">总价</el-radio>
-              </el-form-item>
-            </el-col>
-          </el-row>
-          <el-form-item label="配送方式" prop="shippingType">
-                <el-checkbox-group v-model="form.shippingType" size="medium">
-                 <el-checkbox v-for="(item, index) in shippingTypeOptions" :key="index" :label="item.value"
-                            :disabled="item.disabled">{{item.label}}</el-checkbox>
-                 </el-checkbox-group>
-           </el-form-item>
-
-           <el-form-item label="发货方式" prop="deliveryType">
-                 <el-radio-group v-model="form.deliveryType">
-                          <el-radio :label="item.dictValue" v-for="item in deliveryTypeOptions" >{{item.dictLabel}}</el-radio>
-                 </el-radio-group>
-            </el-form-item>
-
-          <el-form-item label="登录帐号" prop="account" v-if="title != '修改店铺管理'">
-            <el-input v-model="form.account" placeholder="请输入登录帐号" />
-          </el-form-item>
-          <!--        tips-->
-        <span class="tip-text" v-if="title !== '修改店铺管理'">请牢记登录账号,初试密码123456,请及时修改密码</span>
-      </el-form>
-      <div slot="footer" class="dialog-footer">
-        <el-button type="primary" @click="submitForm">确 定</el-button>
-        <el-button @click="cancel">取 消</el-button>
-      </div>
-    </el-dialog>
-      <el-drawer
-            :with-header="false"
-            size="75%"
-             :title="show.title" :visible.sync="show.open">
-         <storeDetails  ref="Details" />
-       </el-drawer>
-
-
-  </div>
-</template>
-
-<script>
-import { listStore, getStore, delStore, addStore, updateStore, exportStore, refreshPasWod } from '@/api/hisStore/store'
-import storeDetails from '../../components/his/storeDetails.vue';
-import {getCitys} from "@/api/store/city";
-export default {
-  name: "Store",
-  components: { storeDetails },
-  data() {
-    return {
-      show:{
-              title:"店铺详情",
-              open:false,
-            },
-shippingType:[],
-      citys:[],
-      licenseuploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
-            uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
-            baseUrl: process.env.VUE_APP_BASE_API,
-      shippingTypeOptions: [{
-        "label": "配送",
-        "value": "1"
-      }, {
-        "label": "自提",
-        "value": "2"
-      }, {
-        "label": "配送自提",
-        "value": "3"
-      }],
-      // 遮罩层
-      loading: true,
-      // 导出遮罩层
-      exportLoading: false,
-      // 选中数组
-      ids: [],
-      // 非单个禁用
-      single: true,
-      // 非多个禁用
-      multiple: true,
-      // 显示搜索条件
-      showSearch: true,
-      // 总条数
-      total: 0,
-      // 店铺管理表格数据
-      storeList: [],
-      // 弹出层标题
-      title: "",
-      // 是否显示弹出层
-      open: false,
-      // 状态字典
-      statusOptions: [],
-      // 审核状态字典
-      isAuditOptions: [],
-      deliveryTypeOptions: [],
-      // 查询参数
-      queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-        storeName: null,
-        address: null,
-        phone: null,
-        status: null,
-        isAudit: null,
-        account: null,
-      },
-      // 表单参数
-      form: {},
-      // 表单校验
-      rules: {
-        storeName: [
-         { required: true, message: "店铺名称不能为空", trigger: "blur" }
-       ],
-       logoUrl: [
-         { required: true, message: "店铺LOGO不能为空", trigger: "blur" }
-       ],
-       cityIds: [
-         { required: true, message: "所属城市不能为空", trigger: "blur" }
-       ],
-      address: [
-        { required: true, message: "地址不能为空", trigger: "blur" }
-      ],
-      licenseImages: [
-        { required: true, message: "资质证书不能为空", trigger: "blur" }
-      ],
-      shippingType: [
-        { required: true, message: "配送方式不能为空", trigger: "blur" }
-      ],
-      account: [
-        { required: true, message: "登录账号不能为空", trigger: "blur" }
-      ],
-      brokerageType: [
-        { required: true, message: "分佣方式不能为空", trigger: "blur" }
-      ],
-      refundPhone: [
-        { required: true, message: "退货电话不能为空", trigger: "blur" }
-      ],
-      refundAddress: [
-        { required: true, message: "退货地址不能为空", trigger: "blur" }
-      ],
-      refundConsignee: [
-        { required: true, message: "退货收货人不能为空", trigger: "blur" }
-      ],
-      deliveryType: [
-        { required: true, message: "发货方式不能为空", trigger: "blur" }
-      ],
-      sendPhone: [
-        { required: true, message: "寄件人电话不能为空", trigger: "blur" },
-      ],
-      phone:  [
-          {
-            pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
-            message: "请输入正确的手机号码",
-            trigger: "blur"
-          }
-        ],
-
-      password: [
-        { required: true, message: "新密码不能为空", trigger: "blur" },
-        { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" }
-      ],
-      }
-    };
-  },
-  created() {
-      this.getCitys();
-    this.getList();
-    this.getDicts("sys_company_status").then(response => {
-      this.statusOptions = response.data;
-    });
-    this.getDicts("sys_company_isaudit").then(response => {
-      this.isAuditOptions = response.data;
-    });
-    this.getDicts("sys_store_delivery_type").then(response => {
-      this.deliveryTypeOptions = response.data;
-    });
-  },
-  methods: {
-
-    handledetails(row){
-            this.show.open=true;
-            setTimeout(() => {
-                 this.$refs.Details.getDetails(row.storeId);
-            }, 1);
-        },
-
-    handleCityChange(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;
-            })
-        },
-
-    licensehandleAvatarSuccess(res, file) {
-        if(res.code===200){
-          this.form.licenseImages=res.url;
-          this.$forceUpdate()
-        }
-        else{
-          this.msgError(res.msg);
-        }
-    },
-        handleAvatarSuccess(res, file) {
-            if(res.code===200){
-              this.form.logoUrl=res.url;
-              this.$forceUpdate()
-            }
-            else{
-              this.msgError(res.msg);
-            }
-        },
-        beforeAvatarUpload(file) {
-          const isLt1M = file.size / 1024 / 1024 < 1;
-          if (!isLt1M) {
-            this.$message.error('上传图片大小不能超过 1MB!');
-          }
-          return   isLt1M;
-        },
-    handleBizLicenseSuccess(res, file) {
-      if(res.code===200){
-        this.form.bizLicense=res.url;
-        this.$forceUpdate()
-      }
-      else{
-        this.msgError(res.msg);
-      }
-    },
-    beforeBizLicenseUpload(file) {
-      const isLt1M = file.size / 1024 / 1024 < 5;
-      if (!isLt1M) {
-        this.$message.error('上传图片大小不能超过 5MB!');
-      }
-      return   isLt1M;
-    },
-
-    /** 查询店铺管理列表 */
-    getList() {
-      this.loading = true;
-      listStore(this.queryParams).then(response => {
-        this.storeList = response.rows;
-        this.total = response.total;
-        this.loading = false;
-      });
-    },
-    // 取消按钮
-    cancel() {
-      this.open = false;
-      this.reset();
-    },
-    // 表单重置
-    reset() {
-      this.form = {
-        storeId: null,
-        cityIds: null,
-        storeName: null,
-        descs: null,
-        logoUrl: null,
-        address: null,
-        lng: null,
-        lat: null,
-        phone: null,
-        licenseImages: null,
-        productCount: null,
-        status: 0,
-        createTime: null,
-        updateTime: null,
-        salesCount: null,
-        balance: null,
-        totalMoney: null,
-        isAudit: 0,
-        account: null,
-        password: null,
-        shippingType: ["1"],
-        brokerageType:"1",
-        brokerageRate:0,
-        fullName: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.storeId)
-      this.single = selection.length!==1
-      this.multiple = !selection.length
-    },
-    /** 新增按钮操作 */
-    handleAdd() {
-      this.reset();
-      this.open = true;
-      this.title = "添加店铺管理";
-
-    },
-    /** 修改按钮操作 */
-    handleUpdate(row) {
-      this.reset();
-      const storeId = row.storeId || this.ids
-      getStore(storeId).then(response => {
-        this.form = response.data;
-        this.open = true;
-        this.title = "修改店铺管理";
-        var str=this.form.shippingType
-        this.form.shippingType=str.split(",")
-        this.form.cityIds=((this.form.cityIds).split(",")).map(Number)
-        if(this.form.brokerageType!=null ){
-          this.form.brokerageType=JSON.stringify(this.form.brokerageType)
-        }
-        if(this.form.deliveryType!=null ){
-          this.form.deliveryType=JSON.stringify(this.form.deliveryType)
-        }
-
-
-
-      });
-    },
-    /** 提交按钮 */
-    submitForm() {
-
-
-      this.$refs["form"].validate(valid => {
-        if (valid) {
-          this.form.cityIds=(this.form.cityIds).toString()
-          this.form.shippingType=(this.form.shippingType).toString()
-          if (this.form.storeId != null) {
-            updateStore(this.form).then(response => {
-              this.msgSuccess("修改成功");
-              this.open = false;
-              this.getList();
-            });
-          } else {
-            addStore(this.form).then(response => {
-              this.msgSuccess("新增成功");
-              this.open = false;
-              this.getList();
-            });
-          }
-        }
-      });
-    },
-    /** 删除按钮操作 */
-    handleDelete(row) {
-      const storeIds = row.storeId || this.ids;
-      this.$confirm('是否确认删除店铺管理编号为"' + storeIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delStore(storeIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
-    },
-    handleRefresh(row) {
-      const storeIds = row.storeId || this.ids;
-      this.$confirm('是否确认重置店铺管理编号为"' + storeIds + '"的密码为123456?', "警告", {
-        confirmButtonText: "确定",
-        cancelButtonText: "取消",
-        type: "warning"
-      }).then(function() {
-        return refreshPasWod(storeIds);
-      }).then(() => {
-        this.getList();
-        this.msgSuccess("删除成功");
-      }).catch(() => {});
-    },
-    /** 导出按钮操作 */
-    handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有店铺管理数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportStore(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
-    }
-  }
-};
-</script>
-<style>
-
-    .avatar-uploader .el-upload {
-       border: 1px dashed #d9d9d9;
-       border-radius: 6px;
-       cursor: pointer;
-       position: relative;
-       overflow: hidden;
-     }
-     .avatar-uploader .el-upload:hover {
-       border-color: #409EFF;
-     }
-
-     .avatar-uploader-icon {
-       font-size: 28px;
-       color: #8c939d;
-       width: 150px;
-       height: 150px;
-       line-height: 150px;
-       text-align: center;
-     }
-</style>

+ 401 - 0
src/views/hisStore/store/recommend.vue

@@ -0,0 +1,401 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+      <el-form-item label="店铺ID" prop="storeId">
+        <el-input
+          v-model="queryParams.storeId"
+          placeholder="请输入店铺ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="店铺名称" prop="storeId">
+        <el-input
+          v-model="queryParams.storeName"
+          placeholder="请输入推荐店铺名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item>
+        <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="['store:recommend: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="['store:recommend: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="['store:recommend:delete']"
+        >删除</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="['store:recommend:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" border :data="recommendScrmList" @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="店铺ID" align="center" prop="storeId" />
+      <el-table-column label="推荐店铺ID" align="center" prop="storeId" />
+      <el-table-column label="推荐店铺名称" align="center" prop="storeName" />
+      <el-table-column label="排序" align="center" prop="sortOrder" />
+      <el-table-column label="开始时间" align="center" prop="beginTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.beginTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="结束时间" align="center" prop="endTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.endTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="更新时间" align="center" prop="updateTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.updateTime) }}</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="['store:recommend:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['store:recommend: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="600px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+        <el-form-item label="推荐店铺Id" prop="storeName">
+          <el-select
+            v-model="form.storeId"
+            filterable
+            remote
+            :remote-method="searchStore"
+            :loading="storeLoading"
+            placeholder="请输入并搜索店铺名称"
+            clearable
+            @change="setStore"
+          >
+            <el-option
+              v-for="item in storeOptions"
+              :key="item.storeId"
+              :label="item.storeId"
+              :value="item.storeId"
+            >
+              <span style="float: left">{{ item.storeName }}</span>
+              <span style="float: right; color: #8492a6; font-size: 13px">ID: {{ item.storeId }}</span>
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <!-- 回显店铺名称,不可编辑 -->
+        <el-form-item label="推荐店铺名称" prop="storeName" >
+          <el-input v-model="form.storeName" placeholder="请输入推荐店铺名称" disabled/>
+        </el-form-item>
+
+        <el-form-item label="排序" prop="sortOrder">
+          <el-input-number v-model="form.sortOrder" controls-position="right" :min="0" />
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="parseInt(dict.dictValue)"
+            >{{dict.dictLabel}}</el-radio>
+          </el-radio-group>
+        </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 {
+  listRecommendScrm,
+  getRecommendScrm,
+  delRecommendScrm,
+  addRecommendScrm,
+  updateRecommendScrm,
+  exportRecommendScrm
+} from "@/api/hisStore/recommend";
+import { listStore } from '@/api/hisStore/store'
+
+export default {
+  name: "RecommendScrm",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 推荐店铺表格数据
+      recommendScrmList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 状态数据字典
+      statusOptions: [],
+      storeLoading: false,    // 店铺搜索加载状态
+      storeOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        storeId: null,
+        storeName: null,
+        status: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        storeId: [
+          { required: true, message: "店铺ID不能为空", trigger: "blur" }
+        ],
+        storeName: [
+          { required: true, message: "推荐店铺名称不能为空", trigger: "blur" }
+        ],
+        sortOrder: [
+          { required: true, message: "排序不能为空", trigger: "blur" }
+        ],
+        status: [
+          { required: true, message: "状态不能为空", trigger: "change" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("common_status").then(response => {
+      this.statusOptions = response.data;
+    });
+  },
+  methods: {
+    /** 查询推荐店铺列表 */
+    getList() {
+      this.loading = true;
+      listRecommendScrm(this.queryParams).then(response => {
+        this.recommendScrmList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    //
+    setStore(){
+      let storeId = this.form.storeId;
+      this.form.storeName = this.storeOptions.filter(item => item.storeId === storeId)[0].storeName;
+    },
+    // 搜索店铺
+    searchStore(query) {
+      if (query !== '') {
+        this.storeLoading = true;
+        // 这里应该调用实际的API来搜索店铺
+        // 示例代码,需要根据实际API调整
+        listStore({ storeName: query }).then(response => {
+          this.storeOptions = response.rows;
+          this.storeLoading = false;
+        }).catch(() => {
+          this.storeLoading = false;
+        });
+      } else {
+        this.storeOptions = [];
+      }
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        storeId: null,
+        storeName: null,
+        sortOrder: 0,
+        status: 0
+      };
+      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
+      getRecommendScrm(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) {
+            updateRecommendScrm(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addRecommendScrm(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 delRecommendScrm(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有推荐店铺数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportRecommendScrm(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 10 - 10
src/views/hisStore/storeProduct/index.vue

@@ -1114,25 +1114,25 @@ export default {
         validation.show = false;
         return;
       }
-      
+
       const img = new Image();
       const config = this.sizeConfig[type];
       const validation = type === 'product' ? this.productImageValidation : this.carouselImageValidation;
-      
+
       // 设置跨域属性,避免CORS问题
       img.crossOrigin = 'anonymous';
-      
+
       img.onload = () => {
         const { width: actualWidth, height: actualHeight } = img;
         const { width: expectedWidth, height: expectedHeight, tolerance } = config;
-        
+
         // 计算比例差异
         const expectedRatio = expectedWidth / expectedHeight;
         const actualRatio = actualWidth / actualHeight;
         const ratioDiff = Math.abs(actualRatio - expectedRatio) / expectedRatio;
-        
+
         validation.show = true;
-        
+
         if (ratioDiff <= tolerance) {
           validation.type = 'success';
           validation.message = `✓ 尺寸符合要求 (实际: ${actualWidth}x${actualHeight}px)`;
@@ -1144,13 +1144,13 @@ export default {
           validation.message = `⚠ ${typeName}尺寸不符合要求!实际: ${actualWidth}x${actualHeight}px (${(actualRatio).toFixed(2)}:1),建议: ${expectedWidth}x${expectedHeight}px (${expectedRatioText})`;
         }
       };
-      
+
       img.onerror = () => {
         validation.show = true;
         validation.type = 'warning';
         validation.message = '图片加载失败,无法验证尺寸,请检查图片URL是否正确';
       };
-      
+
       // 处理相对路径和绝对路径
       const fullImageUrl = this.getFullImageUrl(imageUrl);
       img.src = fullImageUrl;
@@ -1411,7 +1411,7 @@ export default {
             }).catch(() => {});
             return;
           }
-          
+
           if (this.carouselImageValidation.show && this.carouselImageValidation.type === 'warning') {
             this.$confirm('轮播图片尺寸不符合建议要求,是否继续提交?', '提示', {
               confirmButtonText: '继续提交',
@@ -1422,7 +1422,7 @@ export default {
             }).catch(() => {});
             return;
           }
-          
+
           this.doSubmit();
         }
       });

+ 17 - 8
src/views/hisStore/storeProductAudit/index.vue

@@ -120,6 +120,7 @@
       <el-table-column label="商品名称" show-overflow-tooltip align="center" prop="productName" />
       <el-table-column label="分类" align="center" prop="cateName" />
       <el-table-column label="所属公司" align="center" prop="companyName" />
+      <el-table-column label="所属店铺" align="center" prop="storeName" />
       <el-table-column label="售价" align="center" prop="price" >
           <template slot-scope="scope" >
               <span v-if="scope.row.price!=null">{{scope.row.price.toFixed(2)}}</span>
@@ -632,16 +633,27 @@
                   />
             </el-select>
         </el-form-item>
-        <el-form-item label="国药准字" v-if="form.productType==2" prop="prescribeCode">
+        <!-- 所属店铺 -->
+        <el-form-item label="所属店铺">
+          <el-select style="width: 240px" v-model="form.storeId" placeholder="请选择店铺" clearable size="small" >
+            <el-option
+              v-for="item in storeOptions"
+              :key="item.storeId"
+              :label="item.storeName"
+              :value="item.storeId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="国药准字" v-if="form.productType===2" prop="prescribeCode">
           <el-input v-model="form.prescribeCode" placeholder="请输入国药准字" />
         </el-form-item>
-        <el-form-item label="规格" v-if="form.productType==2" prop="prescribeSpec">
+        <el-form-item label="规格" v-if="form.productType===2" prop="prescribeSpec">
           <el-input v-model="form.prescribeSpec" placeholder="请输入规格" />
         </el-form-item>
-        <el-form-item label="生产厂家" v-if="form.productType==2" prop="prescribeFactory">
+        <el-form-item label="生产厂家" v-if="form.productType===2" prop="prescribeFactory">
           <el-input v-model="form.prescribeFactory" placeholder="请输入生产厂家" />
         </el-form-item>
-        <el-form-item label="处方名" v-if="form.productType==2" prop="prescribeName">
+        <el-form-item label="处方名" v-if="form.productType===2" prop="prescribeName">
           <el-input v-model="form.prescribeName" placeholder="请输入处方名" />
         </el-form-item>
       </el-form>
@@ -945,7 +957,6 @@ export default {
       this.isHotOptions = response.data;
       this.isGoodOptions=response.data;
       this.isDisplayOptions=response.data;
-      console.log(response.data)
     });
     this.getDicts("store_product_type").then((response) => {
       this.productTypeOptions = response.data;
@@ -1360,14 +1371,13 @@ export default {
         if(this.form.sliderImage!=null){
           this.photoArr=this.form.sliderImage.split(",");
         }
-        console.log(this.oneFormValidate)
         this.open = true;
         this.title = "审核商品";
       });
     },
     handleUpdate1(oper) {
       let operStr = oper === 1 ? "审核通过" : "审核退回";
-      this.$confirm("是否确认"+operStr+"店铺?", "警告", {
+      this.$confirm("是否确认"+operStr+"商品?", "警告", {
         confirmButtonText: "确定",
         cancelButtonText: "取消",
         type: "warning"
@@ -1420,7 +1430,6 @@ export default {
         param.reason = this.form1.reason;
         param.attachImage = this.form1.attachImage;
         param.isAudit=oper;
-        console.log("param",param)
         return batchAudit(param);
       }).then(res => {
         if(res.code === 200){

+ 65 - 1
src/views/index.vue

@@ -42,7 +42,7 @@
               </div>
 
             </div>
-            <div class="botttombg companycard">
+            <div class="cardafter companycard">
               <div class="card-title1">
                 <img src="../assets/images/tab_enterprise.png" alt="" class="icon-img">
                 企微数量
@@ -51,6 +51,17 @@
                 <count-to :start-val="0" :end-val="qwMemberNum" :duration="3600" class="card-panel-num companynumber" />
               </div>
             </div>
+            <div class="botttombg companycard">
+              <div class="card-title1">
+                <svg-icon icon-class="phone" />
+                pad使用情况
+              </div>
+              <div class="card-value highlight1">
+                <count-to :start-val="0" :end-val="padUsedNum" :duration="3600" class="card-panel-num companynumber" />
+                /
+                <count-to :start-val="0" :end-val="padTotalNum" :duration="1800" class="card-panel-num companynumber" />
+              </div>
+            </div>
           </div>
         </el-col>
 
@@ -218,6 +229,24 @@
         </div>
 
         <div class="action-group">
+          <!-- 选择部门 -->
+          <el-select v-model="deptId" placeholder="请选择部门" size="small" @change="handleDeptChange" style="width: 100px">
+            <el-option
+              v-for="company in deptOptions"
+              :key="company.deptId"
+              :label="company.deptName"
+              :value="company.deptId"
+            />
+          </el-select>
+          <!-- 选择销售公司 -->
+          <el-select  v-model="companyId" placeholder="请选择销售公司" size="small" clearable @change="handleCompanyChange" style="width: 180px" >
+            <el-option
+              v-for="company in companyOptions"
+              :key="company.companyId"
+              :label="company.companyName"
+              :value="company.companyId"
+            />
+          </el-select>
           <el-radio-group v-model="userTypeText" @change="handleUserType">
             <el-radio-button label="会员"></el-radio-button>
             <el-radio-button label="企微"></el-radio-button>
@@ -512,6 +541,8 @@ import {
   watchCourseTopTen, watchEndPlayTrend
 } from "@/api/statistics/statistics";
 import dayjs from 'dayjs';
+import { listDept } from '@/api/system/dept'
+import { listCompany } from '@/api/his/company'
 
 
 const viewCharOption = {
@@ -846,6 +877,11 @@ export default {
   components: {CountTo},
   data() {
     return {
+      deptOptions:[],
+      deptId:this.$store.state.user.deptId,
+      companyInitOptions:[],
+      companyOptions:[],
+      companyId:null,
       percentage: 0,
       // 预测message
       remainMessage: '',
@@ -870,6 +906,10 @@ export default {
       memberCount: 0,
       // 企微数量
       qwMemberNum: 0,
+      // pad使用情况
+      padTotalNum: 0,
+      // pad使用情况
+      padUsedNum: 0,
       // 正常会员数量
       normalNum: 0,
       // 黑名单会员数量
@@ -942,8 +982,29 @@ export default {
   },
   created() {
     this.refresh();
+    listDept().then(res => {
+      this.deptOptions = res.data;
+    });
+    listCompany().then(res => {
+      this.companyIntiOptions = res.rows;
+      this.companyOptions = this.companyIntiOptions.filter(item => item.deptId === this.deptId);
+    });
   },
   methods: {
+    //首页统计选择部门、销售公司
+    handleDeptChange(){
+        this.companyOptions = this.companyIntiOptions.filter(item => item.deptId === this.deptId);
+        this.companyId = null;
+        this.refresh();
+    },
+    handleCompanyChange(){
+      if(this.companyId){
+        this.deptId = this.companyOptions.filter(item => item.companyId === this.companyId)[0].deptId;
+        this.refresh();
+      }else{
+        this.refresh();
+      }
+    },
     handleUserType(){
       if(this.userTypeText === '会员'){
         this.userType = 1
@@ -1082,6 +1143,9 @@ export default {
           this.groupMgrCount = res.data.groupMgrCount??0;
           this.memberCount = res.data.memberCount??0;
           this.qwMemberNum = res.data.qwMemberNum??0;
+          this.padTotalNum = res.data.padTotalNum??0;
+          this.padUsedNum = res.data.padUsedNum??0;
+          this.padInfo = res.data.padInfo;
           this.normalNum = res.data.normalNum??0;
           this.blackNum = res.data.blackNum??0;
           this.todayIncreaseUserNum = res.data.todayIncreaseUserNum??0;

+ 36 - 2
src/views/qw/externalContact/index.vue

@@ -222,6 +222,17 @@
           v-hasPermi="['qw:externalContact:export']"
         >导出</el-button>
       </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportUnionidLoading"
+          @click="handleExportUnionId"
+          v-hasPermi="['qw:externalContact:export']"
+        >导出unionid</el-button>
+      </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
@@ -402,7 +413,7 @@
 </template>
 
 <script>
-import { listExternalContact, getExternalContact, delExternalContact, addExternalContact, updateExternalContact, exportExternalContact } from "@/api/qw/externalContact";
+import { listExternalContact, getExternalContact, delExternalContact, addExternalContact, updateExternalContact, exportExternalContact, exportUnionId } from "@/api/qw/externalContact";
 import {getCompanyList} from "@/api/company/company";
 import {getAllUserlist} from "@/api/company/companyUser";
 import {getQwUserInfo} from "@/api/qw/qwUser";
@@ -420,6 +431,7 @@ export default {
       loading: false,
       // 导出遮罩层
       exportLoading: false,
+      exportUnionidLoading: false,
       //等级状态
       ratingUpFall: [],
       // 性别字典
@@ -908,7 +920,29 @@ export default {
           this.download(response.msg);
           this.exportLoading = false;
         }).catch(() => {});
-    }
+    },
+    /** 导出Unionid按钮操作 */
+    handleExportUnionId() {
+      //验证是否选择企业
+      if(!this.queryParams.companyId){
+        return this.$message.warning({
+          message: "请先选择企业!",
+          duration: 3000
+        })
+      }
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有企业微信客户unionid数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportUnionidLoading = true;
+          return exportUnionId(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportUnionidLoading = false;
+        }).catch(() => {});
+    },
   }
 };
 </script>

+ 6 - 3
src/views/qw/qwCompany/index.vue

@@ -174,9 +174,12 @@
         <el-form-item label="应用回调地接" prop="notifyUrl" >
           <el-input v-model="form.notifyUrl" placeholder="请输入应用回调地接" :readonly="true"/>
         </el-form-item>
-		<el-form-item label="应用id" prop="serverAgentId" >
-		  <el-input v-model="form.serverAgentId" placeholder="请输入serverAgentId" />
-		</el-form-item>
+        <el-form-item label="应用id" prop="serverAgentId" >
+          <el-input v-model="form.serverAgentId" placeholder="请输入serverAgentId" />
+        </el-form-item>
+        <el-form-item label="小程序id" prop="miniAppId" >
+          <el-input v-model="form.miniAppId" placeholder="请输入小程序id" />
+        </el-form-item>
         <el-form-item label="企业可信IP" >
           <div>42.194.245.189;119.29.195.254;129.204.130.233;43.138.187.210;129.204.76.229;159.75.239.132119.29.249.66;122.152.230.82</div>
         </el-form-item>

+ 3 - 0
src/views/qw/sopTemp/index.vue

@@ -595,6 +595,9 @@ export default {
           this.title = "修改";
         }
         this.form = response.data;
+        if(response.data.project){
+          this.form.project = String(response.data.project)
+        }
         this.open = true;
       });
     },

+ 463 - 3
src/views/system/config/config.vue

@@ -178,6 +178,9 @@
             <el-form-item label="会员自动续费协议" prop="vipAutomaticService">
               <editor v-model="form3.vipAutomaticService" :min-height="292"/>
             </el-form-item>
+            <el-form-item label="用户注销协议" prop="vipAutomaticService">
+              <editor v-model="form3.userRemoveService" :min-height="292"/>
+            </el-form-item>
 
             <div class="footer">
               <el-button type="primary" @click="submitForm3">提  交</el-button>
@@ -1596,7 +1599,7 @@
         </el-form>
 
       </el-tab-pane>
-       <el-tab-pane label="企业理念" name="store.concept">
+      <el-tab-pane label="企业理念" name="store.concept">
          <el-form ref="form21" :model="form21" :rules="rules21" label-width="160px">
            <el-form-item   label="企业理念图片" prop="images">
              <Material v-model="images" type="image" :num="10" :width="150" :height="150" />
@@ -1622,6 +1625,344 @@
         </div>
       </el-form>
     </el-tab-pane>
+    <el-tab-pane label="APP推广" name="app.config">
+         <el-form ref="form25" :model="form25" :rules="rules25" label-width="160px">
+           <el-form-item   label="APP推广图片" prop="images">
+             <Material v-model="appImages" type="image" :num="10" :width="150" :height="150" />
+           </el-form-item>
+           <el-form-item label="APP推广视频" prop="videoUrl">
+             <div>
+               <el-upload
+                 ref="upload"
+                 class="upload-demo"
+                 :action="uploadUrl"
+                 :on-success="appHandleSuccess"
+                 :before-upload="beforeUpload"
+                 :limit="1"
+                 :accept="videoAccept"
+               >
+                 <el-button size="small" type="primary">点击上传视频</el-button>
+               </el-upload>
+               <video :src="form25.videoUrl" controls style="max-width: 400px; max-height: 400px;"></video>
+             </div>
+           </el-form-item>
+           <div  class="footer">
+             <el-button type="primary" @click="submitForm25">提  交</el-button>
+        </div>
+      </el-form>
+    </el-tab-pane>
+
+    <el-tab-pane label="健康指标配置" name="his.healthIndexConfig">
+      
+        <el-form ref="form26" :model="form26" label-width="200px">
+          <!-- 红色提示 严格按照对应格式参数填写,指标参数只能是数字和特殊符号,数值保留一位小数,特殊符号只能有 < > ≥ ≤ ~ 不能有空格 -->
+          <el-card class="box-card">
+            <div slot="header" class="clearfix">
+              <span style="color: red;">请严格按照对应格式参数填写,指标参数只能是数字和特殊符号,数值保留一位小数,特殊符号只能有 &lt; &gt; ≥ ≤ ~ 不能有空格</span>
+            </div>
+          </el-card>
+
+
+          
+          <!-- 血糖指标 -->
+        <el-card class="box-card" style="margin-bottom: 20px;">
+          <div slot="header" class="clearfix">
+            <span>血糖指标 (mmol/L)</span>
+          </div>
+          
+          <el-form-item label="空腹血糖正常值">
+            <el-input v-model="form26.bloodGlucose.fasting.normal" placeholder="例如: 3.9-6.1">
+              <template slot="append">mmol/L</template>
+            </el-input>
+          </el-form-item>
+          
+          <el-form-item label="餐后1小时血糖正常值">
+            <el-input v-model="form26.bloodGlucose.post1Hour.normal" placeholder="例如: 6.7-9.0">
+              <template slot="append">mmol/L</template>
+            </el-input>
+          </el-form-item>
+          
+          <el-form-item label="餐后2小时血糖正常值">
+            <el-input v-model="form26.bloodGlucose.post2Hour.normal" placeholder="例如: ≤7.8">
+              <template slot="append">mmol/L</template>
+            </el-input>
+          </el-form-item>
+          
+          <el-form-item label="血糖异常程度配置">
+            <el-table :data="form26.bloodGlucose.severity" style="width: 100%;">
+              <el-table-column prop="level" label="严重程度" width="120">
+                <template slot-scope="scope">
+                  <el-tag :type="scope.row.level === 'normal' ? 'success' : 
+                            scope.row.level === 'mild' ? 'warning' : 'danger'">
+                    {{ scope.row.level === 'normal' ? '正常' : 
+                      scope.row.level === 'mild' ? '轻微' : '严重' }}
+                  </el-tag>
+                </template>
+              </el-table-column>
+              <el-table-column prop="range" label="数值范围">
+                <template slot-scope="scope">
+                  <el-input v-model="scope.row.range" placeholder="例如: <3.9 or 6.1-7.8"></el-input>
+                </template>
+              </el-table-column>
+              <el-table-column prop="description" label="描述">
+                <template slot-scope="scope">
+                  <el-input v-model="scope.row.description" placeholder="例如: 低血糖风险"></el-input>
+                </template>
+              </el-table-column>
+            </el-table>
+          </el-form-item>
+        </el-card>
+        
+        <!-- 血压指标 -->
+        <el-card class="box-card" style="margin-bottom: 20px;">
+          <div slot="header" class="clearfix">
+            <span>血压指标 (mmHg)</span>
+          </div>
+          
+
+          
+          <el-form-item label="血压异常程度配置">
+            <el-table :data="form26.bloodPressure.severity" style="width: 100%;">
+              <el-table-column prop="level" label="严重程度" width="120">
+                <template slot-scope="scope">
+                  <el-tag :type="scope.row.level === 'normal' ? 'success' : 
+                            scope.row.level === 'mild' ? 'warning' : 'danger'">
+                    {{ scope.row.level === 'normal' ? '正常' : 
+                      scope.row.level === 'mild' ? '轻微' : '严重' }}
+                  </el-tag>
+                </template>
+              </el-table-column>
+              <el-table-column prop="type" label="血压类型" width="120">
+                <template slot-scope="scope">
+                  <span>{{ scope.row.type === 'systolic' ? '收缩压' : '舒张压' }}</span>
+                </template>
+              </el-table-column>
+              <el-table-column prop="range" label="数值范围">
+                <template slot-scope="scope">
+                  <el-input v-model="scope.row.range" placeholder="例如: <90 or 120-139"></el-input>
+                </template>
+              </el-table-column>
+              <el-table-column prop="description" label="描述">
+                <template slot-scope="scope">
+                  <el-input v-model="scope.row.description" placeholder="例如: 正常高值"></el-input>
+                </template>
+              </el-table-column>
+            </el-table>
+          </el-form-item>
+        </el-card>
+
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <span>尿酸指标 (μmol/L)</span>
+          </div>
+
+          <el-form-item label="性别分类配置">
+            <el-tabs v-model="form26.uricAcid.activeGender">
+              <el-tab-pane label="男性" name="male">
+                <el-table :data="form26.uricAcid.male" style="width: 100%;">
+                  <el-table-column prop="level" label="风险等级" width="120">
+                    <template slot-scope="scope">
+                      <el-tag :type="scope.row.level === 'normal' ? 'success' : 
+                                scope.row.level === 'mild' ? 'warning' : 'danger'">
+                        {{ scope.row.level === 'normal' ? '正常' : 
+                          scope.row.level === 'mild' ? '不良' : '高风险' }}
+                      </el-tag>
+                    </template>
+                  </el-table-column>
+                  <el-table-column prop="range" label="数值范围">
+                    <template slot-scope="scope">
+                      <el-input v-model="scope.row.range" placeholder="例如: <420"></el-input>
+                    </template>
+                  </el-table-column>
+                  <el-table-column prop="description" label="描述">
+                    <template slot-scope="scope">
+                      <el-input v-model="scope.row.description" placeholder="例如: 正常范围"></el-input>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </el-tab-pane>
+              
+              <el-tab-pane label="女性" name="female">
+                <el-table :data="form26.uricAcid.female" style="width: 100%;">
+                  <el-table-column prop="level" label="风险等级" width="120">
+                    <template slot-scope="scope">
+                      <el-tag :type="scope.row.level === 'normal' ? 'success' : 
+                                scope.row.level === 'mild' ? 'warning' : 'danger'">
+                        {{ scope.row.level === 'normal' ? '正常' : 
+                          scope.row.level === 'mild' ? '不良' : '高风险' }}
+                      </el-tag>
+                    </template>
+                  </el-table-column>
+                  <el-table-column prop="range" label="数值范围">
+                    <template slot-scope="scope">
+                      <el-input v-model="scope.row.range" placeholder="例如: <360"></el-input>
+                    </template>
+                  </el-table-column>
+                  <el-table-column prop="description" label="描述">
+                    <template slot-scope="scope">
+                      <el-input v-model="scope.row.description" placeholder="例如: 正常范围"></el-input>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </el-tab-pane>
+            </el-tabs>
+          </el-form-item>
+        </el-card>
+
+        <!-- Add BMI指标 card after the uric acid card -->
+        <el-card class="box-card" style="margin-bottom: 20px;">
+          <div slot="header" class="clearfix">
+            <span>BMI指标 (kg/m²)</span>
+          </div>
+
+          <el-form-item label="BMI异常程度配置">
+            <el-table :data="form26.bmi.severity" style="width: 100%;">
+              <el-table-column prop="level" label="严重程度" width="120">
+                <template slot-scope="scope">
+                  <el-tag :type="scope.row.level === 'normal' ? 'success' : 
+                            scope.row.level === 'mild' ? 'warning' : 'danger'">
+                    {{ scope.row.level === 'normal' ? '正常' : 
+                      scope.row.level === 'mild' ? '偏瘦' : '偏胖' }}
+                  </el-tag>
+                </template>
+              </el-table-column>
+              <el-table-column prop="range" label="数值范围">
+                <template slot-scope="scope">
+                  <el-input v-model="scope.row.range" placeholder="例如: 18.5-23.9"></el-input>
+                </template>
+              </el-table-column>
+              <el-table-column prop="description" label="描述">
+                <template slot-scope="scope">
+                  <el-input v-model="scope.row.description" placeholder="例如: 正常范围"></el-input>
+                </template>
+              </el-table-column>
+            </el-table>
+          </el-form-item>
+        </el-card>
+
+
+        <!-- 腰围指标 -->
+        <el-card class="box-card" style="margin-bottom: 20px;">
+          <div slot="header" class="clearfix">
+            <span>腰围指标 (cm)</span>
+          </div>
+
+          <el-form-item label="性别分类配置">
+            <el-tabs v-model="form26.waist.activeGender">
+              <el-tab-pane label="男性" name="male">
+                <el-table :data="form26.waist.male" style="width: 100%;">
+                  <el-table-column prop="level" label="风险等级" width="120">
+                    <template slot-scope="scope">
+                      <el-tag :type="scope.row.level === 'normal' ? 'success' : 
+                                scope.row.level === 'mild' ? 'warning' : 'danger'">
+                        {{ scope.row.level === 'normal' ? '正常' : 
+                          scope.row.level === 'mild' ? '偏小' : '偏大' }}
+                      </el-tag>
+                    </template>
+                  </el-table-column>
+                  <el-table-column prop="range" label="数值范围">
+                    <template slot-scope="scope">
+                      <el-input v-model="scope.row.range" placeholder="例如: <90"></el-input>
+                    </template>
+                  </el-table-column>
+                  <el-table-column prop="description" label="描述">
+                    <template slot-scope="scope">
+                      <el-input v-model="scope.row.description" placeholder="例如: 正常范围"></el-input>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </el-tab-pane>
+              
+              <el-tab-pane label="女性" name="female">
+                <el-table :data="form26.waist.female" style="width: 100%;">
+                  <el-table-column prop="level" label="风险等级" width="120">
+                    <template slot-scope="scope">
+                      <el-tag :type="scope.row.level === 'normal' ? 'success' : 
+                                scope.row.level === 'mild' ? 'warning' : 'danger'">
+                        {{ scope.row.level === 'normal' ? '正常' : 
+                          scope.row.level === 'mild' ? '偏小' : '偏大' }}
+                      </el-tag>
+                    </template>
+                  </el-table-column>
+                  <el-table-column prop="range" label="数值范围">
+                    <template slot-scope="scope">
+                      <el-input v-model="scope.row.range" placeholder="例如: <80"></el-input>
+                    </template>
+                  </el-table-column>
+                  <el-table-column prop="description" label="描述">
+                    <template slot-scope="scope">
+                      <el-input v-model="scope.row.description" placeholder="例如: 正常范围"></el-input>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </el-tab-pane>
+            </el-tabs>
+          </el-form-item>
+        </el-card>
+
+        <el-card class="box-card" style="margin-bottom: 20px;">
+          <div slot="header" class="clearfix">
+            <span>臀围指标 (cm)</span>
+          </div>
+
+          <el-form-item label="性别分类配置">
+            <el-tabs v-model="form26.hip.activeGender">
+              <el-tab-pane label="男性" name="male">
+                <el-table :data="form26.hip.male" style="width: 100%;">
+                  <el-table-column prop="level" label="风险等级" width="120">
+                    <template slot-scope="scope">
+                      <el-tag :type="scope.row.level === 'normal' ? 'success' : 
+                                scope.row.level === 'mild' ? 'warning' : 'danger'">
+                        {{ scope.row.level === 'normal' ? '正常' : 
+                          scope.row.level === 'mild' ? '偏小' : '偏大' }}
+                      </el-tag>
+                    </template>
+                  </el-table-column>
+                  <el-table-column prop="range" label="数值范围">
+                    <template slot-scope="scope">
+                      <el-input v-model="scope.row.range" placeholder="例如: 90-100"></el-input>
+                    </template>
+                  </el-table-column>
+                  <el-table-column prop="description" label="描述">
+                    <template slot-scope="scope">
+                      <el-input v-model="scope.row.description" placeholder="例如: 正常范围"></el-input>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </el-tab-pane>
+              
+              <el-tab-pane label="女性" name="female">
+                <el-table :data="form26.hip.female" style="width: 100%;">
+                  <el-table-column prop="level" label="风险等级" width="120">
+                    <template slot-scope="scope">
+                      <el-tag :type="scope.row.level === 'normal' ? 'success' : 
+                                scope.row.level === 'mild' ? 'warning' : 'danger'">
+                        {{ scope.row.level === 'normal' ? '正常' : 
+                          scope.row.level === 'mild' ? '偏小' : '偏大' }}
+                      </el-tag>
+                    </template>
+                  </el-table-column>
+                  <el-table-column prop="range" label="数值范围">
+                    <template slot-scope="scope">
+                      <el-input v-model="scope.row.range" placeholder="例如: 85-95"></el-input>
+                    </template>
+                  </el-table-column>
+                  <el-table-column prop="description" label="描述">
+                    <template slot-scope="scope">
+                      <el-input v-model="scope.row.description" placeholder="例如: 正常范围"></el-input>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </el-tab-pane>
+            </el-tabs>
+          </el-form-item>
+        </el-card>
+        
+        <div class="footer">
+          <el-button type="primary" @click="submitForm26">提交</el-button>
+        </div>
+      </el-form>
+    </el-tab-pane>
     </el-tabs>
 
 
@@ -1661,6 +2002,7 @@ export default {
     return {
       citys:[],
       images:[],
+      appImages:[],
       uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
       videoAccept:"video/*",
       courseMaConfigLoading:false,
@@ -1742,6 +2084,77 @@ export default {
       },
       form24:{
       },
+      form25:{
+      },
+      form26: {
+        bloodGlucose: {
+          fasting: { normal: "" },
+          post1Hour: { normal: "" },
+          post2Hour: { normal: "" },
+          severity: [
+            { level: "normal", range: "", description: "" },
+            { level: "mild", range: "", description: "" },
+            { level: "severe", range: "", description: "" }
+          ]
+        },
+        bloodPressure: {
+          protection: { systolic: "", diastolic: "" },
+          severity: [
+            { level: "normal", type: "systolic", range: "", description: "" },
+            { level: "mild", type: "systolic", range: "", description: "" },
+            { level: "severe", type: "systolic", range: "", description: "" },
+            { level: "normal", type: "diastolic", range: "", description: "" },
+            { level: "mild", type: "diastolic", range: "", description: "" },
+            { level: "severe", type: "diastolic", range: "", description: "" }
+          ]
+        },
+        uricAcid: {
+          activeGender: "male",
+          male: [
+            { level: "normal", range: "", description: "" },
+            { level: "mild", range: "", description: "" },
+            { level: "severe", range: "", description: "" }
+          ],
+          female: [
+            { level: "normal", range: "", description: "" },
+            { level: "mild", range: "", description: "" },
+            { level: "severe", range: "", description: "" }
+          ]
+        },
+        bmi: {
+          severity: [
+            { level: "normal", range: "", description: "" },
+            { level: "mild", range: "", description: "" },
+            { level: "severe", range: "", description: "" }
+          ]
+        },
+        waist: {
+          activeGender: "male",
+          male: [
+            { level: "normal", range: "", description: "" },
+            { level: "mild", range: "", description: "" },
+            { level: "severe", range: "", description: "" }
+          ],
+          female: [
+            { level: "normal", range: "", description: "" },
+            { level: "mild", range: "", description: "" },
+            { level: "severe", range: "", description: "" }
+          ]
+        },
+        hip: {
+          activeGender: "male",
+          male: [
+            { level: "normal", range: "", description: "" },
+            { level: "mild", range: "", description: "" },
+            { level: "severe", range: "", description: "" }
+          ],
+          female: [
+            { level: "normal", range: "", description: "" },
+            { level: "mild", range: "", description: "" },
+            { level: "severe", range: "", description: "" }
+          ]
+        }
+      },
       photoArr:[],
       couponList:[],
       inquirySubTypeOptions:[],
@@ -1795,7 +2208,9 @@ export default {
         cLevelMax: [{ required: true, message: '请输入C级最大值', trigger: 'blur' }],
         dLevelMax: [{ required: true, message: '请输入D级最大值', trigger: 'blur' }],
       },
-      rules21:{}
+      rules21:{},
+      rules25:{},
+      rules26: {},
     };
   },
   created() {
@@ -1817,7 +2232,10 @@ export default {
     },
     images: function(val) {
      this.form21.images = val.join(',')
-   }
+    },
+    appImages: function(val) {
+     this.form25.images = val.join(',')
+    }
   },
   methods: {
 
@@ -1922,6 +2340,12 @@ export default {
       this.form21.videoUrl = response.url;
       this.$refs.upload.clearFiles();
     },
+    appHandleSuccess(response, file) {
+      // 上传成功后的回调函数
+      this.myloading.close();
+      this.form25.videoUrl = response.url;
+      this.$refs.upload.clearFiles();
+    },
     beforeUpload(file) {
       // 上传前的钩子函数,可以在这里对文件进行处理
       // 返回 false 则取消上传
@@ -2118,6 +2542,9 @@ export default {
           if(key=="his.login"){
             this.form22 =JSON.parse(response.data.configValue);
           }
+          if (key === "his.healthIndexConfig") {
+            this.form26 =JSON.parse(response.data.configValue);
+          }
           else if(key=="store.concept"){
             this.configId=response.data.configId;
             this.configKey=response.data.configKey;
@@ -2132,6 +2559,14 @@ export default {
             this.form24 =JSON.parse(response.data.configValue);
             console.log(this.form24.sign)
           }
+          else if(key=="app.config"){
+            this.configId=response.data.configId;
+            this.configKey=response.data.configKey;
+            this.form25 =JSON.parse(response.data.configValue);
+            if(this.form25.images!=null){
+              this.appImages=this.form25.images.split(",");
+            }
+          }
         });
      },
     /** 提交按钮 */
@@ -2215,6 +2650,7 @@ export default {
       }
     });
   },
+  
   submitForm10(){
     var param={configId:this.configId,configValue:JSON.stringify(this.form10)}
     updateConfigByKey(param).then(response => {
@@ -2326,6 +2762,15 @@ export default {
       });
 
     },
+    submitForm25(){
+      var param={configId:this.configId,configKey:this.configKey,configValue:JSON.stringify(this.form25)}
+      console.log(param)
+      updateConfigByKey(param).then(response => {
+        if (response.code === 200) {
+          this.msgSuccess("修改成功");
+        }
+      });
+    },
     submitForm21(){
       var param={configId:this.configId,configKey:this.configKey,configValue:JSON.stringify(this.form21)}
       updateConfigByKey(param).then(response => {
@@ -2334,6 +2779,21 @@ export default {
         }
       });
     },
+    submitForm26() {
+      const param = {
+        configId:this.configId,
+        configKey:this.configKey,
+        configValue: JSON.stringify(this.form26)
+      };
+      
+      updateConfigByKey(param).then(response => {
+        if (response.code === 200) {
+          this.msgSuccess("健康指标配置保存成功");
+        } else {
+          this.msgError("保存失败");
+        }
+      });
+    },
     submitForm24(){
       this.$refs["form24"].validate(valid => {
         if (valid) {

部分文件因文件數量過多而無法顯示