Bläddra i källkod

Merge branch 'master' into bjcz_his_scrm

# Conflicts:
#	src/api/hisStore/storeOrder.js
#	src/views/hisStore/storeOrder/healthStoreList.vue
#	src/views/hisStore/storeOrder/index.vue
#	src/views/hisStore/storeProduct/index.vue
#	src/views/system/config/config.vue
吴树波 3 veckor sedan
förälder
incheckning
d63ef6afd8
100 ändrade filer med 10084 tillägg och 952 borttagningar
  1. 3 3
      .env.development
  2. 2 2
      .env.prod-bjyjb
  3. 3 1
      .env.prod-bly
  4. 40 0
      .env.prod-cqtyt
  5. 40 0
      .env.prod-ddgy
  6. 40 0
      .env.prod-hat
  7. 40 0
      .env.prod-hst
  8. 1 1
      .env.prod-jzzx
  9. 39 0
      .env.prod-knt
  10. 1 1
      .env.prod-sxjz
  11. 8 4
      .env.prod-test
  12. 6 0
      package.json
  13. 46 0
      src/api/company/statistics.js
  14. 9 0
      src/api/company/traffic.js
  15. 3 2
      src/api/course/coursePlaySourceConfig.js
  16. 10 0
      src/api/course/courseRedPacketStatistics.js
  17. 7 0
      src/api/course/qw/courseWatchLog.js
  18. 8 0
      src/api/course/userCourseVideo.js
  19. 9 0
      src/api/fastGpt/fastgptPushTokenTotal.js
  20. 61 0
      src/api/his/answer.js
  21. 16 0
      src/api/his/company.js
  22. 68 8
      src/api/his/complaint.js
  23. 53 0
      src/api/his/dfAccount.js
  24. 53 0
      src/api/his/divItem.js
  25. 9 0
      src/api/his/doctor.js
  26. 10 1
      src/api/his/integralGoods.js
  27. 9 0
      src/api/his/integralOrder.js
  28. 17 0
      src/api/his/package.js
  29. 45 0
      src/api/his/promotionalActive.js
  30. 9 0
      src/api/his/promotionalActiveLog.js
  31. 9 0
      src/api/his/user.js
  32. 8 8
      src/api/hisStore/city.js
  33. 8 0
      src/api/hisStore/statistics.js
  34. 2 2
      src/api/hisStore/store.js
  35. 66 18
      src/api/hisStore/storeOrder.js
  36. 8 0
      src/api/hisStore/storeProduct.js
  37. 0 54
      src/api/hospital/hospital.js
  38. 240 3
      src/api/qw/externalContact.js
  39. 25 0
      src/api/qw/externalContactTransferAudit.js
  40. 14 14
      src/api/statistics/statistics.js
  41. 35 0
      src/api/system/resourceManagement.js
  42. BIN
      src/assets/logo/cqtyt.jpg
  43. BIN
      src/assets/logo/ddgy.jpg
  44. BIN
      src/assets/logo/hat.png
  45. BIN
      src/assets/logo/hst_logo.png
  46. BIN
      src/assets/logo/knt.jpg
  47. 1 1
      src/components/Pagination/index.vue
  48. 9 2
      src/store/modules/user.js
  49. 3 0
      src/views/company/company/index.vue
  50. 7 7
      src/views/company/companyMoneyLogs/index.vue
  51. 42 9
      src/views/company/companyTraffic/index.vue
  52. 42 9
      src/views/company/companyTrafficLog/index.vue
  53. 365 0
      src/views/company/statistics/tuiMoney.vue
  54. 7 0
      src/views/components/course/userCourseCatalogDetails.vue
  55. 26 0
      src/views/components/his/packageDetails.vue
  56. 6 1
      src/views/components/his/storeAfterSalesDetails.vue
  57. 201 18
      src/views/components/his/storeOrderDetails.vue
  58. 14 2
      src/views/components/his/userDetails.vue
  59. 111 0
      src/views/components/his/userIntegralDetails.vue
  60. 32 0
      src/views/course/coursePlaySourceConfig/index.vue
  61. 206 0
      src/views/course/courseRedPacketStatistics/index.vue
  62. 299 0
      src/views/course/courseWatchLog/qw/statisticsCompany.vue
  63. 65 20
      src/views/course/courseWatchLog/statistics.vue
  64. 3 3
      src/views/course/courseWatchLog/watchLogStatistics.vue
  65. 14 2
      src/views/course/userWatchCourseStatistics/index.vue
  66. 15 1
      src/views/course/userWatchCourseTotalStatistics/index.vue
  67. 14 1
      src/views/course/userWatchStatistics/index.vue
  68. 36 15
      src/views/course/videoResource/index.vue
  69. 2055 0
      src/views/crm/externalContact/index.vue
  70. 259 0
      src/views/fastGpt/fastGptPushTokenTotal/index.vue
  71. 20 4
      src/views/fastGpt/fastgptEventLogTotal/index.vue
  72. 22 2
      src/views/his/adv/index.vue
  73. 525 0
      src/views/his/answer/index.vue
  74. 180 17
      src/views/his/company/index.vue
  75. 130 557
      src/views/his/complaint/index.vue
  76. 475 0
      src/views/his/complaint/template.vue
  77. 442 0
      src/views/his/dfAccount/index.vue
  78. 378 0
      src/views/his/divItem/index.vue
  79. 30 2
      src/views/his/doctor/type1.vue
  80. 30 2
      src/views/his/doctor/type2.vue
  81. 26 1
      src/views/his/inquiryOrder/order1.vue
  82. 25 1
      src/views/his/inquiryOrder/order2.vue
  83. 27 0
      src/views/his/inquiryOrder/order3.vue
  84. 77 30
      src/views/his/inquiryOrderReport/index.vue
  85. 26 1
      src/views/his/integralOrder/index.vue
  86. 90 6
      src/views/his/package/index.vue
  87. 59 6
      src/views/his/packageOrder/index.vue
  88. 147 0
      src/views/his/promotionalActive/ChooseCourseVideoComponent.vue
  89. 213 0
      src/views/his/promotionalActive/ChooseDoctorComponent.vue
  90. 176 0
      src/views/his/promotionalActive/ChooseIntegralGoodsComponent.vue
  91. 202 0
      src/views/his/promotionalActive/ChoosePackageComponent.vue
  92. 689 0
      src/views/his/promotionalActive/index.vue
  93. 103 0
      src/views/his/promotionalActive/stats.vue
  94. 352 0
      src/views/his/statistics/afterSalesOrder.vue
  95. 179 0
      src/views/his/statistics/appOrderCountStats.vue
  96. 186 0
      src/views/his/statistics/hisOrderCountStats.vue
  97. 326 104
      src/views/his/storeOrder/order1.vue
  98. 10 2
      src/views/his/storeOrder/order2.vue
  99. 24 1
      src/views/his/storePayment/index.vue
  100. 3 3
      src/views/his/storeProduct/index.vue

+ 3 - 3
.env.development

@@ -1,9 +1,9 @@
 # 页面标题
-VUE_APP_TITLE =小访客管理系统
+VUE_APP_TITLE =互联网医院管理系统
 # 首页菜单标题
-VUE_APP_TITLE_INDEX =小访客
+VUE_APP_TITLE_INDEX =互联网医院
 # 公司名称
-VUE_APP_COMPANY_NAME =西安小访客网络科技有限公司
+VUE_APP_COMPANY_NAME =
 # ICP备案号
 VUE_APP_ICP_RECORD =陕ICP备2025066365号-3
 # ICP网站访问地址

+ 2 - 2
.env.prod-bjyjb

@@ -1,7 +1,7 @@
 # 页面标题
-VUE_APP_TITLE =医健宝互联网医院管理系统
+VUE_APP_TITLE =医健宝医药管理系统
 # 首页菜单标题
-VUE_APP_TITLE_INDEX =医健宝互联网医院
+VUE_APP_TITLE_INDEX =医健宝医药
 # 公司名称
 VUE_APP_COMPANY_NAME =医健宝智慧(北京)医药科技有限公司
 # ICP备案号

+ 3 - 1
.env.prod-bly

@@ -1,5 +1,7 @@
 # 页面标题
-VUE_APP_TITLE = 倍力优会员商城私域平台
+VUE_APP_TITLE =倍力优会员商城平台
+# 首页菜单标题
+VUE_APP_TITLE_INDEX =倍力优会员商城平台
 # 公司名称
 VUE_APP_COMPANY_NAME = 倍力优(北京)健康产业科技有限公司
 # ICP备案号

+ 40 - 0
.env.prod-cqtyt

@@ -0,0 +1,40 @@
+# 页面标题
+VUE_APP_TITLE =重庆泰医堂
+# 首页菜单标题
+VUE_APP_TITLE_INDEX =重庆泰医堂
+# 公司名称
+VUE_APP_COMPANY_NAME =泰安高新区泰医堂中医医院有限公司
+# ICP备案号
+VUE_APP_ICP_RECORD =鲁ICP备2025154120号-1
+# ICP网站访问地址
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/cqtyt.jpg
+# 存储桶配置
+VUE_APP_OBS_ACCESS_KEY_ID = K2UTJGIN7UTZJR2XMXYG
+# 存储桶配置
+VUE_APP_OBS_SECRET_ACCESS_KEY = sbyeNJLbcYmH6copxeFP9pAoksM4NIT9Zw4x0SRX
+# 存储桶配置
+VUE_APP_OBS_SERVER = https://obs.cn-north-4.myhuaweicloud.com
+# 存储桶配置
+VUE_APP_OBS_BUCKET = cqtyt-hw079058881
+# 存储桶配置
+VUE_APP_COS_BUCKET = cqtyt-1323137866
+# 存储桶配置
+VUE_APP_COS_REGION = ap-chongqing
+# 线路一地址
+VUE_APP_VIDEO_LINE_1 = https://cqtytcpv.ylrzcloud.com
+# 线路二地址
+VUE_APP_VIDEO_LINE_2 = https://cqtytobs.ylrztop.com
+
+# 开发环境配置
+ENV = 'production'
+
+# FS管理系统/开发环境
+VUE_APP_BASE_API = '/prod-api'
+
+#默认 1、会员 2、企微
+VUE_APP_COURSE_DEFAULT = 1
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 40 - 0
.env.prod-ddgy

@@ -0,0 +1,40 @@
+# 页面标题
+VUE_APP_TITLE =叮当国医总管理系统
+# 首页菜单标题
+VUE_APP_TITLE_INDEX =叮当国医管理系统
+# 公司名称
+VUE_APP_COMPANY_NAME =重庆云联融智科技有限公司
+# ICP备案号
+VUE_APP_ICP_RECORD =渝ICP备2024031984号-1
+# ICP网站访问地址
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/ddgy.jpg
+# 存储桶配置
+VUE_APP_OBS_ACCESS_KEY_ID = K2UTJGIN7UTZJR2XMXYG
+# 存储桶配置
+VUE_APP_OBS_SECRET_ACCESS_KEY = sbyeNJLbcYmH6copxeFP9pAoksM4NIT9Zw4x0SRX
+# 存储桶配置
+VUE_APP_OBS_SERVER = https://obs.cn-north-4.myhuaweicloud.com
+# 存储桶配置
+VUE_APP_OBS_BUCKET = ddgy-hw079058881
+# 存储桶配置
+VUE_APP_COS_BUCKET = ddgy-1323137866
+# 存储桶配置
+VUE_APP_COS_REGION = ap-chongqing
+# 线路一地址
+VUE_APP_VIDEO_LINE_1 = https://ddgytcpv.ylrzcloud.com
+# 线路二地址
+VUE_APP_VIDEO_LINE_2 = https://ddgyobs.ylrztop.com
+
+# 开发环境配置
+ENV = 'development'
+
+# FS管理系统/开发环境
+VUE_APP_BASE_API = '/prod-api'
+
+#默认 1、会员 2、企微
+VUE_APP_COURSE_DEFAULT = 2
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 40 - 0
.env.prod-hat

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

+ 40 - 0
.env.prod-hst

@@ -0,0 +1,40 @@
+# 页面标题
+VUE_APP_TITLE =互联网医院管理系统
+# 首页菜单标题
+VUE_APP_TITLE_INDEX =鸿森堂管理系统
+# 公司名称
+VUE_APP_COMPANY_NAME =成都温江鸿森堂智慧互联网医院有限公司
+# ICP备案号
+VUE_APP_ICP_RECORD =蜀ICP备2025160310号-3
+# ICP网站访问地址
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/hst_logo.png
+# 存储桶配置
+VUE_APP_OBS_ACCESS_KEY_ID = K2UTJGIN7UTZJR2XMXYG
+# 存储桶配置
+VUE_APP_OBS_SECRET_ACCESS_KEY = sbyeNJLbcYmH6copxeFP9pAoksM4NIT9Zw4x0SRX
+# 存储桶配置
+VUE_APP_OBS_SERVER = https://obs.cn-north-4.myhuaweicloud.com
+# 存储桶配置
+VUE_APP_OBS_BUCKET = hst-hw079058881
+# 存储桶配置
+VUE_APP_COS_BUCKET = hst-1323137866
+# 存储桶配置
+VUE_APP_COS_REGION = ap-chongqing
+# 线路一地址
+VUE_APP_VIDEO_LINE_1 = https://hsttcpv.ylrzcloud.com
+# 线路二地址
+VUE_APP_VIDEO_LINE_2 = https://hstobs.ylrztop.com
+
+# 开发环境配置
+ENV = 'development'
+
+# FS管理系统/开发环境
+VUE_APP_BASE_API = '/prod-api'
+
+#默认 1、会员 2、企微
+VUE_APP_COURSE_DEFAULT = 2
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 1 - 1
.env.prod-jzzx

@@ -1,7 +1,7 @@
 # 页面标题
 VUE_APP_TITLE =九州在线管理系统
 # 首页菜单标题
-VUE_APP_TITLE_INDEX =九州在线
+VUE_APP_TITLE_INDEX =九州好医生
 # 公司名称
 VUE_APP_COMPANY_NAME =成都双流九州在线互联网医院有限公司
 # ICP备案号

+ 39 - 0
.env.prod-knt

@@ -0,0 +1,39 @@
+# 页面标题
+VUE_APP_TITLE = 康年堂SCRM管理系统
+# 首页菜单标题
+VUE_APP_TITLE_INDEX = 康年堂
+# 公司名称
+VUE_APP_COMPANY_NAME = 陕西康年堂医药连锁有限公司
+# ICP备案号
+VUE_APP_ICP_RECORD = 陕ICP备2023011686号-5
+# ICP网站访问地址
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/knt.jpg
+# 存储桶配置
+VUE_APP_OBS_ACCESS_KEY_ID = K2UTJGIN7UTZJR2XMXYG
+# 存储桶配置
+VUE_APP_OBS_SECRET_ACCESS_KEY = sbyeNJLbcYmH6copxeFP9pAoksM4NIT9Zw4x0SRX
+# 存储桶配置
+VUE_APP_OBS_SERVER = https://obs.cn-north-4.myhuaweicloud.com
+# 存储桶配置
+VUE_APP_OBS_BUCKET = jnmy-hw079058881
+# 存储桶配置
+VUE_APP_COS_BUCKET = jnmy-1323137866
+# 存储桶配置
+VUE_APP_COS_REGION = ap-chongqing
+# 线路一地址
+VUE_APP_VIDEO_LINE_1 = https://jnmytcpv.ylrzcloud.com
+# 线路二地址
+VUE_APP_VIDEO_LINE_2 = https://jnmyobs.ylrztop.com
+# 生产环境配置
+ENV = 'production'
+
+#FS管理系统/生产环境
+VUE_APP_BASE_API = '/prod-api'
+
+#默认 1、会员 2、企微
+VUE_APP_COURSE_DEFAULT = 1
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 1 - 1
.env.prod-sxjz

@@ -1,5 +1,5 @@
 # 页面标题
-VUE_APP_TITLE =互联网医院管理系统
+VUE_APP_TITLE =挑宝总管理系统
 # 首页菜单标题
 VUE_APP_TITLE_INDEX =挑宝网
 # 公司名称

+ 8 - 4
.env.prod-test

@@ -8,6 +8,8 @@ VUE_APP_ICP_RECORD =蜀ICP备2023036719号
 VUE_APP_ICP_URL =https://beian.miit.gov.cn
 # 网站LOG
 VUE_APP_LOG_URL =@/assets/logo/logo.png
+
+
 # 存储桶配置
 VUE_APP_OBS_ACCESS_KEY_ID = K2UTJGIN7UTZJR2XMXYG
 # 存储桶配置
@@ -15,15 +17,17 @@ VUE_APP_OBS_SECRET_ACCESS_KEY = sbyeNJLbcYmH6copxeFP9pAoksM4NIT9Zw4x0SRX
 # 存储桶配置
 VUE_APP_OBS_SERVER = https://obs.cn-north-4.myhuaweicloud.com
 # 存储桶配置
-VUE_APP_OBS_BUCKET = zkzh-hw079058881
+VUE_APP_OBS_BUCKET = myhk-hw079058881
 # 存储桶配置
-VUE_APP_COS_BUCKET = zkzh-1323137866
+VUE_APP_COS_BUCKET = myhk-1323137866
 # 存储桶配置
 VUE_APP_COS_REGION = ap-chongqing
 # 线路一地址
-VUE_APP_VIDEO_LINE_1 = https://zkzhtcpv.ylrzcloud.com
+VUE_APP_VIDEO_LINE_1 = https://myhktcpv.ylrzcloud.com
 # 线路二地址
-VUE_APP_VIDEO_LINE_2 = https://zkzhobs.ylrztop.com
+VUE_APP_VIDEO_LINE_2 = https://myhkobs.ylrztop.com
+
+ 
 
 # 开发环境配置
 ENV = 'development'

+ 6 - 0
package.json

@@ -14,10 +14,12 @@
     "build:prod-hcl": "vue-cli-service build --mode prod-hcl",
     "build:prod-myhk": "vue-cli-service build --mode prod-myhk",
     "build:prod-nmgyt": "vue-cli-service build --mode prod-nmgyt",
+    "build:prod-cqtyt": "vue-cli-service build --mode prod-cqtyt",
     "build:prod-bly": "vue-cli-service build --mode prod-bly",
     "build:prod-sxjz": "vue-cli-service build --mode prod-sxjz",
     "build:prod-xfk": "vue-cli-service build --mode prod-xfk",
     "build:prod-jnmy": "vue-cli-service build --mode prod-jnmy",
+    "build:prod-knt": "vue-cli-service build --mode prod-knt",
     "build:prod-hdt": "vue-cli-service build --mode prod-hdt",
     "build:prod-yzt": "vue-cli-service build --mode prod-yzt",
     "build:prod-fcky": "vue-cli-service build --mode prod-fcky",
@@ -39,6 +41,10 @@
     "build:prod-zkzh": "vue-cli-service build --mode prod-zkzh",
     "build:prod-syysy": "vue-cli-service build --mode prod-syysy",
     "build:prod-hyt": "vue-cli-service build --mode prod-hyt",
+    "build:prod-hst": "vue-cli-service build --mode prod-hst",
+    "build:prod-czt": "vue-cli-service build --mode prod-czt",
+    "build:prod-hat": "vue-cli-service build --mode prod-hat",
+    "build:prod-ddgy": "vue-cli-service build --mode prod-ddgy",
     "preview": "node build/index.js --preview",
     "lint": "eslint --ext .js,.vue src"
   },

+ 46 - 0
src/api/company/statistics.js

@@ -39,6 +39,14 @@ export function packageOrder(query) {
     params: query
   })
 }
+
+export function afterSalesOrder(query) {
+  return request({
+    url: '/company/statistics/afterSalesOrder',
+    method: 'get',
+    params: query
+  })
+}
 export function inquiryOrder(query) {
   return request({
     url: '/company/statistics/inquiryOrder',
@@ -46,7 +54,23 @@ export function inquiryOrder(query) {
     params: query
   })
 }
+// 获取互联网医院订单统计数据
+export function getHisOrderCountStats(query) {
+  return request({
+    url: '/company/statistics/hisOrderCountStats',
+    method: 'get',
+    params: query
+  });
+}
 
+// 获取App商城订单统计数据
+export function getAppOrderCount(query) {
+  return request({
+    url: '/company/statistics/appOrderCountStats',
+    method: 'get',
+    params: query
+  });
+}
 
 export function exportStoreOrder(query) {
   return request({
@@ -62,6 +86,14 @@ export function exportPackageOrder(query) {
     params: query
   })
 }
+
+export function exportAfterSalesOrder(query) {
+  return request({
+    url: '/company/statistics/exportAfterSalesOrder',
+    method: 'get',
+    params: query
+  })
+}
 export function exportInquiryOrder(query) {
   return request({
     url: '/company/statistics/exportInquiryOrder',
@@ -141,3 +173,17 @@ export function exportTokenStaticByTime(dateTime) {
   })
 }
 
+export function tuiMoney(query) {
+  return request({
+    url: '/company/statistics/tuiMoney',
+    method: 'get',
+    params: query
+  })
+}
+export function exportTuiMoney(query) {
+  return request({
+    url: '/company/statistics/exportTuiMoney',
+    method: 'get',
+    params: query
+  })
+}

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

@@ -16,3 +16,12 @@ export function listTrafficRecords(query) {
   })
 }
 
+///trafficConversion
+export function trafficConversion(data) {
+  return request({
+    url: '/company/traffic/trafficConversion',
+    method: 'get',
+    params: data
+  })
+}
+

+ 3 - 2
src/api/course/coursePlaySourceConfig.js

@@ -38,9 +38,10 @@ export function del(id) {
   })
 }
 
-export function listAll() {
+export function listAll(companyId) {
   return request({
     url: '/course/playSourceConfig/listAll',
-    method: 'get'
+    method: 'get',
+    params: {companyId}
   })
 }

+ 10 - 0
src/api/course/courseRedPacketStatistics.js

@@ -0,0 +1,10 @@
+import request from '@/utils/request'
+
+// 查询短链课程看课记录列表
+export function list(query) {
+  return request({
+    url: '/course/courseRedPacketStatistics/list',
+    method: 'get',
+    params: query
+  })
+}

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

@@ -23,6 +23,13 @@ export function statisticsList(query) {
     params: query
   })
 }
+export function statisticsListByCompany(query) {
+  return request({
+    url: '/qw/course/courseWatchLog/statisticsListByCompany',
+    method: 'get',
+    params: query
+  })
+}
 export function qwWatchLogStatisticsList(query) {
   return request({
     url: '/qw/course/courseWatchLog/qwWatchLogStatisticsList',

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

@@ -102,4 +102,12 @@ export function getVideoListLikeName(query) {
   })
 }
 
+export function getChooseCourseVideoList(query) {
+  return request({
+    url: '/course/userCourseVideo/getChooseCourseVideoList',
+    method: 'get',
+    params: query
+  })
+}
+
 

+ 9 - 0
src/api/fastGpt/fastgptPushTokenTotal.js

@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+export function getFastGptPushTokenTotal(query) {
+  return request({
+    url: '/qw/qwPushCount/tokenList',
+    method: 'get',
+    params: query
+  })
+}

+ 61 - 0
src/api/his/answer.js

@@ -0,0 +1,61 @@
+import request from '@/utils/request'
+
+// 查询问答列表
+export function listAnswer(query) {
+  return request({
+    url: '/his/answer/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询问答详细
+export function getAnswer(id) {
+  return request({
+    url: '/his/answer/' + id,
+    method: 'get'
+  })
+}
+
+// 新增问答
+export function addAnswer(data) {
+  return request({
+    url: '/his/answer',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改问答
+export function updateAnswer(data) {
+  return request({
+    url: '/his/answer',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除问答
+export function delAnswer(id) {
+  return request({
+    url: '/his/answer/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出问答
+export function exportAnswer(query) {
+  return request({
+    url: '/his/answer/export',
+    method: 'get',
+    params: query
+  })
+}
+
+// 问答列表选项
+export function questionOptions() {
+  return request({
+    url: '/his/answer/allList',
+    method: 'get',
+  })
+}

+ 16 - 0
src/api/his/company.js

@@ -71,3 +71,19 @@ export function exportCompany(query) {
     params: query
   })
 }
+
+// 查询诊所管理详细
+export function getDivConfig(companyId) {
+  return request({
+    url: '/his/company/getDivConfig/' + companyId,
+    method: 'get'
+  })
+}
+
+export function setDiv(data) {
+  return request({
+    url: '/his/company/setDiv',
+    method: 'post',
+    data: data
+  })
+}

+ 68 - 8
src/api/his/complaint.js

@@ -1,19 +1,79 @@
 import request from '@/utils/request'
 
+// 查询投诉模板列表
+export function listTemplate(query) {
+  return request({
+    url: '/his/template/list',
+    method: 'get',
+    params: query
+  })
+}
 
-// 查询用户投诉列表
-export function listComplaint(data) {
+// 查询投诉模板列表
+export function treeListTemplate(query) {
   return request({
-    url: '/user/complaint/list',
+    url: '/his/template/treeList',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询投诉模板详细
+export function getTemplate(id) {
+  return request({
+    url: '/his/template/' + id,
+    method: 'get'
+  })
+}
+
+// 新增投诉模板
+export function addTemplate(data) {
+  return request({
+    url: '/his/template',
     method: 'post',
     data: data
   })
 }
 
+// 修改投诉模板
+export function updateTemplate(data) {
+  return request({
+    url: '/his/template',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除投诉模板
+export function delTemplate(id) {
+  return request({
+    url: '/his/template/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出投诉模板
+export function exportTemplate(query) {
+  return request({
+    url: '/his/template/export',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询用户投诉列表
+export function listComplaint(query) {
+  return request({
+    url: '/his/complaint/list',
+    method: 'get',
+    params: query
+  })
+}
+
 // 查询用户投诉详细
 export function getComplaint(id) {
   return request({
-    url: '/user/complaint/' + id,
+    url: '/his/complaint/' + id,
     method: 'get'
   })
 }
@@ -21,7 +81,7 @@ export function getComplaint(id) {
 // 新增用户投诉
 export function addComplaint(data) {
   return request({
-    url: '/user/complaint',
+    url: '/his/complaint',
     method: 'post',
     data: data
   })
@@ -30,7 +90,7 @@ export function addComplaint(data) {
 // 修改用户投诉
 export function updateComplaint(data) {
   return request({
-    url: '/user/complaint',
+    url: '/his/complaint',
     method: 'put',
     data: data
   })
@@ -39,7 +99,7 @@ export function updateComplaint(data) {
 // 删除用户投诉
 export function delComplaint(id) {
   return request({
-    url: '/user/complaint/' + id,
+    url: '/his/complaint/' + id,
     method: 'delete'
   })
 }
@@ -47,7 +107,7 @@ export function delComplaint(id) {
 // 导出用户投诉
 export function exportComplaint(query) {
   return request({
-    url: '/user/complaint/export',
+    url: '/his/complaint/export',
     method: 'get',
     params: query
   })

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

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询代服账户列表
+export function listAccount(query) {
+  return request({
+    url: '/his/dfAccount/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询代服账户详细
+export function getAccount(id) {
+  return request({
+    url: '/his/dfAccount/' + id,
+    method: 'get'
+  })
+}
+
+// 新增代服账户
+export function addAccount(data) {
+  return request({
+    url: '/his/dfAccount',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改代服账户
+export function updateAccount(data) {
+  return request({
+    url: '/his/dfAccount',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除代服账户
+export function delAccount(id) {
+  return request({
+    url: '/his/dfAccount/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出代服账户
+export function exportAccount(query) {
+  return request({
+    url: '/his/dfAccount/export',
+    method: 'get',
+    params: query
+  })
+}

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

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询分账明细列表
+export function listDivItem(query) {
+  return request({
+    url: '/his/divItem/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询分账明细详细
+export function getDivItem(id) {
+  return request({
+    url: '/his/divItem/' + id,
+    method: 'get'
+  })
+}
+
+// 新增分账明细
+export function addDivItem(data) {
+  return request({
+    url: '/his/divItem',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改分账明细
+export function updateDivItem(data) {
+  return request({
+    url: '/his/divItem',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除分账明细
+export function delDivItem(id) {
+  return request({
+    url: '/his/divItem/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出分账明细
+export function exportDivItem(query) {
+  return request({
+    url: '/his/divItem/export',
+    method: 'get',
+    params: query
+  })
+}

+ 9 - 0
src/api/his/doctor.js

@@ -141,3 +141,12 @@ export function exportDoctor(query) {
     params: query
   })
 }
+
+// 医生选择列表
+export function getChooseDoctorList(query) {
+  return request({
+    url: '/his/doctor/getChooseDoctorList',
+    method: 'get',
+    params: query
+  })
+}

+ 10 - 1
src/api/his/integralGoods.js

@@ -55,4 +55,13 @@ export function exportIntegralGoods(query) {
     method: 'get',
     params: query
   })
-}
+}
+
+// 获取选择积分商品列表
+export function getChooseIntegralGoodsList(query) {
+  return request({
+    url: '/his/integralGoods/getChooseIntegralGoodsList',
+    method: 'get',
+    params: query
+  })
+}

+ 9 - 0
src/api/his/integralOrder.js

@@ -78,3 +78,12 @@ export function getOrderUserPhone(orderId) {
     method: 'get'
   })
 }
+
+//取消订单
+export function cancelOrder(orderCode) {
+  return request({
+    url: '/his/integralOrder/cancelOrder',
+    method: 'post',
+    data: {orderCode}
+  })
+}

+ 17 - 0
src/api/his/package.js

@@ -55,6 +55,14 @@ export function delPackage(packageId) {
   })
 }
 
+//批量复制套餐包
+export function bulkCopy(packageId) {
+  return request({
+    url: '/his/package/bulkCopy/' + packageId,
+    method: 'get'
+  })
+}
+
 // 导出套餐包
 export function exportPackage(query) {
   return request({
@@ -81,3 +89,12 @@ export function modifyPackages(data) {
     data: data
   })
 }
+
+// 获取可选套餐包列表
+export function getChoosePackageList(query) {
+  return request({
+    url: '/his/package/getChoosePackageList',
+    method: 'get',
+    params: query
+  })
+}

+ 45 - 0
src/api/his/promotionalActive.js

@@ -0,0 +1,45 @@
+import request from '@/utils/request'
+
+export function list(query) {
+  return request({
+    url: '/his/promotionActive/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function get(id) {
+  return request({
+    url: '/his/promotionActive/' + id,
+    method: 'get'
+  })
+}
+
+export function add(data) {
+  return request({
+    url: '/his/promotionActive',
+    method: 'post',
+    data: data
+  })
+}
+
+export function update(data) {
+  return request({
+    url: '/his/promotionActive',
+    method: 'put',
+    data: data
+  })
+}
+export function del(id) {
+  return request({
+    url: '/his/promotionActive/' + id,
+    method: 'delete'
+  })
+}
+
+export function getPromotionalActiveOption() {
+  return request({
+    url: '/his/promotionActive/getPromotionalActiveOption',
+    method: 'get',
+  })
+}

+ 9 - 0
src/api/his/promotionalActiveLog.js

@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+export function list(query) {
+  return request({
+    url: '/his/promotionActiveLog/list',
+    method: 'get',
+    params: query
+  })
+}

+ 9 - 0
src/api/his/user.js

@@ -73,6 +73,15 @@ export function exportUser(query) {
   })
 }
 
+// 导出项目用户
+export function exportListProject(query) {
+  return request({
+    url: '/his/user/exportListProject',
+    method: 'get',
+    params: query
+  })
+}
+
 // 获取小黑屋用户列表
 export function darkRoomList(query) {
   return request({

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

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

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

@@ -30,3 +30,11 @@ export function storePayment(query) {
     params
   });
 }
+
+ export function storeOrderStatistics(params) {
+    return request({
+      url: '/store/store/statistics/storeOrderStatistics',
+      method: 'get',
+      params
+    });
+  }

+ 2 - 2
src/api/hisStore/store.js

@@ -53,8 +53,8 @@ export function delStore(storeId) {
 
 export function refreshPasWod(storeId) {
   return request({
-    url: '/store/his/store/refresh'+ storeId,
-    method: 'get'
+    url: '/store/his/store/refresh/'+ storeId,
+    method: 'put'
   })
 }
 

+ 66 - 18
src/api/hisStore/storeOrder.js

@@ -1,11 +1,11 @@
 import request from '@/utils/request'
 
 // 查询订单列表
-export function listStoreOrder(query) {
+export function listStoreOrder(data) {
   return request({
     url: '/store/store/storeOrder/list',
-    method: 'get',
-    params: query
+    method: 'post',
+    data: data
   })
 }
 
@@ -34,11 +34,11 @@ export function listPromotionOrder(query) {
   })
 }
 // 查询健康商城订单列表
-export function listHealthStoreOrder(query) {
+export function listHealthStoreOrder(data) {
   return request({
     url: '/store/store/storeOrder/healthList',
-    method: 'get',
-    params: query
+    method: 'post',
+    data: data
   })
 }
 
@@ -122,39 +122,39 @@ export function delStoreOrder(id) {
 }
 
 // 导出订单
-export function exportStoreOrder(query) {
+export function exportStoreOrder(data) {
   return request({
     url: '/store/store/storeOrder/export',
-    method: 'get',
-    params: query
+    method: 'post',
+    data: data
   })
 }
 
 // 导出订单
-export function exportStoreOrderDetails(query) {
+export function exportStoreOrderDetails(data) {
   return request({
     url: '/store/store/storeOrder/exportDetails',
-    method: 'get',
-    params: query
+    method: 'post',
+    data: data
   })
 }
 
 
 // 导出订单
-export function exportHealthStoreOrder(query) {
+export function exportHealthStoreOrder(data) {
   return request({
     url: '/store/store/storeOrder/healthExport',
-    method: 'get',
-    params: query
+    method: 'post',
+    data: data
   })
 }
 
 // 导出订单
-export function exportHealthStoreOrderDetails(query) {
+export function exportHealthStoreOrderDetails(data) {
   return request({
     url: '/store/store/storeOrder/healthExportDetails',
-    method: 'get',
-    params: query
+    method: 'post',
+    data: data
   })
 }
 
@@ -347,3 +347,51 @@ export function importDeliveryNoteExpressTemplate() {
     method: 'get'
   })
 }
+
+export function queryErpPhone(query) {
+  return request({
+    url: '/store/store/storeOrder/queryErpPhone',
+    method: 'get',
+    params: query
+  })
+}
+
+export function saveErpPhone(data) {
+  return request({
+    url: '/store/store/storeOrder/saveErpPhone',
+    method: 'post',
+    data: data
+  })
+}
+
+export function editErpPhone(data) {
+  return request({
+    url: '/store/store/storeOrder/editErpPhone',
+    method: 'post',
+    data: data
+  })
+}
+
+export function batchCreateErpOrder(data) {
+  return request({
+    url: '/store/store/storeOrder/batchCreateErpOrder',
+    method: 'post',
+    data: data
+  })
+}
+
+export function batchSetErpOrder(data) {
+  return request({
+    url: '/store/store/storeOrder/batchSetErpOrder',
+    method: 'post',
+    data: data
+  })
+}
+
+
+export function getErpAccount() {
+  return request({
+    url: '/store/store/storeOrder/getErpAccount',
+    method: 'get'
+  })
+}

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

@@ -58,6 +58,14 @@ export function delStoreProduct(productId) {
   })
 }
 
+// 批量复制商品
+export function bulkCopy(productId) {
+  return request({
+    url: '/store/store/storeProduct/bulkCopy/' + productId,
+    method: 'get'
+  })
+}
+
 // 导出商品
 export function exportStoreProduct(query) {
   return request({

+ 0 - 54
src/api/hospital/hospital.js

@@ -1,54 +0,0 @@
-import request from '@/utils/request'
-
-// 查询诊所列表
-export function listHospital(query) {
-  return request({
-    url: '/hospital/hospital/list',
-    method: 'get',
-    params: query
-  })
-}
-
-// 查询诊所详细
-export function getHospital(hospitalId) {
-  return request({
-    url: '/hospital/hospital/' + hospitalId,
-    method: 'get'
-  })
-}
-
-// 新增诊所
-export function addHospital(data) {
-  return request({
-    url: '/hospital/hospital',
-    method: 'post',
-    data: data
-  })
-}
-
-// 修改诊所
-export function updateHospital(data) {
-  return request({
-    url: '/hospital/hospital',
-    method: 'put',
-    data: data
-  })
-}
-
-// 删除诊所
-export function delHospital(hospitalId) {
-  return request({
-    url: '/hospital/hospital/' + hospitalId,
-    method: 'delete'
-  })
-}
-
-// 导出诊所
-export function exportHospital(query) {
-  return request({
-    url: '/hospital/hospital/export',
-    method: 'get',
-    params: query
-  })
-}
-

+ 240 - 3
src/api/qw/externalContact.js

@@ -9,6 +9,37 @@ export function listExternalContact(query) {
   })
 }
 
+// 查询企业微信客户列表
+export function getRepeat(query) {
+  return request({
+    url: '/qw/externalContact/getRepeat',
+    method: 'get',
+    params: query
+  })
+}
+
+export function myDeptExtList(query) {
+  return request({
+    url: '/qw/externalContact/myDeptExtList',
+    method: 'get',
+    params: query
+  })
+}
+export function myList(query) {
+  return request({
+    url: '/qw/externalContact/myList',
+    method: 'get',
+    params: query
+  })
+}
+/** 查询 预计发送客户的总数 */
+export function selectCountCustomer(param) {
+  return request({
+    url: '/qw/externalContact/expectQwGroupMsgCountCustomer',
+    method: 'post',
+    data:param,
+  })
+}
 // 查询企业微信客户详细
 export function getExternalContact(id) {
   return request({
@@ -26,6 +57,81 @@ export function addExternalContact(data) {
   })
 }
 
+//同步我的企微客户
+export function syncMyExternalContact(id) {
+  return request({
+    url: '/qw/externalContact/syncMyExternalContact/'+id,
+    method: 'get',
+  })
+}
+
+export function syncMyAddExternalContact(id) {
+  return request({
+    url: '/qw/externalContact/syncAddMyExternalContact/'+id,
+    method: 'get',
+  })
+}
+export function getUserInfo(id) {
+  return request({
+    url: '/qw/externalContact/getUserInfo/'+id,
+    method: 'get',
+  })
+}
+
+export function addUnassigned(data) {
+  return request({
+    url: '/qw/externalContact/addUnassigned',
+    method: 'post',
+    data: data
+  })
+}
+export function addTag(data) {
+  return request({
+    url: '/qw/externalContact/addTag',
+    method: 'post',
+    data: data
+  })
+}
+
+export function addTagByWatch(data) {
+  return request({
+    url: '/qw/externalContact/addTagByWatch',
+    method: 'post',
+    data: data
+  })
+}
+
+
+export function delTag(data) {
+  return request({
+    url: '/qw/externalContact/delTag',
+    method: 'post',
+    data: data
+  })
+}
+
+export function delTagByWatch(data) {
+  return request({
+    url: '/qw/externalContact/delTagByWatch',
+    method: 'post',
+    data: data
+  })
+}
+
+export function resignedTransfer(data) {
+  return request({
+    url: '/qw/externalContact/resignedTransfer',
+    method: 'put',
+    data: data
+  })
+}
+export function transfer(data) {
+  return request({
+    url: '/qw/externalContact/transfer',
+    method: 'put',
+    data: data
+  })
+}
 // 修改企业微信客户
 export function updateExternalContact(data) {
   return request({
@@ -35,6 +141,44 @@ export function updateExternalContact(data) {
   })
 }
 
+// 修改企业微信客户称呼
+export function updateExternalContactCall(data) {
+  return request({
+    url: '/qw/externalContact/call',
+    method: 'put',
+    data: data
+  })
+}
+// 修改企业微信客户
+export function editStatus(data) {
+  return request({
+    url: '/qw/externalContact/editStatus',
+    method: 'put',
+    data: data
+  })
+}
+
+export function editbindCustomer(data) {
+  return request({
+    url: '/qw/externalContact/editbindCustomer',
+    method: 'put',
+    data: data
+  })
+}
+export function bindUserId(data) {
+  return request({
+    url: '/qw/externalContact/bindUserId',
+    method: 'put',
+    data: data
+  })
+}
+
+export function unBindUserId(id) {
+  return request({
+    url: '/qw/externalContact/unBindUserId/'+id,
+    method: 'get',
+  })
+}
 // 删除企业微信客户
 export function delExternalContact(id) {
   return request({
@@ -51,11 +195,104 @@ export function exportExternalContact(query) {
     params: query
   })
 }
+export function exportMyExternalContact(query) {
+  return request({
+    url: '/qw/externalContact/myExport',
+    method: 'get',
+    params: query
+  })
+}
+
+/**
+ * 获取CRM客户列表
+ */
+export function getMyCustomerList(query) {
+  return request({
+    url: '/qw/externalContact/getMyCustomerList',
+    method: 'get',
+    params: query
+  })
+}
+
+/**
+ * 获取小程序的客户
+ */
+export function getMiniProgramCustomer(query) {
+  return request({
+    url: '/qw/externalContact/getMiniCustomer',
+    method: 'get',
+    params: query
+  })
+}
 
-// 导出企业微信客户unionId
-export function exportUnionId(query) {
+/**
+ * 获取课程列表
+ */
+export function getCourseStudyList(query) {
+  return request({
+    url: '/qw/externalContact/getCourseStudyList',
+    method: 'get',
+    params: query
+  })
+}
+
+/**
+ * 设置客户-课节SOP
+ */
+export function setCustomerCourseSop(data) {
+  return request({
+    url: '/qw/externalContact/setCustomerCourseSop',
+    method: 'post',
+    data: data
+  })
+}
+
+
+/**
+ * 批量设置客户-课节SOP
+ */
+export function setCustomerCourseSopList(data) {
+  return request({
+    url: '/qw/externalContact/setCustomerCourseSopList',
+    method: 'post',
+    data: data
+  })
+}
+
+/**
+ * 查询是否已经设置过客户-某个课节的SOP
+ */
+export function getCustomerCourseSop(query) {
+  return request({
+    url: '/qw/externalContact/getCustomerCourseSop',
+    method: 'get',
+    params: query
+  })
+}
+
+
+export function batchUpdateExternalContactNotes(data) {
+  return request({
+    url: '/qw/externalContact/batchUpdateExternalContactNotes',
+    method: 'post',
+    data: data
+  })
+}
+
+// 查询企业微信客户流失删除统计列表
+export function delLossStatistics(query) {
+  return request({
+    url: '/qw/externalContact/delLossStatistics',
+    method: 'get',
+    params: query
+  })
+}
+
+
+// 导出企业微信客户
+export function delLossStatisticsExport(query) {
   return request({
-    url: '/qw/externalContact/exportUnionId',
+    url: '/qw/externalContact/delLossStatisticsExport',
     method: 'get',
     params: query
   })

+ 25 - 0
src/api/qw/externalContactTransferAudit.js

@@ -0,0 +1,25 @@
+import request from '@/utils/request'
+
+export function listExternalContactTransferAudit(query) {
+  return request({
+    url: '/qw/externalContactTransferCompanyAudit/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function detail(auditId, params) {
+  return request({
+    url: '/qw/externalContactTransferCompanyAudit/detail/' + auditId,
+    method: 'get',
+    params: params
+  })
+}
+
+export function audit(data) {
+  return request({
+    url: '/qw/externalContactTransferCompanyAudit/audit',
+    method: 'post',
+    data: data
+  })
+}

+ 14 - 14
src/api/statistics/statistics.js

@@ -33,11 +33,11 @@ export function analysisPreview(param) {
  * @param query
  * @returns {AxiosPromise}
  */
-export function dealerAggregated() {
+export function dealerAggregated(param) {
   return request({
     url: '/index/statistics/dealerAggregated',
     method: 'get',
-    params: {}
+    params: param
   })
 }
 
@@ -45,22 +45,22 @@ export function dealerAggregated() {
  * 消费余额
  * @returns {AxiosPromise}
  */
-export function rechargeComsumption(){
+export function rechargeComsumption(param){
   return request({
     url: '/index/statistics/rechargeComsumption',
     method: 'get',
-    params: {}
+    params: param
   })
 }
 /**
  * 获取统计流量
  * @returns {AxiosPromise}
  */
-export function trafficLog(){
+export function trafficLog(param){
   return request({
     url: '/index/statistics/trafficLog',
     method: 'get',
-    params: {}
+    params: param
   })
 }
 
@@ -71,11 +71,11 @@ export function trafficLog(){
  * @param query
  * @returns {AxiosPromise}
  */
-export function smsBalance() {
+export function smsBalance(query) {
   return request({
     url: '/index/statistics/smsBalance',
     method: 'get',
-    params: {}
+    params: query
   })
 }
 
@@ -83,11 +83,11 @@ export function smsBalance() {
  * 授权信息
  * @returns {*}
  */
-export function authorizationInfo() {
+export function authorizationInfo(param) {
   return request({
     url: '/index/statistics/authorizationInfo',
     method: 'get',
-    params: {}
+    params: param
   })
 }
 
@@ -290,11 +290,11 @@ export function rewardMoneyTrend(param){
  * 获取当月订单数
  * @returns {*}
  */
-export function thisMonthOrderCount(){
+export function thisMonthOrderCount(param){
   return request({
     url: '/index/statistics/thisMonthOrderCount',
     method: 'get',
-    params: {}
+    params: param
   })
 }
 
@@ -302,10 +302,10 @@ export function thisMonthOrderCount(){
  * 获取当月收款数
  * @returns {*}
  */
-export function thisMonthRecvCount(){
+export function thisMonthRecvCount(param){
   return request({
     url: '/index/statistics/thisMonthRecvCount',
     method: 'get',
-    params: {}
+    params: param
   })
 }

+ 35 - 0
src/api/system/resourceManagement.js

@@ -0,0 +1,35 @@
+import request from '@/utils/request'
+
+// 查询部门资源
+export function getDeptResource(deptId) {
+  return request({
+    url: '/system/resourceM/getDeptResource/'+deptId,
+    method: 'get'
+  })
+}
+
+// 查询部门列表
+export function getCompanyResource(companyId) {
+  return request({
+    url: '/system/resourceM/getCompanyResource/'+companyId,
+    method: 'get'
+  })
+}
+
+//更新部门资源
+export function addOrEditDeptResource(data) {
+  return request({
+    url: '/system/resourceM/updateDeptResource',
+    method: 'put',
+    data: data
+  })
+}
+
+//更新公司资源
+export function addOrEditCompanyResource(data) {
+  return request({
+    url: '/system/resourceM/updateCompanyResource',
+    method: 'put',
+    data: data
+  })
+}

BIN
src/assets/logo/cqtyt.jpg


BIN
src/assets/logo/ddgy.jpg


BIN
src/assets/logo/hat.png


BIN
src/assets/logo/hst_logo.png


BIN
src/assets/logo/knt.jpg


+ 1 - 1
src/components/Pagination/index.vue

@@ -36,7 +36,7 @@ export default {
     pageSizes: {
       type: Array,
       default() {
-        return [10, 20, 30, 50]
+        return [10, 20, 30, 50,100,200,300]
       }
     },
     // 移动端页码按钮的数量端默认值5

+ 9 - 2
src/store/modules/user.js

@@ -8,7 +8,9 @@ const user = {
     user:undefined,
     avatar: '',
     roles: [],
-    permissions: []
+    permissions: [],
+    isAdmin: {isCheckPhone:0,isCheckAddress:0},
+    medicalMallConfig: {medicalMall: false,statics: false,audit:false,resource:false,stores:true}
   },
 
   mutations: {
@@ -32,6 +34,9 @@ const user = {
     },
     SET_ISADMIN: (state, isAdmin) => {
       state.isAdmin = isAdmin
+    },
+    SET_MEDICALMALL: (state, medicalMallConfig) => {
+      state.medicalMallConfig = medicalMallConfig
     }
   },
 
@@ -69,13 +74,15 @@ const user = {
           commit('SET_AVATAR', avatar)
           commit('SET_USER', user)
           commit('SET_ISADMIN', res.isAdmin)
+          console.log("res.medicalMallConfig",res.medicalMallConfig)
+          commit('SET_MEDICALMALL', res.medicalMallConfig)
           resolve(res)
         }).catch(error => {
           reject(error)
         })
       })
     },
-    
+
     // 退出系统
     LogOut({ commit, state }) {
       return new Promise((resolve, reject) => {

+ 3 - 0
src/views/company/company/index.vue

@@ -228,6 +228,9 @@
          <el-form-item label="备注" prop="remark">
           <el-input v-model="form.remark" type="textarea"  :rows="2" placeholder="请输入备注" />
         </el-form-item>
+        <el-form-item label="经销商归属" prop="companyBelongOwner">
+          <el-input v-model="form.companyBelongOwner" placeholder="请输入经销售归属" />
+        </el-form-item>
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="submitForm">确 定</el-button>

+ 7 - 7
src/views/company/companyMoneyLogs/index.vue

@@ -90,11 +90,11 @@
           @click="handleExport(1)"
           v-hasPermi="['company:companyMoneyLogs:export1']"
         >导出商城订单明细</el-button>
-		
+
         <!-- <el-button
           type="warning"
           icon="el-icon-download"
-          size="mini" 
+          size="mini"
           @click="handleExport(2)"
           v-hasPermi="['company:companyMoneyLogs:export2']"
         >导出收款订单明细</el-button> -->
@@ -106,8 +106,8 @@
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="ID" align="center" prop="logsId" />
       <el-table-column label="企业" align="center" prop="companyName" />
-      <el-table-column label="金额" align="center" prop="money" />
-      <el-table-column label="余额" align="center" prop="balance" />
+      <el-table-column label="红包金额" align="center" prop="money" />
+      <el-table-column label="红包余额" align="center" prop="balance" />
 
       <el-table-column label="商城订单号" align="center" prop="orderCode"  v-if="queryParams.logsType==3 || queryParams.logsType==4 ||queryParams.logsType==5 || queryParams.logsType==6"  />
       <el-table-column label="支付类型" align="center" prop="payTypeCode"  v-if="queryParams.logsType==3 || queryParams.logsType==4 ||queryParams.logsType==5 || queryParams.logsType==6 " />
@@ -249,7 +249,7 @@ export default {
   },
   methods: {
     handleDetails(row){
-      
+
       const orderId = row.businessId ;
       if(row.logsType==3||row.logsType==4||row.logsType==5||row.logsType==6 ||row.logsType==13||row.logsType==14){
         this.show.open=true;
@@ -263,7 +263,7 @@ export default {
             this.$refs.Details.getDetails(orderId);
       }, 1);
       }
-      
+
     },
     /** 查询企业账户记录列表 */
     getList() {
@@ -322,7 +322,7 @@ export default {
     },
     /** 新增按钮操作 */
     handleAdd() {
-			 
+
       this.reset();
       this.open = true;
       this.title = "添加企业账户记录";

+ 42 - 9
src/views/company/companyTraffic/index.vue

@@ -126,7 +126,9 @@
             placeholder="请输入充值金额(元)"
             controls-position="right"
             style="width: 100%"
+            @input="chargeAmountInput"
           />
+          <span v-if="this.amountToTraffic" class="el-form-item__error"> 约充值 {{ this.amountToTraffic }}流量 </span>
         </el-form-item>
 
         <el-form-item label="备注" prop="remark">
@@ -149,7 +151,7 @@
 </template>
 
 <script>
-import { listTrafficRecords, rechargeTraffic } from "@/api/company/traffic";
+import { listTrafficRecords, rechargeTraffic, trafficConversion } from '@/api/company/traffic'
 import { allList } from '@/api/company/company'
 import { resetForm } from '@/utils/common'
 import { delAdIqiyiAccount } from '@/api/ad/AdIqiyiAccount'
@@ -158,6 +160,7 @@ export default {
   name: "CompanyTraffic",
   data() {
     return {
+      amountToTraffic: 0,
       // 遮罩层
       loading: true,
       // 选中数组
@@ -232,6 +235,35 @@ export default {
         this.loading = false;
       });
     },
+    /** 流量计算*/
+    chargeAmountInput() {
+      if(!this.rechargeForm.chargeAmount){
+        this.amountToTraffic = 0;
+        return;
+      }
+      trafficConversion({traffic:this.rechargeForm.chargeAmount}).then(
+        response => {
+          this.amountToTraffic = response.data;
+          //对流量值进行判断,换算成GB或TB
+          if(!this.amountToTraffic){
+            this.amountToTraffic =  "0 KB";
+          }
+          if(this.amountToTraffic < 1024){
+            this.amountToTraffic =  this.amountToTraffic + " KB";
+          }
+          else if(this.amountToTraffic < 1024 * 1024){
+            this.amountToTraffic = (this.amountToTraffic / 1024).toFixed(2) + " MB";
+          }
+          else if(this.amountToTraffic < 1024 * 1024 * 1024){
+            this.amountToTraffic = (this.amountToTraffic / (1024 * 1024)).toFixed(2) + " GB";
+          }
+          else{
+            this.amountToTraffic = (this.amountToTraffic / (1024 * 1024 * 1024)).toFixed(2) + " TB";
+          }
+        }
+      )
+    }
+    ,
     /** 搜索公司 */
     searchCompanies( query) {
       allList().then(response => {
@@ -263,19 +295,20 @@ export default {
     formatBalance(row){
       //对流量值进行判断,换算成GB或TB
       if(!row.balance){
-        return "0KB";
+        return "0 KB";
       }
-      if(row.balance < 1024){
-        return row.balance + "KB";
+      const absBalance = Math.abs(row.balance); // 获取绝对值
+      if(absBalance < 1024){
+        return row.balance + " KB";
       }
-      else if(row.balance < 1024 * 1024){
-        return (row.balance / 1024).toFixed(2) + "MB";
+      else if(absBalance < 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 if(absBalance < 1024 * 1024 * 1024){
+        return (row.balance / (1024 * 1024)).toFixed(2) + " GB";
       }
       else{
-        return (row.balance / (1024 * 1024 * 1024)).toFixed(2) + "TB";
+        return (row.balance / (1024 * 1024 * 1024)).toFixed(2) + " TB";
       }
     },
 

+ 42 - 9
src/views/company/companyTrafficLog/index.vue

@@ -6,18 +6,13 @@
         <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"
+            v-for="item in formatterCompanyOptions"
             :key="item.dictValue"
             :label="item.dictLabel"
             :value="item.dictValue"
@@ -91,15 +86,15 @@
         </template>
       </el-table-column>
 
-      <el-table-column label="流量数量(KB)" align="center" prop="trafficAmount">
+      <el-table-column label="流量数量" align="center" prop="trafficAmount" >
         <template slot-scope="scope">
           <span :class="scope.row.operationType === 1 ? 'recharge' : 'deduction'">
-            {{ scope.row.operationType === 1 ? '+' : '-' }}{{ scope.row.trafficAmount }}
+            {{ scope.row.operationType === 1 ? '+' : '-' }}{{ formatTrafficAmount(scope.row)}}
           </span>
         </template>
       </el-table-column>
 
-      <el-table-column label="操作后余额(KB)" align="center" prop="balance" />
+      <el-table-column label="操作后余额" align="center" prop="balance" :formatter="formatBalance"/>
 
       <el-table-column label="操作人员" align="center" prop="userName" />
 
@@ -193,6 +188,44 @@ export default {
         this.loading = false;
       });
     },
+    formatBalance(row){
+      //对流量值进行判断,换算成GB或TB
+      if(!row.balance){
+        return "0 KB";
+      }
+      const absBalance = Math.abs(row.balance); // 获取绝对值
+      if(absBalance < 1024){
+        return row.balance + " KB";
+      }
+      else if(absBalance < 1024 * 1024){
+        return (row.balance / 1024).toFixed(2) + " MB";
+      }
+      else if(absBalance < 1024 * 1024 * 1024){
+        return (row.balance / (1024 * 1024)).toFixed(2) + " GB";
+      }
+      else{
+        return (row.balance / (1024 * 1024 * 1024)).toFixed(2) + " TB";
+      }
+    },
+    formatTrafficAmount(row){
+      //对流量值进行判断,换算成GB或TB
+      if(!row.trafficAmount){
+        return "0 KB";
+      }
+      const absBalance = Math.abs(row.trafficAmount); // 获取绝对值
+      if(absBalance < 1024){
+        return row.trafficAmount + " KB";
+      }
+      else if(absBalance < 1024 * 1024){
+        return (row.trafficAmount / 1024).toFixed(2) + " MB";
+      }
+      else if(absBalance < 1024 * 1024 * 1024){
+        return (row.trafficAmount / (1024 * 1024)).toFixed(2) + " GB";
+      }
+      else{
+        return (row.trafficAmount / (1024 * 1024 * 1024)).toFixed(2) + " TB";
+      }
+    },
 
     /** 搜索公司 */
     searchCompanies(query) {

+ 365 - 0
src/views/company/statistics/tuiMoney.vue

@@ -0,0 +1,365 @@
+<template>
+        <div class="app-container">
+            <div class="app-content">
+                 <div class="title">
+                    佣金排行榜
+                </div>
+               <el-form class="search-form" :inline="true" >
+                <el-form-item >
+                  <el-select style="width: 220px" v-model="value" placeholder="请选择日期">
+                    <el-option
+                      v-for="item in options"
+                      :key="item.value"
+                      :label="item.label"
+                      :value="item.value">
+                    </el-option>
+                  </el-select>
+                </el-form-item>
+                <el-form-item label="公司名" prop="companyId">
+                    <el-select filterable style="width: 220px" v-model="companyId" @change="companyChange" placeholder="请选择公司名" clearable size="small">
+                        <el-option
+                          v-for="item in companys"
+                          :key="item.companyId"
+                          :label="item.companyName"
+                          :value="item.companyId"
+                        />
+                  </el-select>
+                </el-form-item>
+                <el-form-item >
+                  <treeselect style="width: 220px" :clearable="false"  v-model="deptId"  :options="deptOptions" :show-count="true" placeholder="请选择归属部门" />
+                </el-form-item>
+                <el-form-item>
+                  <el-select filterable v-model="userIds" placeholder="请选择员工" clearable size="small">
+                      <el-option
+                        v-for="item in users"
+                        :key="item.userId"
+                        :label="item.nickName"
+                        :value="item.userId">
+                      </el-option>
+                    </el-select>
+                </el-form-item>
+
+                <el-form-item>
+                    <el-button type="cyan" icon="el-icon-search"   @click="getVoiceLogs">搜索</el-button>
+                </el-form-item>
+              </el-form>
+               <div class="data-box">
+                  <div class="echart-box">
+                    <div id="echart-customer"></div>
+                  </div>
+                  <div class="table-box">
+                        <el-button class="export" size="small"  @click="handleExport"   v-hasPermi="['statistics:customer:index']">导出</el-button>
+                        <el-table
+                        :data="list"
+                        border
+                        :summary-method="getSummaries"
+                        show-summary
+                        max-height="500"
+                        style="width: 100%;">
+                        <el-table-column
+                          prop="nickName"
+                          label="员工姓名">
+                        </el-table-column>
+                        <el-table-column
+                          prop="tuiMoneyCount"
+                          label="佣金订单数">
+                        </el-table-column>
+                        <el-table-column
+                          prop="tuiMoney"
+                          label="佣金总金额">
+                        </el-table-column>
+                      </el-table>
+                  </div>
+              </div>
+            </div>
+
+          </div>
+</template>
+
+<script>
+import { tuiMoney,exportTuiMoney } from "@/api/company/statistics";
+import { getUserListByDeptId} from "@/api/company/companyUser";
+import echarts from 'echarts'
+import resize from '../../dashboard/mixins/resize'
+import { treeselect } from "@/api/company/companyDept";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import { getCompanyList } from "@/api/company/company";
+export default {
+  name: 'Index',
+  mixins: [resize],
+  components: { Treeselect },
+  watch: {
+    // 监听deptId
+    'deptId': 'currDeptChange'
+  },
+  data() {
+    return {
+       companys:[],
+       deptOptions:[],
+       companyId:undefined,
+       deptId:undefined,
+       userIds:undefined,
+       users:[],
+       dateRange:[],
+       chart: null,
+       options: [{
+          value: '1',
+          label: '今天'
+        }, {
+          value: '2',
+          label: '昨天'
+        }, {
+          value: '3',
+          label: '本周'
+        }, {
+          value: '4',
+          label: '上周'
+        }, {
+          value: '5',
+          label: '本月'
+        }
+        , {
+          value: '6',
+          label: '上月'
+        }
+        , {
+          value: '7',
+          label: '本季度'
+        }
+        , {
+          value: '8',
+          label: '上季度'
+        }
+        , {
+          value: '9',
+          label: '本年'
+        }
+        , {
+          value: '10',
+          label: '上年'
+        }],
+        value: '5',
+        list:[],
+        dates:[],
+        billingTime:[],
+        tuiMoneyCount:[],
+        tuiMoney:[],
+        times:[]
+
+    }
+  },
+   created() {
+       getCompanyList().then(response => {
+        this.companys = response.data;
+        if(this.companys!=null&&this.companys.length>0){
+          this.companyId=this.companys[0].companyId;
+          this.getTreeselect();
+        }
+      });
+  },
+  methods: {
+    companyChange(val){
+      console.log(val);
+      this.companyId=val;
+      this.getTreeselect();
+    },
+    currDeptChange(val){
+      console.log(val)
+      this.deptId=val;
+       this.getUserListByDeptId();
+    },
+     /** 查询部门下拉树结构 */
+    getTreeselect() {
+      var that=this;
+      var param={companyId:this.companyId}
+      treeselect(param).then((response) => {
+        this.deptOptions = response.data;
+        console.log(this.deptOptions)
+        if(response.data!=null&&response.data.length>0){
+          this.deptId=response.data[0].id;
+          that.getVoiceLogs()
+        }
+      });
+    },
+    handleExport(){
+        var data;
+        if(this.userIds!=undefined){
+            data={type:this.value,userIds:this.userIds+"",deptId:this.deptId}
+        }
+        else{
+            data={type:this.value,deptId:this.deptId}
+        }
+        exportTuiMoney(data).then((response) => {
+            console.log(response)
+           this.download(response.msg);
+        });
+
+    },
+    getUserListByDeptId() {
+        this.userIds=undefined;
+        var data={deptId:this.deptId};
+        getUserListByDeptId(data).then(response => {
+          this.users = response.data;
+
+        });
+    },
+     getVoiceLogs(){
+          var data;
+          if(this.userIds!=undefined){
+              data={type:this.value,userIds:this.userIds+"",deptId:this.deptId}
+          }
+          else{
+              data={type:this.value,deptId:this.deptId}
+          }
+          tuiMoney(data).then((response) => {
+           this.list=response.list;
+           this.tuiMoney=response.tuiMoney;
+           this.tuiMoneyCount=response.tuiMoneyCount;
+
+           this.times=response.times;
+            setTimeout(() => {
+              this.initEchart();
+            }, 500);
+        });
+      },
+      initEchart(){
+        var option = {
+          tooltip: {
+              trigger: 'axis',
+              axisPointer: {            // 坐标轴指示器,坐标轴触发有效
+                  type: 'shadow'        // 默认为直线,可选为:'line' | 'shadow'
+              }
+          },
+          legend: {
+              data: ['佣金订单数', '佣金总金额' ]
+          },
+          grid: {
+              left: '3%',
+              right: '4%',
+              bottom: '3%',
+              containLabel: true
+          },
+          xAxis: [
+              {
+                  type: 'category',
+                  data: this.dates
+              }
+          ],
+          yAxis: [
+              {
+                  type: 'value',
+                  axisLabel:{
+                    formatter:'{value}'
+                  }
+              }
+          ],
+          series: [
+              {
+
+                  name: '佣金订单数',
+                  type: 'line',
+                  emphasis: {
+                      focus: 'series'
+                  },
+                  data: this.tuiMoneyCount
+              },
+              {
+
+                  name: '佣金总金额',
+                  type: 'line',
+                  emphasis: {
+                      focus: 'series'
+                  },
+                  data: this.tuiMoney
+              }
+
+          ]
+        };
+        this.chart=echarts.init(document.getElementById("echart-customer"));
+        this.chart.setOption(option,true);
+      },
+       getSummaries(param) {
+        const { columns, data } = param;
+        const sums = [];
+        columns.forEach((column, index) => {
+          if (index === 0) {
+            sums[index] = '总计';
+            return;
+          }
+          const values = data.map(item => Number(item[column.property]));
+          if (!values.every(value => isNaN(value))) {
+            sums[index] = values.reduce((prev, curr) => {
+              const value = Number(curr);
+              if (!isNaN(value)) {
+                return prev + curr;
+              } else {
+                return prev;
+              }
+            }, 0);
+            sums[index] += ' ';
+          } else {
+            sums[index] = '';
+          }
+        });
+
+        return sums;
+      }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.app-container{
+    border: 1px solid #e6e6e6;
+    padding: 12px;
+
+    .app-content{
+      background-color: white;
+      .title{
+        padding: 20px 30px 0px 30px;
+        font-size: 18px;
+        font-weight: bold;
+        color: black;
+
+      }
+      .search-form{
+        margin: 20px 30px 0px 30px;
+      }
+      .data-box{
+        padding: 30px;
+        background-color:  rgb(255, 255, 255);
+        height: 100%;
+
+        .echart-box{
+          margin: 0 auto;
+          text-align: center;
+        }
+        .el-select{
+          margin: 5px 10px;
+        }
+        .table-box{
+          margin-top: 15px;
+          .export{
+            float: right;
+            margin: 10px 0px;
+          }
+        }
+      }
+    }
+}
+  #echart-customer{
+    width:100%;
+    height:320px
+  }
+.vue-treeselect{
+  width: 217px;
+  height: 36px;
+}
+
+</style>
+<style>
+.vue-treeselect__control{
+  display: block;
+}
+</style>

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

@@ -181,6 +181,12 @@
           <el-radio v-model="form.isProduct" :label=0>否</el-radio>
           <el-radio v-model="form.isProduct" :label=1>是</el-radio>
         </el-form-item>
+        <el-form-item label="是否先导课" prop="isFirst">
+          <el-radio-group v-model="form.isFirst">
+            <el-radio :label="1">是</el-radio>
+            <el-radio :label="0">否</el-radio>
+          </el-radio-group>
+        </el-form-item>
         <el-form-item label="商品选择" v-if="form.isProduct === 1">
           <el-button size="small" type="primary" @click="chooseCourseProduct">选取商品</el-button>
           <el-table border width="100%" style="margin-top:5px;" :data="form.courseProducts">
@@ -835,6 +841,7 @@ export default {
         isTranscode: 0,
         transcodeFileKey: null,
         isProduct: 0,
+        isFirst: 0,
         listingStartTime: null,
         listingEndTime: null,
       };

+ 26 - 0
src/views/components/his/packageDetails.vue

@@ -60,6 +60,15 @@
             :src="img"
             :preview-src-list="[img]">
         </el-image>
+    </el-descriptions-item>
+    <el-descriptions-item label="所属小程序">
+      <el-tag
+        v-for="name in appNames"
+        :key="name"
+        style="margin-right: 4px"
+      >
+        {{ name }}
+      </el-tag>
     </el-descriptions-item>
         </el-descriptions>
             </div>
@@ -116,6 +125,7 @@
 
 <script>
 import { listPackage, getPackage, delPackage, addPackage, updatePackage, exportPackage } from "@/api/his/package";
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
   export default {
     name: "patientdetails",
     props:["data"],
@@ -129,6 +139,7 @@ import { listPackage, getPackage, delPackage, addPackage, updatePackage, exportP
        orOptions:[],
        packageTypeOptions: [],
        diseaseTypeOptions: [],
+       appMallOptions:[],
        // 是否删除字典
        isDelOptions: [],
        packageSubTypeOptions:[],
@@ -136,6 +147,15 @@ import { listPackage, getPackage, delPackage, addPackage, updatePackage, exportP
         productJson:[],
       }
     },
+    computed: {
+      appNames() {
+        if (!this.item.appIds) return [];
+        const ids = this.item.appIds.split(',');
+        return ids
+          .map(id => this.appMallOptions.find(opt => opt.appid === id)?.name)
+          .filter(Boolean); // 过滤掉找不到的
+      }
+    },
     created() {
      this.getDicts("sys_company_status").then(response => {
        this.statusOptions = response.data;
@@ -159,9 +179,15 @@ import { listPackage, getPackage, delPackage, addPackage, updatePackage, exportP
      this.getDicts("sys_prescribe_disease_type").then(response => {
        this.diseaseTypeOptions = response.data;
      });
+     this.getAppMallOptions();
 
     },
     methods: {
+      getAppMallOptions() {
+        getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+          this.appMallOptions = response.rows;
+        })
+      },
       getDetails(orderId) {
           this.item=null;
           getPackage(orderId).then(response => {

+ 6 - 1
src/views/components/his/storeAfterSalesDetails.vue

@@ -114,7 +114,12 @@
           </el-table-column>
           <el-table-column label="小计"  align="center">
             <template slot-scope="scope">
-              ¥{{JSON.parse(scope.row.jsonInfo).num*JSON.parse(scope.row.jsonInfo).price}}
+              ¥{{
+                  (
+                    Number(JSON.parse(scope.row.jsonInfo).num) *
+                    Number(JSON.parse(scope.row.jsonInfo).price)
+                  ).toFixed(2)
+                }}
             </template>
           </el-table-column>
         </el-table>

+ 201 - 18
src/views/components/his/storeOrderDetails.vue

@@ -60,7 +60,7 @@
                  </div>
 
                <div class="operate-button-container" v-if="item.status>1">
-                   <el-button size="mini" @click="refund()" v-hasPermi="['his:storeOrder:afterSales']">申请退款</el-button>
+                   <el-button size="mini" @click="chooseRefund()" v-hasPermi="['his:storeOrder:afterSales']">申请退款</el-button>
                </div>
                <div class="operate-button-container" v-if="item.prescribeId!=null&&item.prescribeId!=''" >
                   <el-button size="mini" @click="getPrescribeOrder()" >处方单</el-button>
@@ -125,7 +125,7 @@
      <el-tooltip class="item" effect="dark" :content="showList ? '显示全部' : '隐藏'" placement="top" style="float: right;">
        <el-button size="mini" circle icon="el-icon-search" @click="showListD()" />
      </el-tooltip>
-  <el-table border v-if="showProd!=null" :data="showProd" size="small" style="width: 100%;margin-top: 20px" >
+     <el-table border v-if="showProd!=null" :data="showProd" size="small" style="width: 100%;margin-top: 20px" >
          <el-table-column label="商品图片" width="150" align="center">
            <template slot-scope="scope">
              <img :src="JSON.parse(scope.row.jsonInfo).image" style="height: 80px">
@@ -342,10 +342,25 @@
                           :key="dict.dictValue"
                           :label="dict.dictLabel"
                           :value="dict.dictValue"
-                          :disabled="dict.dictLabel == '待推送'"
+                          :disabled="dict.dictLabel == '待推送' || dict.dictLabel == '退款中' || dict.dictLabel == '退款成功'"
                         />
                       </el-select>
                    </el-form-item>
+                   <el-form-item label="实付金额" prop="payMoney">
+                    <el-input-number
+                      v-model="payMoney"
+                      :precision="2"
+                      :step="0.1"
+                      disabled   
+                    />
+                  </el-form-item>
+                  <el-form-item label="物流代收金额">
+                    <el-input-number v-model="payRemain" :precision="2" :step="0.1" :disabled="isUpdatePayRemain==0"/>
+                  </el-form-item>
+
+                  <el-form-item label="应付金额">
+                    <el-input-number v-model="payPrice" :precision="2" :step="0.1" disabled/>
+                  </el-form-item>
                    <el-form-item label="物流状态" prop="deliveryStatus" >
                    <el-select v-model="editForm.deliveryStatus" placeholder="请选择物流状态" clearable size="small" filterable>
                         <el-option
@@ -423,6 +438,70 @@
                 <prescribeDetails  ref="prescribeDetails" />
               </el-drawer>
 
+              <el-dialog
+                :title="refundDialog.title"
+                :visible.sync="refundDialog.open"
+                width="50%"
+                append-to-body
+                >
+                <el-table border v-if="refundShowProd!=null" :data="refundShowProd" ref="refundTable" size="small"  @selection-change="handleSelectionChange">
+                  <el-table-column type="selection" width="55" align="center" />
+                  
+                  <el-table-column label="商品编码" width="110" align="center">
+                    <template slot-scope="scope">
+                      <p>{{ JSON.parse(scope.row.jsonInfo).barCode }}</p>
+                    </template>
+                  </el-table-column>
+
+                  <el-table-column label="商品名称" align="center">
+                    <template slot-scope="scope">
+                      <p>{{ JSON.parse(scope.row.jsonInfo).productName }}</p>
+                    </template>
+                  </el-table-column>
+
+                  <el-table-column label="原单价" width="100" align="center">
+                    <template slot-scope="scope">
+                      <p>¥{{JSON.parse(scope.row.jsonInfo).price.toFixed(2)}}</p>
+                    </template>
+                  </el-table-column>
+
+                  <el-table-column label="退款单价" width="200" align="center">
+                    <template slot-scope="scope">
+                      <el-input-number 
+                        v-model="scope.row.money" 
+                        :precision="2" 
+                        :step="0.1" 
+                        :min="0"
+                        size="mini"
+                      />
+                    </template>
+                  </el-table-column>
+
+                  <el-table-column label="退款数量" width="200" align="center">
+                    <template slot-scope="scope">
+                      <el-input-number 
+                        v-model="scope.row.num" 
+                        :min="0" 
+                        :max="scope.row.originNum"   
+                        size="mini"
+                      />
+                    </template>
+                  </el-table-column>
+
+                </el-table>
+               
+                <div style="margin-top:10px;">
+                  合计退款金额:
+                  <span style="color:red; font-weight:bold;">
+                    ¥{{ refundForm.refundAmount ? refundForm.refundAmount.toFixed(2) : '0.00' }}
+                  </span>
+                </div>
+                <div slot="footer" class="dialog-footer">
+                  <el-button type="primary" @click="submitRefundForm">确 定</el-button>
+                </div>
+
+              </el-dialog>
+
 
 
 
@@ -443,6 +522,19 @@ import {getCitys} from "@/api/store/city";
     components: { inquiryOrderDetails,packageOrderDetails,prescribeDetails ,msgDetails},
     data() {
       return {
+        isUpdateRefund:0, //是否支持修改退款金额 默认0不支持
+        isUpdatePayRemain:0, //是否支持修改物流代收金额 默认0不支持
+        refundShowProd:[],//原退款明细
+        refundForm:{
+          refundAmount:0
+        },
+        selectedRows:[],
+        refundDialog:{
+          title:"申请退款",
+          open:false,
+        },
+        payRemain: 0,   // 物流代收金额,可改
+        payMoney: 0,    // 实收金额,固定
         expressDialog:{
           title:"物流信息",
           open:false,
@@ -451,7 +543,7 @@ import {getCitys} from "@/api/store/city";
           title:"修改物流单号",
           open:false,
         },
-		sourceOptions:[],
+		    sourceOptions:[],
         prescribeDialog:{
           title:"处方单",
           open:false,
@@ -531,6 +623,8 @@ import {getCitys} from "@/api/store/city";
           deliveryType:null,
           userPhone:null,
           remark:"",
+          payRemain:null,
+          payPrice:null
         },
         editDyRules:{
           deliverySn: [
@@ -613,7 +707,24 @@ import {getCitys} from "@/api/store/city";
             });
 
     },
+    computed: {
+       // 应收金额 = 实收金额 + 代收金额
+      payPrice() {
+        const v = (this.payMoney * 100 + this.payRemain * 100) / 100;
+        return Number(v.toFixed(2));
+      }
+    },
     methods: {
+      updateRefund(row) {
+        // 默认退款金额 = 数量 × 单价
+        row.refundAmount = (row.num * row.money).toFixed(2);
+      },
+      handleSelectionChange(val) {
+        this.refundForm.refundAmount = val
+          .reduce((sum, row) => sum + row.num * row.money, 0)
+          ;
+        this.selectedRows = val;
+      },
       getCitys() {
         return getCitys().then(res => {
           this.citys = res.data || [];
@@ -694,6 +805,8 @@ import {getCitys} from "@/api/store/city";
           this.express = response.data;
           if(this.express!=null&&this.express.Traces!=null){
               this.traces=this.express.Traces
+          } else {
+            this.traces = []
           }
       });
     },
@@ -762,6 +875,8 @@ import {getCitys} from "@/api/store/city";
         const payload = {
           ...this.editForm,
           userAddress: this.buildFullAddress(),
+          payRemain :this.payRemain,
+          payPrice: this.payPrice,
         };
 
         updateStoreOrder(payload).then(response => {
@@ -791,7 +906,9 @@ import {getCitys} from "@/api/store/city";
       this.editForm.status = this.item.status != null ? this.item.status.toString() : "";
       this.editForm.deliveryType = this.item.deliveryType;
       this.editForm.deliveryStatus = this.item.deliveryStatus;
-
+      this.payMoney= this.item.payMoney;
+      this.payRemain = this.item.payRemain;
+      this.payPrice= this.item.payPrice;
       // 等城市数据加载后再解析地址
       const currentAddress = (this.item.userAddress || "").toString().trim();
       this.getCitys().then(() => {
@@ -924,7 +1041,71 @@ import {getCitys} from "@/api/store/city";
       moneyCancel(){
         this.money=null;
         this.moneyVisible=false;
-    },
+      },
+      chooseRefund(){
+        if(this.isUpdateRefund == 1){
+          this.refundShowProd = this.showProd.map(item => {
+            const info = JSON.parse(item.jsonInfo);
+            return {
+              ...item,
+              originNum: item.num, // 原始购买数量
+              num: item.num,       // 可编辑的退款数量
+              price: info.price,
+              money: 0.00,
+              // refundAmount: (item.num * info.price).toFixed(2),
+              refundAmount: 0,
+              jsonInfo: item.jsonInfo
+            }
+          })
+          this.refundForm.refundAmount = 0
+          this.refundDialog.open = true
+          // this.$nextTick(() => {
+          //   // 默认全选表格
+          //   this.$refs.refundTable.toggleAllSelection();
+          // });
+          this.$alert('请先设置退款单价和退款数量,再选择商品', '提示');
+        } else {
+          this.refund(); //正常退款
+        }
+        
+      },
+      submitRefundForm(){
+        if(this.refundForm.refundAmount<=0){
+          return this.$message("退款金额不能为0");
+        }
+        if(this.refundForm.refundAmount>this.item.payMoney){
+          return this.$message("退款金额不能大于实付金额" + this.item.payMoney + "元");
+        }
+        if(this.selectedRows.length==0){
+          return this.$message("请选择退款商品");
+        }
+        const refundList = this.selectedRows.map(row => ({
+          itemId: row.itemId,
+          num: row.num,
+          money:row.money
+        }))
+        const param = {
+          orderId:this.item.orderId,
+          refundList:refundList,
+          refundAmount:this.refundForm.refundAmount
+        }
+        console.log("申请退款数据", param);
+        this.$confirm('是否确认申请退款?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return afterSales(param);
+        }).then(() => {
+          this.msgSuccess("操作成功");
+          getOrder(this.item.orderId).then(response => {
+              this.item = response.data;
+              this.getlogList(this.item.orderId);
+              this.$parent.$parent.getList();
+              this.refundDialog.open = false
+          });
+        }).catch(function() {});
+      },
       refund(){
         var that=this;
         this.$confirm('是否确认申请退款?', "警告", {
@@ -1054,18 +1235,20 @@ import {getCitys} from "@/api/store/city";
         this.storeName=storeName;
         this.item=null;
         this.tuiMoneyLogs=null;
-          getOrder(orderId).then(response => {
-              this.item = response.data;
-              this.tuiMoneyLogs = response.tuiMoneyLogs;
-              this.getlistOrderitem(orderId);
-              this.getlogList(orderId);
-              this.getPayment(orderId);
-              this.msgForm.userId=response.data.userId;
-              this.msgForm.followDoctorId=response.data.followDoctorId;
-              if(this.item.orderType==2){
-                this.getCount(this.item.prescribeId);
-              }
-          });
+        getOrder(orderId).then(response => {
+            this.item = response.data;
+            this.tuiMoneyLogs = response.tuiMoneyLogs;
+            this.getlistOrderitem(orderId);
+            this.getlogList(orderId);
+            this.getPayment(orderId);
+            this.msgForm.userId=response.data.userId;
+            this.msgForm.followDoctorId=response.data.followDoctorId;
+            if(this.item.orderType==2){
+              this.getCount(this.item.prescribeId);
+            }
+            this.isUpdateRefund = response.isUpdateRefund;
+            this.isUpdatePayRemain = response.isUpdatePayRemain
+        });
       },
       getCount(id){
         getPrescribe(id).then(response => {

+ 14 - 2
src/views/components/his/userDetails.vue

@@ -133,6 +133,15 @@
  </div>
     <userInquiryOrderDetails  ref="InquiryDetails" />
    </div>
+
+    <!-- 积分记录 -->
+    <div class="contentx" v-if="item!=null" >
+      <div class="desct">
+            用户积分记录
+      </div>
+          <userIntegralDetails  ref="userIntegralDetail" />
+    </div>
+
  </div>
 </template>
 
@@ -146,10 +155,11 @@ import userStorerDetails from "../his/userStorerDetails.vue";
 import userPatietDetails from "../his/userPatietDetails.vue";
 import userInquiryOrderDetails from "../his/userInquiryOrderDetails.vue";
 import userAddDetails from "../his/userAddDetails.vue";
+    import userIntegralDetails from "../his/userIntegralDetails.vue";
   export default {
     name: "storedet",
     props:["data"],
-     components: { userStorerDetails ,userInquiryOrderDetails,userPatietDetails,userAddDetails},
+     components: { userStorerDetails ,userInquiryOrderDetails,userPatietDetails,userAddDetails,userIntegralDetails},
     data() {
       return {
         patientInfo: process.env.VUE_APP_PATIENT_INFO,
@@ -232,7 +242,9 @@ import userAddDetails from "../his/userAddDetails.vue";
               setTimeout(() => {
                    this.$refs.userAddDetail.getAddList(orderId);
               }, 1);
-
+              setTimeout(() => {
+                  this.$refs.userIntegralDetail.getIntegralLogs(orderId);
+              }, 1);
           });
           this.patient=null;
           getPatientByUserId(orderId).then(response => {

+ 111 - 0
src/views/components/his/userIntegralDetails.vue

@@ -0,0 +1,111 @@
+<!-- UserIntegralLogs.vue -->
+<template>
+  <div class="integral-logs-container">
+    <el-table 
+      v-loading="loading" 
+      border 
+      :data="userIntegralLogsList" 
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column label="用户id" align="center" prop="userId" />
+      <el-table-column label="用户昵称" align="center" prop="nickName" />
+      <el-table-column label="用户电话" align="center" prop="phone" />
+      <el-table-column label="类别" align="center" prop="logType">
+        <template slot-scope="scope">
+          <dict-tag :options="intefralLogTypeOptions" :value="scope.row.logType"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="积分" align="center" prop="integral" />
+      <el-table-column label="积分余额" align="center" prop="balance" />
+      <el-table-column label="订单关联id" align="center" prop="businessId" />
+      <el-table-column label="时间" align="center" prop="createTime" />
+    </el-table>
+    
+    <!-- 分页组件 -->
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { listUserIntegralLogs} from "@/api/his/userIntegralLogs";
+
+export default {
+  name: 'UserIntegralLogs',
+  props: {
+    fsUserId: {
+      type: [String, Number],
+      required: false
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      userIntegralLogsList: [],
+      total: 0,
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: this.fsUserId
+      },
+      intefralLogTypeOptions: [],
+      selections: []
+    }
+  },
+  watch: {
+    fsUserId: {
+      handler(newVal) {
+        this.queryParams.userId = newVal;
+        this.getList();
+      },
+      immediate: true
+    }
+  },
+
+  created() {
+    this.getList();
+    this.getDictOptions();
+  },
+  methods: {
+    // 获取积分日志列表
+    getList() {
+
+      if (!this.queryParams.userId) return;
+      
+      this.loading = true;
+      listUserIntegralLogs(this.queryParams).then(response => {
+        this.userIntegralLogsList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    getIntegralLogs(fsUserId){
+        this.queryParams.userId=fsUserId;
+        this.getList();
+    },
+    // 获取字典选项
+    getDictOptions() {
+      // 获取积分日志类型字典
+        this.getDicts("sys_integral_log_type").then(response => {
+            this.intefralLogTypeOptions = response.data;
+        });
+    },
+    
+    // 处理选择变化
+    handleSelectionChange(selection) {
+      this.selections = selection;
+    }
+  }
+}
+</script>
+
+<style scoped>
+.integral-logs-container {
+  padding: 20px;
+}
+</style>

+ 32 - 0
src/views/course/coursePlaySourceConfig/index.vue

@@ -137,6 +137,11 @@
           <dict-tag  :options="typesOptions" :value="scope.row.type"/>
         </template>
       </el-table-column>
+      <el-table-column label="互医/商城小程序" align="center" prop="isMall" width="80px">
+        <template slot-scope="scope">
+          <el-tag prop="isMall" v-for="(item, index) in isMallOptions" v-if="scope.row.isMall==item.dictValue">{{item.dictLabel}}</el-tag>
+        </template>
+      </el-table-column>
       <el-table-column label="创建时间" align="center" prop="createTime" />
       <el-table-column label="修改时间" align="center" prop="updateTime" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
@@ -200,6 +205,21 @@
             />
           </el-select>
         </el-form-item>
+        <el-form-item label="是否是互医/商城小程序" prop="isMall">
+          <el-select
+            v-model="form.isMall"
+            style="width: 220px"
+            clearable
+            size="small"
+          >
+            <el-option
+              v-for="item in isMallOptions"
+              :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>
@@ -276,6 +296,16 @@ export default {
       list: [],
       total: 0,
       typesOptions: [],
+      isMallOptions:[
+        {
+          dictLabel: "是",
+          dictValue: 1
+        },
+        {
+          dictLabel: "否",
+          dictValue: 0
+        }
+      ],
       title: null,
       open: false,
       form: {},
@@ -419,6 +449,7 @@ export default {
     handleAdd() {
       this.reset()
       this.open = true
+        this.form.isMall = 0;
       this.title = "添加小程序配置"
     },
     handleUpdate(row) {
@@ -429,6 +460,7 @@ export default {
           ...response.data,
           type: response.data.type.toString()
         }
+        this.searchCompanies("");
         this.open = true
         this.title = "修改小程序配置"
       })

+ 206 - 0
src/views/course/courseRedPacketStatistics/index.vue

@@ -0,0 +1,206 @@
+<template>
+  <div class="course-red-packet-statistics">
+    <!-- 查询条件 -->
+    <el-card class="search-card">
+      <el-form :model="queryForm" ref="queryForm" label-width="80px" inline>
+        <el-row :gutter="20">
+          <el-col :span="6">
+            <el-form-item label="公司名" prop="companyId">
+              <el-select filterable style="width: 220px" v-model="queryForm.companyId" @change="handleSeller" placeholder="请选择公司名" clearable size="small">
+                <el-option
+                  v-for="item in companys"
+                  :key="item.companyId"
+                  :label="item.companyName"
+                  :value="item.companyId"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          
+          <el-col :span="6">
+            <el-form-item label="员工" prop="nickName" v-if="queryForm.companyId">
+              <el-select v-model="queryForm.companyUserId" remote placeholder="请选择" filterable clearable  style="width: 100%;" @keyup.enter.native="handleQuery">
+                <el-option
+                  v-for="dict in companyUserList"
+                  :key="dict.userId"
+                  :label="`${dict.nickName}`"
+                  :value="dict.userId">
+                </el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          
+          <el-col :span="6">
+            <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="change"></el-date-picker>
+            </el-form-item>
+          </el-col>
+          
+          <el-col :span="6">
+            <el-form-item label="状态" prop="status">
+              <el-select v-model="queryForm.status" placeholder="请选择状态" clearable style="width: 100%">
+                <el-option label="全部" value=""></el-option>
+                <el-option label="发送中" value="0"></el-option>
+                <el-option label="已发送" value="1"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        
+        <el-row>
+          <el-col :span="24" class="text-right">
+            <el-button type="primary" @click="handleSearch">查询</el-button>
+            <el-button @click="resetQuery">重置</el-button>
+          </el-col>
+        </el-row>
+      </el-form>
+    </el-card>
+    
+    <!-- 统计结果 -->
+    <el-card class="result-card">
+      <div slot="header">
+        <span>红包发送统计</span>
+      </div>
+      
+      <el-table :data="statisticsData" border style="width: 100%" v-loading="loading">
+        <el-table-column prop="companyName" label="公司名称" align="center"></el-table-column>
+        <el-table-column prop="nickName" label="员工姓名" align="center"></el-table-column>
+        <el-table-column prop="companyUserId" label="员工编号" align="center"></el-table-column>
+        <el-table-column prop="redPacketNum" label="红包数" align="center"></el-table-column>
+        <el-table-column prop="redPacketTotalMoney" label="总金额(元)" align="center">
+          <template slot-scope="scope">
+            {{ scope.row.redPacketTotalMoney.toFixed(2) }}
+          </template>
+        </el-table-column>
+      </el-table>
+      
+      <div class="pagination-container">
+        <el-pagination
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+          :current-page="pageInfo.currentPage"
+          :page-sizes="[10, 20, 50, 100]"
+          :page-size="pageInfo.pageSize"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="pageInfo.total">
+        </el-pagination>
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script>
+import {getCompanyList} from "@/api/company/company";
+import {getUserList} from "@/api/company/companyUser";
+import {list} from "@/api/course/courseRedPacketStatistics";
+export default {
+  name: 'CourseRedPacketStatistics',
+  data() {
+    return {
+      companys:[],
+      companyUserList:[],
+      createTime: [],
+      queryForm: {
+        companyId: '',
+        companyUserId: '',
+        startTime:null,
+        endTime:null,
+        status: ''
+      },
+      statisticsData: [],
+      loading: false,
+      pageInfo: {
+        currentPage: 1,
+        pageSize: 10,
+        total: 0
+      }
+    }
+  },
+  mounted() {
+    this.getList()
+  },
+  created() {
+      getCompanyList().then(response => {
+          this.companys = response.data;
+          if(this.companys!=null&&this.companys.length>0){
+            this.companyId=this.companys[0].companyId;
+          }
+      });
+    },
+  methods: {
+    
+    
+    handleSearch() {
+      this.pageInfo.currentPage = 1
+      this.getList();
+    },
+    change() {
+      if (this.createTime) {
+        this.queryForm.startTime = this.createTime[0];
+        this.queryForm.endTime = this.createTime[1];
+      } else {
+        this.queryForm.startTime = null;
+        this.queryForm.endTime = null;
+      }
+    },
+    handleSeller(){
+      console.log(this.queryForm.companyId)
+      if(this.queryForm.companyId != null) {
+        getUserList(this.queryForm.companyId).then(res=>{
+          if(res.code === 200) {
+            this.companyUserList = res.data
+          }
+        })
+      }
+    },
+    
+    resetQuery() {
+      this.$refs.queryForm.resetFields()
+      this.queryForm.dateRange = []
+      this.handleSearch()
+    },
+    
+    getList() {
+      this.loading = true
+      // 查询统计
+      list(this.queryForm).then(response => {
+        this.statisticsData = response.data.list;
+        this.pageInfo.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    
+    handleSizeChange(val) {
+      this.pageInfo.pageSize = val
+      this.pageInfo.currentPage = 1
+      this.getList()
+    },
+    
+    handleCurrentChange(val) {
+      this.pageInfo.currentPage = val
+      this.getList()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.course-red-packet-statistics {
+  padding: 20px;
+  
+  .search-card {
+    margin-bottom: 20px;
+  }
+  
+  .result-card {
+    .pagination-container {
+      margin-top: 20px;
+      text-align: right;
+    }
+  }
+  
+  .text-right {
+    text-align: right;
+  }
+}
+</style>

+ 299 - 0
src/views/course/courseWatchLog/qw/statisticsCompany.vue

@@ -0,0 +1,299 @@
+<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">
+        <el-select filterable style="width: 220px" v-model="queryParams.companyId" placeholder="请选择公司名" clearable size="small">
+          <el-option
+            v-for="item in companys"
+            :key="item.companyId"
+            :label="item.companyName"
+            :value="item.companyId"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="课程" prop="courseId">
+        <el-select filterable  v-model="queryParams.courseId" placeholder="请选择课程"  clearable size="small" @change="courseChange(queryParams.courseId)">
+          <el-option
+            v-for="dict in courseLists"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="小节" prop="videoId">
+        <el-select filterable  v-model="queryParams.videoId" placeholder="请选择小节"  clearable size="small">
+          <el-option
+            v-for="dict in videoList"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker v-model="createTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
+      </el-form-item>
+
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table border v-loading="loading" :data="courseWatchLogList" show-summary>
+      <el-table-column label="公司名称" align="center" prop="companyName" />
+      <el-table-column label="发课时间" align="center" prop="createTime"/>
+      <el-table-column label="待看课" align="center" prop="type3" />
+      <el-table-column label="看课中" align="center" prop="type1" />
+      <el-table-column label="已完课" align="center" prop="type2" />
+      <el-table-column label="看课中断" align="center" prop="type4" />
+    </el-table>
+  </div>
+</template>
+
+<script>
+import {
+  listCourseWatchLog,
+  getCourseWatchLog,
+  delCourseWatchLog,
+  addCourseWatchLog,
+  updateCourseWatchLog,
+  exportCourseWatchLog,
+  statisticsList,
+  statisticsListByCompany
+} from '@/api/course/qw/courseWatchLog'
+import { courseList,videoList } from '@/api/course/courseRedPacketLog'
+import {getCompanyList} from "@/api/company/company";
+export default {
+  name: "CourseWatchLog",
+  data() {
+    return {
+      companys:[],
+      activeName:"00",
+      createTime:null,
+      courseLists:[],
+      videoList:[],
+      logTypeOptions:[],
+      // 遮罩层
+      loading: false,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 短链课程看课记录表格数据
+      courseWatchLogList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: null,
+        nickName: null,
+        videoId: null,
+        logType: null,
+        qwExternalContactId: null,
+        duration: null,
+        qwUserId: null,
+        companyUserId: null,
+        companyId: null,
+        courseId: null,
+        sTime:null,
+        eTime:null,
+        scheduleStartTime: null,
+        scheduleEndTime: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      },
+      scheduleTime: null,
+    };
+  },
+  created() {
+    getCompanyList().then(response => {
+      this.companys = response.data;
+      if(this.companys!=null&&this.companys.length>0){
+        this.companyId=this.companys[0].companyId;
+        this.getTreeselect();
+      }
+    });
+    courseList().then(response => {
+      this.courseLists = response.list;
+    });
+    this.getList();
+    this.getDicts("sys_course_watch_log_type").then(response => {
+      this.logTypeOptions = response.data;
+    });
+  },
+  methods: {
+    courseChange(row){
+      this.queryParams.videoId=null;
+      if(row === ''){
+        this.videoList=[];
+        return
+      }
+      videoList(row).then(response => {
+        this.videoList=response.list
+      });
+    },
+    change() {
+      if (this.createTime != null) {
+        this.queryParams.sTime = this.createTime[0];
+        this.queryParams.eTime = this.createTime[1];
+      } else {
+        this.queryParams.sTime = null;
+        this.queryParams.eTime = null;
+      }
+    },
+    handleClickX(tab,event){
+      this.activeName=tab.name;
+      if(tab.name=="00"){
+        this.queryParams.logType=null;
+      }else{
+        this.queryParams.logType=tab.name;
+      }
+      this.getList()
+    },
+    /** 查询短链课程看课记录列表 */
+    getList() {
+      this.loading = true;
+      statisticsListByCompany(this.queryParams).then(response => {
+        this.courseWatchLogList = response.rows;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        logId: null,
+        userId: null,
+        videoId: null,
+        logType: null,
+        createTime: null,
+        updateTime: null,
+        qwExternalContactId: null,
+        duration: null,
+        qwUserId: null,
+        companyUserId: null,
+        companyId: null,
+        courseId: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.createTime = null;
+      this.scheduleTime = null;
+      this.queryParams.sTime = null;
+      this.queryParams.eTime = null;
+      this.queryParams.scheduleStartTime = null;
+      this.queryParams.scheduleEndTime = null;
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.logId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加短链课程看课记录";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const logId = row.logId || this.ids
+      getCourseWatchLog(logId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改短链课程看课记录";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.logId != null) {
+            updateCourseWatchLog(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addCourseWatchLog(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const logIds = row.logId || this.ids;
+      this.$confirm('是否确认删除短链课程看课记录编号为"' + logIds + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delCourseWatchLog(logIds);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有短链课程看课记录数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportCourseWatchLog(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    },
+    handleScheduleTimeChange(val) {
+      if (val) {
+        this.queryParams.scheduleStartTime = val[0];
+        this.queryParams.scheduleEndTime = val[1];
+      } else {
+        this.queryParams.scheduleStartTime = null;
+        this.queryParams.scheduleEndTime = null;
+      }
+    },
+  }
+};
+</script>

+ 65 - 20
src/views/course/courseWatchLog/statistics.vue

@@ -75,7 +75,14 @@
       </el-form-item>
     </el-form>
 
-    <el-table border v-loading="loading" :data="courseWatchLogList" @selection-change="handleSelectionChange"  show-summary>
+    <el-table
+      border
+      v-loading="loading"
+      :data="courseWatchLogList"
+      @selection-change="handleSelectionChange"
+      show-summary
+      :summary-method="getSummaries"
+    >
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="用户" align="center" prop="userName" />
       <el-table-column label="对应销售" align="center" prop="companyUserName" />
@@ -185,6 +192,44 @@ export default {
 
   },
   methods: {
+    /** 自定义合计方法 */
+    getSummaries(param) {
+      const { columns, data } = param;
+      const sums = [];
+      columns.forEach((column, index) => {
+        if (index === 0) {
+          sums[index] = '合计';
+          return;
+        }
+
+        // 排除不需要合计的列(小节名称和其他文本列)
+        const excludeColumns = ['userName', 'companyUserName', 'createTime', 'projectName', 'courseName', 'videoName'];
+        const prop = column.property;
+
+        if (excludeColumns.includes(prop)) {
+          sums[index] = '--';
+          return;
+        }
+
+        // 对数值列进行合计
+        const values = data.map(item => Number(item[prop]));
+        if (!values.every(value => isNaN(value))) {
+          sums[index] = values.reduce((prev, curr) => {
+            const value = Number(curr);
+            if (!isNaN(value)) {
+              return prev + curr;
+            } else {
+              return prev;
+            }
+          }, 0);
+        } else {
+          sums[index] = '--';
+        }
+      });
+
+      return sums;
+    },
+
     handleSeller(){
       console.log(this.queryParams.companyId)
       if(this.queryParams.companyId != null) {
@@ -351,30 +396,30 @@ export default {
     handleDelete(row) {
       const logIds = row.logId || this.ids;
       this.$confirm('是否确认删除短链课程看课记录编号为"' + logIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delCourseWatchLog(logIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return delCourseWatchLog(logIds);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
       this.$confirm('是否确认导出所有短链课程看课记录数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportCourseWatchLog(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportCourseWatchLog(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     },
     handleScheduleTimeChange(val) {
       if (val) {

+ 3 - 3
src/views/course/courseWatchLog/watchLogStatistics.vue

@@ -61,7 +61,7 @@
 import { listCourseWatchLog, getCourseWatchLog, delCourseWatchLog, addCourseWatchLog, updateCourseWatchLog, exportCourseWatchLog,watchLogStatistics,watchLogStatisticsExport } from "@/api/course/courseWatchLog";
 import {allList}from "@/api/company/company";
 import { courseList,videoList } from '@/api/course/courseRedPacketLog'
-import {getUserList} from "@/api/company/companyUser";
+// import {getUserList} from "@/api/company/companyUser";
 export default {
   name: "CourseWatchLog",
   data() {
@@ -131,11 +131,11 @@ export default {
     this.getDicts("sys_course_watch_log_type").then(response => {
       this.logTypeOptions = response.data;
     });
-    getUserList().then(res=>{
+/*    getUserList().then(res=>{
       if(res.code === 200) {
         this.companyUserList = res.data
       }
-    })
+    })*/
   },
   methods: {
     courseChange(row){

+ 14 - 2
src/views/course/userWatchCourseStatistics/index.vue

@@ -57,6 +57,16 @@
         />
       </el-form-item>
 
+      <el-form-item label="经销商" prop="companyBelongOwner">
+        <el-input
+          v-model="queryParams.companyBelongOwner"
+          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>
@@ -80,6 +90,7 @@
 
     <el-table border v-loading="loading" :data="userWatchCourseStatisticsList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="经销商归属" align="center" prop="companyBelongOwner" />
       <el-table-column label="营期名称" align="center" prop="periodName" />
       <el-table-column label="营期线" align="center" prop="periodStartingTime" />
       <el-table-column label="播出时间" align="center" prop="courseStartDateTime" />
@@ -97,7 +108,7 @@
       <el-table-column label="正确人数" align="center" prop="answerRightNum" />
       <el-table-column label="正确率" align="center" prop="answerRightRatePercent" />
       <el-table-column label="红包领取个数" align="center" prop="redPacketNum" />
-      <el-table-column label="红包领取额" align="center" prop="redPacketAmount" />
+      <el-table-column label="红包领取额" align="center" prop="redPacketAmount" />
     </el-table>
 
     <pagination
@@ -248,7 +259,8 @@ export default {
         answerRightNum: null,
         answerRightRate: null,
         redPacketNum: null,
-        redPacketAmount: null
+        redPacketAmount: null,
+        companyBelongOwner: null
       },
       // 表单参数
       form: {},

+ 15 - 1
src/views/course/userWatchCourseTotalStatistics/index.vue

@@ -56,6 +56,16 @@
         />
       </el-form-item>
 
+      <el-form-item label="经销商" prop="companyBelongOwner">
+        <el-input
+          v-model="queryParams.companyBelongOwner"
+          placeholder="请输入经销商归属"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
 <!--      <el-form-item label="所属销售" prop="companyUserName">-->
 <!--        <el-input-->
 <!--          v-model="queryParams.companyUserName"-->
@@ -88,6 +98,7 @@
 
     <el-table border v-loading="loading" :data="userWatchCourseStatisticsList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="经销商归属" align="center" prop="companyBelongOwner" />
       <el-table-column label="营期名称" align="center" prop="periodName" />
       <el-table-column label="营期线" align="center" prop="periodStartingTime" />
       <el-table-column label="播出时间" align="center" prop="courseStartDateTime" />
@@ -102,6 +113,8 @@
       <el-table-column label="完播人数" align="center" prop="completeWatchNum" />
       <el-table-column label="完播率" align="center" prop="completeWatchRatePercent" />
       <el-table-column label="红包领取个数" align="center" prop="redPacketNum" />
+      <el-table-column label="红包领取总额" align="center" prop="redPacketAmount" />
+
     </el-table>
 
     <pagination
@@ -252,7 +265,8 @@ export default {
         answerRightNum: null,
         answerRightRate: null,
         redPacketNum: null,
-        redPacketAmount: null
+        redPacketAmount: null,
+        companyBelongOwner: null
       },
       // 表单参数
       form: {},

+ 14 - 1
src/views/course/userWatchStatistics/index.vue

@@ -30,6 +30,16 @@
         />
       </el-form-item>
 
+      <el-form-item label="经销商" prop="companyBelongOwner">
+        <el-input
+          v-model="queryParams.companyBelongOwner"
+          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>
@@ -54,6 +64,7 @@
 
     <el-table border v-loading="loading" :data="userWatchStatisticsList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="经销商归属" align="center" prop="companyBelongOwner" />
       <el-table-column label="营期名称" align="center" prop="periodName" />
       <el-table-column label="营期线" align="center" prop="periodStartingTime" width="180">
         <template slot-scope="scope">
@@ -68,6 +79,7 @@
       <el-table-column label="完播人数" align="center" prop="completeWatchNum" />
       <el-table-column label="完播率" align="center" prop="completeWatchRatePercent" />
 
+
     </el-table>
 
     <pagination
@@ -158,7 +170,8 @@ export default {
         userNum: null,
         watchNum: null,
         completeWatchNum: null,
-        completeWatchRate: null
+        completeWatchRate: null,
+        companyBelongOwner: null
       },
       // 表单参数
       form: {},

+ 36 - 15
src/views/course/videoResource/index.vue

@@ -332,7 +332,7 @@
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button @click="cancel">取消</el-button>
-        <el-button type="primary" @click="submitForm" :disabled="isUploading">
+        <el-button type="primary" @click="submitForm" :loading="add" :disabled="isUploading || add">
           {{ isUploading ? '上传中...' : '保存' }}
         </el-button>
       </div>
@@ -406,6 +406,11 @@
             {{ getTypeName(scope.row.typeId) }}
           </template>
         </el-table-column>
+        <el-table-column label="子分类" align="center" min-width="100">
+          <template slot-scope="scope">
+            {{ getTypeName(scope.row.typeSubId) }}
+          </template>
+        </el-table-column>
         <el-table-column label="关联项目" align="center" min-width="100">
           <template slot-scope="scope">
           <a
@@ -522,7 +527,7 @@
 
       <div class="dialog-footer">
         <el-button @click="cancelBatch">取 消</el-button>
-        <el-button type="primary" @click="submitBatchAdd">保 存</el-button>
+        <el-button type="primary" :loading="add" :disabled="add || isUploading" @click="submitBatchAdd">保 存</el-button>
       </div>
       <!-- 批量上传视频弹窗 -->
       <el-dialog
@@ -1094,9 +1099,10 @@ export default {
       this.$refs["form"].validate(valid => {
         if (valid) {
           if (this.add){
-            this.$message.warning("文件上传中,请稍后再试")
+            this.$message.warning("请勿重复提交")
             return
           }
+          this.add = true
 
           const params = Object.assign({}, this.form);
           params.projectIds = this.form.projectIds.join(',');
@@ -1107,7 +1113,7 @@ export default {
                 this.open = false;
                 this.getList();
               }
-            });
+            })
           } else {
             addVideoResource(params).then(response => {
               if (response.code === 200) {
@@ -1115,7 +1121,7 @@ export default {
                 this.open = false;
                 this.getList();
               }
-            });
+            })
           }
         }
       });
@@ -1273,7 +1279,7 @@ export default {
             this.uploadCancellationTokens.set(form.tempId, tokens);
           }
         });
-        
+
         let line_1 = `${process.env.VUE_APP_VIDEO_LINE_1}${data.urlPath}`;
         form.fileKey = data.urlPath.substring(1);
         form.videoUrl = line_1;
@@ -1310,7 +1316,7 @@ export default {
             this.uploadCancellationTokens.set(form.tempId, tokens);
           }
         });
-        
+
         form.line2 = `${process.env.VUE_APP_VIDEO_LINE_2}/${data.urlPath}`;
 
         // 更新线路2状态为成功
@@ -1355,7 +1361,7 @@ export default {
       const file = options.file;
       this.getMediaDuration(file);
       this.currentUploadProgress = { total: 0, line1: 0, line2: 0, line1Status: 'pending', line2Status: 'pending' };
-      
+
       try {
         await this.getFirstThumbnail(file, this.form);
         const [line1Result, line2Result] = await Promise.allSettled([
@@ -1414,6 +1420,7 @@ export default {
     /** 批量新增 */
     handleBatchAdd() {
       this.batchAddVisible = true;
+      this.add =false
       this.videoList = []; // 清空之前的视频列表
     },
     /** 批量修改 */
@@ -1486,12 +1493,24 @@ export default {
     },
     /** 提交批量添加 */
     submitBatchAdd() {
+      if (this.videoList.length === 0) {
+        this.$message.warning("请选择视频");
+        return;
+      }
+
       // 检查是否所有选中的视频都已上传完成
       const incompleteVideos = this.videoList.filter(item => (item.progress || 0) < 100);
       if (incompleteVideos.length > 0) {
         this.$message.warning('有未完成上传的视频,请先完成上传');
         return;
       }
+
+      if (this.add){
+        this.$message.warning("请勿重复提交")
+        return
+      }
+      this.add = true
+
       // 调用批量添加API
       const videoList = JSON.parse(JSON.stringify(this.videoList));
       videoList.forEach(item => {
@@ -1503,7 +1522,7 @@ export default {
           this.batchAddVisible = false;
           this.getList();
         }
-      });
+      })
     },
     /** 获取分类名称 */
     getTypeName(typeId) {
@@ -1564,7 +1583,7 @@ export default {
             console.error('Error cancelling COS upload:', error);
           }
         }
-        
+
         // Cancel OBS upload if exists
         if (cancellationTokens.obs) {
           try {
@@ -1574,7 +1593,7 @@ export default {
             console.error('Error cancelling OBS upload:', error);
           }
         }
-        
+
         // Remove cancellation tokens
         this.uploadCancellationTokens.delete(row.tempId);
       }
@@ -1716,6 +1735,7 @@ export default {
         return;
       }
 
+      this.isUploading = true;
       this.isProcessingBatch = true;
 
       while (this.uploadQueue.length > 0) {
@@ -1750,6 +1770,7 @@ export default {
       }
 
       this.isProcessingBatch = false;
+      this.isUploading = false;
       this.$message.success('所有视频上传队列处理完成!');
     },
 
@@ -2082,7 +2103,7 @@ export default {
             console.error('Error cancelling COS upload:', error);
           }
         }
-        
+
         // Cancel OBS upload if exists
         if (cancellationTokens.obs) {
           try {
@@ -2092,7 +2113,7 @@ export default {
             console.error('Error cancelling OBS upload:', error);
           }
         }
-        
+
         // Remove cancellation tokens
         this.uploadCancellationTokens.delete(row.tempId);
       }
@@ -2176,7 +2197,7 @@ export default {
           tokens.cos = uploadInfo.cancel;
           this.uploadCancellationTokens.set(tempVideo.tempId, tokens);
         });
-        
+
         let line_1 = `${process.env.VUE_APP_VIDEO_LINE_1}${data.urlPath}`;
         tempVideo.fileKey = data.urlPath.substring(1);
         tempVideo.videoUrl = line_1;
@@ -2202,7 +2223,7 @@ export default {
           tokens.obs = uploadInfo.cancel;
           this.uploadCancellationTokens.set(tempVideo.tempId, tokens);
         });
-        
+
         tempVideo.line2 = `${process.env.VUE_APP_VIDEO_LINE_2}/${data.urlPath}`;
         return { success: true, url: tempVideo.line2 };
       } catch (error) {

+ 2055 - 0
src/views/crm/externalContact/index.vue

@@ -0,0 +1,2055 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+      <el-form-item label="企微公司" prop="corpId">
+            <el-select v-model="queryParams.corpId" placeholder="企微公司"  size="small" @change="updateCorpId()">
+              <el-option
+                v-for="dict in myQwCompanyList"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="dict.dictValue"
+              />
+            </el-select>
+      </el-form-item>
+      <el-form-item label="客户名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入客户名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="活码id" prop="wayId">
+        <el-input
+          v-model="queryParams.wayId"
+          placeholder="请输入活码id"
+          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"
+          @input="searchQwUser"
+          @focus="showQwUserDropdown = true"
+          @blur="hideDropdownWithDelay"
+          @clear="onQwUserNameClear"
+        />
+        <!-- 下拉建议 -->
+        <div v-if="showQwUserDropdown && qwUserSuggestions.length > 0" class="suggestion-box"  @scroll="handleScroll">
+          <div
+            v-for="item in qwUserSuggestions"
+            :key="item.dictValue"
+            class="suggestion-item"
+            @click="selectQwUser(item.dictValue,item.dictLabel)"
+          >
+            {{ item.dictLabel }}
+          </div>
+        </div>
+      </el-form-item>
+      <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="companyUser">
+        <el-input
+          v-model="queryParams.companyUser"
+          placeholder="请输入昵称或者手机号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="性别" prop="gender">
+        <el-select v-model="queryParams.gender" placeholder="状态" clearable size="small">
+          <el-option
+            v-for="dict in genderOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="客户等级" prop="level">
+        <el-select v-model="queryParams.level" placeholder="客户等级" clearable size="small">
+          <el-option
+            v-for="dict in ratingType"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="等级升降" prop="levelType">
+        <el-select v-model="queryParams.levelType" placeholder="等级升降" clearable size="small">
+          <el-option
+            v-for="dict in ratingUpFall"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
+
+      <el-form-item label="电话号码" prop="remarkMobiles">
+        <el-input
+          v-model="queryParams.remarkMobiles"
+          placeholder="请输入备注电话号码"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="来源" prop="addWay">
+
+        <el-select v-model="queryParams.addWay" placeholder="来源" clearable size="small">
+          <el-option
+            v-for="dict in addWayOptions"
+            :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="addWay">
+
+        <el-select v-model="queryParams.transferStatus" placeholder="转接状态" clearable size="small">
+          <el-option
+            v-for="dict in transferStatusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="是否绑定会员" prop="isBindMini">
+        <el-select v-model="queryParams.isBindMini" placeholder="是否绑定会员" clearable size="small" @change="handleQuery" >
+          <el-option
+            v-for="dict in isBindMiniOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="标签" prop="tagIds">
+<!--        <el-select v-model="selectTags" remote multiple placeholder="请选择" filterable  style="width: 100%;">-->
+<!--          <el-option-->
+<!--            v-for="dict in tagList"-->
+<!--            :label="dict.name"-->
+<!--            :value="dict.tagId">-->
+<!--          </el-option>-->
+<!--        </el-select>-->
+
+        <div @click="hangleChangeTags()" style="cursor: pointer; border: 1px solid #e6e6e6; background-color: white; overflow: hidden; flex-grow: 1;width: 250px">
+          <div style="min-height: 35px; max-height: 200px; overflow-y: auto;">
+            <el-tag type="success"
+                    closable
+                    :disable-transitions="false"
+                    v-for="list in this.selectTags"
+                    :key="list.tagId"
+                    @close="handleCloseTags(list)"
+                    style="margin: 3px;"
+            >{{list.name}}
+            </el-tag>
+          </div>
+        </div>
+
+
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input
+          v-model="queryParams.remark"
+          placeholder="请输入备注"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </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="change"></el-date-picker>
+      </el-form-item>
+
+
+
+
+      <el-form-item label="流失时间" prop="lossTime">
+        <el-date-picker clearable size="small"
+                        v-model="queryParams.lossTime"
+                        type="date"
+                        value-format="yyyy-MM-dd"
+                        placeholder="选择流失时间">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="删除时间" prop="delTime">
+        <el-date-picker clearable size="small"
+                        v-model="queryParams.delTime"
+                        type="date"
+                        value-format="yyyy-MM-dd"
+                        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="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['qw:externalContact:add']"
+        >同步</el-button>
+      </el-col> -->
+<!--      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          @click="handleBatchUpdateNotes"
+          v-hasPermi="['qw:externalContact:edit']"
+        >批量修改备注
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          @click="handleBatchUpdateNotesFilter"
+          v-hasPermi="['qw:externalContact:edit']"
+        >批量修改备注(筛选条件)
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['qw:externalContact:edit']"
+        >修改备注</el-button>
+      </el-col>-->
+
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['qw:externalContact:export']"
+        >导出</el-button>
+      </el-col>
+<!--      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          @click="addUserTag"
+          v-hasPermi="['qw:externalContact:addTag']"
+        >批量添加标签</el-button>
+      </el-col>-->
+<!--      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          size="mini"
+          @click="delUserTag"
+          v-hasPermi="['qw:externalContact:delTag']"
+        >批量移除标签</el-button>
+      </el-col>
+	  <el-col :span="1.5">
+	    <el-button
+	      type="primary"
+	      plain
+	      size="mini"
+	      @click="updateTalk"
+        v-hasPermi="['qw:externalContactInfo:updateTalk']"
+	    >批量更改交流状态</el-button>
+	  </el-col>-->
+<!--       <el-col :span="1.5">-->
+<!--        <el-button-->
+<!--          type="primary"-->
+<!--          plain-->
+<!--          size="mini"-->
+<!--          @click="setUserCourseSop"-->
+<!--          v-hasPermi="['qw:externalContact:setCourseSop']"-->
+<!--        >批量设置课程SOP</el-button>-->
+<!--      </el-col>-->
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+<!--    <el-tabs type="card" v-model="isBindActiveName" @tab-click="handleClickX">-->
+<!--      <el-tab-pane label="全部" name="all"></el-tab-pane>-->
+<!--      <el-tab-pane label="已绑定CRM" name="isBind"></el-tab-pane>-->
+<!--      <el-tab-pane label="未绑定CRM" name="noBind"></el-tab-pane>-->
+<!--    </el-tabs>-->
+
+    <el-table v-loading="loading" :data="externalContactList" @selection-change="handleSelectionChange" border>
+      <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="avatar" width="100px">
+        <template slot-scope="scope">
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover">
+            <img slot="reference" :src="scope.row.avatar" width="60px">
+            <img :src="scope.row.avatar" style="max-width: 200px;">
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column label="企微客户名称"  prop="name" width="110px"/>
+      <el-table-column label="客户称呼"  prop="stageStatus" width="110px"/>
+      <el-table-column label="销售企微昵称" align="center" prop="qwUserName" width="120px"/>
+      <el-table-column label="企微部门" align="center" prop="departmentName" width="120px"/>
+      <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="gender">
+        <template slot-scope="scope">
+          <dict-tag :options="genderOptions" :value="scope.row.gender"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="描述信息" align="center" prop="description" />
+      <el-table-column label="标签" align="center" prop="tagIdsName" width="300px">
+<!--        <template slot-scope="scope">-->
+<!--          <div v-for="name in scope.row.tagIdsName"  style="display: inline;">-->
+<!--          <el-tag type="success">{{ name }}</el-tag>-->
+<!--          </div>-->
+<!--        </template>-->
+        <template slot-scope="scope">
+          <div class="tag-container">
+            <div class="tag-list">
+              <el-tag
+                v-for="name in scope.row.tagIdsName"
+                :key="name"
+                type="success"
+                size="small"
+              >
+                {{ name }}
+              </el-tag>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="是否回复" align="center" prop="isReply" width="120px" >
+        <template slot-scope="scope">
+          <span v-if="scope.row.isReply === 1"><el-tag type="success">已回复</el-tag></span>
+          <span v-else-if="scope.row.isReply === 0"><el-tag type="info">未回复</el-tag></span>
+          <span v-else>{{ scope.row.isReply }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="status" width="120px" >
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="客户等级" align="center" prop="level" width="120px" >
+        <template slot-scope="scope">
+          <dict-tag :options="ratingType" :value="scope.row.level"/>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="state参数" align="center" prop="state" width="100px" />
+
+      <el-table-column label="等级状态" align="center" prop="levelType" width="120px" >
+        <template slot-scope="scope">
+          <dict-tag :options="ratingUpFall" :value="scope.row.levelType"/>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="添加时间" align="center" prop="createTime" width="100px" />
+      <el-table-column label="流失时间" align="center" prop="lossTime" width="100px" />
+      <el-table-column label="删除时间" align="center" prop="delTime" width="100px" />
+      <el-table-column label="注册时间" align="center" prop="registerTime" width="100px" />
+      <el-table-column label="备注电话号码" align="center" prop="remarkMobiles" width="150px">
+        <template slot-scope="scope">
+          <div v-for="i in JSON.parse(scope.row.remarkMobiles)" :key="i">{{i}}</div>
+        </template>
+      </el-table-column>
+      <el-table-column label="备注企业名称" align="center" prop="remarkCorpName" />
+      <el-table-column label="来源" align="center" prop="addWay" width="100px">
+        <template slot-scope="scope">
+          <dict-tag :options="addWayOptions" :value="scope.row.addWay"/>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="转接状态" align="center" prop="transferStatus" width="100px" >
+        <template slot-scope="scope">
+          <dict-tag :options="transferStatusOptions" :value="scope.row.transferStatus"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="企业id" align="center" prop="corpId" />
+      <el-table-column label="是否绑定会员" width="100px" align="center" fixed="right">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.fsUserId" >已绑定</el-tag>
+          <el-tag v-else type="info"> 未绑定</el-tag>
+        </template>
+      </el-table-column>
+<!--      <el-table-column label="修改" align="center" class-name="small-padding fixed-width" width="120px" fixed="right">
+        <template slot-scope="scope">
+          <el-button
+            v-if="scope.row.status==0||scope.row.status==2"
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['qw:externalContact:edit']"
+          >修改备注</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-user-solid"
+            @click="handleAppellation(scope.row)"
+          >修改客户称呼</el-button>
+        </template>
+      </el-table-column>-->
+<!--      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120px" fixed="right">
+        <template slot-scope="scope">
+&lt;!&ndash;          <el-button&ndash;&gt;
+&lt;!&ndash;            size="mini"&ndash;&gt;
+&lt;!&ndash;            type="text"&ndash;&gt;
+&lt;!&ndash;            icon="el-icon-edit-outline"&ndash;&gt;
+&lt;!&ndash;            @click="handleUpdateCustomer(scope.row)"&ndash;&gt;
+&lt;!&ndash;            >&ndash;&gt;
+&lt;!&ndash;            <span v-if="scope.row.customerId">换绑CRM</span>&ndash;&gt;
+&lt;!&ndash;            <span v-else>绑定CRM</span>&ndash;&gt;
+&lt;!&ndash;          </el-button>&ndash;&gt;
+
+&lt;!&ndash;          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit-outline"
+            @click="handleUpdateUser(scope.row)"
+            >
+            <span v-if="scope.row.fsUserId">换绑会员</span>
+            <span v-else>绑定会员</span>
+          </el-button>
+
+          <el-button
+            v-if="scope.row.fsUserId"
+            size="mini"
+            type="text"
+            icon="el-icon-thumb"
+            @click="handleUnBindUserId(scope.row)"
+            v-hasPermi="['qw:externalContact:unBindUserId']"
+          >
+            <span>解除会员绑定</span>
+          </el-button>&ndash;&gt;
+
+
+&lt;!&ndash;          <el-button v-if="scope.row.customerId"&ndash;&gt;
+&lt;!&ndash;            size="mini"&ndash;&gt;
+&lt;!&ndash;            type="text"&ndash;&gt;
+&lt;!&ndash;            icon="el-icon-paperclip"&ndash;&gt;
+&lt;!&ndash;            @click="handleShow(scope.row)"&ndash;&gt;
+&lt;!&ndash;          >CRM客户详情</el-button>&ndash;&gt;
+          <el-button
+             size="mini"
+             type="text"
+             @click="handledetails(scope.row)"
+             >AI获取用户信息
+          </el-button>
+          <el-button
+             size="mini"
+             type="text"
+             @click="handleMemberdetails(scope.row)"
+             v-if="scope.row.fsUserId"
+             >
+             <span>会员详细</span>
+          </el-button>
+        </template>
+      </el-table-column>-->
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <el-drawer size="75%" :title="show.title" :visible.sync="show.open">
+      <customer-details  ref="customerDetails" @refreshList="refreshList"/>
+    </el-drawer>
+
+    <el-drawer
+        :with-header="false"
+        size="75%"
+          :title="show.title" :visible.sync="show.open">
+      <userDetails  ref="userDetails" />
+    </el-drawer>
+
+
+    <!--  搜索标签   -->
+    <el-dialog :title="changeTagDialog.title" :visible.sync="changeTagDialog.open" style="width:100%;height: 100%" append-to-body>
+
+      <div>搜索标签:
+        <el-input v-model="queryTagParams.name" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags(queryTagParams.name)">搜索</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
+      </div>
+      <div v-for="item in tagGroupList" :key="item.id"  >
+        <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
+          <span class="name-background">{{ item.name }}</span>
+        </div>
+        <!-- 添加外层滚动容器 -->
+        <div class="scroll-wrapper">
+          <div class="tag-container">
+            <a
+              v-for="tagItem in item.tag"
+              class="tag-box"
+              @click="tagSelection(tagItem)"
+              :class="{ 'tag-selected': tagItem.isSelected }"
+            >
+              {{ tagItem.name }}
+            </a>
+          </div>
+        </div>
+      </div>
+
+      <pagination
+        v-show="tagTotal>0"
+        :total="tagTotal"
+        :page.sync="queryTagParams.pageNum"
+        :limit.sync="queryTagParams.pageSize"
+        @pagination="getPageListTagGroup"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="tagSubmitForm()">确 定</el-button>
+        <el-button @click="tagCancel()">取消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog title="批量添加标签" :visible.sync="tagOpen" width="800px" append-to-body>
+      <div>搜索标签:
+        <el-input v-model="tagChange.tagName" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags(tagChange.tagName)">搜索</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
+      </div>
+      <el-form ref="form" :model="addTagForm"  label-width="80px">
+        <div v-for="item in tagGroupList" :key="item.id" >
+          <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
+            <span class="name-background">{{ item.name }}</span>
+          </div>
+          <!-- 添加外层滚动容器 -->
+          <div class="scroll-wrapper">
+            <div class="tag-container">
+              <a
+                v-for="tagItem in item.tag"
+                class="tag-box"
+                @click="tagSelection(tagItem)"
+                :class="{ 'tag-selected': tagItem.isSelected }"
+              >
+                {{ tagItem.name }}
+              </a>
+            </div>
+          </div>
+        </div>
+      </el-form>
+      <pagination
+        v-show="tagTotal>0"
+        :total="tagTotal"
+        :page.sync="queryTagParams.pageNum"
+        :limit.sync="queryTagParams.pageSize"
+        @pagination="getPageListTagGroup"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="addTagSubmitForm()">确 定</el-button>
+        <el-button @click="addTagCancel">取 消</el-button>
+      </div>
+    </el-dialog>
+    <el-dialog title="批量添加客户备注" :visible.sync="notesOpen.open" width="800px" append-to-body>
+      <el-card>
+        <el-row>
+          <el-col>
+            <el-radio-group v-model="notesOpen.nameType" style="margin-bottom: 2%">
+              <el-radio :label="1">
+                客户名称添加在【新备注】【前】
+              </el-radio>
+              <el-radio :label="2">
+                客户名称添加在【新备注】【后】
+              </el-radio>
+              <el-radio :label="3">
+                不添加客户名称
+              </el-radio>
+            </el-radio-group>
+          </el-col>
+          <el-col>
+            <el-radio-group v-model="notesOpen.type">
+              <el-radio
+                :label="1"
+              >添加【新备注】在最【前】面
+              </el-radio>
+              <el-radio
+                :label="2"
+              >添加【新备注】在最【后】面
+              </el-radio>
+              <el-radio
+                :label="3"
+              >替换所有备注
+              </el-radio>
+            </el-radio-group>
+          </el-col>
+          <el-col>
+            <el-input v-model="notesOpen.notes" placeholder="请输入客户备注(最多20个字,含已有的)" clearable size="small"
+                      maxlength="20" show-word-limit style="width: 500px;margin-top: 3%"/>
+            <div style="color: #999;font-size: 14px;display: flex;align-items: center;">
+              <i class="el-icon-info"></i>
+              由于企业微信官方限制,备注最多20个字,且自动会去除末尾超出的字
+            </div>
+          </el-col>
+        </el-row>
+      </el-card>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="notesSubmitForm()">确 定</el-button>
+        <el-button @click="notesCancel()">取消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog title="批量移除标签" :visible.sync="tagDelOpen" width="800px" append-to-body>
+      <div>搜索标签:
+        <el-input v-model="tagChange.tagName" placeholder="请输入标签名称" clearable size="small" style="width: 200px;margin-right: 10px" />
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleSearchTags(tagChange.tagName)">搜索</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="cancelSearchTags">重置</el-button>
+      </div>
+      <el-form ref="form" :model="addTagForm"  label-width="80px">
+        <div v-for="item in tagGroupList" :key="item.id" >
+          <div style="font-size: 20px;margin-top: 20px;margin-bottom: 20px;">
+            <span class="name-background">{{ item.name }}</span>
+          </div>
+          <!-- 添加外层滚动容器 -->
+          <div class="scroll-wrapper">
+            <div class="tag-container">
+              <a
+                v-for="tagItem in item.tag"
+                class="tag-box"
+                @click="tagSelection(tagItem)"
+                :class="{ 'tag-selected': tagItem.isSelected }"
+              >
+                {{ tagItem.name }}
+              </a>
+            </div>
+          </div>
+        </div>
+      </el-form>
+      <pagination
+        v-show="tagTotal>0"
+        :total="tagTotal"
+        :page.sync="queryTagParams.pageNum"
+        :limit.sync="queryTagParams.pageSize"
+        @pagination="getPageListTagGroup"
+      />
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="tagDelSubmitForm()">确 定</el-button>
+        <el-button @click="DelTagCancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 添加或修改企业微信客户对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+
+
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
+        </el-form-item>
+        <el-form-item label="描述信息" prop="description">
+          <el-input v-model="form.description" type="textarea" :rows="3" placeholder="请输入描述信息" />
+        </el-form-item>
+
+        <el-form-item label="备注电话号码" prop="remarkMobiles">
+
+          <el-tag
+            :key="tag"
+            v-for="tag in remarkMobiles"
+            closable
+            :disable-transitions="false"
+            @close="handleClose(tag)">
+            {{tag}}
+          </el-tag>
+          <el-input
+            style="width:110px"
+            class="input-new-tag"
+            v-if="inputVisible"
+            v-model="inputValue"
+            ref="saveTagInput"
+            size="small"
+            @keyup.enter.native="handleInputConfirm"
+            @blur="handleInputConfirm"
+          >
+          </el-input>
+          <el-button v-else class="button-new-tag" size="small" style="width: 110px" @click="showInput">新增电话</el-button>
+
+        </el-form-item>
+
+
+        <el-form-item label="备注企业名称" prop="remarkCorpName">
+          <el-input v-model="form.remarkCorpName" placeholder="请输入备注企业名称" />
+        </el-form-item>
+
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog :title="callOpen.title" :visible.sync="callOpen.open" width="500px" append-to-body>
+      <el-form ref="callOpenFrom" :model="callOpenFrom" :rules="callOpenRule" label-width="110px">
+        <el-form-item label="客户称呼" prop="stageStatus">
+          <el-input v-model="callOpenFrom.stageStatus" placeholder="请输入客户称呼" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer" >
+        <el-button type="primary" @click="submitCallOpenFrom">确 定</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 绑定客户   -->
+    <el-dialog :title="bindCustomer.title" :visible.sync="bindCustomer.open"  width="1200px" append-to-body>
+      <mycustomer ref="mycustomer"  @bindCustomerId="bindCustomerId"></mycustomer>
+    </el-dialog>
+
+<!--    设置一个课程sop-->
+    <el-dialog :title="setSop.title" :visible.sync="setSop.open"  width="1200px" append-to-body>
+      <SopDialog ref="SopDialog"  @bindCourseSop="bindCourseSop"></SopDialog>
+    </el-dialog>
+
+    <el-dialog :title="user.title" :visible.sync="user.open" width="800px" append-to-body>
+      <selectUser ref="selectUser" @bindMiniCustomerId="bindMiniCustomerId"></selectUser>
+    </el-dialog>
+
+	<el-dialog :title="info.title" :visible.sync="info.open"   width="1100px" append-to-body>
+	  <info  ref="Details" />
+	</el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  bindUserId,
+  addTag,
+  delTag,
+  batchUpdateExternalContactNotes,
+  listExternalContact,
+  getExternalContact,
+  delExternalContact,
+  addExternalContact,
+  updateExternalContact,
+  exportExternalContact,
+  editbindCustomer,
+  setCustomerCourseSop,
+  getCustomerCourseSop,
+  setCustomerCourseSopList,
+  unBindUserId, updateExternalContactCall
+} from '@/api/qw/externalContact'
+/*import {getMyQwUserList, getMyQwCompanyList, updateUser,getQwUserListLikeName} from "@/api/qw/user";*/
+import {getMyQwUserList, getMyQwCompanyList, updateUser} from "@/api/qw/user";
+import {listTag, getTag, searchTags,} from "@/api/qw/tag";
+import { allListTagGroup} from "@/api/qw/tagGroup";
+/*import mycustomer from '@/views/qw/externalContact/mycustomer'
+import customerDetails from '@/views/qw/externalContact/customerDetails'
+import SopDialog from '@/views/course/sop/SopDialog.vue'
+import  selectUser  from "@/views/qw/externalContact/selectUser.vue";
+import info from "@/views/qw/externalContact/info.vue";
+import { editTalk } from "@/api/qw/externalContactInfo";*/
+import PaginationMore from "../../../components/PaginationMore/index.vue";
+/*import userDetails from '@/views/store/components/userDetails.vue';*/
+export default {
+  name: "ExternalContact",
+  /*components:{PaginationMore, mycustomer,customerDetails,SopDialog,selectUser,info,userDetails},*/
+  components:{PaginationMore},
+  data() {
+    return {
+      notesOpen: {
+        type: 1,
+        nameType: 3,
+        addType: 0,
+        filter: false,
+        open: false,
+        notes: null,
+      },
+      user:{
+        open:false,
+        title:"修改客户"
+      },
+      userForm:{
+        id:null,
+        fsUserId:null,
+      },
+      info:{
+        title:"用户信息",
+        open:false,
+      },
+      // ...其他已有数据
+      qwUserSuggestions: [],       // 已展示的数据
+      showQwUserDropdown: false,   // 控制下拉框显示
+      qwUserLoading: false,        // 加载状态
+      qwUserNoMore: false,         // 是否还有更多数据
+      qwUserPageNum: 1,            // 当前页码
+      qwUserPageSize: 10,          // 每页数量
+      qwUserTotal: 0,               // 总数
+      isBindMiniOptions:[
+        {dictLabel:"已绑定",dictValue:'isBindMini'},
+        {dictLabel:"未绑定",dictValue:'noBindMini'},
+      ],
+      //标签弹窗选择
+      tagChange:{
+        open:false,
+        index:null,
+      },
+	  sTime:null,
+	  eTime:null,
+	  createTime:null,
+      // 遮罩层
+      loading: false,
+      // 导出遮罩层
+      exportLoading: false,
+      tagOpen:false,
+      tagDelOpen:false,
+      // 选中数组
+      ids: [],
+      isBindActiveName:"all",
+      remarkMobiles: [],
+      inputVisible: false,
+      inputValue: '',
+      // 非单个禁用
+      single: true,
+      tagGroupList: [],
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 企业微信客户表格数据
+      externalContactList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 用户类别字典
+      typeOptions: [],
+      ratingType: [],
+      ratingUpFall: [],
+      // 性别字典
+      genderOptions: [],
+
+      addTagForm:{
+        userIds:[],
+        tagIds:[]
+      },
+
+      myQwCompanyList:[],
+      show:{
+        title:"客户详情",
+        open:false,
+      },
+
+      //存储选择的客户
+      chooseCustomerSOP:null,
+
+      setSop:{
+        title:"选择课节SOP",
+        open:false,
+        //区分单选1还是多选2
+        type:null,
+      },
+      //合成的客户-课节SOP参数
+      customerCourseForm:{},
+
+      //查询是否已经设置过客户-某个课节的SOP
+      customerCourseFormLogs:{},
+      //绑定客户
+      bindCustomer:{
+        title:null,
+        open:false,
+      },
+      callOpen:{
+        open:false,
+        title: '修改客户称呼',
+      },
+      callOpenFrom:{
+        id:null,
+        stageStatus:null,
+      },
+      callOpenRule:{
+        stageStatus:[{required:true,message:"员工称呼不能为空",trigger:"blur"}]
+      },
+      //绑定的参数表
+      qwFormCustomer:{
+        externalContactId:null,
+        customerId:null,
+      },
+      // 来源字典
+      addWayOptions: [],
+
+      //标签
+      changeTagDialog:{
+        title:"",
+        open:false,
+      },
+
+      queryTagParams:{
+        pageNum: 1,
+        pageSize: 5,
+        total:0,
+        name:null,
+        corpId:null,
+      },
+
+      tagTotal:0,
+
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: null,
+        qwUserName:null,
+        externalUserId: null,
+        name: null,
+        avatar: null,
+        type: null,
+        qwUserId:null,
+        gender: null,
+        description: null,
+        tagIds: null,
+        remark:null,
+        remarkMobiles: null,
+        remarkCorpName: null,
+        addWay: null,
+        operUserid: null,
+        corpId: null,
+        companyId: null,
+        status:null,
+        transferStatus:null,
+        isBind:null,
+        isBindMini:null,
+        lossTime:null,
+        sTime:null,
+        eTime:null,
+        createTime:null,
+        level:null,
+        wayId:null,
+        levelType:null,
+        companyUser:null
+      },
+      selectTags:[],
+      // 表单参数
+      form: {},
+      tagList:[],
+      transferStatusOptions:[],
+      statusOptions:[],
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+
+    this.getDicts("sys_qw_externalContact_type").then(response => {
+      this.typeOptions = response.data;
+    });
+
+    this.getDicts("sys_qw_sop_rating_type").then(response => {
+      this.ratingType = response.data;
+    });
+
+    this.getDicts("sys_qw_sop_rating_upFall").then(response => {
+      this.ratingUpFall = response.data;
+    });
+
+
+    getMyQwCompanyList().then(response => {
+            this.myQwCompanyList = response.data;
+            if(this.myQwCompanyList!=null){
+              // this.queryParams.corpId=this.myQwCompanyList[0].dictValue
+              //
+              // var listTagFrom={corpId:this.queryParams.corpId}
+              // listTag(listTagFrom).then(response => {
+              //   this.tagList = response.rows;
+              // });
+              this.getList();
+
+            }
+    });
+
+
+    this.getDicts("sys_sex").then(response => {
+      this.genderOptions = response.data;
+    });
+    this.getDicts("sys_qw_externalContact_addWay").then(response => {
+      this.addWayOptions = response.data;
+    });
+
+
+
+    this.getDicts("sys_qw_external_contact_status").then(response => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("sys_qw_transfer_status").then(response => {
+      this.transferStatusOptions = response.data;
+    });
+
+  },
+  methods: {
+    handleMemberdetails(row){
+            this.show.open=true;
+            setTimeout(() => {
+                 this.$refs.userDetails.getDetails(row.fsUserId);
+            }, 1);
+    },
+    onQwUserNameClear() {
+      this.queryParams.qwUserId = null;  // 同时清空 qwUserId
+    },
+    // 搜索企微用户
+    searchQwUser(query) {
+      if (!query.trim()) {
+        this.qwUserSuggestions = [];
+        this.showQwUserDropdown = false;
+        this.qwUserNoMore = false;
+        this.qwUserPageNum = 1;
+        return;
+      }
+
+      this.queryParams.qwUserName = query;
+      this.qwUserPageNum = 1;
+      this.qwUserNoMore = false;
+      this.qwUserSuggestions = [];
+      this.fetchQwUsers(query);
+    },
+
+    fetchQwUsers(query) {
+      const params = {
+        qwUserName: query,
+        pageNum: this.qwUserPageNum,
+        pageSize: this.qwUserPageSize
+      };
+
+      this.qwUserLoading = true;
+
+      getQwUserListLikeName(params).then(res => {
+        const list = res.data.list || [];
+        const total = res.data.total || 0;
+
+        this.qwUserSuggestions = [...this.qwUserSuggestions, ...list];
+        this.qwUserTotal = total;
+
+        // 判断是否还有更多数据
+        if (this.qwUserSuggestions.length >= total) {
+          this.qwUserNoMore = true;
+        }
+
+        this.showQwUserDropdown = true;
+      }).finally(() => {
+        this.qwUserLoading = false;
+      });
+    },
+
+    // 选择企微用户
+    selectQwUser(key,value) {
+      this.queryParams.qwUserName = value;
+      this.queryParams.qwUserId = key;
+      this.showQwUserDropdown = false;
+      this.handleQuery(); // 可选:自动触发查询
+    },
+
+    // 延迟隐藏下拉框,防止点击失效
+    hideDropdownWithDelay() {
+      setTimeout(() => {
+        this.showQwUserDropdown = false;
+      }, 200);
+    },
+    handleScroll(e) {
+      const container = e.target;
+      const scrollTop = container.scrollTop;
+      const scrollHeight = container.scrollHeight;
+      const clientHeight = container.clientHeight;
+
+      // 距离底部小于 20px 触发加载
+      if (scrollHeight - scrollTop - clientHeight < 20 && !this.qwUserLoading && !this.qwUserNoMore) {
+        this.qwUserPageNum += 1;
+        this.fetchQwUsers(this.queryParams.qwUserName);
+      }
+    },
+
+
+	  change(){
+			if(this.createTime!=null){
+			  this.queryParams.sTime=this.createTime[0];
+			  this.queryParams.eTime=this.createTime[1];
+			}else{
+			  this.queryParams.sTime=null;
+			  this.queryParams.eTime=null;
+			}
+
+		  },
+    updateCorpId(){
+      var listTagFrom={corpId:this.queryParams.corpId}
+        listTag(listTagFrom).then(response => {
+          this.tagList = response.rows;
+        });
+        this.getList();
+     },
+    /** 查询企业微信客户列表 */
+    getList() {
+      this.loading = true;
+      const { qwUserName, ...queryParams } = this.queryParams;
+      listExternalContact(queryParams).then(response => {
+        this.externalContactList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    bindMiniCustomerId(row){
+      console.log(row)
+      this.userForm.fsUserId=row;
+      bindUserId(this.userForm).then(res=>{
+         if (res.code==200){
+           this.$message.success('绑定成功')
+         }else {
+           this.$message.error('绑定失败:',res.msg)
+         }
+         this.getList()
+         this.user.open=false;
+      })
+    },
+    /** 查看客户详情 */
+    handleShow(row){
+      this.show.open=true;
+      var that=this;
+      const tab = "visit";
+      setTimeout(() => {
+        that.$refs.customerDetails.getDetails(row.customerId);
+        that.$refs.customerDetails.handleClick(tab);
+
+      }, 200);
+    },
+
+	handledetails(row){
+		this.info.open=true;
+		setTimeout(() => {
+			 this.$refs.Details.getDetails(row.id);
+		}, 1);
+	},
+
+	closeInfo(){
+		this.info.open=false
+	},
+    handleClickX(tab, event) {
+
+      this.queryParams.isBind=tab.name;
+      this.handleQuery();
+    },
+
+    handleClose(tag) {
+      this.remarkMobiles.splice(this.remarkMobiles.indexOf(tag), 1);
+    },
+    showInput() {
+      this.inputVisible = true;
+      this.$nextTick(_ => {
+        this.$refs.saveTagInput.$refs.input.focus();
+      });
+    },
+    handleInputConfirm() {
+      let inputValue = this.inputValue;
+      if (inputValue) {
+        this.remarkMobiles.push(inputValue);
+      }
+      this.inputVisible = false;
+      this.inputValue = '';
+    },
+
+    addUserTag(){
+
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要添加标签的客户');
+      }
+
+      this.getPageListTagGroup();
+
+      setTimeout(() => {
+
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            this.tagGroupList[i].tag[x].isSelected=false;
+          }
+        }
+      }, 200);
+
+
+      this.tagOpen = true;
+
+    },
+
+
+    getPageListTagGroup(){
+      this.queryTagParams.corpId=this.queryParams.corpId
+      allListTagGroup(this.queryTagParams).then(response => {
+        this.tagGroupList = response.rows;
+        this.tagTotal = response.total;
+      });
+    },
+
+    delUserTag(){
+
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要移除标签的客户');
+      }
+      this.getPageListTagGroup();
+
+      setTimeout(() => {
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            this.tagGroupList[i].tag[x].isSelected=false;
+          }
+        }
+      }, 200);
+
+      this.tagDelOpen = true;
+
+    },
+
+
+    //搜索的标签
+    hangleChangeTags(){
+
+      this.changeTagDialog.title="搜索的标签"
+      this.changeTagDialog.open=true;
+
+      // 获取 tagListFormIndex 中的所有 tagId,用于快速查找
+      const selectedTagIds = new Set(
+        (this.selectTags || []).map(tagItem => tagItem?.tagId)
+      );
+
+      this.queryTagParams.name=null;
+
+      this.getPageListTagGroup();
+
+      setTimeout(() => {
+        for (let i = 0; i < this.tagGroupList.length; i++) {
+          for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+            this.tagGroupList[i].tag[x].isSelected = selectedTagIds.has(this.tagGroupList[i].tag[x].tagId);
+          }
+        }
+      }, 200);
+
+
+    },
+
+    //删除一些选择的标签
+    handleCloseTags(list){
+      const ls = this.selectTags.findIndex(t => t.tagId === list.tagId);
+      if (ls !== -1) {
+        this.selectTags.splice(ls, 1);
+        this.selectTags = [...this.selectTags];
+      }
+
+      if (this.selectTags!=null && this.selectTags.length>0){
+        // 确保 this.form.tags 是数组
+        if (!this.queryParams.tagIds) {
+          this.queryParams.tagIds = []; // 如果未定义,初始化
+        } else {
+          this.queryParams.tagIds = []; // 清空已有数据
+        }
+
+        // 遍历并添加 tagId
+        this.selectTags.forEach(tag => {
+          if (tag.tagId) { // 确保 tagId 存在
+            this.queryParams.tagIds.push(tag.tagId);
+          }
+        });
+        this.queryParams.tagIds=this.queryParams.tagIds.join(",");
+      }else {
+        this.queryParams.tagIds=null;
+      }
+
+    },
+
+    //重新获取页面数据
+    refreshList(){
+      this.getList();
+    },
+
+    //批量设置课程sop
+    setUserCourseSop(){
+
+      if(this.ids==null||this.ids==""){
+        return  this.$message('请选择需要设置课程SOP的客户');
+      }
+
+      this.$confirm('批量设置客户课节SOP可能会存在重复,确定要批量设置吗?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+          this.setSop.open = true;
+          this.setSop.type = 2;
+        })
+        .catch(() => {
+          // 可以处理用户点击“取消”的逻辑
+        });
+
+    },
+    tagSelection(row){
+
+      row.isSelected= !row.isSelected;
+      this.$forceUpdate();
+    },
+
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    addTagCancel() {
+
+      this.tagOpen = false;
+
+      this.addTagForm={
+        userIds:[],
+        tagIds:[]
+      };
+    },
+
+    DelTagCancel() {
+      this.tagDelOpen = false;
+
+      this.addTagForm={
+        userIds:[],
+        tagIds:[]
+      };
+    },
+    addTagSubmitForm(){
+
+      for (let i = 0; i < this.tagGroupList.length; i++) {
+        for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+          if(this.tagGroupList[i].tag[x].isSelected==true){
+            this.addTagForm.tagIds.push(this.tagGroupList[i].tag[x].tagId)
+          }
+
+        }
+      }
+      if(this.addTagForm.tagIds==[]||this.addTagForm.tagIds==null||this.addTagForm.tagIds==""){
+        return  this.$message('请选择标签');
+      }
+
+      this.addTagForm.corpId=this.queryParams.corpId
+      this.addTagForm.userIds=this.ids;
+
+
+      let loadingRock = this.$loading({
+        lock: true,
+        text: '正在执行中请稍后~~请不要刷新页面!!',
+        spinner: 'el-icon-loading',
+        background: 'rgba(0, 0, 0, 0.7)'
+      });
+
+
+      addTag(this.addTagForm).then(response => {
+       this.msgSuccess(response.msg);
+       this.tagOpen = false;
+        loadingRock.close();
+       this.addTagForm={
+         userIds:[],
+         tagIds:[]
+       };
+       this.getList()
+     }).finally(res=>{
+        loadingRock.close();
+      });
+
+    },
+    tagDelSubmitForm(){
+      for (let i = 0; i < this.tagGroupList.length; i++) {
+        for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+          if(this.tagGroupList[i].tag[x].isSelected==true){
+            this.addTagForm.tagIds.push(this.tagGroupList[i].tag[x].tagId)
+          }
+
+        }
+      }
+      if(this.addTagForm.tagIds==[]||this.addTagForm.tagIds==null||this.addTagForm.tagIds==""){
+        return  this.$message('请选择标签');
+      }
+       this.addTagForm.corpId=this.queryParams.corpId
+      this.addTagForm.userIds=this.ids;
+
+      let loadingRock = this.$loading({
+        lock: true,
+        text: '正在执行中请稍后~~请不要刷新页面!!',
+        spinner: 'el-icon-loading',
+        background: 'rgba(0, 0, 0, 0.7)'
+      });
+
+
+      delTag(this.addTagForm).then(response => {
+       this.msgSuccess(response.msg);
+       this.tagDelOpen = false;
+        loadingRock.close();
+       this.addTagForm={
+         userIds:[],
+         tagIds:[]
+       };
+       this.getList()
+     }).finally(res=>{
+        loadingRock.close();
+      });
+    },
+
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        userId: null,
+        externalUserId: null,
+        name: null,
+        companyUserId:null,
+        customerId:null,
+        avatar: null,
+        type: null,
+        gender: null,
+        remark: null,
+        description: null,
+        tagIds: null,
+        remarkMobiles: null,
+        remarkCorpName: null,
+        addWay: null,
+        operUserid: null,
+        corpId: null,
+        companyId: null,
+        transferStatus:null,
+        status:null,
+        sTime:null,
+        eTime:null,
+        createTime:null,
+        transferTime:null,
+        transferNum:null,
+        lossTime:null,
+        delTime:null,
+        state:null,
+        wayId:null,
+        stageStatus:null,
+        customerName:null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+
+      if (this.selectTags!=null && this.selectTags.length>0){
+        // 确保 this.form.tags 是数组
+        if (!this.queryParams.tagIds) {
+          this.queryParams.tagIds = []; // 如果未定义,初始化
+        } else {
+          this.queryParams.tagIds = []; // 清空已有数据
+        }
+
+        // 遍历并添加 tagId
+        this.selectTags.forEach(tag => {
+          if (tag.tagId) { // 确保 tagId 存在
+            this.queryParams.tagIds.push(tag.tagId);
+          }
+        });
+        this.queryParams.tagIds=this.queryParams.tagIds.join(",");
+      }else {
+        this.queryParams.tagIds=null;
+      }
+
+
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    handleSearchTags(name){
+
+      if (!name){
+        return this.$message.error("请输入要搜索的标签")
+      }
+
+      this.queryTagParams.name=name;
+      this.queryTagParams.corpId=this.queryParams.corpId;
+
+      searchTags(this.queryTagParams).then(response => {
+        this.tagGroupList = response.rows;
+      });
+
+    },
+
+    cancelSearchTags(){
+      this.resetSearchQueryTag()
+
+      this.getPageListTagGroup();
+    },
+    //确定选择标签
+    tagSubmitForm(){
+
+      for (let i = 0; i < this.tagGroupList.length; i++) {
+        for (let x = 0; x < this.tagGroupList[i].tag.length; x++) {
+          if (this.tagGroupList[i].tag[x].isSelected === true) {
+
+            if (!this.selectTags) {
+              this.selectTags = [];
+            }
+
+            // 检查当前 tag 是否已经存在于 tagListFormIndex[index] 中
+            let tagExists = this.selectTags.some(
+              tag => tag.id === this.tagGroupList[i].tag[x].id
+            );
+
+            // 如果 tag 不存在于 tagListFormIndex[index] 中,则新增
+            if (!tagExists) {
+              this.selectTags.push(this.tagGroupList[i].tag[x]);
+            }
+          }
+        }
+      }
+      if (!this.selectTags || this.selectTags.length === 0) {
+        return this.$message('请选择标签');
+      }
+
+      this.changeTagDialog.open = false;
+    },
+
+    //取消选择标签
+    tagCancel(){
+      this.changeTagDialog.open = false;
+    },
+
+
+    resetSearchQueryTag(){
+
+      this.queryTagParams= {
+        pageNum: 1,
+        pageSize: 10,
+        total:0,
+        name:null,
+      };
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.corpId= this.myQwCompanyList[0].dictValue;
+      this.selectTags=[];
+	   this.createTime=null;
+	  this.queryParams.sTime=null;
+	  this.queryParams.eTime=null;
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.loading=true;
+      this.form.corpId=this.queryParams.corpId
+     addExternalContact(this.form).then(response => {
+       this.msgSuccess("同步成功");
+       this.getList();
+     }).finally(()=>{
+       this.loading=false;
+     });
+
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getExternalContact(id).then(response => {
+        this.form = response.data;
+        if(this.form.remarkMobiles!=null){
+          this.remarkMobiles=JSON.parse(this.form.remarkMobiles)
+        }else{
+          this.remarkMobiles=[]
+        }
+
+        this.open = true;
+        this.title = "修改企业微信客户";
+      });
+    },
+
+    handleAppellation(val){
+      this.callOpen.open=true;
+      this.callOpenFrom.stageStatus=val.stageStatus;
+      this.callOpenFrom.id=val.id;
+    },
+
+    /** 绑定客户操作 */
+    handleUpdateCustomer(row){
+       this.bindCustomer.title="绑定客户"
+        this.bindCustomer.open=true;
+        this.form.id=row.id
+        this.form.externalUserId=row.externalUserId
+        this.form.name=row.name
+    },
+
+    handleUpdateUser(row){
+        this.user.title="绑定客户"
+        this.user.open=true;
+        this.userForm.id=row.id;
+    },
+
+    handleUnBindUserId(val){
+
+      this.$confirm(
+        '确认解绑客户:<span style="color: green;">' + val.name + '' +
+        '</span> 的小程序用户?<br><span style="color: red;">【ps:可能会导致客户无法看课】</span>',
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+          dangerouslyUseHTMLString: true // 允许使用 HTML 字符串
+        }
+      ).then(() => {
+        return unBindUserId(val.id);
+      }).then(response => {
+        this.getList();
+        this.msgSuccess("解绑成功");
+      }).finally(res=>{
+        this.getList();
+      })
+    },
+
+    bindCustomerId(row){
+
+      console.log("row",row)
+      // this.qwFormCustomer.customerId=row;
+      this.form.customerId=row;
+      this.form.corpId=this.queryParams.corpId;
+      this.msgWarning("绑定中.....同步信息中.....");
+
+      editbindCustomer(this.form).then(res=>{
+        //清空表单
+        this.reset();
+        this.bindCustomer.open = false;
+        this.msgSuccess("绑定成功");
+        this.getList();
+
+      })
+
+    },
+    //设置一个SOP
+    setCourseSOP(row) {
+
+      // 检查 row.miniUserId 是否为 null
+      if (row.miniUserId === null || row.miniUserId === undefined) {
+        return this.$confirm('当前客户【CRM客户详情】中 未绑定小程序客户,请先绑定', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).catch(error => {
+          this.msgWarning("操作取消:", error);
+        });
+      } else {
+        this.chooseCustomerSOP = row;
+        this.setSop.open = true;
+        this.setSop.type=1;
+      }
+    },
+
+    //选择课程SOP
+    // 用于设置 customerCourseForm 和 customerCourseFormLogs 的共同属性
+    setCommonProperties(form, row) {
+      form.qwUserid = this.chooseCustomerSOP.userId;
+      form.companyUserId = this.chooseCustomerSOP.companyUserId;
+      form.externalUserId = this.chooseCustomerSOP.externalUserId;
+      form.customerId = this.chooseCustomerSOP.customerId;
+      form.miniUserId = this.chooseCustomerSOP.miniUserId;
+      form.businessId = row.businessId;
+    },
+
+    bindCourseSop(row,days) {
+
+      if (this.setSop.type==2){
+        this.setSop.open = false;
+        this.loading=true;
+        this.msgWarning("设定中.....同步信息中.....");
+
+        setCustomerCourseSopList({ids:this.ids,fsCourseSopId:row.id,days:days}).then(res=>{
+
+          let msg=" 批量设置成功数【" + res.successNum + "】,<br>"
+
+          if (res.failCRM.length>0){
+            msg+="失败的客户【" + res.failCRM + "】,原因是未绑定CRM客户。<br>"
+          }
+          if (res.failMiNi.length>0){
+            msg+="失败的客户【" + res.failMiNi + "】,原因是CRM中未绑定小程序客户。<br>"
+          }
+          if (res.failCompany.length>0){
+            msg+="失败的客户【" + res.failCompany + "】,原因是客户没有所属成员。<br>"
+          }
+
+
+          return this.$confirm(msg, "提示", {
+            confirmButtonText: "确定",
+            cancelButtonText: "取消",
+            type: "warning",
+            dangerouslyUseHTMLString: true // 允许使用HTML标签
+          }).catch(error => {
+            this.msgSuccess("操作完成~");
+          });
+
+        }).finally(()=>{
+          this.loading = false;
+          this.getList();
+        })
+      }else if (this.setSop.type==1){
+
+      // 设置 customerCourseFormLogs 的属性
+      this.setCommonProperties(this.customerCourseFormLogs, row);
+
+      // 设置 customerCourseForm 的属性
+      this.setCommonProperties(this.customerCourseForm, row);
+      this.customerCourseForm.sopId = row.id;
+      this.customerCourseForm.sopType = row.sopType;
+      this.customerCourseForm.setting = row.setting;
+      this.customerCourseForm.days = days;
+
+      // 执行异步操作
+      getCustomerCourseSop(this.customerCourseFormLogs)
+        .then(res => {
+          if (res) {
+            return this.$confirm('当前客户已设置过相同课程课节SOP,确定还要再次设置吗?', "警告", {
+              confirmButtonText: "确定",
+              cancelButtonText: "取消",
+              type: "warning"
+            });
+          } else {
+            return Promise.resolve(); // 如果没有设置过,直接执行后续操作
+          }
+        })
+        .then(() => {
+          this.loading = true;
+          this.setSop.open = false;
+          this.msgSuccess("设定中.....同步信息中.....");
+
+          return setCustomerCourseSop(this.customerCourseForm);
+        })
+        .then(() => {
+          this.msgSuccess("设定成功");
+        })
+        .catch(error => {
+          this.msgWarning("操作取消:", error);
+        })
+        .finally(() => {
+          this.loading = false;
+          this.getList();
+        });
+      }
+    },
+    submitCallOpenFrom(){
+
+      this.$refs["callOpenFrom"].validate(valid => {
+        if (valid) {
+
+          if (this.callOpenFrom.id != null && this.callOpenFrom.stageStatus != null) {
+            updateExternalContactCall(this.callOpenFrom).then(res=>{
+              this.$message.success('修改成功');
+              this.callOpen.open=false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            this.form.remarkMobiles=JSON.stringify(this.remarkMobiles)
+            updateExternalContact(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addExternalContact(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 delExternalContact(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+
+	updateTalk(row){
+		const ids = row.id || this.ids;
+		this.$confirm('是否确认批量更改用户信息为非首次交流', "警告", {
+		    confirmButtonText: "确定",
+		    cancelButtonText: "取消",
+		    type: "warning"
+		  }).then(function() {
+		    return editTalk(ids);
+		  }).then(() => {
+		    this.getList();
+		    this.msgSuccess("成功");
+		  }).catch(() => {});
+	},
+    /** 导出按钮操作 */
+    handleExport() {
+      const { qwUserName, ...queryParams } = this.queryParams;
+      this.$confirm('是否确认导出所有企业微信客户数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportExternalContact(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    },
+    handleBatchUpdateNotesFilter() {
+      this.notesOpen.open = true;
+      this.notesOpen.filter = true;
+    },
+    handleBatchUpdateNotes() {
+
+      if (this.ids == null || this.ids == "") {
+        return this.$message('请选择需要添加备注的客户');
+      }
+
+      this.notesOpen.open = true;
+      this.notesOpen.filter = false;
+
+    },
+    notesSubmitForm() {
+
+      if (this.notesOpen.notes == null || this.notesOpen.notes == "") {
+        return this.$message.error("请输入备注内容");
+      }
+
+      // let loadingRock = this.$loading({
+      //   lock: true,
+      //   text: '正在执行中请稍后~~请不要刷新页面!!',
+      //   spinner: 'el-icon-loading',
+      //   background: 'rgba(0, 0, 0, 0.7)'
+      // });
+
+      let obj = JSON.parse(JSON.stringify(this.queryParams))
+      console.log(obj);
+      if(obj.tagIds !== null && obj.tagIds !== undefined && obj.tagIds !== ''){
+        obj.tagIds = obj.tagIds.split(",");
+      }
+      batchUpdateExternalContactNotes({
+        addType: 0,
+        userIds: this.ids,
+        notes: this.notesOpen.notes,
+        type: this.notesOpen.type,
+        nameType: this.notesOpen.nameType,
+        filter: this.notesOpen.filter,
+        param: obj
+      }).then(res => {
+
+        this.resultMessage = res.msg;
+        this.$message.success("正在执行中...");
+        // this.resultDialogVisible = true; // 显示弹窗
+        // this.resultTitle = '批量修改备注结果';
+
+      }).finally(res => {
+        this.getList();
+        // loadingRock.close();
+        this.notesCancel();
+      })
+
+    },
+  }
+};
+
+</script>
+<style scoped>
+/* CSS 样式 */
+.tag-container {
+  display: flex;
+  flex-wrap: wrap; /* 超出宽度时自动换行 */
+  gap: 8px; /* 设置标签之间的间距 */
+}
+.name-background {
+  display: inline-block;
+  background-color: #abece6; /* 背景颜色 */
+  padding: 4px 8px; /* 调整内边距,让背景包裹文字 */
+  border-radius: 4px; /* 可选:设置圆角 */
+}
+/* CSS 样式 */
+.tag-container {
+  display: flex;
+  flex-wrap: wrap; /* 超出宽度时自动换行 */
+  gap: 8px; /* 设置标签之间的间距 */
+}
+.name-background {
+  display: inline-block;
+  background-color: #abece6; /* 背景颜色 */
+  padding: 4px 8px; /* 调整内边距,让背景包裹文字 */
+  border-radius: 4px; /* 可选:设置圆角 */
+}
+.tag-box {
+  padding: 8px 12px;
+  border: 1px solid #989797;
+  border-radius: 4px;
+  cursor: pointer;
+  display: inline-block;
+}
+
+.tag-selected {
+  background-color: #00bc98;
+  color: #fff;
+  border-color: #00bc98;
+}
+
+.el-tag + .el-tag {
+  margin-left: 10px;
+}
+
+
+
+.button-new-tag {
+      margin-left: 10px;
+      height: 32px;
+      line-height: 30px;
+      padding-top: 0;
+      padding-bottom: 0;
+    }
+    .input-new-tag {
+      width: 90px;
+      margin-left: 10px;
+      vertical-align: bottom;
+    }
+
+
+.suggestion-box {
+  position: absolute;
+  z-index: 999;
+  background: #fff;
+  border: 1px solid #ddd;
+  max-height: 200px;
+  overflow-y: auto;
+  width: 100%;
+}
+
+.suggestion-item {
+  padding: 10px;
+  cursor: pointer;
+}
+.suggestion-item:hover {
+  background-color: #f5f7fa;
+}
+/* 新增的滚动容器样式(不影响原有样式) */
+.scroll-wrapper {
+  max-height: 130px; /* 大约三行的高度 */
+  overflow-y: auto;  /* 垂直滚动 */
+  padding-right: 5px; /* 为滚动条留出空间 */
+}
+
+/* 美化滚动条(可选) */
+.scroll-wrapper::-webkit-scrollbar {
+  width: 6px;
+}
+.scroll-wrapper::-webkit-scrollbar-thumb {
+  background: rgba(0, 0, 0, 0.2);
+  border-radius: 3px;
+}
+
+.tag-container {
+  max-height: 200px;
+  overflow-y: auto;
+  padding: 1px;
+  border: 1px solid #ebeef5;
+  border-radius: 1px;
+  background-color: #fafafa;
+}
+.tag-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+.scroll-hint {
+  text-align: center;
+  color: #909399;
+  font-size: 12px;
+  padding: 1px 0;
+}
+.container {
+  max-width: 800px;
+  margin: 0 auto;
+  padding: 10px;
+}
+.title {
+  text-align: center;
+  color: #303133;
+  margin-bottom: 30px;
+}
+.demo-table {
+  width: 100%;
+  margin-bottom: 30px;
+}
+.instructions {
+  background-color: #f5f7fa;
+  padding: 15px;
+  border-radius: 1px;
+  margin-bottom: 20px;
+}
+</style>

+ 259 - 0
src/views/fastGpt/fastGptPushTokenTotal/index.vue

@@ -0,0 +1,259 @@
+<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" >
+        <el-select v-model="queryParams.companyId" placeholder="请选择所属公司" filterable size="small">
+          <el-option v-for="(option, index) in companyList" :key="index" :value="option.dictValue" :label="option.dictLabel"></el-option>
+        </el-select>
+      </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="fastGptPushTokenTotalList" :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="companyName" />
+      <el-table-column label="token消耗" align="center" prop="count" />
+      <el-table-column label="时间" align="center" prop="statTime" />
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { listFastgptEventLogTotal, exportFastgptEventLogTotal, getFastGptRoleAppKeyList} from "@/api/fastGpt/fastgptEventLogTotal";
+import { getFastGptPushTokenTotal} from "@/api/fastGpt/fastgptPushTokenTotal";
+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'
+import {allList} from "@/api/company/company";
+
+
+
+export default {
+  name: "FastgptEventLogTotal",
+  components: {SelectTree,TreeSelect},
+  data() {
+    return {
+      createTime:null,
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      selectedCompanyList: [],
+      companyList:[],
+      deptList: [],
+      companyUserList: [],
+      selectedAppKey: null,
+      selectedAppKeyLabel: '',
+      appKeyOptions: [],
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // token统计表格数据
+      fastGptPushTokenTotalList: [],
+      // 弹出层标题
+      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.getAllCompany();
+
+  },
+
+  methods: {
+    getAllCompany() {
+      allList().then(response => {
+        this.companyList = response.rows;
+        this.companyList.push({dictLabel: "无",
+          dictValue: "0"})
+      });
+    },
+    /** 查询ai事件埋点统计列表 */
+    getList() {
+      this.loading = true;
+
+      getFastGptPushTokenTotal(this.queryParams).then(response => {
+        console.log(response)
+        this.fastGptPushTokenTotalList = response.rows;
+        this.total = response.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();
+    },
+    // 表单重置
+    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>

+ 20 - 4
src/views/fastGpt/fastgptEventLogTotal/index.vue

@@ -64,7 +64,7 @@
       <el-table-column label="角色名称" align="center" prop="roleName" />
       <el-table-column label="时间" align="center" prop="statTime" />
       <el-table-column
-        v-for="dict in typeOptions"
+        v-for="dict in sortedTypeOptions"
         :key="dict.dictValue"
         :label="dict.dictLabel"
         align="center">
@@ -72,9 +72,9 @@
           <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>
+          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>
@@ -179,6 +179,22 @@ export default {
     });
 
   },
+  // 在 data() 中添加一个新的计算属性或方法来处理排序后的 typeOptions
+  computed: {
+    sortedTypeOptions() {
+      if (!this.typeOptions || this.typeOptions.length === 0) return [];
+
+      // 将 dictValue 为 '11' 的选项过滤出来并放到最后
+      const normalOptions = this.typeOptions.filter(option => option.dictValue !== '11');
+      const lastOption = this.typeOptions.find(option => option.dictValue === '11');
+
+      if (lastOption) {
+        return [...normalOptions, lastOption];
+      }
+      return normalOptions;
+    }
+  },
+
   methods: {
     /** 查询ai事件埋点统计列表 */
     getList() {

+ 22 - 2
src/views/his/adv/index.vue

@@ -158,7 +158,7 @@
     />
 
     <!-- 添加或修改广告对话框 -->
-    <el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
+    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
       <el-form ref="form" :model="form" :rules="rules" label-width="90px">
         <el-form-item label="标题名称" prop="advTitle">
           <el-input v-model="form.advTitle" placeholder="请输入广告标题" />
@@ -202,6 +202,16 @@
        <el-form-item label="文章内容" v-show="form.showType==3">
          <editor ref="myeditor" @on-text-change="updateText" />
        </el-form-item>
+        <el-form-item label="活动" prop="activeId" v-show="form.showType === '5'">
+          <el-select v-model="form.activeId"  placeholder="请选择活动" >
+            <el-option
+              v-for="item in activeOptions"
+              :key="item.dictValue"
+              :label="item.dictLabel"
+              :value="item.dictValue"
+            ></el-option>
+          </el-select>
+        </el-form-item>
         <el-form-item label="状态">
           <el-radio-group v-model="form.status">
              <el-radio :label="item.dictValue" v-for="item in statusOptions" >{{item.dictLabel}}</el-radio>
@@ -220,6 +230,7 @@
 <script>
 import { listAdv, getAdv, delAdv, addAdv, updateAdv, exportAdv } from "@/api/his/adv";
 import Editor from '@/components/Editor/wang';
+import { getPromotionalActiveOption } from '@/api/his/promotionalActive'
 export default {
   name: "Adv",
   components: { Editor },
@@ -230,6 +241,7 @@ export default {
       showOptions: [],
       devOptions: [],
       statusOptions: [],
+      activeOptions: [],
       // 遮罩层
       loading: true,
       // 导出遮罩层
@@ -296,8 +308,15 @@ export default {
     this.getDicts("sys_adv_type").then(response => {
       this.devOptions = response.data;
     });
+    this.getActiveOption()
   },
   methods: {
+    getActiveOption() {
+      getPromotionalActiveOption().then(response => {
+        console.log(response)
+        this.activeOptions = response.list;
+      });
+    },
     updateText(text){
         this.form.content=text
       },
@@ -345,7 +364,8 @@ export default {
         status: "0",
         sort: null,
         advType: null,
-        showType: null
+        showType: null,
+        activeId: null
       };
       this.resetForm("form");
     },

+ 525 - 0
src/views/his/answer/index.vue

@@ -0,0 +1,525 @@
+<template>
+  <div class="app-container">
+    <!-- <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <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:answer: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:answer: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:answer: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:answer:export']"
+        >导出</el-button>
+      </el-col> -->
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="answerList" @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="questionName" />
+      <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:answer:edit']">修改</el-button>
+          <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
+            v-hasPermi="['his:answer:remove']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
+      @pagination="getList" />
+
+    <!-- 添加或修改问答对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="1000px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="110px">
+        <el-form-item label="问答名称" prop="questionName">
+          <el-input v-model="form.questionName" placeholder="请输入内容" />
+        </el-form-item>
+        <div v-if="form.answers && form.answers.length == 0" class="empty-state">
+          <div class="empty-state-icon">
+            <i class="el-icon-document"></i>
+          </div>
+          <p>暂无问题,请点击下方按钮添加</p>
+        </div>
+
+        <div v-for="(answer, index) in form.answers" :key="index" class="answer-section">
+          <div class="answer-section-header">
+            <span class="answer-section-title">
+              <span class="answer-section-number">{{ index + 1 }}</span>
+              问题 {{ index + 1 }}
+            </span>
+            <div>
+              <el-button 
+                v-if="index !== 0" 
+                type="danger" 
+                size="mini" 
+                icon="el-icon-delete"
+                @click="delItem(answer, index)">
+                删除问题
+              </el-button>
+            </div>
+          </div>
+          
+          <el-row :gutter="15">
+            <el-col :span="16">
+              <el-form-item label="问题标题" :prop="`answers[${index}].title`" :rules="rules.title">
+                <el-input v-model="answer.title" placeholder="请输入问题标题"></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          
+          <el-form-item label="选项配置">
+            <div v-for="(option, optionIndex) in answer.options" :key="optionIndex" class="option-item">
+              <div class="option-input">
+                <el-input 
+                  v-model="answer.options[optionIndex].name" 
+                  :placeholder="`选项 ${optionIndex + 1}`">
+                </el-input>
+              </div>
+              <div class="option-actions">
+                <el-button 
+                  v-if="optionIndex + 1 === answer.options.length"
+                  type="primary" 
+                  size="mini" 
+                  icon="el-icon-plus"
+                  circle
+                  @click="addOption(index, optionIndex)">
+                </el-button>
+                <el-button 
+                  v-if="optionIndex !== 0"
+                  type="danger" 
+                  size="mini" 
+                  icon="el-icon-minus"
+                  circle
+                  @click="delOption(answer.options, optionIndex)">
+                </el-button>
+              </div>
+            </div>
+            <div class="option-tip">
+              <span>提示:至少保留一个选项,点击 + 按钮添加更多选项</span>
+            </div>
+          </el-form-item>
+        </div>
+        
+        <div class="add-section-btn">
+          <el-button 
+            type="primary" 
+            icon="el-icon-plus"
+            @click="addItem(form.answers.length)">
+            添加问题
+          </el-button>
+        </div>
+        
+        <!-- <div v-for="(i, index) in form.answers" :key="index">
+          <el-row>
+            <el-col :span="8">
+              <el-form-item label="标题" prop="title">
+                <el-input v-model="i.title"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-button style="margin: 5px;" v-if="index + 1 == form.answers.length"
+                @click="addItem(form.answers.length)" type="primary" size="mini">+</el-button>
+              <el-button style="margin: 5px;" v-if="index !== 0" type="danger" size="mini"
+                @click="delItem(i, index)">-</el-button>
+            </el-col>
+
+          </el-row>
+        </div> -->
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listAnswer, getAnswer, delAnswer, addAnswer, updateAnswer, exportAnswer } from "@/api/his/answer";
+
+export default {
+  name: "Answer",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 问答表格数据
+      answerList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        jsonInfo: null,
+      },
+      form: {
+            questionName: '',
+            answers: [
+              {
+                title: '',
+                options: [{name:'',value:0}]
+              }
+            ]
+          },
+          rules: {
+            questionName: [
+              { required: true, message: '请输入问答名称', trigger: 'blur' }
+            ],
+            title: [
+              { required: true, message: '请输入问题标题', trigger: 'blur' }
+            ]
+          }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    addItem(length) {
+          this.form.answers.push({
+            title: '',
+            options: [{name:'',value:0}]
+          })
+        },
+        delItem(item, index) {
+          if (this.form.answers.length > 1) {
+            this.$confirm('确定要删除这个问题吗?', '提示', {
+              confirmButtonText: '确定',
+              cancelButtonText: '取消',
+              type: 'warning'
+            }).then(() => {
+              this.form.answers.splice(index, 1)
+              this.$message({
+                type: 'success',
+                message: '删除成功!'
+              });
+            }).catch(() => {
+              this.$message({
+                type: 'info',
+                message: '已取消删除'
+              });          
+            });
+          } else {
+            this.$message.warning('至少保留一个问题')
+          }
+        },
+        addOption(answerIndex, optionIndex) {
+          this.form.answers[answerIndex].options.push({name:'',value:optionIndex + 1})
+        },
+        delOption(options, index) {
+          if (options.length > 1) {
+            this.$confirm('确定要删除这个选项吗?', '提示', {
+              confirmButtonText: '确定',
+              cancelButtonText: '取消',
+              type: 'warning'
+            }).then(() => {
+              options.splice(index, 1)
+              this.$message({
+                type: 'success',
+                message: '删除成功!'
+              });
+            }).catch(() => {
+              this.$message({
+                type: 'info',
+                message: '已取消删除'
+              });          
+            });
+          } else {
+            this.$message.warning('至少保留一个选项')
+          }
+        },
+    // addItem(length) {
+    //   this.form.answers.push({
+    //     title: '',
+    //     options: [],
+    //   })
+    // },
+    // delItem(item, index) {
+    //   this.form.answers.splice(index, 1)
+    // },
+    // addItem1(length,n) {
+    //   this.form.answers[n].options.push('')
+    // },
+    // delItem2(item, index) {
+    //   this.form.answers.splice(index, 1)
+    // },
+    /** 查询问答列表 */
+    getList() {
+      this.loading = true;
+      listAnswer(this.queryParams).then(response => {
+        this.answerList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        jsonInfo: 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 = "添加问答";
+      if (this.form.answers == null) {
+        this.form = {
+          answers: [{
+            title: '',
+            options: [{name:'',value:0}]
+          }
+
+          ]
+        }
+      }
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getAnswer(id).then(response => {
+        this.form = response.data;
+        if (this.form.answers == null) {
+          this.form = {
+            answers: [{
+              title: '',
+              options: [{name:'',value:0}]
+            }
+
+            ]
+          }
+        }
+        this.form.questionName = response.data.questionName;
+        this.form.id = response.data.id;
+        this.open = true;
+        this.title = "修改问答";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.answers) {
+            this.form.jsonInfo = JSON.stringify(this.form.answers);
+          }
+          if (this.form.id != null) {
+            updateAnswer(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addAnswer(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 delAnswer(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => { });
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有问答数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportAnswer(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => { });
+    }
+  }
+};
+</script>
+<style>
+    .form-container {
+      max-width: 900px;
+      margin: 30px auto;
+      padding: 25px;
+      background: #fff;
+      border-radius: 10px;
+      box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
+    }
+    .form-header {
+      margin-bottom: 25px;
+      padding-bottom: 15px;
+      border-bottom: 1px solid #ebeef5;
+    }
+    .form-header h2 {
+      margin: 0;
+      color: #303133;
+      font-size: 22px;
+    }
+    .form-header p {
+      margin: 8px 0 0;
+      color: #606266;
+      font-size: 14px;
+    }
+    .answer-section {
+      margin: 25px 0;
+      padding: 20px;
+      border: 1px solid #e6e9f0;
+      border-radius: 8px;
+      background-color: #f9fafc;
+      transition: all 0.3s ease;
+    }
+    .answer-section:hover {
+      border-color: #c0c4cc;
+      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+    }
+    .answer-section-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 20px;
+      padding-bottom: 12px;
+      border-bottom: 1px dashed #dcdfe6;
+    }
+    .answer-section-title {
+      font-weight: 600;
+      color: #303133;
+      font-size: 16px;
+    }
+    .answer-section-number {
+      display: inline-flex;
+      align-items: center;
+      justify-content: center;
+      width: 24px;
+      height: 24px;
+      background: #409EFF;
+      color: white;
+      border-radius: 50%;
+      font-size: 12px;
+      margin-right: 8px;
+    }
+    .option-item {
+      display: flex;
+      align-items: center;
+      margin-bottom: 12px;
+    }
+    .option-input {
+      flex: 1;
+    }
+    .option-actions {
+      margin-left: 10px;
+      display: flex;
+      gap: 5px;
+    }
+    .section-actions {
+      display: flex;
+      justify-content: flex-end;
+      margin-top: 20px;
+    }
+    .add-section-btn {
+      margin-top: 15px;
+      text-align: center;
+    }
+    .el-form-item {
+      margin-bottom: 20px;
+    }
+    .el-col {
+      padding-right: 15px;
+    }
+    .el-col:last-child {
+      padding-right: 0;
+    }
+    .option-tip {
+      margin-top: 10px;
+      color: #909399;
+      font-size: 12px;
+    }
+    .empty-state {
+      text-align: center;
+      padding: 30px;
+      color: #909399;
+    }
+    .empty-state-icon {
+      font-size: 48px;
+      margin-bottom: 15px;
+      color: #c0c4cc;
+    }
+  </style>
+

+ 180 - 17
src/views/his/company/index.vue

@@ -118,9 +118,9 @@
       </el-table-column>
       <el-table-column label="管理员账号" align="center" prop="userName"/>
       <el-table-column label="限制用户数量" align="center" prop="limitUserCount"/>
-      <el-table-column label="限制pad数量" align="center" prop="maxPadNum" :formatter="padNumFormatter"/>
-      <el-table-column label="占用pad数量" align="center" prop="usedNum"/>
-      <el-table-column label="所属部门" align="center" prop="deptId">
+      <el-table-column label="限制pad数量" align="center" prop="maxPadNum" :formatter="padNumFormatter" v-if="this.$store.state.user.medicalMallConfig.resource"/>
+      <el-table-column label="占用pad数量" align="center" prop="usedNum" v-if="this.$store.state.user.medicalMallConfig.resource"/>
+      <el-table-column label="所属部门" align="center" prop="deptId" v-if="this.$store.state.user.medicalMallConfig.resource">
         <template slot-scope="scope">
           <el-tag prop="deptId" v-for="(item, index) in deptOptions" :key="'deptId'+index"
                   v-if="scope.row.deptId===item.deptId"
@@ -134,7 +134,7 @@
       <el-table-column label="创建时间" align="center" prop="createTime" width="180"/>
       <el-table-column label="更新时间" align="center" prop="updateTime" width="180"/>
       <!--      <el-table-column label="主机重启时间" align="center" prop="restartTime" width="180" />-->
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="200px">
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="220px">
         <template slot-scope="scope">
           <el-button
             size="mini"
@@ -176,7 +176,13 @@
             v-hasPermi="['his:company:deduct']"
           >扣款
           </el-button>
-
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleRevenue(scope.row)"
+            v-hasPermi="['company:company:revenue']"
+          >分账配置</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -212,7 +218,7 @@
           </el-select>
         </el-form-item>
         <!-- 所属部门 -->
-        <el-form-item label="所属部门" prop="deptId">
+        <el-form-item label="所属部门" prop="deptId" v-if="this.$store.state.user.medicalMallConfig.resource">
           <el-select
             v-model="form.deptId"
             placeholder="请选择"
@@ -239,7 +245,7 @@
         <el-form-item label="员工数量" prop="limitUserCount">
           <el-input-number v-model="form.limitUserCount" :min="1" :max="10000"></el-input-number>
         </el-form-item>
-        <el-form-item label="pad数量" prop="maxPadNum">
+        <el-form-item label="pad数量" prop="maxPadNum" v-if="this.$store.state.user.medicalMallConfig.resource">
           <el-input-number v-model="form.maxPadNum" :min="-1" :max="10000"></el-input-number>
           <span class="pad-tips">
             注:-1表示不做限制
@@ -419,9 +425,6 @@
             />
           </el-select>
         </el-form-item>
-        <el-form-item label="PAD分配数量" prop="maxPadNum">
-          <el-input-number v-model="form.maxPadNum" placeholder="默认-1不限制"/>
-        </el-form-item>
         <el-form-item label="备注" prop="remark">
           <el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入备注"/>
         </el-form-item>
@@ -476,6 +479,99 @@
         <el-button @click="deduct.open=false">取 消</el-button>
       </div>
     </el-dialog>
+
+    <el-dialog :title="revenue.title" :visible.sync="revenue.open" width="800px" append-to-body>
+      <el-form ref="revenueForm"  :model="revenueForm" label-width="150px">
+        <el-form-item label="公司">
+          <el-input v-model="revenueForm.companyName" disabled/>
+        </el-form-item>
+       
+        <el-form-item label="开启分账">
+          <el-switch
+            v-model="revenueForm.divFlag"
+            active-color="#13ce66"
+            inactive-color="#ff4949"
+            active-value="1"
+            inactive-value="0"
+          >
+          </el-switch>
+        </el-form-item>
+        
+        <el-form-item label="分账模式" v-if="revenueForm.divFlag == 1">
+          <el-radio v-model="revenueForm.delayAcctFlag" label="N">实时分账</el-radio>
+          <el-radio v-model="revenueForm.delayAcctFlag" label="Y">延时分账</el-radio>
+        </el-form-item>
+        <el-form-item label="是否使用百分比分账">
+          <el-switch
+            v-model="revenueForm.percentageFlag"
+            active-color="#13ce66"
+            inactive-color="#ff4949"
+            active-value="Y"
+            inactive-value="N"
+          >
+          </el-switch>
+        </el-form-item>
+        <el-form-item label="是否净值分账" v-if="revenueForm.percentageFlag == 'Y'">
+          <el-switch
+            v-model="revenueForm.iscCleanSplit"
+            active-color="#13ce66"
+            inactive-color="#ff4949"
+            active-value="Y"
+            inactive-value="N"
+          >
+          </el-switch>
+        </el-form-item>
+        <div v-if="revenueForm.divFlag == 1">
+            <el-form-item label="分账接收方配置">
+              <el-tooltip content="批量设置erp账户" placement="top">
+                <el-button type="primary" icon="el-icon-plus" @click="addAcctInfo" style="margin-bottom: 5px;">
+                  添加新接收方
+                </el-button>
+              </el-tooltip>
+              
+            </el-form-item>
+
+            <div v-for="(account, index) in revenueForm.acctInfos" :key="index"
+                 style="border: 1px solid #dcdfe6; padding: 20px; margin-bottom: 20px; border-radius: 4px;"
+            >
+              <div style="display: flex; justify-content: between; align-items: center; margin-bottom: 15px;">
+                <div style="margin: 0; color: #409eff;">账户 {{ index + 1 }}</div>
+                <el-button
+                  type="danger"
+                  icon="el-icon-delete"
+                  size="mini"
+                  @click="removeAcctInfo(index)"
+                  v-if="revenueForm.acctInfos.length > 0"
+                >
+                  删除账户
+                </el-button>
+              </div>
+
+              <el-form-item label="分账接收方ID" :prop="`acctInfos.${index}.huifuId`">
+                <el-input v-model="account.huifuId"   placeholder="斗拱开户时生成;示例值:6666000123120001"></el-input>
+              </el-form-item>
+              <el-form-item label="账户号" :prop="`acctInfos.${index}.acctId`" >
+                <el-input v-model="account.acctId"  placeholder="可指定账户号,仅支持基本户、现金户,不填默认为基本户;示例值:F00598600"></el-input>
+              </el-form-item>
+              
+              <el-form-item label="分账百分比%" v-if="revenueForm.percentageFlag == 'Y'" :prop="`acctInfos.${index}.percentageDiv`"  >
+                <el-input-number v-model="account.percentageDiv" :precision="2" :step="0.1" :min="0" :max="100" placeholder="示例值:23.50,表示23.50%。acct_infos中全部分账百分比之和必须为100.00%。"></el-input-number>
+              </el-form-item>
+              <el-form-item label="分账金额" v-if="revenueForm.percentageFlag == 'N'" :prop="`acctInfos.${index}.divAmt`"  >
+                <el-input-number v-model="account.divAmt" :precision="2" :step="1" :min="0.01" placeholder="单位元,需保留小数点后两位,示例值:1.00 ,最低传入0.01"></el-input-number>
+              </el-form-item>
+              
+            </div>
+          </div>
+
+       
+       
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitRevenueForm">确 定</el-button>
+        <el-button @click="revenue.open=false">取 消</el-button>
+      </div>
+    </el-dialog>
   </div>
 </template>
 
@@ -489,7 +585,9 @@ import {
   recharge,
   deduct,
   exportCompany,
-  resetPwd
+  resetPwd,
+  getDivConfig,
+  setDiv
 } from '@/api/his/company'
 import { getFollowDoctorList } from '@/api/his/doctor'
 import { docList } from '@/api/his/doctor'
@@ -504,6 +602,14 @@ export default {
   name: 'Company',
   data() {
     return {
+      //分账参数
+      revenue:{
+          open: false,
+          title: '分账配置'
+      },
+      revenueForm:{
+        acctInfos: [] 
+      },
       // 表单参数
       deductForm: {
         money: 0
@@ -673,6 +779,50 @@ export default {
     })
   },
   methods: {
+    // 添加分账账户
+    addAcctInfo() {
+      console.log("-----------------",this.revenueForm)
+      this.revenueForm.acctInfos.push({
+        huifuId: '',
+        acctId: '',
+        percentageDiv: null,
+        divAmt: null
+      })
+    },
+    // 删除接收方账户
+    removeAcctInfo(index) {
+      this.$confirm('确认删除该接收方账户?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.revenueForm.acctInfos.splice(index, 1)
+        this.$message.success('删除成功')
+      }).catch(() => {
+      })
+    },
+    handleRevenue(row){
+      const companyId = row.companyId
+      //查询配置
+      this.revenueForm.isAdd = 1
+      getDivConfig(companyId).then(response => {
+        if(response.data){
+          this.revenueForm = response.data
+          if(response.data.acctInfos == null){
+            this.revenueForm.acctInfos = []
+          }
+          if(response.data.divFlag){
+            this.revenueForm.divFlag = String(response.data.divFlag)
+          }
+        }
+      })
+      this.revenueForm.companyId = companyId
+      this.revenueForm.companyName = row.companyName
+      if(row.divFlag){
+        this.revenueForm.divFlag == "0"
+      }
+      this.revenue.open = true
+    },
     handleRecharge(row) {
       const companyId = row.companyId
       this.rechargeForm.companyId = row.companyId
@@ -703,6 +853,20 @@ export default {
         }
       })
     },
+    submitRevenueForm(){
+      var param = this.revenueForm;
+      console.log("--------------",param)
+      if(param.companyId && param.divFlag){
+        setDiv(param).then(response => {
+            if (response.code === 200) {
+              this.msgSuccess(response.msg)
+              this.revenue.open = false
+              this.getList()
+            }
+          })
+        console.log("--------------",param)
+      }
+    },
     /** 提交按钮 */
     submitDeductForm() {
       this.$refs['deductForm'].validate(valid => {
@@ -797,17 +961,17 @@ export default {
     /** 新增按钮操作 */
     handleAdd() {
       this.reset()
-      this.getAppList()
+      this.getAppList(null)
       this.open = true
       this.doctorIds = []
       this.title = '添加公司'
     },
     /** 修改按钮操作 */
     handleUpdate(row) {
+      const companyId = row.companyId || this.ids
       this.reset()
-      this.getAppList()
+      this.getAppList(companyId)
       this.doctorIds = []
-      const companyId = row.companyId || this.ids
       getCompany(companyId).then(response => {
         this.form = response.data
         this.form.usedNum = row.usedNum
@@ -830,12 +994,11 @@ export default {
         }
       })
     },
-    getAppList() {
+    getAppList(companyId) {
       this.maAppList = []
       this.miniAppList = []
       this.customAppList = []
-      const key = 'courseMa.config'
-      listAll(key).then(response => {
+      listAll().then(response => {
         const { code, data } = response
         if (code === 200) {
           if (data) {

+ 130 - 557
src/views/his/complaint/index.vue

@@ -10,6 +10,15 @@
           @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="phone">
         <el-input
           v-model="queryParams.phone"
@@ -19,6 +28,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
+      <!-- 添加处理状态筛选 -->
       <el-form-item label="处理状态" prop="isHandle">
         <el-select
           v-model="queryParams.isHandle"
@@ -31,7 +41,7 @@
         </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-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>
@@ -40,6 +50,38 @@
     </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:complaint: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:complaint: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:complaint:remove']"
+        >删除</el-button>
+      </el-col> -->
       <el-col :span="1.5">
         <el-button
           type="warning"
@@ -57,53 +99,21 @@
     <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="userName" />
+      <!-- <el-table-column label="联系方式" align="center" prop="phone" /> -->
       <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"
-      >
+      <!-- 修改处理状态列显示 -->
+      <el-table-column label="是否处理" align="center" prop="isHandle">
         <template slot-scope="scope">
           <el-tag
-            :type="(scope.row.isHandleStore == 1)? 'success' : 'warning'"
+            :type="scope.row.isHandle == 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" prop="remarks" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button
@@ -113,6 +123,13 @@
             v-hasPermi="['his:complaint:edit']"
             @click="handleUpdate(scope.row)"
           >投诉详情</el-button>
+          <!-- <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['his:complaint:edit']"
+          >修改</el-button> -->
           <el-button
             size="mini"
             type="text"
@@ -133,238 +150,60 @@
     />
 
     <!-- 修改用户投诉对话框 -->
-    <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>
+    <el-dialog :title="title" :visible.sync="open" width="700px" 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="投诉内容" 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.urls && form.urls!=''">
+          <div v-for="(url, index) in imageUrls(form.urls)" :key="index" class="image-container">
+            <el-image :src="url" :preview-src-list="[url]" style="width: 100px; height: 100px;"></el-image>
           </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-item label="交易截图" v-if="form.tradeImage && form.tradeImage!=''">
+          <!-- <ImageUpload v-model="form.tradeImage" type="image" :num="10" :width="150" :height="150" /> -->
+          <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="account" v-if="form.account && form.account!=''">
+          <el-input v-model="form.account"  :disabled="true"/>
+        </el-form-item>
+        <!-- 修改处理状态为下拉选择 -->
+        <el-form-item label="是否处理" prop="isHandle">
+          <el-select v-model="form.isHandle" placeholder="请选择处理状态">
+            <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" />
         </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>
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</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';
+import { listComplaint, getComplaint, delComplaint, addComplaint, updateComplaint, exportComplaint } from "@/api/his/complaint";
+
 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,
@@ -386,14 +225,12 @@ export default {
       title: "",
       // 是否显示弹出层
       open: false,
-      // 当前激活的标签页
-      activeTab: 'complaint',
       // 查询参数
       queryParams: {
         pageNum: 1,
         pageSize: 10,
         userId: null,
-        userName: null,
+        userName: null, // 添加用户名查询参数
         templateId: null,
         content: null,
         phone: null,
@@ -411,92 +248,43 @@ export default {
         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(",");
     },
+    /**
+     * 格式化处理状态显示
+     * @param {Number} status - 处理状态 0:未处理 1:已处理
+     * @returns {String} - 格式化后的状态文本
+     */
     formatHandleStatus(status) {
       return status == 1 ? '已处理' : '未处理';
     },
+
     /** 查询用户投诉列表 */
     getList() {
       this.loading = true;
+      console.log(this.queryParams);
       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 = {
@@ -508,71 +296,54 @@ export default {
         urls: null,
         account: null,
         createTime: null,
-        isHandle: 0,
+        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 => {
+      const id = row.id || this.ids
+      getComplaint(id).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 => {
@@ -593,6 +364,7 @@ export default {
         }
       });
     },
+    
     /** 删除按钮操作 */
     handleDelete(row) {
       const ids = row.id || this.ids;
@@ -607,6 +379,7 @@ export default {
           this.msgSuccess("删除成功");
         }).catch(() => {});
     },
+    
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
@@ -623,216 +396,16 @@ export default {
         }).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);
+        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;
         }
-      });
-    },
-    // 编辑回复
-    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>
+</script>

+ 475 - 0
src/views/his/complaint/template.vue

@@ -0,0 +1,475 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      
+      <el-form-item label="投诉分类" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入投诉分类"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+     
+      <el-form-item>
+        <el-button type="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:template:add']"
+        >新增</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:template:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table
+      height="500" 
+      border
+      v-loading="loading"
+      :data="templateList"
+      row-key="id"
+      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+    >
+      <el-table-column label="ID" align="left" prop="id" />
+      <el-table-column label="投诉分类" align="left" prop="name" />
+      <el-table-column label="排序" sortable align="center" prop="sort" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            v-if="isLeafNode(scope.row)"
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleDesc(scope.row)"
+            v-hasPermi="['his:template:edit']"
+          >填写字段</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['his:template:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['his:template:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <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="parentId">
+          <treeselect 
+            v-model="form.parentId" 
+            :options="categoryOptions" 
+            :show-count="true" 
+            :normalizer="normalizer" 
+            :disable-branch-nodes="false"
+            :searchable="true"
+            :clearable="true"
+            placeholder="请选择上级分类" 
+          />
+        </el-form-item>
+        <el-form-item label="投诉分类" prop="name">
+          <el-input v-model="form.name" placeholder="请输入标签名称" />
+        </el-form-item>
+        <el-form-item label="排序" prop="sort">
+          <el-input-number v-model="form.sort" placeholder="请输入排序" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog title="选择填写字段" :visible.sync="descOpen" width="600px" append-to-body>
+      <!-- 添加表头说明 -->
+      <div class="field-header">
+        <div class="field-name-header">字段名称</div>
+        <div class="field-required-header">是否必填</div>
+      </div>
+      
+      <el-checkbox-group v-model="descForm">
+        <div v-for="(item, index) in fields" :key="index" class="field-item">
+          <div class="field-checkbox-wrapper">
+            <el-checkbox :label="item.label" name="desc" v-model="item.checked"></el-checkbox>
+          </div>
+          <div class="field-switch-wrapper">
+            <el-switch
+              v-model="item.isRequire"
+              active-value="1"
+              inactive-value="0"
+              :disabled="!item.checked"
+              class="require-switch"
+            ></el-switch>
+          </div>
+        </div>
+      </el-checkbox-group>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitDescForm">确 定</el-button>
+        <el-button @click="descCancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { treeListTemplate, listTemplate, getTemplate, delTemplate, addTemplate, updateTemplate, exportTemplate } from "@/api/his/complaint";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "Template",
+  components: {
+    Treeselect
+  },
+  data() {
+    return {
+      descId: null,
+      fields: [
+        { label: "详细内容", checked: false, isRequire: 0, desc: "content",type:"文本框" },
+        { label: "联系方式", checked: false, isRequire: 0, desc: "phone",type:"文本框"},
+        { label: "上传图片", checked: false, isRequire: 0, desc: "urls",type:"图片" },
+        { label: "交易截图", checked: false, isRequire: 0, desc: "tradeImage",type:"图片" },
+        { label: "被投诉人账号信息", checked: false, isRequire: 0, desc: "account",type:"文本框" },
+      ],
+      descOpen: false,
+      categoryOptions: [],
+      loading: true,
+      exportLoading: false,
+      ids: [],
+      single: true,
+      multiple: true,
+      showSearch: true,
+      total: 0,
+      templateList: [],
+      title: "",
+      open: false,
+      queryParams: {
+        name: null,
+        isDel: null
+      },
+      form: {},
+      rules: {
+        parentId: [
+          { required: true, message: "上级编码不能为空", trigger: "blur" }
+        ],
+        sort: [
+          { required: true, message: "同级下排序不能为空", trigger: "blur" }
+        ],
+        name: [
+          { required: true, message: "投诉分类不能为空", trigger: "blur" }
+        ],
+      }
+    };
+  },
+  computed: {
+    descForm: {
+      get() {
+        return this.fields.filter(item => item.checked).map(item => item.label);
+      },
+      set(value) {
+        this.fields.forEach(item => {
+          item.checked = value.includes(item.label);
+        });
+      },
+    },
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /**
+     * 判断是否为叶子节点(最后一级)
+     */
+    isLeafNode(row) {
+      return !row.children || row.children.length === 0;
+    },
+
+    submitDescForm() {
+      const result = this.fields
+        .filter(item => item.checked)
+        .map(item => ({
+          name: item.label,
+          isRequire: item.isRequire,
+          desc: item.desc,
+          type: item.type,
+        }));
+      console.log("提交的数据:", result);
+      const param = { id: this.descId, description: JSON.stringify(result) }
+      updateTemplate(param).then(response => {
+        this.msgSuccess("修改成功");
+        this.descOpen = false;
+        this.getList();
+      });
+    },
+    
+    /** 转换标签数据结构 */
+    normalizer(node) {
+      if (node.children && !node.children.length) {
+        delete node.children;
+      }
+      return {
+        id: node.id,
+        label: node.name,
+        children: node.children
+      };
+    },
+    
+    /** 查询部门下拉树结构 */
+    getTreeselect() {
+      treeListTemplate().then(response => {
+        const rootOption = { id: 0, name: '根目录', children: response.data || [] };
+        this.categoryOptions = [rootOption];
+      });
+    },
+    
+    /** 查询投诉模板列表 */
+    getList() {
+      this.loading = true;
+      treeListTemplate(this.queryParams).then(response => {
+        this.templateList = response.data;
+        this.total = response.data.length;
+        this.loading = false;
+      });
+    },
+    
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    
+    descCancel() {
+      this.descOpen = false;
+      this.descReset();
+    },
+    
+    descReset() {
+      this.descForm = [];
+    },
+    
+    reset() {
+      this.form = {
+        id: null,
+        parentId: 0,
+        sort: null,
+        name: null,
+        updateTime: null,
+        createTime: null,
+        isDel: null
+      };
+      this.resetForm("form");
+    },
+    
+    handleQuery() {
+      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.getTreeselect();
+      this.open = true;
+      this.title = "添加投诉模板";
+    },
+    
+    handleDesc(row) {
+      if (!this.isLeafNode(row)) {
+        this.msgWarning("只有最后一级分类才能配置填写字段");
+        return;
+      }
+      
+      this.descOpen = true;
+      this.descId = row.id
+      if (row.description) {
+        const description = JSON.parse(row.description);
+        
+        this.fields.forEach(field => {
+          // 修复:添加 return 语句或者直接使用箭头函数的简写形式
+          const found = description.find(item => item.name === field.label);
+          
+          if (found) {
+            field.checked = true;
+            field.isRequire = found.isRequire;
+          } else {
+            field.checked = false;
+            field.isRequire = 0;
+          }
+        });
+      } else {
+        // 重置所有字段
+        this.fields.forEach(field => {
+          field.checked = false;
+          field.isRequire = 0;
+        });
+      }
+      
+      // 添加调试信息,查看最终的 fields 状态
+      console.log("最终 fields 状态:", JSON.stringify(this.fields));
+    },
+    
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      this.getTreeselect();
+      const id = row.id || this.ids
+      getTemplate(id).then(response => {
+        this.form = response.data;
+        if (this.form.parentId === null || this.form.parentId === undefined) {
+          this.form.parentId = 0;
+        }
+        this.open = true;
+        this.title = "修改投诉模板";
+      });
+    },
+    
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateTemplate(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addTemplate(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 delTemplate(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有投诉模板数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportTemplate(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
+    }
+  }
+};
+</script>
+
+<style scoped>
+/* 表头样式 */
+.field-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 15px;
+  padding: 10px 0;
+  border-bottom: 1px solid #e4e7ed;
+  font-weight: bold;
+  color: #606266;
+}
+
+.field-name-header {
+  flex: 1;
+  text-align: left;
+  padding-left: 20px;
+}
+
+.field-required-header {
+  width: 120px;
+  text-align: center;
+}
+
+/* 字段项样式 */
+.field-item {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 15px;
+  padding: 8px 0;
+  border-bottom: 1px solid #f0f0f0;
+}
+
+.field-checkbox-wrapper {
+  flex: 1;
+  display: flex;
+  align-items: center;
+}
+
+.field-checkbox-wrapper .el-checkbox {
+  margin-right: 20px;
+}
+
+.field-switch-wrapper {
+  width: 120px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.require-switch {
+  margin: 0;
+}
+
+/* 对话框内容区域样式调整 */
+.el-dialog__body {
+  padding: 20px;
+}
+</style>

+ 442 - 0
src/views/his/dfAccount/index.vue

@@ -0,0 +1,442 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="AppKey" prop="dfAppKey">
+        <el-input
+          v-model="queryParams.dfAppKey"
+          placeholder="请输入dfAppKey"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="Appsecret" prop="dfAppsecret">
+        <el-input
+          v-model="queryParams.dfAppsecret"
+          placeholder="请输入dfAppsecret"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="登录账号" prop="loginAccount">
+        <el-input
+          v-model="queryParams.loginAccount"
+          placeholder="请输入登录账号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+    
+      <el-form-item label="月结账号" prop="monthlyCard">
+        <el-input
+          v-model="queryParams.monthlyCard"
+          placeholder="请输入月结账号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="物流产品" prop="expressProductCode">
+        <el-select v-model="queryParams.expressProductCode" placeholder="请选择物流产品编码" clearable size="small">
+          <el-option
+            v-for="dict in expressOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="寄件人" prop="senderName">
+        <el-input
+          v-model="queryParams.senderName"
+          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:dfAccount: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:dfAccount: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:dfAccount: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:dfAccount:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="accountList" @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="key" align="center" prop="dfAppKey" />
+      <el-table-column label="secret" align="center" prop="dfAppsecret" />
+      <el-table-column label="登录账号" align="center" prop="loginAccount" />
+      <el-table-column label="回调地址" align="center" prop="callBackUrl" />
+      <el-table-column label="月结账号" align="center" prop="monthlyCard" />
+      <el-table-column label="物流产品" align="center" >
+        <template slot-scope="scope">
+          <dict-tag :options="expressOptions" :value="scope.row.expressProductCode"/>
+        </template>
+        </el-table-column>  
+      <el-table-column label="寄件人姓名" align="center" prop="senderName" />
+      <el-table-column label="寄件人手机" align="center" prop="senderPhone" />
+      <el-table-column label="寄件人省" align="center" prop="senderProvince" />
+      <el-table-column label="寄件人市" align="center" prop="senderCity" />
+      <el-table-column label="寄件人区" align="center" prop="senderDistrict" />
+      <el-table-column label="寄件人地址" align="center" prop="senderAddress" />
+      <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:dfAccount:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['his:dfAccount: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="Key" prop="dfAppKey">
+          <el-input v-model="form.dfAppKey" placeholder="请输入dfAppKey" />
+        </el-form-item>
+        <el-form-item label="secret" prop="dfAppsecret">
+          <el-input v-model="form.dfAppsecret" placeholder="请输入dfAppsecret" />
+        </el-form-item>
+        <el-form-item label="登录账号" prop="loginAccount">
+          <el-input v-model="form.loginAccount" placeholder="请输入登录账号" />
+        </el-form-item>
+        <el-form-item label="回调地址" prop="callBackUrl">
+          <el-input v-model="form.callBackUrl" placeholder="请输入回调地址" />
+        </el-form-item>
+        <el-form-item label="月结账号" prop="monthlyCard">
+          <el-input v-model="form.monthlyCard" placeholder="请输入月结账号" />
+        </el-form-item>
+        <el-form-item label="物流产品" prop="expressProductCode">
+          <el-select v-model="form.expressProductCode" placeholder="请选择物流产品编码" clearable size="small">
+            <el-option
+              v-for="dict in expressOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="dict.dictValue"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="寄件姓名" prop="senderName">
+          <el-input v-model="form.senderName" placeholder="请输入寄件人姓名" />
+        </el-form-item>
+        <el-form-item label="寄件手机" prop="senderPhone">
+          <el-input v-model="form.senderPhone" placeholder="寄件人手机" />
+        </el-form-item>
+        <el-form-item label="省市区" prop="cityIds">
+          <el-cascader
+            placeholder="请选择寄件人省市区"
+            ref="citySelect"
+            v-model="form.cityIds"
+            :options="citys"
+            @change="handleCityChange()"
+          >
+          </el-cascader>
+        </el-form-item>
+        <el-form-item label="详细地址" prop="senderAddress">
+          <el-input v-model="form.senderAddress" 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 { listAccount, getAccount, delAccount, addAccount, updateAccount, exportAccount } from "@/api/his/dfAccount";
+import { getCitys } from '@/api/store/city'
+export default {
+  name: "Account",
+  data() {
+    return {
+      citys: [],
+      expressOptions:[],//物流产品编码
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 代服账户表格数据
+      accountList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        dfAppKey: null,
+        dfAppsecret: null,
+        loginAccount: null,
+        callBackUrl: null,
+        monthlyCard: null,
+        expressProductCode: null,
+        senderName: null,
+        senderPhone: null,
+        senderProvince: null,
+        senderCity: null,
+        senderDistrict: null,
+        senderAddress: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        dfAppKey: [
+          { required: true, message: "key不能为空", trigger: "blur" }
+        ],
+        dfAppsecret: [
+          { required: true, message: "secret不能为空", trigger: "blur" }
+        ],
+        loginAccount: [
+          { required: true, message: "登录账户不能为空", trigger: "blur" }
+        ],
+        callBackUrl: [
+          { required: true, message: "回调地址不能为空", trigger: "blur" }
+        ],
+        monthlyCard: [
+          { required: true, message: "月结账户不能为空", trigger: "blur" }
+        ],
+        expressProductCode: [
+          { required: true, message: "物流产品不能为空", trigger: "blur" }
+        ],
+        senderName: [
+          { required: true, message: "寄件人不能为空", trigger: "blur" }
+        ],
+        senderPhone: [
+          { required: true, message: "寄件人电话不能为空", trigger: "blur" }
+        ],
+        cityIds: [
+          { required: true, message: "省市区不能为空", trigger: "blur" }
+        ],
+        senderAddress: [
+          { required: true, message: "详细地址不能为空", trigger: "blur" }
+        ],
+      }
+    };
+  },
+  created() {
+    this.getCitys();
+    this.getDicts("df_account_express").then(response => {
+      this.expressOptions = response.data;
+    });
+    this.getList();
+  },
+  methods: {
+    handleCityChange() {
+      var nodes = this.$refs.citySelect.getCheckedNodes()
+      this.form.senderProvince = nodes[0].pathLabels[0]
+      this.form.senderCity = nodes[0].pathLabels[1]
+      this.form.senderDistrict = nodes[0].pathLabels[2]
+    },
+    getCitys() {
+      getCitys().then(res => {
+        this.loading = false
+        this.citys = res.data
+      })
+    },
+    /** 查询代服账户列表 */
+    getList() {
+      this.loading = true;
+      listAccount(this.queryParams).then(response => {
+        this.accountList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        dfAppKey: null,
+        dfAppsecret: null,
+        loginAccount: null,
+        callBackUrl: null,
+        monthlyCard: null,
+        expressProductCode: null,
+        senderName: null,
+        senderPhone: null,
+        senderProvince: null,
+        senderCity: null,
+        senderDistrict: null,
+        senderAddress: 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
+      getAccount(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改代服账户";
+        this.form.cityIds = JSON.parse(response.data.cityIds)
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          this.form.cityIds = JSON.stringify(this.form.cityIds)
+          if (this.form.id != null) {
+            updateAccount(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addAccount(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 delAccount(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有代服账户数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportAccount(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 378 - 0
src/views/his/divItem/index.vue

@@ -0,0 +1,378 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="85px">
+      <el-form-item label="订单号" prop="orderCode">
+        <el-input
+          v-model="queryParams.orderCode"
+          placeholder="请输入订单编号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="支付订单号" prop="payCode">
+        <el-input
+          v-model="queryParams.payCode"
+          placeholder="请输入支付订单号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择" @keyup.enter.native="handleQuery" size="small">
+          <el-option
+            v-for="item in options"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value">
+          </el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="延迟分账" prop="isDelay">
+        <el-select v-model="queryParams.isDelay" placeholder="请选择" @keyup.enter.native="handleQuery" size="small">
+          <el-option
+            v-for="item in delayOptions"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value">
+          </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:divItem: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:divItem: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:divItem: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:divItem:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="divItemList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="订单编号" align="center" prop="orderCode" />
+      <el-table-column label="支付订单号" align="center" prop="payCode" />
+      <el-table-column label="支付状态" align="center" prop="isPay" >
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.isPay == 1">成功</el-tag>
+          <el-tag v-if="scope.row.isPay == 0">失败</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="延迟分账" align="center" prop="isDelay" >
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.isDelay == 1">是</el-tag>
+          <el-tag v-if="scope.row.isDelay == 0">否</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="分账明细" align="center" prop="detail" />
+      <el-table-column label="退款明细" align="center" prop="refundDetail" />
+      <el-table-column label="创建时间" align="center" prop="createTime" />
+      <el-table-column label="更新时间" align="center" prop="updateTime" />
+      <!-- <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:divItem:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['his:divItem: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="orderCode">
+          <el-input v-model="form.orderCode" placeholder="请输入订单编号" />
+        </el-form-item>
+        <el-form-item label="支付订单号" prop="payCode">
+          <el-input v-model="form.payCode" placeholder="请输入支付订单号" />
+        </el-form-item>
+        <el-form-item label="分账明细" prop="detail">
+          <el-input v-model="form.detail" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="是否支付成功 0否 1是" prop="isPay">
+          <el-input v-model="form.isPay" placeholder="请输入是否支付成功 0否 1是" />
+        </el-form-item>
+        <el-form-item label="是否延迟分账 0否 1是" prop="isDelay">
+          <el-input v-model="form.isDelay" placeholder="请输入是否延迟分账 0否 1是" />
+        </el-form-item>
+        <el-form-item label="是否退款 0否 1是" prop="isRefund">
+          <el-input v-model="form.isRefund" placeholder="请输入是否退款 0否 1是" />
+        </el-form-item>
+        <el-form-item label="退款明细" prop="refundDetail">
+          <el-input v-model="form.refundDetail" 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 { listDivItem, getDivItem, delDivItem, addDivItem, updateDivItem, exportDivItem } from "@/api/his/divItem";
+
+export default {
+  name: "DivItem",
+  data() {
+    return {
+      delayOptions:[
+      {
+          value:0,
+          label:"否"
+        },
+        {
+          value:1,
+          label:"是"
+        }
+      ],
+      options:[
+        {
+          value:1,
+          label:"支付"
+        },
+        {
+          value:0,
+          label:"退款"
+        }
+      ],
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 分账明细表格数据
+      divItemList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        orderCode: null,
+        payCode: null,
+        detail: null,
+        isPay: null,
+        isDelay: 0,
+        isRefund: null,
+        refundDetail: null,
+        status:1
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        orderCode: [
+          { required: true, message: "订单编号不能为空", trigger: "blur" }
+        ],
+        payCode: [
+          { required: true, message: "支付订单号不能为空", trigger: "blur" }
+        ],
+        isPay: [
+          { required: true, message: "是否支付成功 0否 1是不能为空", trigger: "blur" }
+        ],
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询分账明细列表 */
+    getList() {
+      this.loading = true;
+      var params = this.queryParams;
+      if(params.status == 1){
+        params.isPay = null;
+        params.isRefund = 0;
+      } else{
+        params.isPay = null;
+        params.isRefund = 1;
+      }
+      listDivItem(this.queryParams).then(response => {
+        this.divItemList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        orderCode: null,
+        payCode: null,
+        detail: null,
+        isPay: null,
+        isDelay: null,
+        isRefund: null,
+        createTime: null,
+        updateTime: null,
+        refundDetail: 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
+      getDivItem(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) {
+            updateDivItem(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addDivItem(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 delDivItem(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有分账明细数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportDivItem(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 30 - 2
src/views/his/doctor/type1.vue

@@ -485,7 +485,7 @@
                   </el-col>
             </el-row>
             <el-row>
-                  <el-col :span="24">
+                  <el-col :span="12">
                       <el-form-item label="身份证反面" prop="idCardBackUrl">
                         <el-upload id="sf"
                          v-model="form.idCardBackUrl"
@@ -499,6 +499,20 @@
                         </el-upload>
                       </el-form-item>
                   </el-col>
+                  <el-col :span="12">
+                      <el-form-item label="医生签名" prop="signUrl">
+                        <el-upload id="sign"
+                         v-model="form.signUrl"
+                         class="avatar-uploader"
+                         :action="bauploadUrl"
+                         :show-file-list="false"
+                         :on-success="signhandleAvatarSuccess"
+                         :before-upload="beforeAvatarUpload">
+                         <img v-if="form.signUrl" :src="form.signUrl" class="avatar" width="150px">
+                         <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+                        </el-upload>
+                      </el-form-item>
+                  </el-col>
             </el-row>
 
         <el-row>
@@ -635,7 +649,7 @@
          
          <el-row>
                <el-col :span="12">
-                 <el-form-item label="登录账号" prop="account" v-if="form.doctorId==null||form.doctorId==''">
+                 <el-form-item label="登录账号" prop="account" >
                    <el-input v-model="form.account" placeholder="请输入账号名称" />
                  </el-form-item>
                </el-col>
@@ -1084,6 +1098,15 @@ export default {
                   this.msgError(res.msg);
                 }
      },
+     signhandleAvatarSuccess(res, file) {
+                if(res.code==200){
+                  this.form.signUrl=res.url;
+                  this.$forceUpdate();
+                }
+                else{
+                  this.msgError(res.msg);
+                }
+     },
 
     handleAvatarSuccess(res, file) {
             if(res.code==200){
@@ -1483,6 +1506,11 @@ export default {
       min-height: 150px;
       display: block;
     }
+    #sign .avatar{
+      min-width: 120px;
+      min-height: 80px;
+      display: block;
+    }
     .avatar {
          min-width: 150px;
          min-height: 150px;

+ 30 - 2
src/views/his/doctor/type2.vue

@@ -396,7 +396,7 @@
                 </el-col>
           </el-row>
           <el-row>
-                <el-col :span="24">
+                <el-col :span="12">
                     <el-form-item label="身份证反面" prop="idCardBackUrl">
                        <el-upload
                                   v-model="form.idCardBackUrl"
@@ -410,6 +410,20 @@
                       </el-upload>
                     </el-form-item>
                 </el-col>
+                <el-col :span="12">
+                  <el-form-item label="医生签名" prop="signUrl">
+                    <el-upload id="sign"
+                               v-model="form.signUrl"
+                               class="avatar-uploader"
+                               :action="bauploadUrl"
+                               :show-file-list="false"
+                               :on-success="signhandleAvatarSuccess"
+                               :before-upload="beforeAvatarUpload">
+                      <img v-if="form.signUrl" :src="form.signUrl" class="avatar" width="150px">
+                      <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+                    </el-upload>
+                  </el-form-item>
+                </el-col>
           </el-row>
 
       <el-row>
@@ -536,6 +550,7 @@ export default {
       certificateBack:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
       practise:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
       practiseBack:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
+      bauploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
       orOptions: [],
       isauditOptions: [],
       positionOptions: [],
@@ -778,7 +793,15 @@ export default {
                   this.msgError(res.msg);
                 }
      },
-
+    signhandleAvatarSuccess(res, file) {
+      if(res.code==200){
+        this.form.signUrl=res.url;
+        this.$forceUpdate();
+      }
+      else{
+        this.msgError(res.msg);
+      }
+    },
     handleAvatarSuccess(res, file) {
             if(res.code==200){
               this.form.certificateImages=res.url;
@@ -1124,4 +1147,9 @@ export default {
        line-height: 150px;
        text-align: center;
     }
+  #sign .avatar{
+    min-width: 120px;
+    min-height: 80px;
+    display: block;
+  }
 </style>

+ 26 - 1
src/views/his/inquiryOrder/order1.vue

@@ -47,6 +47,17 @@
              @keyup.enter.native="handleQuery"
            />
        </el-form-item>
+       
+       <el-form-item label="所属小程序" prop="coursePlaySourceConfigId">
+         <el-select v-model="queryParams.coursePlaySourceConfigId" placeholder="请选择所属小程序" clearable size="small">
+           <el-option
+             v-for="dict in appMallOptions"
+             :key="dict.id"
+             :label="dict.name + '(' + dict.appid + ')'"
+             :value="dict.id"
+           />
+         </el-select>
+       </el-form-item>
         <el-form-item label="问诊开始时间" prop="startTime">
            <el-date-picker v-model="startTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
         </el-form-item>
@@ -101,6 +112,7 @@
       <el-table-column label="问诊标题" align="center" prop="title" show-overflow-tooltip />
       <el-table-column label="病人名称" align="center" prop="patientName" />
       <el-table-column label="医生名称" align="center" prop="doctorName" />
+      <el-table-column label="小程序名称" align="center" prop="miniProgramName" width="120px" />
       <el-table-column label="状态" align="center" prop="status" >
         <template slot-scope="scope">
           <dict-tag :options="inquiryStatusOptions" :value="scope.row.status" />
@@ -198,6 +210,7 @@ import inquiryOrderDetails from '../../components/his/inquiryOrderDetails.vue';
 import msgDetails from '../../components/his/msgDetails.vue';
 import msgServiceDetails from '../../components/his/msgServiceDetails.vue';
 import { getTask } from "@/api/common";
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
 export default {
   name: "inquiryOrder",
   components: { inquiryOrderDetails,msgDetails,msgServiceDetails },
@@ -275,6 +288,7 @@ export default {
         doctorName:null,
         patientName:null,
         sendName:null,
+        coursePlaySourceConfigId:null,
       },
       // 表单参数
       form: {},
@@ -286,6 +300,7 @@ export default {
       inquiryPayOptions:[],
       inquiryOrderOptions:[],
       orOptions:[],
+      appMallOptions:[],
     };
   },
 
@@ -308,6 +323,10 @@ export default {
       this.getDicts("sys_inquiry_sub_type").then(response => {
         this.inquirySubTypeOptions = response.data;
       });
+      
+      // 获取小程序选项列表
+      this.getAppMallOptions();
+      
     this.getList();
   },
   methods: {
@@ -543,7 +562,13 @@ export default {
 			},10000);
 		  }
         }).catch(() => {});
-    }
+    },
+    // 获取小程序选项列表
+    getAppMallOptions() {
+      getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+        this.appMallOptions = response.rows;
+      })
+    },
   }
 };
 </script>

+ 25 - 1
src/views/his/inquiryOrder/order2.vue

@@ -37,6 +37,17 @@
       <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="coursePlaySourceConfigId">
+         <el-select v-model="queryParams.coursePlaySourceConfigId" placeholder="请选择所属小程序" clearable size="small">
+           <el-option
+             v-for="dict in appMallOptions"
+             :key="dict.id"
+             :label="dict.name + '(' + dict.appid + ')'"
+             :value="dict.id"
+           />
+         </el-select>
+       </el-form-item>
 
 
 
@@ -94,6 +105,7 @@
       <el-table-column label="咨询标题" align="center" prop="title" show-overflow-tooltip />
       <el-table-column label="病人名称" align="center" prop="patientName" />
       <el-table-column label="医生名称" align="center" prop="doctorName" />
+      <el-table-column label="小程序名称" align="center" prop="miniProgramName" width="120px" />
       <el-table-column label="员工" align="center" prop="companyUserName" />
       <el-table-column label="公司" align="center" prop="companyName" />
       <el-table-column label="状态" align="center" prop="status" >
@@ -193,6 +205,7 @@ import {allList}from "@/api/company/company";
 import inquiryOrderDetails from '../../components/his/inquiryOrderDetails.vue';
 import msgDetails from '../../components/his/msgDetails.vue';
 import { getTask } from "@/api/common";
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
 export default {
   name: "ofast",
   components: { inquiryOrderDetails,msgDetails },
@@ -268,6 +281,7 @@ export default {
         phone:null,
         inquirySubType:null,
         companyUserName:null,
+        coursePlaySourceConfigId:null,
       },
       // 表单参数
       form: {},
@@ -281,6 +295,7 @@ export default {
       inquiryOrderOptions:[],
       inquirySubTypeOptions:[],
       orOptions:[],
+      appMallOptions:[],
     };
   },
   created() {
@@ -305,6 +320,9 @@ export default {
 
     this.getList();
     this.getAllCompany();
+    
+    // 获取小程序选项列表
+    this.getAppMallOptions();
   },
   methods: {
     getMsg(row){
@@ -569,7 +587,13 @@ export default {
 		   },10000);
 		 }
         }).catch(() => {});
-    }
+    },
+    // 获取小程序选项列表
+    getAppMallOptions() {
+      getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+        this.appMallOptions = response.rows;
+      })
+    },
   }
 };
 </script>

+ 27 - 0
src/views/his/inquiryOrder/order3.vue

@@ -49,6 +49,17 @@
            <el-input v-model="queryParams.phone" placeholder="请输入会员电话"  clearable  size="small" @keyup.enter.native="handleQuery"/>
        </el-form-item>
 
+      <el-form-item label="所属小程序" prop="coursePlaySourceConfigId">
+        <el-select v-model="queryParams.coursePlaySourceConfigId" placeholder="请选择所属小程序" clearable size="small">
+          <el-option
+            v-for="dict in appMallOptions"
+            :key="dict.id"
+            :label="dict.name + '(' + dict.appid + ')'"
+            :value="dict.id"
+          />
+        </el-select>
+      </el-form-item>
+
       <el-form-item label="订单类型" prop="orderType">
          <el-select v-model="queryParams.orderType" placeholder="状态" clearable size="small">
                  <el-option
@@ -155,6 +166,7 @@
 
       </el-table-column>
       <el-table-column label="科室名称" align="center" prop="deptName" />
+      <el-table-column label="小程序名称" align="center" prop="miniProgramName" width="120px" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="100px">
         <template slot-scope="scope">
        <el-button
@@ -200,11 +212,13 @@ import inquiryOrderDetails from '../../components/his/inquiryOrderDetails.vue';
 import msgDetails from '../../components/his/msgDetails.vue';
 import {allList}from "@/api/company/company";
 import { getTask } from "@/api/common";
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
 export default {
   name: "omedicine",
   components: { inquiryOrderDetails,msgDetails },
   data() {
     return {
+      appMallOptions: [],
       companyList:[],
       msgForm:{
           pageNum: 1,
@@ -274,6 +288,7 @@ export default {
         patientName:null,
         sendName:null,
         phone:null,
+        coursePlaySourceConfigId:null,
       },
       // 表单参数
       form: {},
@@ -286,6 +301,7 @@ export default {
       inquiryOrderOptions:[],
       inquirySubTypeOptions:[],
       orOptions:[],
+      appMallOptions:[],
     };
   },
   created() {
@@ -307,6 +323,10 @@ export default {
     this.getDicts("sys_inquiry_sub_type").then(response => {
       this.inquirySubTypeOptions = response.data;
     });
+    
+    // 获取小程序选项列表
+    this.getAppMallOptions();
+    
     this.getList();
     this.getAllCompany();
   },
@@ -316,6 +336,12 @@ export default {
         this.companyList = response.rows;
       });
     },
+    // 获取小程序选项列表
+    getAppMallOptions() {
+      getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+        this.appMallOptions = response.rows;
+      })
+    },
     getMsg(row){
       const orderId = row.orderId;
       const doctorName = row.doctorName;
@@ -417,6 +443,7 @@ export default {
     this.startTime=null;
     this.queryParams.sTime=null;
     this.queryParams.eTime=null;
+    this.queryParams.coursePlaySourceConfigId=null;
     this.handleQuery();
   },
   change(){

+ 77 - 30
src/views/his/inquiryOrderReport/index.vue

@@ -1,10 +1,13 @@
 <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" >
-      <el-select v-model="queryParams.companyId" placeholder="请选择所属公司" filterable size="small">
-            <el-option v-for="(option, index) in companyList" :key="index" :value="option.dictValue" :label="option.dictLabel"></el-option>
-       </el-select>
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+      <el-form-item label="所属公司" prop="companyId">
+        <el-select v-model="queryParams.companyId" placeholder="请选择所属公司" filterable clearable size="small">
+          <el-option v-for="(option, index) in companyList" :key="index" :value="option.dictValue" :label="option.dictLabel"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="员工" prop="companyUserNickName">
+        <el-input v-model="queryParams.companyUserNickName" placeholder="请输入员工名称" clearable size="small" @keyup.enter.native="handleQuery"/>
       </el-form-item>
       <el-form-item label="订单号" prop="orderId">
         <el-input
@@ -15,8 +18,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-
-      <el-form-item label="报告编号" prop="reportSn" >
+      <el-form-item label="报告编号" prop="reportSn">
         <el-input
           v-model="queryParams.reportSn"
           placeholder="请输入报告编号"
@@ -26,14 +28,11 @@
         />
       </el-form-item>
       <el-form-item label="子类型" prop="inquirySubType">
-         <el-select v-model="queryParams.inquirySubType" placeholder="子类型" clearable size="small">
-            <el-option v-for="dict in inquirySubTypeOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
-         </el-select>
-      </el-form-item>
-      <el-form-item label="员工" prop="companyUserNickName">
-           <el-input  v-model="queryParams.companyUserNickName"  placeholder="请输入员工名称" clearable size="small" @keyup.enter.native="handleQuery"/>
+        <el-select v-model="queryParams.inquirySubType" placeholder="子类型" clearable size="small">
+          <el-option v-for="dict in inquirySubTypeOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
+        </el-select>
       </el-form-item>
-      <el-form-item label="患者名称" prop="patientName" >
+      <el-form-item label="患者名称" prop="patientName">
         <el-input
           v-model="queryParams.patientName"
           placeholder="请输入患者名称"
@@ -42,7 +41,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="手机号" prop="patientMobile" >
+      <el-form-item label="手机号" prop="patientMobile">
         <el-input
           v-model="queryParams.patientMobile"
           placeholder="请输入手机号"
@@ -51,7 +50,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="导医" prop="userName" >
+      <el-form-item label="导医" prop="userName">
         <el-input
           v-model="queryParams.userName"
           placeholder="请输入导医"
@@ -60,7 +59,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="医生名称" prop="doctorName" >
+      <el-form-item label="医生名称" prop="doctorName">
         <el-input
           v-model="queryParams.doctorName"
           placeholder="请输医生名称"
@@ -70,21 +69,34 @@
         />
       </el-form-item>
       <el-form-item label="咨询状态" prop="inquiryStatus">
-         <el-select v-model="queryParams.inquiryStatus" placeholder="状态" clearable size="small">
-                 <el-option
-                   v-for="dict in inquiryStatusOptions"
-                   :key="dict.dictValue"
-                   :label="dict.dictLabel"
-                   :value="dict.dictValue"
-                 />
-               </el-select>
+        <el-select v-model="queryParams.inquiryStatus" placeholder="状态" clearable size="small">
+          <el-option
+            v-for="dict in inquiryStatusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      
+      <el-form-item label="所属小程序" prop="coursePlaySourceConfigId">
+        <el-select v-model="queryParams.coursePlaySourceConfigId" placeholder="请选择所属小程序" clearable size="small">
+          <el-option
+            v-for="dict in appMallOptions"
+            :key="dict.id"
+            :label="dict.name + '(' + dict.appid + ')'"
+            :value="dict.id"
+          />
+        </el-select>
       </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="change"></el-date-picker>
+      
+      <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="change"></el-date-picker>
       </el-form-item>
       <el-form-item label="首次分诊时间" prop="updateTime">
-          <el-date-picker v-model="updateTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
+        <el-date-picker v-model="updateTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></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>
@@ -119,6 +131,7 @@
       <el-table-column label="医生名称" align="center" prop="doctorName" />
       <el-table-column label="公司" align="center" prop="companyName" />
       <el-table-column label="员工" align="center" prop="companyUserName" />
+      <el-table-column label="小程序名称" align="center" prop="miniProgramName" width="120px" />
       <el-table-column label="咨询结果" align="center" prop="inquiryResult" />
       <el-table-column label="状态" align="center" prop="status">
         <template slot-scope="scope">
@@ -368,6 +381,7 @@ import {listdocuser} from "@/api/his/doctor";
 import { getIllness } from "@/api/his/illnessLibrary";
 import {allList}from "@/api/company/company";
 import { getTask } from "@/api/common";
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
 export default {
   name: "InquiryOrderReport",
   components: { inquiryOrderReportDetails },
@@ -432,6 +446,7 @@ export default {
       inquiryStatusOptions:[],
       inquirySubTypeOptions:[],
       companyList:[],
+      appMallOptions:[],
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -448,6 +463,7 @@ export default {
         userName: null,
         inquiryStatus:null,
         doctorName:null,
+        coursePlaySourceConfigId:null,
       },
       // 表单参数
       form: {},
@@ -479,6 +495,10 @@ export default {
     getBody().then(response => {
           this.body=response;
       });
+    
+    // 获取小程序选项列表
+    this.getAppMallOptions();
+    
     this.getAllCompany();
   },
   methods: {
@@ -511,6 +531,12 @@ export default {
         this.companyList = response.rows;
       });
     },
+    // 获取小程序选项列表
+    getAppMallOptions() {
+      getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+        this.appMallOptions = response.rows;
+      })
+    },
     selectOK(rows){
 
       if(this.form.inquiryResult==null){
@@ -603,9 +629,14 @@ export default {
     resetQuery() {
       this.resetForm("queryForm");
       this.createTime=null;
+      this.updateTime=null;
       this.queryParams.sTime=null;
       this.queryParams.eTime=null;
-      this.inquiryStatus=null;
+      this.queryParams.beginTime=null;
+      this.queryParams.endTime=null;
+      this.queryParams.coursePlaySourceConfigId=null;
+      // 注意:不重置status,保持当前tab状态
+      // this.queryParams.status 保持不变
       this.handleQuery();
     },
     // 多选框选中数据
@@ -888,7 +919,23 @@ export default {
           },10000);
         }
         }).catch(() => {});
-    }
+    },
+    /** tab切换操作 */
+    handleClickX(tab, event) {
+      if(tab.name=="10"){
+        this.queryParams.status=null;
+      }else{
+        this.queryParams.status=tab.name;
+      }
+      this.handleQuery();
+    },
+    /** 查看详情操作 */
+    handledetails(row){
+      this.show.open=true;
+      setTimeout(() => {
+        this.$refs.Details.getDetails(row.reportId);
+      }, 1);
+    },
   }
 };
 </script>

+ 26 - 1
src/views/his/integralOrder/index.vue

@@ -147,6 +147,13 @@
              @click="handledetails(scope.row)"
              >详情
           </el-button>
+          <el-button
+              size="mini"
+              type="text"
+              @click="cancelOrder(scope.row.orderCode)"
+              v-if="scope.row.status === '1'"
+            >取消订单
+            </el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -256,7 +263,7 @@
 </template>
 
 <script>
-import {importTemplate, listIntegralOrder,importExpressTemplate, getIntegralOrder, delIntegralOrder, addIntegralOrder, updateIntegralOrder, exportIntegralOrder } from "@/api/his/integralOrder";
+import {importTemplate, listIntegralOrder,importExpressTemplate, getIntegralOrder, delIntegralOrder, addIntegralOrder, updateIntegralOrder, exportIntegralOrder,cancelOrder } from "@/api/his/integralOrder";
 import integralOrderDetails from '../../components/his/integralOrderDetails.vue';
 import { getToken } from "@/utils/auth";
 import {getCompanyList} from "@/api/company/company";
@@ -355,6 +362,24 @@ export default {
     });
   },
   methods: {
+     //取消订单
+     cancelOrder(orderCode){
+      this.$confirm('确定取消此订单?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        console.log("orderCode",orderCode)
+        cancelOrder(orderCode).then(()=>{
+          this.$message({
+            type: 'success',
+            message: '取消成功!'
+          });
+          this.getList();
+        })
+      }).catch(() => {
+      });
+    },
     change(){
           if(this.createTime!=null){
             this.queryParams.sTime=this.createTime[0];

+ 90 - 6
src/views/his/package/index.vue

@@ -91,6 +91,16 @@
           />
         </el-select>
       </el-form-item>
+      <el-form-item label="所属小程序" prop="appName" >
+        <el-select v-model="queryParams.appId" placeholder="请选择" clearable>
+          <el-option
+            v-for="dict in appMallOptions"
+            :key="dict.appid"
+            :label="dict.name + '(' + dict.appid + ')'"
+            :value="dict.appid"
+          />
+        </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>
@@ -152,6 +162,17 @@
 
               >导入</el-button>
       </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          :disabled="multiple"
+          @click="bulkCopy"
+          v-hasPermi="['his:package:bulkCopy']"
+        >批量复制</el-button>
+      </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
@@ -538,6 +559,26 @@
                   />
           </el-select>
         </el-form-item>
+        <el-form-item label="所属小程序" prop="appId">
+          <el-select v-model="appId" placeholder="请选择所属小程序" clearable size="small" multiple>
+            <el-option
+              v-for="dict in appMallOptions"
+              :key="dict.appid"
+              :label="dict.name + '(' + dict.appid + ')'"
+              :value="dict.appid"
+            />
+          </el-select>
+        </el-form-item>
+        <!-- <el-form-item label="问答" prop="questionId" >
+           <el-select v-model="form.questionId" placeholder="请选择问答">
+              <el-option
+                  v-for="dict in questionOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="parseInt(dict.dictValue)"
+                />
+           </el-select>
+        </el-form-item> -->
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="submitForm">确 定</el-button>
@@ -608,10 +649,21 @@
 </template>
 
 <script>
-import { listPackage, getPackage, delPackage, addPackage, updatePackage, exportPackage,importTemplate,modifyPackages } from "@/api/his/package";
+import {
+  listPackage,
+  getPackage,
+  delPackage,
+  addPackage,
+  updatePackage,
+  exportPackage,
+  importTemplate,
+  modifyPackages,
+  bulkCopy
+} from "@/api/his/package";
 import {getAllFollowTempName } from "@/api/his/followTemp";
 import {getAllCateList} from "@/api/his/packageCate";
 import {allIcd } from "@/api/his/icd";
+// import {questionOptions } from "@/api/his/answer";
 import packageDetails from '../../components/his/packageDetails.vue';
 import productAttrValueSelect from "../../components/his/productAttrValueSelect.vue";
 import { listStore } from "@/api/his/storeProduct";
@@ -620,7 +672,8 @@ import { getToken } from "@/utils/auth";
 import Material from '@/components/Material'
 import ImageUpload from '@/components/ImageUpload'
 import { Loading } from 'element-ui';
-import { getOptions } from '@/api/his/packageSolarTerm'
+import { getOptions } from '@/api/his/packageSolarTerm';
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
 export default {
   name: "Package",
   components: { packageDetails,Editor,productAttrValueSelect,Material },
@@ -634,6 +687,7 @@ export default {
   },
   data() {
     return {
+      appId:[],
       open1: false,
       form1:{},
       finalQuality:1,
@@ -659,6 +713,7 @@ export default {
               url: process.env.VUE_APP_BASE_API + "/his/package/importData"
             },
       productTypeOptions: [],
+      // questionOptions: [],
       storeId:null,
       storeOPtions:[],
       usageFrequencyUnitOptions:[{
@@ -718,6 +773,7 @@ export default {
       isDelOptions: [],
       packageSubTypeOptions:[],
       solarTermOptions: [],
+      appMallOptions:[],
       photoArr:[],
       // 查询参数
       queryParams: {
@@ -807,10 +863,14 @@ export default {
       this.privateTypeOptions = response.data.privateType;
     });
     this.getTemp();
-    this.getSolarTermOptions()
+    this.getSolarTermOptions(),
+    this.getAppMallOptions();
     listStore().then(response => {
       this.storeOPtions = response.rows;
     });
+    // questionOptions().then(res => {
+    //   this.questionOptions = res.rows;
+    // })
   },
   methods: {
     getSolarTermLabel(solarTerm) {
@@ -824,6 +884,11 @@ export default {
         this.solarTermOptions = response.data;
       })
     },
+    getAppMallOptions() {
+      getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+        this.appMallOptions = response.rows;
+      })
+    },
     handleUpdateMore(row){
       this.reset1();
       this.title = "批量修改套餐状态";
@@ -1105,6 +1170,7 @@ export default {
         if(this.form.followNum!=null ){
           this.form.followNum=JSON.stringify(this.form.followNum)
         }
+        this.appId=this.form.appIds ? this.form.appIds.split(',') : [];
         setTimeout(() => {
                   if(this.form.desc==null){
                     this.$refs.myeditor.setText("");
@@ -1138,14 +1204,18 @@ export default {
             this.form.productJson=JSON.stringify(this.drugList)
           }
           this.form.describeJson = JSON.stringify(this.describeJson);
-          if (this.form.packageId != null) {
-            updatePackage(this.form).then(response => {
+          const params = {
+            ...this.form,
+            appIds: this.appId.join(',') // 数组转字符串
+          };
+          if (params.packageId != null) {
+            updatePackage(params).then(response => {
               this.msgSuccess("修改成功");
               this.open = false;
               this.getList();
             });
           } else {
-            addPackage(this.form).then(response => {
+            addPackage(params).then(response => {
               this.msgSuccess("新增成功");
               this.open = false;
               this.getList();
@@ -1247,6 +1317,20 @@ export default {
       });
     },
     /** 删除按钮操作 */
+    bulkCopy(row) {
+      const packageIds = row.packageId || this.ids;
+      this.$confirm('是否确认复制套餐包编号为"' + packageIds + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return bulkCopy(packageIds);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("批量复制成功");
+      }).catch(() => {});
+    },
+    /** 删除按钮操作 */
     handleDelete(row) {
       const packageIds = row.packageId || this.ids;
       this.$confirm('是否确认删除套餐包编号为"' + packageIds + '"的数据项?', "警告", {

+ 59 - 6
src/views/his/packageOrder/index.vue

@@ -109,6 +109,17 @@
         </el-select>
       </el-form-item>
 
+      <el-form-item label="所属小程序" prop="coursePlaySourceConfigId">
+        <el-select v-model="queryParams.coursePlaySourceConfigId" placeholder="请选择所属小程序" clearable size="small">
+          <el-option
+            v-for="dict in appMallOptions"
+            :key="dict.id"
+            :label="dict.name + '(' + dict.appid + ')'"
+            :value="dict.id"
+          />
+        </el-select>
+      </el-form-item>
+
       <el-form-item label="开始时间" prop="startTime">
         <el-date-picker v-model="startTime" size="small" style="width: 220px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="startChange"></el-date-picker>
       </el-form-item>
@@ -146,6 +157,7 @@
       <el-table-column label="订单号" align="center" prop="orderSn" width="120px"/>
       <el-table-column label="所属公司" align="center" prop="companyName" />
       <el-table-column label="员工" align="center" prop="companyUserName" />
+      <el-table-column label="小程序名称" align="center" prop="miniProgramName" width="120px" />
       <el-table-column label="套餐名称" align="center" prop="packageName" />
       <el-table-column label="套餐别名" align="center" prop="packageSecondName" width="100px"/>
       <el-table-column label="天数" align="center" prop="days" />
@@ -286,6 +298,7 @@ import { treeselect } from "@/api/company/companyDept";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 import { getTask } from "@/api/common";
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
 export default {
   watch: {
     // 监听deptId
@@ -309,6 +322,8 @@ export default {
       startTime:null,
       // 导出遮罩层
       exportLoading: false,
+      // 导出任务检查计数器
+      exportCheckCount: 0,
       // 选中数组
       ids: [],
       createTime:null,
@@ -336,6 +351,7 @@ export default {
       payTypeOptions:[],
       deliveryPayStatusOptions:[],
       deliveryStatusOptions:[],
+      appMallOptions:[],
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -364,6 +380,7 @@ export default {
         companyName:null,
         deptId:null,
         source:null,
+        coursePlaySourceConfigId:null,
       },
       // 表单参数
       form: {},
@@ -406,6 +423,9 @@ export default {
     this.getDicts("sys_package_sub_type").then(response => {
       this.packageSubTypeOptions = response.data;
     });
+    
+    // 获取小程序选项列表
+    this.getAppMallOptions();
   },
   methods: {
     /** 查询套餐订单列表 */
@@ -569,27 +589,54 @@ export default {
         this.exportLoading = true;
         return exportPackageOrder(queryParams);
       }).then(response => {
-       
-          if(response.code==200){
+        if(response.code==200){
           that.msgSuccess(response.msg);
           that.taskId=response.data;
+          that.exportCheckCount = 0; // 添加检查计数器
           that.time=setInterval(function(){
-            //查订单
+            that.exportCheckCount++;
+            //查任务状态
             getTask(that.taskId).then(res => {
+              // 任务完成
               if(res.data.status==1){
                 that.exportLoading = false;
-                clearTimeout(that.time)
+                clearInterval(that.time);
                 that.time=null;
                 that.download(res.data.fileUrl);
               }
+              // 任务失败
+              else if(res.data.status==-1 || res.data.status==2){
+                that.exportLoading = false;
+                clearInterval(that.time);
+                that.time=null;
+                that.msgError('导出任务失败,请重试');
+              }
+              // 超时处理(检查超过30次,即5分钟)
+              else if(that.exportCheckCount > 30){
+                that.exportLoading = false;
+                clearInterval(that.time);
+                that.time=null;
+                that.msgError('导出任务超时,请稍后重试');
+              }
+            }).catch(err => {
+              // API调用失败
+              that.exportCheckCount++;
+              if(that.exportCheckCount > 30){
+                that.exportLoading = false;
+                clearInterval(that.time);
+                that.time=null;
+                that.msgError('导出任务查询失败,请重试');
+              }
             });
-          },10000);
+          },10000); // 10秒查询一次
         }
         else{
           that.msgError(response.msg);
           that.exportLoading = false;
         }
-      }).catch(() => {});
+      }).catch(() => {
+        that.exportLoading = false;
+      });
     },
     /** 查询部门下拉树结构 */
     getTreeselect() {
@@ -611,6 +658,12 @@ export default {
       this.queryParams.deptId=val;
       this.getList();
     },
+    // 获取小程序选项列表
+    getAppMallOptions() {
+      getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+        this.appMallOptions = response.rows;
+      })
+    },
   }
 };
 </script>

+ 147 - 0
src/views/his/promotionalActive/ChooseCourseVideoComponent.vue

@@ -0,0 +1,147 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="课程" prop="courseId">
+        <el-select filterable  v-model="queryParams.courseId" placeholder="请选择课程"  clearable size="small" style="width: 100%" :value-key="'dictValue'">
+          <el-option
+            v-for="dict in courseList"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="parseInt(dict.dictValue)"
+          />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table border v-loading="loading" :data="list" @selection-change="handleSelectionChange" ref="videoTable" :row-key="'videoId'" :reserve-selection="true">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="课程名称" align="center" prop="courseName" />
+      <el-table-column label="小节名称" align="center" prop="courseVideoName" />
+      <el-table-column label="视频名称" align="center" prop="videoName" />
+      <el-table-column label="时长" align="center" prop="duration"/>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <div class="footer-button">
+      <el-button @click="cancel">取消</el-button>
+      <el-button type="primary" @click="submit">确定</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import { courseList } from '@/api/course/courseRedPacketLog'
+import { getChooseCourseVideoList } from '@/api/course/userCourseVideo'
+
+export default {
+  name: "ChooseCourseVideoComponent",
+  props: {
+    videoIds: {
+      type: Array,
+      default: () => []
+    }
+  },
+  activated() {
+    // keep-alive 激活时恢复选中
+    this.$nextTick(() => {
+      this.restoreSelection()
+    })
+  },
+  watch: {
+    // videoIds 变化时重新恢复选中
+    videoIds: {
+      immediate: false,
+      handler() {
+        this.$nextTick(() => this.restoreSelection())
+      }
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      showSearch: true,
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        courseId: null
+      },
+      courseList: [],
+      total: 0,
+      list: [],
+      selected: []
+    }
+  },
+  created() {
+    courseList().then(response => {
+      this.courseList = response.list;
+    });
+    this.handleQuery()
+  },
+  methods: {
+    handleQuery() {
+      this.queryParams.pageNum = 1
+      this.getList()
+    },
+    resetQuery() {
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        courseId: null
+      }
+      this.handleQuery()
+    },
+    getList() {
+      this.loading = true
+      getChooseCourseVideoList(this.queryParams).then(response => {
+        this.list = response.data.list
+        this.total = response.data.total
+        this.loading = false
+        // 列表加载后,根据传入的 videoIds 自动选中
+        this.$nextTick(() => this.restoreSelection())
+      })
+    },
+    handleSelectionChange(selection) {
+      this.selected = selection
+    },
+    cancel() {
+      this.$emit('closeChoose')
+    },
+    submit() {
+      this.$emit('selectConfirm', this.selected)
+    },
+    // 恢复勾选状态
+    restoreSelection() {
+      const tableRef = this.$refs.videoTable
+      if (!tableRef || !Array.isArray(this.list) || !Array.isArray(this.videoIds)) return
+      tableRef.clearSelection()
+      if (this.videoIds.length === 0) return
+      const idsSet = new Set(this.videoIds)
+      this.list.forEach(row => {
+        if (row && idsSet.has(row.videoId)) {
+          tableRef.toggleRowSelection(row, true)
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.footer-button {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 40px;
+}
+</style>

+ 213 - 0
src/views/his/promotionalActive/ChooseDoctorComponent.vue

@@ -0,0 +1,213 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <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="hospitalId" >
+        <el-select v-model="queryParams.hospitalId" placeholder="请选择所属医院" clearable filterable size="small">
+          <el-option v-for="(option, index) in hospitalList" :key="index" :value="option.dictValue" :label="option.dictLabel"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="科室" prop="deptId">
+        <el-select v-model="queryParams.deptId" placeholder="请选择所属科室" clearable size="small">
+          <el-option
+            v-for="dict in depList"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="职称" prop="position">
+        <el-select v-model="queryParams.position" placeholder="职称" clearable size="small">
+          <el-option
+            v-for="dict in positionOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="手机号" prop="mobile">
+        <el-input
+          v-model="queryParams.mobile"
+          placeholder="请输入手机号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table border v-loading="loading" :data="list" @selection-change="handleSelectionChange" ref="doctorTable" :row-key="'doctorId'" :reserve-selection="true">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="医生名称" align="center" prop="doctorName"/>
+      <el-table-column label="所属医院" align="center" prop="hospitalName"/>
+      <el-table-column label="科室" align="center" prop="deptName"/>
+      <el-table-column label="职称" align="center" prop="position"/>
+      <el-table-column label="手机号" align="center" prop="mobile"/>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <div class="footer-button">
+      <el-button @click="cancel">取消</el-button>
+      <el-button type="primary" @click="submit">确定</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import{listDepartment} from "@/api/his/disease";
+import{listAllHospital} from "@/api/his/hospital";
+import { getChooseDoctorList } from '@/api/his/doctor'
+
+export default {
+  name: "ChooseDoctorComponent",
+  props: {
+    doctorIds: {
+      type: Array,
+      default: () => []
+    }
+  },
+  activated() {
+    // keep-alive 激活时恢复选中
+    this.$nextTick(() => {
+      this.restoreSelection()
+    })
+  },
+  watch: {
+    // doctorIds 变化时重新恢复选中
+    doctorIds: {
+      immediate: false,
+      handler() {
+        this.$nextTick(() => this.restoreSelection())
+      }
+    }
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: false,
+      // 显示搜索条件
+      showSearch: true,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        doctorName: null,
+        hospitalId: null,
+        deptId: null,
+        position: null,
+        mobile: null
+      },
+      //医院列表
+      hospitalList:[],
+      //科室列表
+      depList:[],
+      positionOptions: [],
+      // 总条数
+      total: 0,
+      // 课程列表
+      list: [],
+      selected: [],
+    }
+  },
+  created() {
+    this.getHospitaldeplist();
+    this.getdeplist();
+    this.getDicts("sys_doc_position").then(response => {
+      this.positionOptions = response.data;
+    });
+    this.handleQuery()
+  },
+  methods: {
+    handleQuery() {
+      this.queryParams.pageNum = 1
+      this.getList()
+    },
+    resetQuery() {
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        doctorName: null,
+        hospitalId: null,
+        deptId: null,
+        position: null,
+        mobile: null
+      }
+      this.handleQuery()
+    },
+    getList() {
+      this.loading = true
+      getChooseDoctorList(this.queryParams).then(response => {
+        this.list = response.data.list
+        this.total = response.data.total
+        this.loading = false
+        // 列表加载后,根据传入的 videoIds 自动选中
+        this.$nextTick(() => this.restoreSelection())
+      })
+    },
+    /** 查询医院列表 */
+    getHospitaldeplist() {
+      listAllHospital().then(response => {
+        this.hospitalList = response.rows;
+      });
+    },
+    /** 查询科室列表 */
+    getdeplist() {
+      listDepartment().then(response => {
+        this.depList = response.rows;
+      });
+    },
+    handleSelectionChange(selection) {
+      this.selected = selection
+    },
+    cancel() {
+      this.$emit('closeChoose')
+    },
+    submit() {
+      this.$emit('selectConfirm', this.selected)
+    },
+    // 恢复勾选状态
+    restoreSelection() {
+      const tableRef = this.$refs.doctorTable
+      if (!tableRef || !Array.isArray(this.list) || !Array.isArray(this.doctorIds)) return
+      tableRef.clearSelection()
+      if (this.doctorIds.length === 0) return
+      const idsSet = new Set(this.doctorIds)
+      this.list.forEach(row => {
+        if (row && idsSet.has(row.doctorId)) {
+          tableRef.toggleRowSelection(row, true)
+        }
+      })
+    }
+  },
+}
+</script>
+
+<style scoped>
+.footer-button {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 40px;
+}
+</style>

+ 176 - 0
src/views/his/promotionalActive/ChooseIntegralGoodsComponent.vue

@@ -0,0 +1,176 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="商品名称" prop="goodsName">
+        <el-input
+          v-model="queryParams.goodsName"
+          placeholder="请输入商品名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="商品分类" prop="goodsType">
+        <el-select v-model="queryParams.goodsType" placeholder="请选择商品分类" clearable size="small">
+          <el-option
+            v-for="dict in goodsTypeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table border v-loading="loading" :data="list" @selection-change="handleSelectionChange" ref="integralGoodsTable" :row-key="'goodsId'" :reserve-selection="true">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="商品名称" align="center" prop="goodsName"/>
+      <el-table-column label="商品分类" align="center" prop="goodsTypeName"/>
+      <el-table-column label="封面图片" align="center" prop="goodsImg" width="120">
+        <template slot-scope="scope">
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover"
+          >
+            <img slot="reference" :src="scope.row.goodsImg" width="100">
+            <img :src="scope.row.goodsImg" style="max-width: 150px;">
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column label="商品价格" align="center" prop="cash"/>
+      <el-table-column label="所需积分" align="center" prop="integral"/>
+      <el-table-column label="库存" align="center" prop="stock"/>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <div class="footer-button">
+      <el-button @click="cancel">取消</el-button>
+      <el-button type="primary" @click="submit">确定</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getChooseIntegralGoodsList } from '@/api/his/integralGoods'
+
+export default {
+  name: "ChooseIntegralGoodsComponent",
+  props: {
+    goodsIds: {
+      type: Array,
+      default: () => []
+    }
+  },
+  activated() {
+    // keep-alive 激活时恢复选中
+    this.$nextTick(() => {
+      this.restoreSelection()
+    })
+  },
+  watch: {
+    // goodsIds 变化时重新恢复选中
+    goodsIds: {
+      immediate: false,
+      handler() {
+        this.$nextTick(() => this.restoreSelection())
+      }
+    }
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        goodsName: null,
+        goodsType: null
+      },
+      // 商品分类字典
+      goodsTypeOptions: [],
+      // 总条数
+      total: 0,
+      // 数据
+      list: [],
+      selected: []
+    }
+  },
+  created() {
+    this.handleQuery();
+    this.getDicts("sys_integral_goods_type").then(response => {
+      this.goodsTypeOptions = response.data;
+    });
+  },
+  methods: {
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    resetQuery() {
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        goodsName: null,
+        goodsType: null
+      };
+      this.handleQuery();
+    },
+    getList() {
+      this.loading = true
+      getChooseIntegralGoodsList(this.queryParams).then(response => {
+        this.list = response.data.list
+        this.total = response.data.total
+        this.loading = false
+        // 列表加载后,根据传入的 goodsIds 自动选中
+        this.$nextTick(() => this.restoreSelection())
+      })
+    },
+    handleSelectionChange(selection) {
+      this.selected = selection
+    },
+    cancel() {
+      this.$emit('closeChoose')
+    },
+    submit() {
+      this.$emit('selectConfirm', this.selected)
+    },
+    // 恢复勾选状态
+    restoreSelection() {
+      const tableRef = this.$refs.integralGoodsTable
+      if (!tableRef || !Array.isArray(this.list) || !Array.isArray(this.goodsIds)) return
+      tableRef.clearSelection()
+      if (this.goodsIds.length === 0) return
+      const idsSet = new Set(this.goodsIds)
+      this.list.forEach(row => {
+        if (row && idsSet.has(row.goodsId)) {
+          tableRef.toggleRowSelection(row, true)
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.footer-button {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 40px;
+}
+</style>

+ 202 - 0
src/views/his/promotionalActive/ChoosePackageComponent.vue

@@ -0,0 +1,202 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px">
+      <el-form-item label="套餐包名称" prop="packageName">
+        <el-input
+          v-model="queryParams.packageName"
+          placeholder="请输入套餐包名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="套餐包别名" prop="secondName">
+        <el-input
+          v-model="queryParams.secondName"
+          placeholder="套餐包别名"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="套餐类型" prop="packageType">
+        <el-select v-model="queryParams.packageType" placeholder="请选择" clearable size="small">
+          <el-option
+            v-for="dict in packageTypeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="子类型" prop="packageSubType">
+        <el-select v-model="queryParams.packageSubType" placeholder="请选择子类型" clearable size="small">
+          <el-option
+            v-for="dict in packageSubTypeOptions"
+            :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-table border v-loading="loading" :data="list" @selection-change="handleSelectionChange" ref="packageTable" :row-key="'packageId'" :reserve-selection="true">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="封面图片" width="120" align="center">
+        <template slot-scope="scope">
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover"
+          >
+            <img slot="reference" :src="scope.row.packageImg" width="100">
+            <img :src="scope.row.packageImg" style="max-width: 150px;">
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column label="套餐包名称" align="center" prop="packageName"/>
+      <el-table-column label="套餐包别名" align="center" prop="secondName"/>
+      <el-table-column label="套餐类型" align="center" prop="packageTypeName"/>
+      <el-table-column label="子类型" align="center" prop="packageSubTypeName"/>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <div class="footer-button">
+      <el-button @click="cancel">取消</el-button>
+      <el-button type="primary" @click="submit">确定</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getChoosePackageList } from '@/api/his/package'
+
+export default {
+  name: "ChoosePackageComponent",
+  props: {
+    packageIds: {
+      type: Array,
+      default: () => []
+    }
+  },
+  activated() {
+    // keep-alive 激活时恢复选中
+    this.$nextTick(() => {
+      this.restoreSelection()
+    })
+  },
+  watch: {
+    // packageIds 变化时重新恢复选中
+    packageIds: {
+      immediate: false,
+      handler() {
+        this.$nextTick(() => this.restoreSelection())
+      }
+    }
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 列表参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        packageName: null,
+        secondName: null,
+        packageType: null,
+        packageSubType: null,
+      },
+      // 套餐类型字典
+      packageTypeOptions: [],
+      // 子类型字典
+      packageSubTypeOptions: [],
+      // 总条数
+      total: 0,
+      // 表格数据
+      list: [],
+      selected: [],
+    }
+  },
+  created() {
+    this.getDicts("sys_package_type").then(response => {
+      this.packageTypeOptions = response.data;
+    });
+    this.getDicts("sys_package_sub_type").then(response => {
+      this.packageSubTypeOptions = response.data;
+    });
+    this.getList();
+  },
+  methods: {
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    resetQuery() {
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        packageName: null,
+        secondName: null,
+        packageType: null,
+        packageSubType: null,
+      };
+      this.handleQuery();
+    },
+    getList() {
+      this.loading = true;
+      getChoosePackageList(this.queryParams).then(response => {
+        this.list = response.data.list
+        this.total = response.data.total
+        this.loading = false
+        // 列表加载后,根据传入的 packageIds 自动选中
+        this.$nextTick(() => this.restoreSelection())
+      })
+    },
+    handleSelectionChange(selection) {
+      this.selected = selection
+    },
+    cancel() {
+      this.$emit('closeChoose')
+    },
+    submit() {
+      this.$emit('selectConfirm', this.selected)
+    },
+    // 恢复勾选状态
+    restoreSelection() {
+      const tableRef = this.$refs.packageTable
+      if (!tableRef || !Array.isArray(this.list) || !Array.isArray(this.packageIds)) return
+      tableRef.clearSelection()
+      if (this.packageIds.length === 0) return
+      const idsSet = new Set(this.packageIds)
+      this.list.forEach(row => {
+        if (row && idsSet.has(row.packageId)) {
+          tableRef.toggleRowSelection(row, true)
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.footer-button {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 40px;
+}
+</style>

+ 689 - 0
src/views/his/promotionalActive/index.vue

@@ -0,0 +1,689 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px" @submit.native.prevent>
+      <el-form-item label="活动标题" prop="title">
+        <el-input v-model="queryParams.title"
+                  placeholder="请输入活动标题"
+                  clearable
+                  size="small"
+                  @keyup.enter.native="handleQuery" />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button type="primary"
+                   icon="el-icon-plus"
+                   size="mini"
+                   @click="handleAdd"
+                   v-has-permi="['his:promotionalActive:add']">新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="success"
+                   icon="el-icon-edit"
+                   size="mini"
+                   :disabled="single"
+                   @click="handleUpdate"
+                   v-has-permi="['his:promotionalActive:edit']">修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="danger"
+                   icon="el-icon-delete"
+                   size="mini"
+                   :disabled="multiple"
+                   @click="handleDelete"
+                   v-has-permi="['his:promotionalActive:remove']">删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange" border>
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="活动标题" align="center" prop="title" width="200" />
+      <el-table-column label="活动主题" align="center" prop="theme" width="250" >
+        <template slot-scope="scope">
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover"
+          >
+            <img slot="reference" :src="scope.row.theme" style="max-height: 80px; width: auto;">
+            <img :src="scope.row.theme" style="max-width: 150px; max-height: 150px; width: auto;">
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column label="活动内容" align="center" prop="content">
+        <template slot-scope="scope">
+          <div v-if="scope.row.content">
+            <el-image
+              v-for="(img, index) in parseImages(scope.row.content)"
+              :key="index"
+              style="width: 50px; height: 50px; margin-right: 5px; margin-bottom: 5px;"
+              :src="img"
+              :preview-src-list="parseImages(scope.row.content)"
+              fit="cover">
+            </el-image>
+          </div>
+          <span v-else>-</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createTime" width="100" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
+        <template slot-scope="scope">
+          <el-button size="mini"
+                     type="text"
+                     icon="el-icon-edit"
+                     @click="handleUpdate(scope.row)"
+                     v-has-permi="['his:promotionalActive:edit']">修改</el-button>
+          <el-button size="mini"
+                     type="text"
+                     icon="el-icon-delete"
+                     @click="handleDelete(scope.row)"
+                     v-has-permi="['his:promotionalActive:remove']">删除</el-button>
+          <el-button size="mini"
+                     type="text"
+                     icon="el-icon-view"
+                     v-has-permi="['his:promotionalActive:view']"
+                     @click="handleView(scope.row)">查看</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="1200px" append-to-body>
+      <el-form v-loading="formLoading" :model="form" ref="form" :rules="rules" label-width="110px">
+        <el-form-item label="活动标题" prop="title">
+          <el-input v-model="form.title" placeholder="请输入活动标题" clearable size="small" />
+        </el-form-item>
+        <el-form-item label="活动主题" prop="theme">
+          <ImageUpload v-model="form.theme" type="image" :limit="1" :width="150" :height="150"/>
+        </el-form-item>
+        <el-form-item label="活动内容" prop="content">
+          <ImageUpload v-model="form.content" type="image" :limit="3" :width="150" :height="150"/>
+        </el-form-item>
+        <el-form-item label="视频区" prop="videoList">
+          <el-button size="small" type="primary" @click="chooseCourseVideo">选取课程小节</el-button>
+          <el-table border width="100%" style="margin-top:5px;" :data="form.videoList">
+            <el-table-column label="所属课程" align="center" prop="courseName" />
+            <el-table-column label="小节名称" align="center" prop="courseVideoName"/>
+            <el-table-column label="视频文件名称" align="center" prop="videoName"/>
+            <el-table-column label="时长" align="center" prop="duration"/>
+            <el-table-column label="操作" align="center">
+              <template slot-scope="scope">
+                <el-button size="mini"
+                           type="text"
+                           icon="el-icon-delete"
+                           @click="handleCourseVideoDelete(scope.row)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-form-item>
+        <el-form-item label="问诊区" prop="doctorList">
+          <el-button size="small" type="primary" @click="chooseDoctor">选取问诊医生</el-button>
+          <el-table border width="100%" style="margin-top:5px;" :data="form.doctorList">
+            <el-table-column label="医生姓名" align="center" prop="doctorName" />
+            <el-table-column label="所属医院" align="center" prop="hospitalName"/>
+            <el-table-column label="所属科室" align="center" prop="deptName"/>
+            <el-table-column label="职称" align="center" prop="position"/>
+            <el-table-column label="操作" align="center">
+              <template slot-scope="scope">
+                <el-button size="mini"
+                           type="text"
+                           icon="el-icon-delete"
+                           @click="handleDoctorDelete(scope.row)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-form-item>
+        <el-form-item label="积分商品" prop="goodsList">
+          <el-button size="small" type="primary" @click="chooseGoods">选取商品</el-button>
+          <el-table border width="100%" style="margin-top:5px;" :data="form.goodsList">
+            <el-table-column label="商品名称" align="center" prop="goodsName" />
+            <el-table-column label="封面图片" align="center" prop="goodsImg">
+              <template slot-scope="scope">
+                <el-popover
+                  placement="right"
+                  title=""
+                  trigger="hover"
+                >
+                  <img slot="reference" :src="scope.row.goodsImg" width="100">
+                  <img :src="scope.row.goodsImg" style="max-width: 150px;">
+                </el-popover>
+              </template>
+            </el-table-column>
+            <el-table-column label="商品分类" align="center" prop="goodsTypeName"/>
+            <el-table-column label="商品价格" align="center" prop="cash"/>
+            <el-table-column label="所需积分" align="center" prop="integral"/>
+            <el-table-column label="库存" align="center" prop="stock"/>
+            <el-table-column label="操作" align="center">
+              <template slot-scope="scope">
+                <el-button size="mini"
+                           type="text"
+                           icon="el-icon-delete"
+                           @click="handleGoodsDelete(scope.row)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-form-item>
+        <el-form-item label="疗法包" prop="packageList">
+          <el-button size="small" type="primary" @click="choosePackage">选取疗法包</el-button>
+          <el-table border width="100%" style="margin-top:5px;" :data="form.packageList">
+            <el-table-column label="封面图片" width="120" align="center">
+              <template slot-scope="scope">
+                <el-popover
+                  placement="right"
+                  title=""
+                  trigger="hover"
+                >
+                  <img slot="reference" :src="scope.row.packageImg" width="100">
+                  <img :src="scope.row.packageImg" style="max-width: 150px;">
+                </el-popover>
+              </template>
+            </el-table-column>
+            <el-table-column label="疗法名称" align="center" prop="packageName" />
+            <el-table-column label="疗法别名" align="center" prop="secondName"/>
+            <el-table-column label="类型" align="center" prop="packageTypeName"/>
+            <el-table-column label="子类型" align="center" prop="packageSubTypeName"/>
+            <el-table-column label="操作" align="center">
+              <template slot-scope="scope">
+                <el-button size="mini"
+                           type="text"
+                           icon="el-icon-delete"
+                           @click="handlePackageDelete(scope.row)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary"
+                   @click="submitForm"
+                   :loading="addOrUpdating"
+                   :disabled="addOrUpdating">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog :title="videoDialog.title" :visible.sync="videoDialog.open" width="1200px" append-to-body>
+      <choose-course-video-component :videoIds="this.form.videoList.map(item => item.videoId)"
+                                     @closeChoose="closeChooseCourseVideo"
+                                     @selectConfirm="selectConfirmCourseVideo"/>
+    </el-dialog>
+
+    <el-dialog :title="doctorDialog.title" :visible.sync="doctorDialog.open" width="1200px" append-to-body>
+      <choose-doctor-component :doctorIds="this.form.doctorList.map(item => item.doctorId)"
+                              @closeChoose="closeChooseDoctor"
+                              @selectConfirm="selectConfirmDoctor"/>
+    </el-dialog>
+
+    <el-dialog :title="goodsDialog.title" :visible.sync="goodsDialog.open" width="1200px" append-to-body>
+      <choose-integral-goods-component :goodsIds="this.form.goodsList.map(item => item.goodsId)"
+                                      @closeChoose="closeChooseGoods"
+                                      @selectConfirm="selectConfirmGoods"/>
+    </el-dialog>
+
+    <el-dialog :title="packageDialog.title" :visible.sync="packageDialog.open" width="1200px" append-to-body>
+      <choose-package-component :packageIds="this.form.packageList.map(item => item.packageId)"
+                              @closeChoose="closeChoosePackage"
+                              @selectConfirm="selectConfirmPackage"/>
+    </el-dialog>
+
+    <el-drawer
+      :with-header="false"
+      size="75%"
+      :title="show.title"
+      :visible.sync="show.open" append-to-body>
+      <div v-if="show.data" v-loading="formLoading" class="detail-container">
+        <div class="detail-header">
+          <div class="detail-title">
+            {{ show.data.title || '查看详情' }}
+          </div>
+          <el-button type="text" icon="el-icon-close" @click="show.open=false"></el-button>
+        </div>
+
+        <el-card shadow="never" class="block-card">
+          <div slot="header" class="card-header">基本信息</div>
+          <el-descriptions :column="1" border size="small">
+            <el-descriptions-item label="活动标题">{{ show.data.title || '-' }}</el-descriptions-item>
+            <el-descriptions-item label="创建时间">{{ show.data.createTime || '-' }}</el-descriptions-item>
+            <el-descriptions-item label="活动主题">
+              <div class="theme-wrapper">
+                <img v-if="show.data.theme" :src="show.data.theme" class="theme-image" />
+                <span v-else>-</span>
+              </div>
+            </el-descriptions-item>
+            <el-descriptions-item label="活动内容">
+              <div v-if="show.data.content" class="image-gallery">
+                <el-image
+                  v-for="(img, index) in parseImages(show.data.content)"
+                  :key="index"
+                  :src="img"
+                  :preview-src-list="parseImages(show.data.content)"
+                  fit="cover"
+                  class="gallery-item"
+                />
+              </div>
+              <span v-else>-</span>
+            </el-descriptions-item>
+          </el-descriptions>
+        </el-card>
+
+        <el-card shadow="never" class="block-card">
+          <div slot="header" class="card-header">视频区</div>
+          <el-table v-if="(show.data.videoList || []).length" :data="show.data.videoList" border size="small">
+            <el-table-column label="所属课程" align="center" prop="courseName" />
+            <el-table-column label="小节名称" align="center" prop="courseVideoName"/>
+            <el-table-column label="视频文件名称" align="center" prop="videoName"/>
+            <el-table-column label="时长" align="center" prop="duration"/>
+          </el-table>
+          <span v-else>-</span>
+        </el-card>
+
+        <el-card shadow="never" class="block-card">
+          <div slot="header" class="card-header">问诊区</div>
+          <el-table v-if="(show.data.doctorList || []).length" :data="show.data.doctorList" border size="small">
+            <el-table-column label="医生姓名" align="center" prop="doctorName" />
+            <el-table-column label="所属医院" align="center" prop="hospitalName"/>
+            <el-table-column label="所属科室" align="center" prop="deptName"/>
+            <el-table-column label="职称" align="center" prop="position"/>
+          </el-table>
+          <span v-else>-</span>
+        </el-card>
+
+        <el-card shadow="never" class="block-card">
+          <div slot="header" class="card-header">积分商品</div>
+          <el-table v-if="(show.data.goodsList || []).length" :data="show.data.goodsList" border size="small">
+            <el-table-column label="商品名称" align="center" prop="goodsName" />
+            <el-table-column label="封面图片" align="center" prop="goodsImg">
+              <template slot-scope="scope">
+                <el-popover placement="right" title="" trigger="hover">
+                  <img slot="reference" :src="scope.row.goodsImg" class="thumb" />
+                  <img :src="scope.row.goodsImg" class="popover-img" />
+                </el-popover>
+              </template>
+            </el-table-column>
+            <el-table-column label="商品分类" align="center" prop="goodsTypeName"/>
+            <el-table-column label="商品价格" align="center" prop="cash"/>
+            <el-table-column label="所需积分" align="center" prop="integral"/>
+            <el-table-column label="库存" align="center" prop="stock"/>
+          </el-table>
+          <span v-else>-</span>
+        </el-card>
+
+        <el-card shadow="never" class="block-card">
+          <div slot="header" class="card-header">疗法包</div>
+          <el-table v-if="(show.data.packageList || []).length" :data="show.data.packageList" border size="small">
+            <el-table-column label="封面图片" width="120" align="center">
+              <template slot-scope="scope">
+                <el-popover placement="right" title="" trigger="hover">
+                  <img slot="reference" :src="scope.row.packageImg" class="thumb" />
+                  <img :src="scope.row.packageImg" class="popover-img" />
+                </el-popover>
+              </template>
+            </el-table-column>
+            <el-table-column label="疗法名称" align="center" prop="packageName" />
+            <el-table-column label="疗法别名" align="center" prop="secondName"/>
+            <el-table-column label="类型" align="center" prop="packageTypeName"/>
+            <el-table-column label="子类型" align="center" prop="packageSubTypeName"/>
+          </el-table>
+          <span v-else>-</span>
+        </el-card>
+      </div>
+    </el-drawer>
+  </div>
+</template>
+
+<script>
+import ChooseCourseVideoComponent from '@/views/his/promotionalActive/ChooseCourseVideoComponent.vue'
+import ChooseDoctorComponent from '@/views/his/promotionalActive/ChooseDoctorComponent.vue'
+import ChooseIntegralGoodsComponent from '@/views/his/promotionalActive/ChooseIntegralGoodsComponent.vue'
+import ChoosePackageComponent from '@/views/his/promotionalActive/ChoosePackageComponent.vue'
+import { add, update, list, get, del } from '@/api/his/promotionalActive'
+
+export default {
+  name: 'promotionalActive',
+  components: {
+    ChooseCourseVideoComponent,
+    ChooseDoctorComponent,
+    ChooseIntegralGoodsComponent,
+    ChoosePackageComponent
+  },
+  data() {
+    return {
+      loading: false,
+      single: true,
+      multiple: true,
+      ids: [],
+      showSearch: true,
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        title: null,
+      },
+      total: 0,
+      list: [],
+      title: '新增',
+      open: false,
+      form: {
+        id: null,
+        title: null,
+        theme: null,
+        content: null,
+        goodsList: [],
+        packageList: [],
+        doctorList: [],
+        videoList: [],
+      },
+      formLoading: false,
+      rules: {
+        title: [
+          { required: true, message: '请输入活动标题', trigger: 'blur' }
+        ],
+        theme: [
+          { required: true, message: '请上传活动主题', trigger: 'blur' }
+        ],
+        content: [
+          { required: true, message: '请上传活动内容', trigger: 'blur' }
+        ]
+      },
+      videoDialog: {
+        open: false,
+        title: '课程小节选择',
+      },
+      doctorDialog: {
+        open: false,
+        title: '问诊医生选择',
+      },
+      goodsDialog: {
+        open: false,
+        title: '积分商品选择',
+      },
+      packageDialog: {
+        open: false,
+        title: '疗法包选择',
+      },
+      addOrUpdating: false,
+      show: {
+        open: false,
+        title: '查看详情',
+      }
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    // 解析逗号分隔的图片URL字符串
+    parseImages(images) {
+      if (!images) return [];
+      return images.split(',').filter(img => img.trim() !== '');
+    },
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    resetQuery() {
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        title: null,
+      };
+      this.getList();
+    },
+    getList() {
+      this.loading = true
+      list(this.queryParams).then(response => {
+        this.list = response.rows
+        this.total = response.total
+        this.loading = false
+      })
+    },
+    handleAdd() {
+      this.reset()
+      this.open = true
+      this.addOrUpdating = false
+      this.title = '添加活动'
+    },
+    reset() {
+      this.form = {
+        id: null,
+        title: null,
+        theme: null,
+        content: null,
+        goodsList: [],
+        packageList: [],
+        doctorList: [],
+        videoList: [],
+      }
+      this.resetForm("form");
+    },
+    handleUpdate(row) {
+      const id = row.id || this.ids
+      this.reset()
+      this.formLoading = true
+      get(id).then(response => {
+        this.form = {
+          ...response.data,
+          goodsList: response.data.goodsList || [],
+          packageList: response.data.packageList || [],
+          doctorList: response.data.doctorList || [],
+          videoList: response.data.videoList || []
+        }
+        this.formLoading = false
+      })
+      this.open = true
+      this.addOrUpdating = false
+      this.title = '修改活动'
+    },
+    handleDelete(row) {
+      const ids = row.id || this.ids
+      this.$confirm('是否确认删除积分商品编号为"' + ids + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return del(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.multiple = !selection.length
+      this.single = selection.length !== 1
+    },
+    handleView(row) {
+      this.formLoading = true
+      this.show.open = true
+      get(row.id).then(response => {
+        this.show.data = {
+          ...response.data,
+          goodsList: response.data.goodsList || [],
+          packageList: response.data.packageList || [],
+          doctorList: response.data.doctorList || [],
+          videoList: response.data.videoList || []
+        }
+        this.formLoading = false
+      })
+    },
+    chooseCourseVideo() {
+      this.videoDialog.open = true
+    },
+    closeChooseCourseVideo() {
+      this.videoDialog.open = false
+    },
+    selectConfirmCourseVideo(data) {
+      this.form.videoList = []
+      data.forEach(item => {
+        this.form.videoList.push(item)
+      })
+      this.videoDialog.open = false
+    },
+    handleCourseVideoDelete(row) {
+      this.form.videoList.splice(this.form.videoList.indexOf(row), 1)
+    },
+    chooseDoctor() {
+      this.doctorDialog.open = true
+    },
+    closeChooseDoctor() {
+      this.doctorDialog.open = false
+    },
+    selectConfirmDoctor(data) {
+      this.form.doctorList = []
+      data.forEach(item => {
+        this.form.doctorList.push(item)
+      })
+      this.doctorDialog.open = false
+    },
+    handleDoctorDelete(row) {
+      this.form.doctorList.splice(this.form.doctorList.indexOf(row), 1)
+    },
+    chooseGoods() {
+      this.goodsDialog.open = true
+    },
+    closeChooseGoods() {
+      this.goodsDialog.open = false
+    },
+    selectConfirmGoods(data) {
+      this.form.goodsList = []
+      data.forEach(item => {
+        this.form.goodsList.push(item)
+      })
+      this.goodsDialog.open = false
+    },
+    handleGoodsDelete(row) {
+      this.form.goodsList.splice(this.form.goodsList.indexOf(row), 1)
+    },
+    choosePackage() {
+      this.packageDialog.open = true
+    },
+    closeChoosePackage() {
+      this.packageDialog.open = false
+    },
+    selectConfirmPackage(data) {
+      this.form.packageList = []
+      data.forEach(item => {
+        this.form.packageList.push(item)
+      })
+      this.packageDialog.open = false
+    },
+    handlePackageDelete(row) {
+      this.form.packageList.splice(this.form.packageList.indexOf(row), 1)
+    },
+    submitForm() {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          const params = {
+            id: this.form.id,
+            title: this.form.title,
+            theme: this.form.theme,
+            content: this.form.content,
+            goodsIds: this.form.goodsList.map(item => item.goodsId),
+            packageIds: this.form.packageList.map(item => item.packageId),
+            doctorIds: this.form.doctorList.map(item => item.doctorId),
+            videoIds: this.form.videoList.map(item => item.videoId),
+          }
+
+          this.addOrUpdating = true
+          if (this.form.id) {
+            update(params).then(res => {
+              this.msgSuccess("修改成功");
+              this.open = false
+              this.getList()
+            })
+            return
+          }
+
+          add(params).then(res => {
+            this.msgSuccess("新增成功");
+            this.open = false
+            this.getList()
+          })
+        }
+      })
+    },
+    cancel() {
+      this.open = false
+      this.reset()
+    }
+  }
+}
+</script>
+
+<style scoped>
+.detail-container {
+  padding: 12px 16px 20px;
+}
+
+.detail-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 4px 0 8px;
+  margin-bottom: 8px;
+  border-bottom: 1px solid #f0f0f0;
+}
+
+.detail-title {
+  font-size: 16px;
+  font-weight: 600;
+}
+
+.block-card {
+  margin-bottom: 12px;
+}
+
+.card-header {
+  font-weight: 600;
+}
+
+.theme-wrapper {
+  display: flex;
+  align-items: center;
+  min-height: 120px;
+}
+
+.theme-image {
+  max-width: 100%;
+  max-height: 240px;
+  width: auto;
+  display: block;
+}
+
+.image-gallery {
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.gallery-item {
+  width: 100px;
+  height: 100px;
+  margin-right: 8px;
+  margin-bottom: 8px;
+}
+
+.thumb {
+  max-height: 80px;
+  width: auto;
+}
+
+.popover-img {
+  max-width: 150px;
+  max-height: 150px;
+  width: auto;
+}
+</style>

+ 103 - 0
src/views/his/promotionalActive/stats.vue

@@ -0,0 +1,103 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="活动标题" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入活动标题"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="日期" prop="date">
+        <el-date-picker
+          v-model="queryParams.date"
+          type="datetimerange"s
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          value-format="yyyy-MM-dd"
+          clearable
+          size="small"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" :data="list" border>
+      <el-table-column label="活动标题" align="center" prop="title" />
+      <el-table-column label="首页浏览量" align="center" prop="homeViews" />
+      <el-table-column label="视频区点击量" align="center" prop="videoClick" />
+      <el-table-column label="问诊区点击量" align="center" prop="doctorClick"/>
+      <el-table-column label="产品区点击量" align="center" prop="goodsClick" />
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { list } from '@/api/his/promotionalActiveLog'
+
+export default {
+  name: 'promotionalActiveStats',
+  data() {
+    return {
+      showSearch: true,
+      loading: false,
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        name: null,
+        date: null,
+      },
+      total: 0,
+      list: null,
+    }
+  },
+  created() {
+    this.handleQuery()
+  },
+  methods: {
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    resetQuery() {
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        name: null,
+      }
+      this.handleQuery()
+    },
+    getList() {
+      this.loading = true
+      const params = {
+        ...this.queryParams,
+        startTime: this.queryParams.date && this.queryParams.date[0],
+        endTime: this.queryParams.date && this.queryParams.date[1],
+      }
+      list(params).then(response => {
+        this.list = response.rows
+        this.total = response.total
+        this.loading = false
+      })
+    },
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 352 - 0
src/views/his/statistics/afterSalesOrder.vue

@@ -0,0 +1,352 @@
+<template>
+    <div class="app-container">
+        <div class="app-content">
+             <div class="title">
+               售后订单统计
+            </div>
+           <el-form class="search-form" :inline="true" >
+            <el-form-item >
+              <el-select v-model="value" placeholder="请选择日期">
+                <el-option
+                  v-for="item in options"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value">
+                </el-option>
+              </el-select>
+            </el-form-item>
+            <el-form-item >
+              <treeselect :clearable="false"  v-model="deptId"  :options="deptOptions" :show-count="true" placeholder="请选择归属部门" />
+            </el-form-item>
+            <el-form-item>
+              <el-select filterable v-model="userIds" placeholder="请选择员工" clearable size="small">
+                  <el-option
+                    v-for="item in users"
+                    :key="item.userId"
+                    :label="item.nickName"
+                    :value="item.userId">
+                  </el-option>
+                </el-select>
+            </el-form-item>
+           <el-form-item label="下单日期" prop="createTime">
+                    <el-date-picker clearable size="small" style="width: 205.4px"
+                      v-model="dateRange"
+                      type="daterange"
+                      value-format="yyyy-MM-dd"
+                      start-placeholder="开始日期" end-placeholder="结束日期"
+                      >
+                    </el-date-picker>
+            </el-form-item>
+            <el-form-item>
+                <el-button type="cyan" icon="el-icon-search"   @click="afterSalesOrder">搜索</el-button>
+            </el-form-item>
+          </el-form>
+           <div class="data-box">
+              <div class="echart-box">
+                <div id="echart-customer"></div>
+              </div>
+              <div class="table-box">
+                    <el-button class="export" size="small"  @click="handleExport" >导出</el-button>
+                    <el-table
+                    :data="list"
+                    border
+                    :summary-method="getSummaries"
+                    show-summary
+                    max-height="500"
+                    style="width: 100%;">
+                    <el-table-column
+                      prop="nickName"
+                      label="员工姓名">
+                    </el-table-column>
+                    <el-table-column
+                      prop="orderCount"
+                      label="订单数">
+                    </el-table-column>
+                    <el-table-column
+                      prop="payPrice"
+                      label="订单金额">
+                    </el-table-column>
+  
+                  </el-table>
+              </div>
+          </div>
+        </div>
+  
+      </div>
+  </template>
+  
+  <script>
+  import { afterSalesOrder,exportAfterSalesOrder } from "@/api/company/statistics";
+  import { getUserListByDeptId} from "@/api/company/companyUser";
+  import echarts from 'echarts'
+  import resize from '../../dashboard/mixins/resize'
+  import { treeselect } from "@/api/company/companyDept";
+  import Treeselect from "@riophae/vue-treeselect";
+  import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+  
+  export default {
+  name: 'Index',
+  mixins: [resize],
+  components: { Treeselect },
+  watch: {
+  // 监听deptId
+  'deptId': 'currDeptChange'
+  },
+  data() {
+  return {
+   deptOptions:[],
+   deptId:undefined,
+   userIds:undefined,
+   users:[],
+   dateRange:[],
+   chart: null,
+   options: [{
+      value: '1',
+      label: '今天'
+    }, {
+      value: '2',
+      label: '昨天'
+    }, {
+      value: '3',
+      label: '本周'
+    }, {
+      value: '4',
+      label: '上周'
+    }, {
+      value: '5',
+      label: '本月'
+    }
+    , {
+      value: '6',
+      label: '上月'
+    }
+    , {
+      value: '7',
+      label: '本季度'
+    }
+    , {
+      value: '8',
+      label: '上季度'
+    }
+    , {
+      value: '9',
+      label: '本年'
+    }
+    , {
+      value: '10',
+      label: '上年'
+    }],
+    value: '5',
+    list:[],
+    dates:[],
+    orderCount:[],
+    payPrice:[],
+  
+  }
+  },
+  created() {
+  this.getTreeselect();
+  },
+  methods: {
+    currDeptChange(val){
+    console.log(val)
+    this.deptId=val;
+    this.getUserListByDeptId();
+  },
+  /** 查询部门下拉树结构 */
+  getTreeselect() {
+  var that=this;
+  treeselect().then((response) => {
+    this.deptOptions = response.data;
+    console.log(this.deptOptions)
+    if(response.data!=null&&response.data.length>0){
+      this.deptId=response.data[0].id;
+      that.afterSalesOrder()
+    }
+  });
+  },
+  handleExport(){
+    var data;
+    if(this.userIds!=undefined){
+        data={type:this.value,userIds:this.userIds+"",deptId:this.deptId}
+    }
+    else{
+        data={type:this.value,deptId:this.deptId}
+    }
+    if(this.dateRange){
+        data.startTime = this.dateRange[0];
+        data.endTime = this.dateRange[1];
+      }
+    exportAfterSalesOrder(data).then((response) => {
+        console.log(response)
+       this.download(response.msg);
+    });
+  
+  },
+  getUserListByDeptId() {
+    this.userIds=undefined;
+    var data={deptId:this.deptId};
+    getUserListByDeptId(data).then(response => {
+      this.users = response.data;
+  
+    });
+  },
+  afterSalesOrder(){
+      var data;
+      if(this.userIds!=undefined){
+          data={type:this.value,userIds:this.userIds+"",deptId:this.deptId}
+      }
+      else{
+          data={type:this.value,deptId:this.deptId}
+      }
+      if(this.dateRange){
+        data.startTime = this.dateRange[0];
+        data.endTime = this.dateRange[1];
+      }
+      afterSalesOrder(data).then((response) => {
+       this.list=response.list;
+       this.dates=response.dates;
+       this.orderCount=response.orderCount;
+       this.payPrice=response.payPrice;
+        setTimeout(() => {
+          this.initEchart();
+        }, 500);
+    });
+  },
+  initEchart(){
+    var option = {
+      tooltip: {
+          trigger: 'axis',
+          axisPointer: {            // 坐标轴指示器,坐标轴触发有效
+              type: 'shadow'        // 默认为直线,可选为:'line' | 'shadow'
+          }
+      },
+      legend: {
+          data: ['订单数', '订单金额' ]
+      },
+      grid: {
+          left: '3%',
+          right: '4%',
+          bottom: '3%',
+          containLabel: true
+      },
+      xAxis: [
+          {
+              type: 'category',
+              data: this.dates
+          }
+      ],
+      yAxis: [
+          {
+              type: 'value',
+              axisLabel:{
+                formatter:'{value}'
+              }
+          }
+      ],
+      series: [
+          {
+  
+              name: '订单数',
+              type: 'line',
+              emphasis: {
+                  focus: 'series'
+              },
+              data: this.orderCount
+          },
+          {
+  
+              name: '订单金额',
+              type: 'line',
+              emphasis: {
+                  focus: 'series'
+              },
+              data: this.payPrice
+          }
+  
+      ]
+    };
+    this.chart=echarts.init(document.getElementById("echart-customer"));
+    this.chart.setOption(option,true);
+  },
+   getSummaries(param) {
+    const { columns, data } = param;
+    const sums = [];
+    columns.forEach((column, index) => {
+      if (index === 0) {
+        sums[index] = '总计';
+        return;
+      }
+      const values = data.map(item => Number(item[column.property]));
+      if (!values.every(value => isNaN(value))) {
+        const total = values.reduce((prev, curr) => {
+          const value = Number(curr);
+          return !isNaN(value) ? prev + curr : prev;
+        }, 0);
+        sums[index] = total.toFixed(2);
+      } else {
+        sums[index] = '';
+      }
+    });
+  
+    return sums;
+  }
+  }
+  }
+  </script>
+  
+  <style lang="scss" scoped>
+  .app-container{
+  border: 1px solid #e6e6e6;
+  padding: 12px;
+  
+  .app-content{
+  background-color: white;
+  .title{
+    padding: 20px 30px 0px 30px;
+    font-size: 18px;
+    font-weight: bold;
+    color: black;
+  
+  }
+  .search-form{
+    margin: 20px 30px 0px 30px;
+  }
+  .data-box{
+    padding: 30px;
+    background-color:  rgb(255, 255, 255);
+    height: 100%;
+  
+    .echart-box{
+      margin: 0 auto;
+      text-align: center;
+    }
+    .el-select{
+      margin: 5px 10px;
+    }
+    .table-box{
+      margin-top: 15px;
+      .export{
+        float: right;
+        margin: 10px 0px;
+      }
+    }
+  }
+  }
+  }
+  #echart-customer{
+  width:100%;
+  height:320px
+  }
+  .vue-treeselect{
+  width: 217px;
+  height: 36px;
+  }
+  
+  </style>
+  <style>
+  .vue-treeselect__control{
+  display: block;
+  }
+  </style>
+  

+ 179 - 0
src/views/his/statistics/appOrderCountStats.vue

@@ -0,0 +1,179 @@
+<template>
+  <div class="app-container">
+    <div class="app-content">
+      <div class="title">App商城订单统计</div>
+      <el-form class="search-form" :inline="true">
+        <el-form-item>
+          <treeselect
+            :clearable="false"
+            v-model="companyId"
+            :options="deptOptions"
+            :show-count="true"
+            placeholder="请选择归属部门"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-select
+            filterable
+            v-model="companyUserId"
+            placeholder="请选择员工"
+            clearable
+            size="small"
+          >
+            <el-option
+              v-for="item in users"
+              :key="item.userId"
+              :label="item.nickName"
+              :value="item.userId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="下单日期">
+          <el-date-picker
+            clearable
+            size="small"
+            style="width: 205.4px"
+            v-model="dateRange"
+            type="daterange"
+            value-format="yyyy-MM-dd"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" icon="el-icon-search" @click="search">搜索</el-button>
+        </el-form-item>
+      </el-form>
+
+      <div class="data-box">
+        <div class="table-box">
+          <el-table
+            :data="tableData"
+            border
+            max-height="500"
+            style="width: 100%"
+          >
+            <el-table-column prop="totalOrderCount" label="订单总数" />
+            <el-table-column prop="fullPayOrderCount" label="全款支付订单数" />
+            <el-table-column prop="codOrderCount" label="物流代收支付订单数" />
+            <el-table-column prop="depositCodOrderCount" label="付定金的物流代收订单数" />
+            <el-table-column prop="noDepositCodOrderCount" label="0定金的物流代收订单数" />
+            <el-table-column prop="totalOrderAmount" label="订单总金额" />
+            <el-table-column prop="depositAmount" label="定金总金额" />
+            <el-table-column prop="codAmount" label="物流代收总金额" />
+          </el-table>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getAppOrderCount } from "@/api/company/statistics";
+import { getUserListByDeptId } from "@/api/company/companyUser";
+import { treeselect } from "@/api/company/companyDept";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "AppOrderCountStats",
+  components: { Treeselect },
+  watch: {
+    companyId: {
+      handler(newVal) {
+        if (newVal != null) {
+          this.companyUserId = null;
+          this.getUserListByDeptId();
+        } else {
+          this.users = [];
+          this.companyUserId = null;
+        }
+      }
+    }
+  },
+  data() {
+    return {
+      companyId: null,
+      companyUserId: null,
+      users: [],
+      deptOptions: [],
+      dateRange: [],
+      tableData: []
+    };
+  },
+  created() {
+    this.loadDeptTree();
+  },
+  methods: {
+    loadDeptTree() {
+      treeselect().then(response => {
+        this.deptOptions = response.data;
+        if (response.data && response.data.length > 0) {
+          this.companyId = response.data[0].id;
+        }
+      });
+    },
+
+    getUserListByDeptId() {
+      if (!this.companyId) return;
+      getUserListByDeptId({ deptId: this.companyId }).then(response => {
+        this.users = response.data || [];
+      });
+    },
+
+    search() {
+      const params = {
+        companyId: this.companyId,
+        companyUserId: this.companyUserId,
+        startTime: this.dateRange?.[0] || undefined,
+        endTime: this.dateRange?.[1] ? this.dateRange[1] + " 23:59:59" : undefined
+      };
+
+      getAppOrderCount(params).then(response => {
+        const vo = response.data;
+        this.tableData = vo ? [vo] : [];
+      });
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.app-container {
+  border: 1px solid #e6e6e6;
+  padding: 12px;
+
+  .app-content {
+    background-color: white;
+    .title {
+      padding: 20px 30px 0px 30px;
+      font-size: 18px;
+      font-weight: bold;
+      color: black;
+    }
+    .search-form {
+      margin: 20px 30px 0px 30px;
+    }
+    .data-box {
+      padding: 30px;
+      background-color: rgb(255, 255, 255);
+      height: 100%;
+
+      .table-box {
+        margin-top: 15px;
+      }
+    }
+  }
+}
+
+.vue-treeselect {
+  width: 217px;
+  height: 36px;
+}
+</style>
+
+<style>
+.vue-treeselect__control {
+  display: block;
+}
+</style>

+ 186 - 0
src/views/his/statistics/hisOrderCountStats.vue

@@ -0,0 +1,186 @@
+<template>
+  <div class="app-container">
+    <div class="app-content">
+      <div class="title">互联网医院订单统计</div>
+      <el-form class="search-form" :inline="true">
+        <el-form-item>
+          <treeselect
+            :clearable="false"
+            v-model="companyId"
+            :options="deptOptions"
+            :show-count="true"
+            placeholder="请选择归属部门"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-select
+            filterable
+            v-model="companyUserId"
+            placeholder="请选择员工"
+            clearable
+            size="small"
+          >
+            <el-option
+              v-for="item in users"
+              :key="item.userId"
+              :label="item.nickName"
+              :value="item.userId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="下单日期">
+          <el-date-picker
+            clearable
+            size="small"
+            style="width: 205.4px"
+            v-model="dateRange"
+            type="daterange"
+            value-format="yyyy-MM-dd"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" icon="el-icon-search" @click="search">搜索</el-button>
+        </el-form-item>
+      </el-form>
+
+      <div class="data-box">
+        <div class="table-box">
+          <el-table
+            :data="tableData"
+            border
+            max-height="500"
+            style="width: 100%"
+          >
+            <el-table-column prop="totalOrderCount" label="订单总数" />
+            <el-table-column prop="fullPayOrderCount" label="全款支付订单数" />
+            <el-table-column prop="codOrderCount" label="物流代收支付订单数" />
+            <el-table-column prop="depositCodOrderCount" label="付定金的物流代收订单数" />
+            <el-table-column prop="noDepositCodOrderCount" label="0定金的物流代收订单数" />
+            <el-table-column prop="totalOrderAmount" label="订单总金额" />
+            <el-table-column prop="depositAmount" label="定金总金额" />
+            <el-table-column prop="codAmount" label="物流代收总金额" />
+          </el-table>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getHisOrderCountStats } from "@/api/company/statistics";
+import { getUserListByDeptId } from "@/api/company/companyUser";
+import { treeselect } from "@/api/company/companyDept";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "HisOrderCountStats",
+  components: { Treeselect },
+  watch: {
+    // 监听 companyId 变化,自动重载员工列表
+    companyId: {
+      handler(newVal) {
+        if (newVal != null) {
+          this.companyUserId = null; // 清空已选员工
+          this.getUserListByDeptId();
+        } else {
+          this.users = [];
+          this.companyUserId = null;
+        }
+      },
+      immediate: false
+    }
+  },
+  data() {
+    return {
+      companyId: null,        // 销售公司(部门)ID
+      companyUserId: null,    // 销售人员(员工)ID
+      users: [],              // 员工列表
+      deptOptions: [],        // 部门树形数据
+      dateRange: [],          // 日期范围
+      tableData: []           // 表格数据
+    };
+  },
+  created() {
+    this.loadDeptTree();
+  },
+  methods: {
+    // 加载部门树
+    loadDeptTree() {
+      treeselect().then(response => {
+        this.deptOptions = response.data;
+        if (response.data && response.data.length > 0) {
+          // 默认选中第一个部门
+          this.companyId = response.data[0].id;
+          // 触发 watch 自动加载员工(无需手动调用)
+        }
+      });
+    },
+
+    // 根据 companyId 获取员工列表
+    getUserListByDeptId() {
+      if (!this.companyId) return;
+      getUserListByDeptId({ deptId: this.companyId }).then(response => {
+        this.users = response.data || [];
+      });
+    },
+
+    // 搜索统计
+    search() {
+      const params = {
+        companyId: this.companyId,
+        companyUserId: this.companyUserId,
+        startTime: this.dateRange?.[0] || undefined,
+        endTime: this.dateRange?.[1] ? this.dateRange[1] + " 23:59:59" : undefined
+      };
+
+      getHisOrderCountStats(params).then(response => {
+        const vo = response.data;
+        this.tableData = vo ? [vo] : [];
+      });
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.app-container {
+  border: 1px solid #e6e6e6;
+  padding: 12px;
+
+  .app-content {
+    background-color: white;
+    .title {
+      padding: 20px 30px 0px 30px;
+      font-size: 18px;
+      font-weight: bold;
+      color: black;
+    }
+    .search-form {
+      margin: 20px 30px 0px 30px;
+    }
+    .data-box {
+      padding: 30px;
+      background-color: rgb(255, 255, 255);
+      height: 100%;
+
+      .table-box {
+        margin-top: 15px;
+      }
+    }
+  }
+}
+
+.vue-treeselect {
+  width: 217px;
+  height: 36px;
+}
+</style>
+
+<style>
+.vue-treeselect__control {
+  display: block;
+}
+</style>

+ 326 - 104
src/views/his/storeOrder/order1.vue

@@ -292,6 +292,17 @@
         </el-select>
       </el-form-item>
 
+      <el-form-item label="所属小程序" prop="coursePlaySourceConfigId">
+        <el-select v-model="queryParams.coursePlaySourceConfigId" placeholder="请选择所属小程序" clearable size="small">
+          <el-option
+            v-for="dict in appMallOptions"
+            :key="dict.id"
+            :label="dict.name + '(' + dict.appid + ')'"
+            :value="dict.id"
+          />
+        </el-select>
+      </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>
@@ -433,16 +444,38 @@
             >创建erp</el-button>
           </el-tooltip>
         </el-col>
-        <!-- <el-col :span="1.5">
-          <el-tooltip content="批量推送erp" placement="top">
-            <el-tag
-              plain
-              size="mini"
-              effect="plain"
-            v-hasPermi="['his:storeOrder:createErpOrder']"
-          >创建erp</el-tag>
-          </el-tooltip>
-        </el-col> -->
+        <el-col :span="1.5">
+          <el-button
+            disabled
+            plain
+            type="primary"
+            size="mini"
+        >应付金额: {{ payPriceTotal}}</el-button>
+      </el-col>
+        <el-col :span="1.5">
+          <el-button
+            disabled
+            plain
+            type="primary"
+            size="mini"
+        >实付金额: {{payMoneyTotal}}</el-button>
+        </el-col>
+        <el-col :span="1.5">
+          <el-button
+            disabled
+            plain
+            type="primary"
+            size="mini"
+        >物流代收金额: {{payRemainTotal }}</el-button>
+        </el-col>
+        <el-col :span="1.5">
+          <el-button
+            disabled
+            plain
+            type="primary"
+            size="mini"
+        >订单量/金额: {{ total }}/{{payPriceTotal }}</el-button>
+        </el-col>
         <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
       </el-row>
       <el-tabs type="card" v-model="actName" @tab-click="handleClickX">
@@ -452,8 +485,8 @@
       <el-table ref="orderTable" height="500" v-loading="loading" border :data="orderList" @selection-change="handleSelectionChange"
         @sort-change="handleSortChange" :default-sort="{prop: 'createTime', order: 'descending'}">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="ERP电话" align="center" prop="erpPhone" v-if="SFDFopen && orderStatus!=null && orderStatus != 1"/>
-        <el-table-column label="ERP账号" align="center" prop="erpAccount" v-if="SFDFopen && orderStatus!=null && orderStatus != 1"/>
+        <el-table-column label="ERP电话" align="center" prop="erpPhone" width="120px" v-if="SFDFopen && orderStatus!=null && orderStatus != 1"/>
+        <el-table-column label="ERP账号" align="center" prop="erpAccount" width="120px" v-if="SFDFopen && orderStatus!=null && orderStatus != 1"/>
         <el-table-column label="处方单编号" align="center" prop="prescribeCode" width="180px"/>
         <el-table-column label="药品订单号" align="center" prop="orderCode" width="180px"/>
         <el-table-column label="所属公司" align="center" prop="companyName" />
@@ -464,6 +497,7 @@
           </template>
         </el-table-column>
         <el-table-column label="店铺名称" align="center" prop="storeName" />
+        <el-table-column label="小程序名称" align="center" prop="miniProgramName" width="120px" />
         <el-table-column label="就诊人" align="center" prop="patientName" />
         <el-table-column label="收货人" align="center" prop="userName" />
         <el-table-column label="套餐名称" align="center" prop="packageName" width="100px" sortable="custom" :sort-orders="['ascending', 'descending']">
@@ -492,6 +526,7 @@
         </el-table-column>
           <el-table-column label="下单时间" align="center" prop="createTime" width="180" />
         <el-table-column label="支付时间" align="center" prop="payTime" width="180" />
+        <el-table-column label="发货时间" align="center" prop="deliverySendTime" width="180" />
         <el-table-column label="订单状态" align="center" prop="status" >
           <template slot-scope="scope">
                 <dict-tag :options="orderOptions" :value="scope.row.status"/>
@@ -512,7 +547,7 @@
                 <dict-tag :options="deliveryPayStatusOptions" :value="scope.row.deliveryPayStatus"/>
           </template>
         </el-table-column>
-        <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right">
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="100px" fixed="right">
           <template slot-scope="scope">
               <el-button
                   size="mini"
@@ -523,6 +558,9 @@
           </template>
         </el-table-column>
       </el-table>
+      <div>
+        商品数量合计:{{ productInfo }}
+      </div>
       <pagination
         v-show="total>0"
         :total="total"
@@ -764,6 +802,50 @@
         >确认</el-button>
       </div>
     </el-dialog>
+
+    <!-- 导出字段选择对话框 -->
+    <el-dialog :title="exportFieldDialog.title" :visible.sync="exportFieldDialog.open" width="800px" append-to-body>
+      <div v-loading="exportFieldDialog.loading">
+        <div style="margin-bottom: 20px;">
+          <el-button type="primary" size="small" @click="selectAllFields">全选</el-button>
+          <el-button type="default" size="small" @click="unselectAllFields">全不选</el-button>
+          <el-button type="success" size="small" @click="selectDefaultFields">选择常用</el-button>
+        </div>
+        
+        <div class="field-selection-container">
+          <el-row :gutter="20">
+            <el-col :span="8" v-for="field in exportFieldOptions" :key="field.key">
+              <el-checkbox 
+                v-model="field.checked" 
+                :label="field.label"
+                style="margin-bottom: 12px; width: 100%;"
+              >
+                {{ field.label }}
+              </el-checkbox>
+            </el-col>
+          </el-row>
+        </div>
+        
+        <div class="field-count-info" style="margin-top: 20px; padding: 10px; background: #f5f7fa; border-radius: 4px;">
+          <i class="el-icon-info"></i>
+          <span v-if="getSelectedFieldsCount() > 0">
+            已选择 <span style="color: #409EFF; font-weight: bold;">{{ getSelectedFieldsCount() }}</span> 个字段
+          </span>
+          <span v-else style="color: #E6A23C; font-weight: bold;">
+            <i class="el-icon-warning"></i>
+            未选择任何字段,将导出所有字段
+          </span>
+        </div>
+      </div>
+      
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="cancelExportFieldDialog">取 消</el-button>
+        <el-button 
+          type="primary" 
+          @click="confirmExportFields"
+        >确认导出</el-button>
+      </div>
+    </el-dialog>
   </div>
 </template>
 
@@ -779,6 +861,7 @@ import { treeselect } from "@/api/company/companyDept";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 import { getTask } from "@/api/common";
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
 export default {
   name: "Order",
   components: { storeOrderDetails,Treeselect  },
@@ -788,6 +871,10 @@ export default {
   },
   data() {
     return {
+      productInfo:"",
+      payPriceTotal:"0",
+      payMoneyTotal:"0",
+      payRemainTotal:"0",
       // 新增排序相关数据
       currentSort: {
         prop: null,
@@ -897,6 +984,73 @@ export default {
       loading: true,
       // 导出遮罩层
       exportLoading: false,
+      // 导出字段选择弹窗
+      exportFieldDialog: {
+        open: false,
+        title: "选择导出字段",
+        loading: false
+      },
+      // 可选择的导出字段列表
+      exportFieldOptions: [
+        { key: 'orderCode', label: '订单号', checked: true },
+        { key: 'prescribeCode', label: '处方单号', checked: true },
+        { key: 'userId', label: '会员ID', checked: false },
+        { key: 'extendOrderId', label: '管易云订单号', checked: false },
+        { key: 'companyName', label: '所属公司', checked: true },
+        { key: 'companyUserNickName', label: '所属销售', checked: true },
+        { key: 'storeName', label: '店铺名称', checked: true },
+        { key: 'miniProgramName', label: '小程序名称', checked: true },
+        { key: 'orderType', label: '订单类型', checked: false },
+        { key: 'userName', label: '收货人姓名', checked: true },
+        { key: 'userPhone', label: '收货人电话', checked: true },
+        { key: 'userAddress', label: '详细地址', checked: true },
+        { key: 'totalPrice', label: '商品金额', checked: true },
+        { key: 'totalNum', label: '商品数量', checked: true },
+        { key: 'payPrice', label: '应付金额', checked: true },
+        { key: 'payMoney', label: '实付金额', checked: true },
+        { key: 'payRemain', label: '物流代收金额', checked: false },
+        { key: 'discountMoney', label: '优惠金额', checked: false },
+        { key: 'createTime', label: '下单时间', checked: true },
+        { key: 'payTime', label: '支付时间', checked: true },
+        { key: 'payType', label: '支付方式', checked: true },
+        { key: 'status', label: '订单状态', checked: true },
+        { key: 'refundTime', label: '退款时间', checked: false },
+        { key: 'deliverySendTime', label: '发货时间', checked: false },
+        { key: 'refundMoney', label: '退款金额', checked: false },
+        { key: 'deliveryCode', label: '快递公司编号', checked: false },
+        { key: 'deliveryName', label: '快递公司', checked: false },
+        { key: 'deliverySn', label: '快递单号', checked: false },
+        { key: 'remark', label: '备注', checked: false },
+        { key: 'deliveryPayStatus', label: '物流代收结算状态', checked: false },
+        { key: 'deliveryTime', label: '快递账单日期', checked: false },
+        { key: 'deliveryPayTime', label: '快递结算日期', checked: false },
+        { key: 'deliveryPayMoney', label: '物流结算费用', checked: false },
+        { key: 'deliveryStatus', label: '物流状态', checked: false },
+        { key: 'deliveryType', label: '物流跟踪状态', checked: false },
+        { key: 'packageName', label: '套餐名称', checked: true },
+        { key: 'packageSecondName', label: '套餐包别名', checked: false },
+        { key: 'orderBuyType', label: '订单购买类型', checked: false },
+        { key: 'channel', label: '公众号/渠道', checked: false },
+        { key: 'scheduleName', label: '档期归属', checked: false },
+        { key: 'tuiMoneyStatus', label: '推广佣金状态', checked: false },
+        { key: 'orderChannel', label: '渠道', checked: false },
+        { key: 'qwSubject', label: '企微主体', checked: false },
+        { key: 'cycle', label: '疗程天数', checked: false },
+        { key: 'followFrequency', label: '随访频率', checked: false },
+        { key: 'followCount', label: '随访次数', checked: false },
+        { key: 'patientName', label: '就诊人', checked: true },
+        { key: 'relation', label: '与本人关系', checked: false },
+        { key: 'user', label: '会员', checked: false },
+        { key: 'doctorName', label: '医生', checked: false },
+        { key: 'packageCateName', label: '套餐包分类', checked: false },
+        { key: 'age', label: '年龄', checked: false },
+        { key: 'sex', label: '性别', checked: false },
+        { key: 'erpPhone', label: 'ERP电话', checked: false },
+        { key: 'erpAccount', label: 'ERP账号', checked: false },
+        { key: 'source', label: '订单来源', checked: false }
+      ],
+      // 已选择的导出字段
+      selectedExportFields: [],
       // 选中数组
       ids: [],
       // 非单个禁用
@@ -981,6 +1135,7 @@ export default {
 		    source:null,
         companyId:null,
         companyIds:null,
+        coursePlaySourceConfigId:null,
       },
       // 表单参数
       form: {},
@@ -1000,6 +1155,7 @@ export default {
        storeOPtions:[],
        deliveryPayStatusOptions:[],
        deliveryStatusOptions:[],
+       appMallOptions:[],
     };
   },
   created() {
@@ -1064,6 +1220,7 @@ export default {
           this.deliveryStatusOptions = response.data;
     });
     this.getErpAccountList();
+    this.getAppMallOptions();
   },
   methods: {
     // 新增排序处理方法
@@ -1178,6 +1335,18 @@ export default {
       listOrder(this.queryParams).then(response => {
         this.orderList = response.rows;
         this.total = response.total;
+        if(this.total>0){
+          this.payPriceTotal = response.payPriceTotal;
+          this.payMoneyTotal = response.payMoneyTotal;
+          this.payRemainTotal = response.payRemainTotal;
+          this.productInfo = response.productInfo;
+        } else {
+          this.payPriceTotal = "0"
+          this.payMoneyTotal = "0"
+          this.payRemainTotal = "0"
+          this.productInfo = response.productInfo;
+        }
+        
         this.loading = false;
         
         if(response.msg == 'jnmy'){
@@ -1396,7 +1565,6 @@ export default {
           this.executeCreateErpOrder();
         });
       }
-      this.getList();
     },
 
     async executSetErpOrder() {
@@ -1447,6 +1615,7 @@ export default {
           this.$message.success('订单ERP账号设置成功');
           this.cancelErpAccountDialog();
           this.getErpAccountList(); // 刷新列表
+          this.getList();
         } else {
           this.$message.error(response.msg || 'ERP账号设置失败');
         }
@@ -1507,6 +1676,7 @@ export default {
           this.$message.success('ERP订单创建成功');
           this.cancelErpAccountDialog();
           this.getErpAccountList(); // 刷新列表
+          this.getList();
         } else {
           this.$message.error(response.msg || 'ERP订单创建失败');
         }
@@ -1798,59 +1968,6 @@ export default {
         this.storeOPtions = response.rows;
       });
     },
-    /** 查询订单列表 */
-    getList() {
-      this.loading = true;
-      if(this.payTypeArr.length>0){
-        this.queryParams.payType=this.payTypeArr.toString();
-      }
-      else{
-        this.queryParams.payType=null
-      }
-      if(this.scheduleIdArr.length>0){
-        this.queryParams.scheduleId=this.scheduleIdArr.toString();
-      }
-      else{
-        this.queryParams.scheduleId=null
-      }
-      if(this.buyTypeArr.length>0){
-        this.queryParams.orderBuyType=this.buyTypeArr.toString();
-      }
-      else{
-        this.queryParams.orderbuyType=null
-      }
-      if(this.channelArr.length>0){
-        this.queryParams.orderChannel=this.channelArr.toString();
-      }
-      else{
-        this.queryParams.orderChannel=null
-      }
-      if(this.qwSubjectArr.length>0){
-        this.queryParams.qwSubject=this.qwSubjectArr.toString();
-      }
-      else{
-        this.queryParams.qwSubject=null
-      }
-      if(this.companyIds && this.companyIds.length>1){
-        this.queryParams.companyIds = this.companyIds
-        this.queryParams.companyId = null;
-        this.queryParams.deptId = null;
-      } else {
-        this.queryParams.companyId = this.companyId
-        this.queryParams.companyIds = null;
-      }
-      listOrder(this.queryParams).then(response => {
-        this.orderList = response.rows;
-        this.total = response.total;
-        this.loading = false;
-        if(response.msg == 'jnmy'){
-          this.SFDFopen = true;
-        } else{
-          this.SFDFopen = false;
-        }
-      });
-
-    },
     // 取消按钮
     cancel() {
       this.open = false;
@@ -2125,64 +2242,154 @@ export default {
     },
     /** 导出按钮操作 */
     handleOrderExport() {
-		var that=this;
+      // 打开字段选择对话框
+      this.exportFieldDialog.open = true;
+    },
+    
+    // 导出字段选择相关方法
+    // 全选字段
+    selectAllFields() {
+      this.exportFieldOptions.forEach(field => {
+        field.checked = true;
+      });
+    },
+    
+    // 全不选字段
+    unselectAllFields() {
+      this.exportFieldOptions.forEach(field => {
+        field.checked = false;
+      });
+    },
+    
+    // 选择常用字段
+    selectDefaultFields() {
+      // 先全不选
+      this.unselectAllFields();
+      // 然后选择常用字段
+      const defaultFields = ['orderCode', 'prescribeCode', 'companyName', 'companyUserNickName', 
+                           'storeName', 'miniProgramName', 'userName', 'userPhone', 'userAddress', 'totalPrice', 
+                           'totalNum', 'payPrice', 'payMoney', 'createTime', 'payTime', 
+                           'payType', 'status', 'packageName', 'patientName'];
+      this.exportFieldOptions.forEach(field => {
+        if (defaultFields.includes(field.key)) {
+          field.checked = true;
+        }
+      });
+    },
+    
+    // 获取已选择字段数量
+    getSelectedFieldsCount() {
+      return this.exportFieldOptions.filter(field => field.checked).length;
+    },
+    
+    // 取消导出字段选择
+    cancelExportFieldDialog() {
+      this.exportFieldDialog.open = false;
+    },
+    
+    // 确认导出字段
+    confirmExportFields() {
+      // 获取已选择的字段
+      const selectedFieldsArray = this.exportFieldOptions.filter(field => field.checked);
+      
+      let selectedFields = '';
+      if (selectedFieldsArray.length === 0) {
+        // 如果没有选择任何字段,则导出全部字段(不传filter参数)
+        selectedFields = null;
+      } else {
+        // 如果选择了字段,则只导出选中的字段
+        selectedFields = selectedFieldsArray.map(field => field.key).join(',');
+      }
+      
+      // 关闭弹窗
+      this.exportFieldDialog.open = false;
+      
+      // 执行导出操作
+      this.doExportOrder(selectedFields);
+    },
+    
+    // 执行导出操作
+    doExportOrder(selectedFields) {
+      var that = this;
+      
+      // 处理查询参数
       if(this.payTypeArr.length>0){
         this.queryParams.payType=this.payTypeArr.toString();
-      }
-      else{
+      } else {
         this.queryParams.payType=null
       }
+      
       if(this.scheduleIdArr.length>0){
         this.queryParams.scheduleId=this.scheduleIdArr.toString();
-      }
-      else{
+      } else {
         this.queryParams.scheduleId=null
       }
+      
       if(this.buyTypeArr.length>0){
         this.queryParams.orderBuyType=this.buyTypeArr.toString();
-      }
-      else{
+      } else {
         this.queryParams.orderbuyType=null
       }
+      
       if(this.channelArr.length>0){
         this.queryParams.orderChannel=this.channelArr.toString();
-      }
-      else{
+      } else {
         this.queryParams.orderChannel=null
       }
+      
       if(this.qwSubjectArr.length>0){
         this.queryParams.qwSubject=this.qwSubjectArr.toString();
-      }
-      else{
+      } else {
         this.queryParams.qwSubject=null
       }
+      
       const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有订单数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportOrder2(queryParams);
-        }).then(response => {
-			console.log(response)
-		  if(response.code==200){
-			  console.log(response.msg)
-		  that.msgSuccess(response.msg);
-		  that.taskId=response.data;
-		  that.time=setInterval(function(){
-			//查订单
-			getTask(that.taskId).then(res => {
-			  if(res.data.status==1){
-				that.exportLoading = false;
-				clearTimeout(that.time)
-				that.time=null;
-				that.download(res.data.fileUrl);
-			  }
-			});
-		  },10000);
-                }
-        }).catch(() => {});
+      
+      // 根据是否选择字段显示不同的确认消息
+      let confirmMessage = '';
+      if (selectedFields === null) {
+        confirmMessage = '没有选择字段,将导出所有字段的订单数据,确认继续?';
+      } else {
+        const fieldCount = selectedFields.split(',').length;
+        confirmMessage = `确认导出选中的 ${fieldCount} 个字段的订单数据?`;
+      }
+      
+      this.$confirm(confirmMessage, "确认导出", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        
+        // 构建请求参数
+        const requestParams = {...queryParams};
+        // 只有当selectedFields不为null时才添加filter参数
+        if (selectedFields !== null) {
+          requestParams.filter = selectedFields;
+        }
+        
+        return exportOrder2(requestParams);
+      }).then(response => {
+        console.log(response)
+        if(response.code==200){
+          console.log(response.msg)
+          that.msgSuccess(response.msg);
+          that.taskId=response.data;
+          that.time=setInterval(function(){
+            //查订单
+            getTask(that.taskId).then(res => {
+              if(res.data.status==1){
+                that.exportLoading = false;
+                clearTimeout(that.time)
+                that.time=null;
+                that.download(res.data.fileUrl);
+              }
+            });
+          },10000);
+        }
+      }).catch(() => {
+        this.exportLoading = false;
+      });
     },
       /** 查询部门下拉树结构 */
     getTreeselect() {
@@ -2219,6 +2426,12 @@ export default {
           this.queryParams.deptId=val;
           this.getList();
     },
+    // 获取小程序选项列表
+    getAppMallOptions() {
+      getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+        this.appMallOptions = response.rows;
+      })
+    },
   }
 };
 </script>
@@ -2299,6 +2512,15 @@ export default {
   padding: 8px 0;
 }
 
+/* 表格布局优化 */
+.el-table {
+  min-width: 100%;
+  table-layout: fixed;
+}
+
+.el-table .el-table__body-wrapper {
+  overflow-x: auto;
+}
 
 .tip-text {
   display: flex;

+ 10 - 2
src/views/his/storeOrder/order2.vue

@@ -79,7 +79,6 @@
       </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="change"></el-date-picker>
         </el-form-item>
@@ -186,6 +185,7 @@ import { listPrescribe, getPrescribe, delPrescribe, addPrescribe, updatePrescrib
 import prescribeDetails from '../../components/his/prescribeDetails.vue';
 import {allList}from "@/api/company/company";
 import { getTask } from "@/api/common";
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
 export default {
   name: "Prescribe",
   components: { prescribeDetails },
@@ -255,7 +255,8 @@ export default {
         auditSTime:null,
         auditETime:null,
         doctorName:null,
-        orderStatus:null
+        orderStatus:null,
+        appId:null
       },
        actName:"10",
       // 表单参数
@@ -267,6 +268,7 @@ export default {
       prescribeType:[],
       orOptions:[],
       sexOptions:[],
+      appMallOptions:[],
     };
   },
   created() {
@@ -287,9 +289,15 @@ export default {
         this.orderStatusOptions = response.data;
       });
 
+    this.getAppMallOptions();
     this.getList();
   },
   methods: {
+    getAppMallOptions() {
+      getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+        this.appMallOptions = response.rows;
+      })
+    },
     getAllCompany() {
       allList().then(response => {
         this.companyList = response.rows;

+ 24 - 1
src/views/his/storePayment/index.vue

@@ -104,6 +104,16 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item> -->
+       <el-form-item label="所属小程序" prop="coursePlaySourceConfigId">
+         <el-select v-model="queryParams.coursePlaySourceConfigId" placeholder="请选择所属小程序" clearable size="small">
+           <el-option
+             v-for="dict in appMallOptions"
+             :key="dict.id"
+             :label="dict.name + '(' + dict.appid + ')'"
+             :value="dict.id"
+           />
+         </el-select>
+       </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="change"></el-date-picker>
       </el-form-item>
@@ -157,6 +167,7 @@
         </template>
       </el-table-column>
 
+      <el-table-column label="小程序名称" align="center" prop="miniProgramName" width="120px" />
       <el-table-column label="状态" align="center" prop="status">
         <template slot-scope="scope">
           <dict-tag :options="statusOptions" :value="scope.row.status"/>
@@ -213,6 +224,7 @@ import { listStorePayment, getStorePayment, delStorePayment, addStorePayment, up
 import { getTask } from "@/api/common";
 import storePayDetails from '../../components/his/storePayDetails.vue';
 import { getCompanyList } from "@/api/company/company";
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
 export default {
   name: "StorePayment",
   components: { storePayDetails },
@@ -251,6 +263,7 @@ export default {
       statusOptions: [],
       busineOptitons: [],
        actName:"10",
+      appMallOptions:[],
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -274,6 +287,7 @@ export default {
         storeId: null,
         businessCode:null,
         phone:null,
+        coursePlaySourceConfigId:null,
       },
       // 表单参数
       form: {},
@@ -299,6 +313,9 @@ export default {
     this.getDicts("sys_store_payment_share_status").then(response => {
       this.shareOptions = response.data;
     });
+    
+    // 获取小程序选项列表
+    this.getAppMallOptions();
   },
   methods: {
     handleClickX(tab, event) {
@@ -476,7 +493,13 @@ export default {
           },10000);
         }
         }).catch(() => {});
-    }
+    },
+    // 获取小程序选项列表
+    getAppMallOptions() {
+      getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+        this.appMallOptions = response.rows;
+      })
+    },
   }
 };
 </script>

+ 3 - 3
src/views/his/storeProduct/index.vue

@@ -836,9 +836,9 @@ export default {
         specType: [
          { required: true, message: "规格不能为空", trigger: "blur" }
        ],
-        storeId: [
-         { required: true, message: "所属店铺不能为空", trigger: "blur" }
-       ],
+       //  storeId: [
+       //   { required: true, message: "所属店铺不能为空", trigger: "blur" }
+       // ],
         productType: [
          { required: true, message: "商品类型不能为空", trigger: "blur" }
        ],

Vissa filer visades inte eftersom för många filer har ändrats