瀏覽代碼

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	package.json
Guos 1 月之前
父節點
當前提交
78e7b03c4a
共有 100 個文件被更改,包括 9983 次插入495 次删除
  1. 4 0
      .env.development
  2. 1 1
      .env.prod-bjzm
  3. 44 0
      .env.prod-cfryt
  4. 40 0
      .env.prod-fzbt
  5. 40 0
      .env.prod-gzzdy
  6. 4 0
      .env.prod-hat
  7. 44 0
      .env.prod-hsyy
  8. 40 0
      .env.prod-jnsyj
  9. 3 0
      .env.prod-myhk
  10. 6 3
      .env.prod-sft
  11. 4 0
      .env.prod-sxjz
  12. 4 0
      .env.prod-syysy
  13. 12 7
      .env.prod-ylrz
  14. 4 1
      .env.prod-yxj
  15. 3 0
      .gitignore
  16. 16 0
      Dockerfile
  17. 38 0
      nginx.conf
  18. 6 3
      package.json
  19. 53 0
      src/api/company/companyRedPacketBalanceLogs.js
  20. 4 4
      src/api/course/courseAnswerlogs.js
  21. 16 0
      src/api/course/coursePlaySourceConfig.js
  22. 14 5
      src/api/course/courseRedPacketLog.js
  23. 22 4
      src/api/course/courseWatchLog.js
  24. 17 0
      src/api/course/qw/courseWatchLog.js
  25. 7 0
      src/api/course/userCoursePeriod.js
  26. 34 0
      src/api/course/userVideo.js
  27. 8 0
      src/api/his/integralOrder.js
  28. 71 0
      src/api/his/redPacketConfig.js
  29. 9 0
      src/api/hisStore/storePayment.js
  30. 7 0
      src/api/hisStore/storeProduct.js
  31. 24 0
      src/api/live/live.js
  32. 10 0
      src/api/live/liveAfterSales.js
  33. 36 0
      src/api/live/liveData.js
  34. 8 0
      src/api/live/liveOrder.js
  35. 64 0
      src/api/live/mergedOrder.js
  36. 31 1
      src/api/login.js
  37. 53 0
      src/api/merchantAppConfig/merchantAppConfig.js
  38. 86 0
      src/api/qw/applyIpad.js
  39. 65 0
      src/api/qw/externalContactInfo.js
  40. 10 0
      src/api/qw/friendWelcome.js
  41. 9 0
      src/api/qw/qwIpadServer.js
  42. 4 4
      src/api/qw/sop.js
  43. 4 4
      src/api/qw/sopTemp.js
  44. 8 0
      src/api/qw/user.js
  45. 8 0
      src/api/system/user.js
  46. 二進制
      src/assets/logo/cfryt.png
  47. 二進制
      src/assets/logo/gzzdy_logo.png
  48. 二進制
      src/assets/logo/hsyy.png
  49. 二進制
      src/assets/logo/jnsyj.png
  50. 493 0
      src/components/City/indexZm.vue
  51. 139 0
      src/components/Editor/wangZm.vue
  52. 18 8
      src/store/modules/user.js
  53. 92 0
      src/utils/hsy.js
  54. 6 1
      src/utils/obs.js
  55. 83 0
      src/views/WechatLoginDialog.vue
  56. 318 0
      src/views/company/companyRedPacketBalanceLogs/index.vue
  57. 248 4
      src/views/components/course/userCourseCatalogDetails.vue
  58. 75 2
      src/views/components/his/integralOrderDetails.vue
  59. 25 13
      src/views/components/his/storeOrderDetails.vue
  60. 2 0
      src/views/components/his/storeOrderDetails2.vue
  61. 2313 0
      src/views/components/index/statisticsDashboard.vue
  62. 72 0
      src/views/components/index/welcomePage.vue
  63. 78 22
      src/views/course/courseAnswerlogs/index.vue
  64. 43 11
      src/views/course/courseFinishTemp/index.vue
  65. 266 4
      src/views/course/coursePlaySourceConfig/index.vue
  66. 165 45
      src/views/course/courseRedPacketLog/index.vue
  67. 38 2
      src/views/course/courseTrafficLog/index.vue
  68. 65 5
      src/views/course/courseTrafficLog/statistics.vue
  69. 86 22
      src/views/course/courseWatchLog/index.vue
  70. 97 2
      src/views/course/courseWatchLog/qw/statistics.vue
  71. 40 1
      src/views/course/courseWatchLog/statistics.vue
  72. 2 2
      src/views/course/fsCourseProductOrder/index.vue
  73. 195 5
      src/views/course/userCourse/index.vue
  74. 3 2
      src/views/course/userCourse/public.vue
  75. 106 29
      src/views/course/userCoursePeriod/statistics.vue
  76. 139 35
      src/views/course/videoResource/index.vue
  77. 9 1
      src/views/his/adv/index.vue
  78. 21 8
      src/views/his/company/index.vue
  79. 285 9
      src/views/his/integralOrder/index.vue
  80. 738 0
      src/views/his/merchantAppConfig/index.vue
  81. 15 4
      src/views/his/packageOrder/index.vue
  82. 423 0
      src/views/his/redPacketConfig/index.vue
  83. 143 142
      src/views/his/storeOrder/order1.vue
  84. 28 8
      src/views/his/user/indexProject.vue
  85. 22 0
      src/views/his/userIntegralLogs/index.vue
  86. 21 0
      src/views/hisStore/adv/index.vue
  87. 21 0
      src/views/hisStore/components/productAfterSalesOrder.vue
  88. 4 0
      src/views/hisStore/components/productOrder.vue
  89. 3 1
      src/views/hisStore/menu/index.vue
  90. 23 6
      src/views/hisStore/shippingTemplates/index.vue
  91. 1 1
      src/views/hisStore/store/audit.vue
  92. 12 7
      src/views/hisStore/store/index.vue
  93. 44 5
      src/views/hisStore/storeAfterSales/index.vue
  94. 1 0
      src/views/hisStore/storeCouponIssue/index.vue
  95. 40 12
      src/views/hisStore/storeOrder/healthStoreList.vue
  96. 70 26
      src/views/hisStore/storeOrder/index.vue
  97. 25 1
      src/views/hisStore/storePayment/index.vue
  98. 17 12
      src/views/hisStore/storeProduct/index.vue
  99. 1807 0
      src/views/hisStore/storeProduct/indexZm.vue
  100. 8 0
      src/views/hisStore/storeProductAudit/index.vue

+ 4 - 0
.env.development

@@ -26,6 +26,10 @@ VUE_APP_COS_REGION = ap-chongqing
 VUE_APP_VIDEO_LINE_1 = https://xfktcpv.ylrzcloud.com
 # 线路二地址
 VUE_APP_VIDEO_LINE_2 = https://xfkobs.ylrztop.com
+#火山云视频地址域名
+VUE_APP_VIDEO_URL = https://myhkvolcengine.ylrztop.com
+#火山云视频点播空间名
+VUE_APP_HSY_SPACE = myhk-2114522511
 
 
 VUE_APP_LIVE_WS_URL = ws://127.0.0.1:7114/ws

+ 1 - 1
.env.prod-bjzm

@@ -23,7 +23,7 @@ VUE_APP_COS_BUCKET = bjzmky-1323137866
 # 存储桶配置
 VUE_APP_COS_REGION = ap-chongqing
 # 线路一地址
-VUE_APP_VIDEO_LINE_1 = https://bjzmky-1323137866.cos.ap-chongqing.myqcloud.com
+VUE_APP_VIDEO_LINE_1 = http://bjzmkytcpv.ylrzcloud.com
 # 线路二地址
 VUE_APP_VIDEO_LINE_2 = https://bjzmobs.ylrztop.com
 

+ 44 - 0
.env.prod-cfryt

@@ -0,0 +1,44 @@
+# 页面标题
+VUE_APP_TITLE =赤峰润元堂
+# 首页菜单标题
+VUE_APP_TITLE_INDEX =赤峰润元堂
+# 公司名称
+VUE_APP_COMPANY_NAME =赤峰润元堂健康咨询有限公司
+# ICP备案号
+VUE_APP_ICP_RECORD =蒙ICP备2024019526号-1
+# ICP网站访问地址
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/cfryt.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 = cfryt-hw079058881
+# 存储桶配置
+VUE_APP_COS_BUCKET = ryt-1323137866
+# 存储桶配置
+VUE_APP_COS_REGION = ap-chongqing
+# 线路一地址
+VUE_APP_VIDEO_LINE_1 = https://ryttcpv.ylrzcloud.com
+# 线路二地址
+VUE_APP_VIDEO_LINE_2 = https://cfrytobs.ylrztop.com
+#火山云视频地址域名
+VUE_APP_VIDEO_URL = https://rytvolcengine.ylrztop.com
+#火山云视频点播空间名
+VUE_APP_HSY_SPACE = ryt-2114522511
+
+# 开发环境配置
+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-fzbt

@@ -0,0 +1,40 @@
+# 页面标题
+VUE_APP_TITLE =福州白兔管理系统
+# 首页菜单标题
+VUE_APP_TITLE_INDEX =福州白兔管理系统
+# 公司名称
+VUE_APP_COMPANY_NAME =福州高新区白兔健康咨询有限公司
+# ICP备案号
+VUE_APP_ICP_RECORD =闽ICP备2024081011号-3
+# ICP网站访问地址
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/myhk.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 = myhk-hw079058881
+# 存储桶配置
+VUE_APP_COS_BUCKET = myhk-1323137866
+# 存储桶配置
+VUE_APP_COS_REGION = ap-chongqing
+# 线路一地址
+VUE_APP_VIDEO_LINE_1 = https://myhktcpv.ylrzcloud.com
+# 线路二地址
+VUE_APP_VIDEO_LINE_2 = https://myhkobs.ylrztop.com
+
+# 开发环境配置
+ENV = 'production'
+
+# FS管理系统/开发环境
+VUE_APP_BASE_API = '/prod-api'
+
+#默认 1、会员 2、企微
+VUE_APP_COURSE_DEFAULT = 2
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 40 - 0
.env.prod-gzzdy

@@ -0,0 +1,40 @@
+# 页面标题
+VUE_APP_TITLE =郑多燕总管理系统
+# 首页菜单标题
+VUE_APP_TITLE_INDEX =郑多燕管理系统
+# 公司名称
+VUE_APP_COMPANY_NAME =广州郑多燕健康管理有限公司
+# ICP备案号
+VUE_APP_ICP_RECORD =粤ICP备2023104913号-7
+# ICP网站访问地址
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/gzzdy_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 = gzzdy1-hw079058881
+# 存储桶配置
+VUE_APP_COS_BUCKET = gzzdy1-1323137866
+# 存储桶配置
+VUE_APP_COS_REGION = ap-chongqing
+# 线路一地址
+VUE_APP_VIDEO_LINE_1 = https://gzzdytcpv.ylrzcloud.com
+# 线路二地址
+VUE_APP_VIDEO_LINE_2 = https://gzzdyobs.ylrztop.com
+
+# 开发环境配置
+ENV = 'development'
+
+# FS管理系统/开发环境
+VUE_APP_BASE_API = '/prod-api'
+
+#默认 1、会员 2、企微
+VUE_APP_COURSE_DEFAULT = 2
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 4 - 0
.env.prod-hat

@@ -26,6 +26,10 @@ VUE_APP_COS_REGION = ap-chongqing
 VUE_APP_VIDEO_LINE_1 = https://hattcpv.ylrzcloud.com
 # 线路二地址
 VUE_APP_VIDEO_LINE_2 = https://hatobs.ylrztop.com
+#火山云视频地址域名
+VUE_APP_VIDEO_URL = https://hatvolcengine.ylrztop.com
+#火山云视频点播空间名
+VUE_APP_HSY_SPACE = hat-2114522511
 
 # 开发环境配置
 ENV = 'development'

+ 44 - 0
.env.prod-hsyy

@@ -0,0 +1,44 @@
+# 页面标题
+VUE_APP_TITLE =河山医院
+# 首页菜单标题
+VUE_APP_TITLE_INDEX =河山医院
+# 公司名称
+VUE_APP_COMPANY_NAME =哈尔滨市河山医院有限公司
+# ICP备案号
+VUE_APP_ICP_RECORD =蒙ICP备2024019526号-1
+# ICP网站访问地址
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/hsyy.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 = hsyy-hw079058881
+# 存储桶配置
+VUE_APP_COS_BUCKET = heshanyy-1323137866
+# 存储桶配置
+VUE_APP_COS_REGION = ap-chongqing
+# 线路一地址
+VUE_APP_VIDEO_LINE_1 = https://heshanyytcpv.ylrzcloud.com
+# 线路二地址
+VUE_APP_VIDEO_LINE_2 = https://hsyyobs.ylrztop.com
+#火山云视频地址域名
+VUE_APP_VIDEO_URL = https://heshanyyvolcengine.ylrztop.com
+#火山云视频点播空间名
+VUE_APP_HSY_SPACE = heshanyy-2114522511
+
+# 开发环境配置
+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-jnsyj

@@ -0,0 +1,40 @@
+# 页面标题
+VUE_APP_TITLE =济南顺亿景SCRM管理系统
+# 首页菜单标题
+VUE_APP_TITLE_INDEX =济南顺亿景
+# 公司名称
+VUE_APP_COMPANY_NAME =济南顺亿景
+# ICP备案号
+VUE_APP_ICP_RECORD =蜀ICP备2024052643号
+# ICP网站访问地址
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/jnsyj.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 = jnsyj-hw079058881
+# 存储桶配置
+VUE_APP_COS_BUCKET = jnsyj-1323137866
+# 存储桶配置
+VUE_APP_COS_REGION = ap-chongqing
+# 线路一地址
+VUE_APP_VIDEO_LINE_1 = https://jnsyjtcpv.ylrzcloud.com
+# 线路二地址
+VUE_APP_VIDEO_LINE_2 = https://jnsyjobs.ylrztop.com
+
+# 开发环境配置
+ENV = 'development'
+
+# FS管理系统/开发环境
+VUE_APP_BASE_API = '/prod-api'
+
+#默认 1、会员 2、企微
+VUE_APP_COURSE_DEFAULT = 1
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 3 - 0
.env.prod-myhk

@@ -38,3 +38,6 @@ VUE_APP_COURSE_DEFAULT = 2
 
 # 路由懒加载
 VUE_CLI_BABEL_TRANSPILE_MODULES = true
+
+# 项目
+VUE_APP_PROJECT = 'myhk'

+ 6 - 3
.env.prod-sft

@@ -17,13 +17,16 @@ VUE_APP_OBS_SECRET_ACCESS_KEY = sbyeNJLbcYmH6copxeFP9pAoksM4NIT9Zw4x0SRX
 # 存储桶配置
 VUE_APP_OBS_SERVER = https://obs.cn-north-4.myhuaweicloud.com
 # 存储桶配置
-VUE_APP_OBS_BUCKET = sft-hw079058881
+#VUE_APP_COS_BUCKET = sft-1361917636
+VUE_APP_COS_BUCKET = cqsft-1323137866
 # 存储桶配置
-VUE_APP_COS_BUCKET = sft-1323137866
+VUE_APP_OBS_BUCKET = sft-hw079058881
 # 存储桶配置
 VUE_APP_COS_REGION = ap-chongqing
+
 # 线路一地址
-VUE_APP_VIDEO_LINE_1 = https://sfttcpv.ylrzcloud.com
+#VUE_APP_VIDEO_LINE_1 = https://video.sft12.cn
+VUE_APP_VIDEO_LINE_1 = https://cqsfttcpv.ylrzcloud.com
 # 线路二地址
 VUE_APP_VIDEO_LINE_2 = https://sftobs.ylrztop.com
 

+ 4 - 0
.env.prod-sxjz

@@ -26,6 +26,10 @@ VUE_APP_COS_REGION = ap-chongqing
 VUE_APP_VIDEO_LINE_1 = https://sxjztcpv.ylrzcloud.com
 # 线路二地址
 VUE_APP_VIDEO_LINE_2 = https://sxjzobs.ylrztop.com
+#火山云视频地址域名
+VUE_APP_VIDEO_URL = https://sxjzvolcengine.ylrztop.com
+#火山云视频点播空间名
+VUE_APP_HSY_SPACE = sxjz-2114522511
 
 # 开发环境配置
 ENV = 'development'

+ 4 - 0
.env.prod-syysy

@@ -26,6 +26,10 @@ VUE_APP_COS_REGION = ap-chongqing
 VUE_APP_VIDEO_LINE_1 = https://syysytcpv.ylrzcloud.com
 # 线路二地址
 VUE_APP_VIDEO_LINE_2 = https://syysyobs.ylrztop.com
+#火山云视频地址域名
+VUE_APP_VIDEO_URL = https://syysyvolcengine.ylrztop.com
+#火山云视频点播空间名
+VUE_APP_HSY_SPACE = syysy-2114522511
 
 # 开发环境配置
 ENV = 'development'

+ 12 - 7
.env.prod-ylrz

@@ -1,10 +1,10 @@
 #该文本用于打包测试平台
 # 页面标题
-VUE_APP_TITLE =云联融智互联网医院管理系统
+VUE_APP_TITLE =云联融智SCRM管理系统
 # 首页菜单标题
-VUE_APP_TITLE_INDEX =云联融智互联网医院
+VUE_APP_TITLE_INDEX =云联融智SCRM
 # 公司名称
-VUE_APP_COMPANY_NAME =云联融智科技有公司
+VUE_APP_COMPANY_NAME =云联融智科技有公司
 # ICP备案号
 VUE_APP_ICP_RECORD =
 # ICP网站访问地址
@@ -18,15 +18,15 @@ VUE_APP_OBS_SECRET_ACCESS_KEY = sbyeNJLbcYmH6copxeFP9pAoksM4NIT9Zw4x0SRX
 # 存储桶配置
 VUE_APP_OBS_SERVER = https://obs.cn-north-4.myhuaweicloud.com
 # 存储桶配置
-VUE_APP_OBS_BUCKET = jkj-hw079058881
+VUE_APP_OBS_BUCKET = myhk-hw079058881
 # 存储桶配置
-VUE_APP_COS_BUCKET = jkj-1323137866
+VUE_APP_COS_BUCKET = ylrz-1323137866
 # 存储桶配置
 VUE_APP_COS_REGION = ap-chongqing
 # 线路一地址
-VUE_APP_VIDEO_LINE_1 = https://jkjtcpv.ylrzcloud.com
+VUE_APP_VIDEO_LINE_1 = https://ylrztcpv.ylrzcloud.com
 # 线路二地址
-VUE_APP_VIDEO_LINE_2 = https://jkjobs.ylrztop.com
+VUE_APP_VIDEO_LINE_2 = https://myhkkobs.ylrztop.com
 
 # 开发环境配置
 ENV = 'production'
@@ -39,3 +39,8 @@ VUE_APP_COURSE_DEFAULT = 1
 
 # 路由懒加载
 VUE_CLI_BABEL_TRANSPILE_MODULES = true
+
+# 患者信息
+VUE_APP_PATIENT_INFO = '客户信息'
+# 添加病人
+VUE_APP_ADD_PATIENT = '添加信息'

+ 4 - 1
.env.prod-yxj

@@ -26,7 +26,10 @@ VUE_APP_COS_REGION = ap-chongqing
 VUE_APP_VIDEO_LINE_1 = https://yxjtcpv.ylrzcloud.com
 # 线路二地址
 VUE_APP_VIDEO_LINE_2 = https://whyxjobs.ylrztop.com
-
+#火山云视频地址域名
+VUE_APP_VIDEO_URL = https://whyxjvolcengine.ylrztop.com
+#火山云视频点播空间名
+VUE_APP_HSY_SPACE = whyxj-2114522511
 # 开发环境配置
 ENV = 'development'
 

+ 3 - 0
.gitignore

@@ -25,3 +25,6 @@ pnpm-debug.log*
 
 package-lock.json
 yarn.lock
+
+# AGENTS.md - 项目指导文档,不上传到远程仓库
+AGENTS.md

+ 16 - 0
Dockerfile

@@ -0,0 +1,16 @@
+
+
+#基于官方 NGINX 镜像部署(精简镜像)
+FROM nginx:alpine
+
+# 复制本地打包好的 dist 目录到 NGINX 静态资源目录
+COPY ./dist /usr/share/nginx/html
+
+# 替换 NGINX 默认配置(用我们自定义的 nginx.conf)
+COPY ./nginx.conf /etc/nginx/nginx.conf
+
+# 暴露容器端口(与 nginx.conf 中 listen 一致)
+#EXPOSE 80
+
+# 启动 NGINX(前台运行,避免容器启动后退出)
+CMD ["nginx", "-g", "daemon off;"]

+ 38 - 0
nginx.conf

@@ -0,0 +1,38 @@
+# nginx.conf
+worker_processes  5;
+
+events {
+    worker_connections  1024;
+}
+
+http {
+    include       mime.types;
+    default_type  application/octet-stream;
+    client_max_body_size 200m;
+    sendfile        on;
+    keepalive_timeout  65;
+
+    server {
+        listen       80;  # 容器内端口
+        server_name  localhost;
+
+        # 前端静态资源目录(对应容器内的 /usr/share/nginx/html)
+        root   /usr/share/nginx/html;
+        index  index.html;
+
+        # 关键:处理 VUE Router history 模式(避免刷新 404)
+        location / {
+            try_files $uri $uri/ /index.html;  # 所有路由指向 index.html
+        }
+
+        # 关键:反向代理 API(解决跨域,替换为你的真实后端地址)
+        location /prod-api/ {
+            proxy_pass http://192.168.58.159:7772/;  # 后端 API 地址(末尾加 / 避免路径拼接问题)
+            proxy_set_header Host $host;
+            proxy_set_header X-Real-IP $remote_addr;
+            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+            proxy_set_header X-Forwarded-Proto $scheme;  # 传递 HTTPS 协议
+        }
+
+     }
+}

+ 6 - 3
package.json

@@ -17,6 +17,7 @@
     "build:prod-cqtyt": "vue-cli-service build --mode prod-cqtyt",
     "build:prod-heyantang": "vue-cli-service build --mode prod-heyantang",
     "build:prod-bly": "vue-cli-service build --mode prod-bly",
+    "build:prod-fzbt": "vue-cli-service build --mode prod-fzbt",
     "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",
@@ -24,7 +25,6 @@
     "build:prod-knt2": "vue-cli-service build --mode prod-knt2",
     "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",
     "build:prod-sft": "vue-cli-service build --mode prod-sft",
     "build:prod-zsjk": "vue-cli-service build --mode prod-zsjk",
     "build:prod-lmjy": "vue-cli-service build --mode prod-lmjy",
@@ -50,6 +50,10 @@
     "build:prod-ddgy": "vue-cli-service build --mode prod-ddgy",
     "build:prod-yxj": "vue-cli-service build --mode prod-yxj",
     "build:prod-bjzm": "vue-cli-service build --mode prod-bjzm",
+    "build:prod-gzzdy": "vue-cli-service build --mode prod-gzzdy",
+    "build:prod-cfryt": "vue-cli-service build --mode prod-cfryt",
+    "build:prod-hsyy": "vue-cli-service build --mode prod-hsyy",
+    "build:prod-jnsyj": "vue-cli-service build --mode prod-jnsyj",
     "build:prod-shdn": "vue-cli-service build --mode prod-shdn",
     "preview": "node build/index.js --preview",
     "lint": "eslint --ext .js,.vue src"
@@ -118,14 +122,13 @@
     "@vue/cli-plugin-eslint": "4.4.6",
     "@vue/cli-service": "4.4.6",
     "babel-eslint": "10.1.0",
-    "baseline-browser-mapping": "^2.9.6",
     "chalk": "4.1.0",
     "connect": "3.6.6",
     "eslint": "7.15.0",
     "eslint-plugin-vue": "7.2.0",
     "lint-staged": "10.5.3",
+    "node-sass": "4.14.1",
     "runjs": "4.4.2",
-    "sass": "^1.96.0",
     "sass-loader": "8.0.2",
     "script-ext-html-webpack-plugin": "2.1.5",
     "svg-sprite-loader": "5.1.1",

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

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询企业红包余额记录列表
+export function listCompanyRedPacketBalanceLogs(query) {
+  return request({
+    url: '/company/companyRedPacketBalanceLogs/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询企业红包余额记录详细
+export function getCompanyRedPacketBalanceLogs(logsId) {
+  return request({
+    url: '/company/companyRedPacketBalanceLogs/' + logsId,
+    method: 'get'
+  })
+}
+
+// 新增企业红包余额记录
+export function addCompanyRedPacketBalanceLogs(data) {
+  return request({
+    url: '/company/companyRedPacketBalanceLogs',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改企业红包余额记录
+export function updateCompanyRedPacketBalanceLogs(data) {
+  return request({
+    url: '/company/companyRedPacketBalanceLogs',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除企业红包余额记录
+export function delCompanyRedPacketBalanceLogs(logsId) {
+  return request({
+    url: '/company/companyRedPacketBalanceLogs/' + logsId,
+    method: 'delete'
+  })
+}
+
+// 导出企业红包余额记录
+export function exportCompanyRedPacketBalanceLogs(query) {
+  return request({
+    url: '/company/companyRedPacketBalanceLogs/export',
+    method: 'get',
+    params: query
+  })
+}

+ 4 - 4
src/api/course/courseAnswerlogs.js

@@ -4,8 +4,8 @@ import request from '@/utils/request'
 export function listLogs(query) {
   return request({
     url: '/course/courseAnswerLog/list',
-    method: 'get',
-    params: query
+    method: 'post',
+    data: query
   })
 }
 
@@ -47,7 +47,7 @@ export function delLogs(logId) {
 export function exportLogs(query) {
   return request({
     url: '/course/courseAnswerLog/export',
-    method: 'get',
-    params: query
+    method: 'post',
+    data: query
   })
 }

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

@@ -31,6 +31,22 @@ export function update(data) {
   })
 }
 
+export function updateBindConfig(data) {
+  return request({
+    url: '/course/playSourceConfig/updateBindConfig',
+    method: 'put',
+    data: data
+  })
+}
+
+export function updateUnbindConfig(data) {
+  return request({
+    url: '/course/playSourceConfig/updateUnbindConfig',
+    method: 'put',
+    data: data
+  })
+}
+
 export function del(id) {
   return request({
     url: '/course/playSourceConfig/' + id,

+ 14 - 5
src/api/course/courseRedPacketLog.js

@@ -4,8 +4,17 @@ import request from '@/utils/request'
 export function listCourseRedPacketLog(query) {
   return request({
     url: '/course/courseRedPacketLog/list',
-    method: 'get',
-    params: query
+    method: 'POST',
+    data: query
+  })
+}
+
+// 查询短链课程看课记录列表
+export function listCourseRedPacketLogPage(data) {
+  return request({
+    url: '/course/courseRedPacketLog/pageList',
+    method: 'post',
+    data: data
   })
 }
 
@@ -55,10 +64,10 @@ export function delCourseRedPacketLog(logId) {
 }
 
 // 导出短链课程看课记录
-export function exportCourseRedPacketLog(query) {
+export function exportCourseRedPacketLog(data) {
   return request({
     url: '/course/courseRedPacketLog/export',
-    method: 'get',
-    params: query
+    method: 'post',
+    data: data
   })
 }

+ 22 - 4
src/api/course/courseWatchLog.js

@@ -4,8 +4,17 @@ import request from '@/utils/request'
 export function listCourseWatchLog(query) {
   return request({
     url: '/course/courseWatchLog/list',
-    method: 'get',
-    params: query
+    method: 'POST',
+    data: query
+  })
+}
+
+// 查询短链课程看课记录列表
+export function listCourseWatchLogPage(query) {
+  return request({
+    url: '/course/courseWatchLog/pageList',
+    method: 'post',
+    data: query
   })
 }
 
@@ -47,10 +56,19 @@ export function delCourseWatchLog(logId) {
 export function exportCourseWatchLog(query) {
   return request({
     url: '/course/courseWatchLog/export',
-    method: 'get',
-    params: query
+    method: 'post',
+    data: query
   })
 }
+//会员看课统计导出
+export function exportCourseWatchLogStatisticsExport(query) {
+  return request({
+    url: '/course/courseWatchLog/statisticsExport',
+    method: 'POST',
+    data: query
+  })
+}
+
 
 
 export function statisticsList(query) {

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

@@ -112,6 +112,15 @@ export function exportCourseWatchLog(query) {
   })
 }
 
+export function exportCourseWatchLogStatisticsExportQw(query) {
+  return request({
+    url: '/qw/course/courseWatchLog/statisticsExport',
+    method: 'POST',
+    data: query
+  })
+}
+
+
 export function watchLogStatisticsExport(query) {
   return request({
     url: '/qw/course/courseWatchLog/watchLogStatisticsExport',
@@ -126,3 +135,11 @@ export function listBytrainingCampId(query) {
     params: query
   })
 }
+
+export function getSignProjectName() {
+  return request({
+    url: '/qw/course/courseWatchLog/getSignProjectName',
+    method: 'get'
+  })
+}
+

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

@@ -148,6 +148,13 @@ export function periodCountSelect(data) {
   })
 }
 
+export function exportInfo(query) {
+  return request({
+    url: '/course/period/exportInfo',
+    method: 'post',
+    data: query
+  })
+}
 // 获取营期选项列表
 export function getPeriodListLikeName(query) {
   return request({

+ 34 - 0
src/api/course/userVideo.js

@@ -104,3 +104,37 @@ export function getThumbnail(file) {
     }
   });
 }
+
+
+//火山云视频上传
+export function uploadUserVideo(file,uploadId) {
+  const formData = new FormData();
+  formData.append('file', file);
+  formData.append('uploadId', uploadId)
+  return request({
+    url: '/course/userVideo/uploadUserVideo',
+    method: 'post',
+    data: formData,
+    headers: {
+      'Content-Type': 'multipart/form-data'
+    }
+  });
+}
+
+// 查询火山云视频上传进度
+export function getUploadProgress(uploadId) {
+  return request({
+    url: '/course/userVideo/uploadProgress',
+    method: 'get',
+    params: { uploadId }
+  });
+}
+
+export function HsyAssumeRoleService() {
+  return request({
+    url: '/course/userVideo/HsyAssumeRoleService',
+    method: 'get',
+  });
+}
+
+

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

@@ -132,4 +132,12 @@ export function getIntegralTemplate(){
     url: '/his/integralOrder/importUpdateOrderTemplate',
     method: 'get'
   })
+}
+
+// 获取订单操作记录
+export function getOrderLogs(orderId) {
+  return request({
+    url: '/his/logs/order/' + orderId,
+    method: 'get'
+  })
 }

+ 71 - 0
src/api/his/redPacketConfig.js

@@ -0,0 +1,71 @@
+import request from '@/utils/request'
+
+// 查询多商户配置列表
+export function listMore(query) {
+  return request({
+    url: '/redPacket/more/list',
+    method: 'get',
+    params: query
+  })
+}
+
+
+export function getRedPacketMchId(query) {
+  return request({
+    url: '/redPacket/more/getRedPacketConfig',
+    method: 'get',
+    params: query
+  })
+}
+
+
+// 查询多商户配置详细
+export function getMore(id) {
+  return request({
+    url: '/redPacket/more/' + id,
+    method: 'get'
+  })
+}
+
+// 新增多商户配置
+export function addMore(data) {
+  return request({
+    url: '/redPacket/more',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改多商户配置
+export function updateMore(data) {
+  return request({
+    url: '/redPacket/more',
+    method: 'put',
+    data: data
+  })
+}
+
+export function updateChangeMchId(data) {
+  return request({
+    url: '/redPacket/more/updateChangeMchId',
+    method: 'post',
+    data: data
+  })
+}
+
+// 删除多商户配置
+export function delMore(id) {
+  return request({
+    url: '/redPacket/more/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出多商户配置
+export function exportMore(query) {
+  return request({
+    url: '/redPacket/more/export',
+    method: 'get',
+    params: query
+  })
+}

+ 9 - 0
src/api/hisStore/storePayment.js

@@ -76,3 +76,12 @@ export function setPayNotify(data) {
     data: data
   })
 }
+
+//同步订单状态
+export function oneClickShipping(data) {
+  return request({
+    url: '/store/store/storePayment/oneClickShipping',
+    method: 'post',
+    data: data
+  })
+}

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

@@ -57,6 +57,13 @@ export function delStoreProduct(productId) {
     method: 'delete'
   })
 }
+// 复制商品
+export function copyStoreProduct(productId) {
+  return request({
+    url: '/store/store/storeProduct/copyStoreProduct?productId=' + productId,
+    method: 'get'
+  })
+}
 
 // 批量复制商品
 export function bulkCopy(productId) {

+ 24 - 0
src/api/live/live.js

@@ -134,3 +134,27 @@ export function copyLive(data) {
     params: data
   })
 }
+
+// 查询公司list
+export function getCompanyDropList() {
+  return request({
+    url: '/live/live/getCompanyDropList',
+    method: 'get'
+  })
+}
+
+// 根据公司查询主体list
+export function getQwCorpList(companyId) {
+  return request({
+    url: '/live/live/getQwCorpList/' + companyId,
+    method: 'get'
+  })
+}
+// 根据主体条件查询标签信息
+export function getTagsListByCorpId(qwTagGroup) {
+  return request({
+    url: '/live/live/getTagsListByCorpId',
+    method: 'get',
+    params:qwTagGroup
+  })
+}

+ 10 - 0
src/api/live/liveAfterSales.js

@@ -90,3 +90,13 @@ export function audit2(data) {
     data: data
   })
 }
+
+export function handleImmediatelyRefund(data) {
+  return request({
+    url: '/live/liveAfterSales/handleImmediatelyRefund',
+    method: 'post',
+    data: data
+  })
+}
+
+

+ 36 - 0
src/api/live/liveData.js

@@ -20,3 +20,39 @@ export function listLiveData(data) {
     data:data,
   })
 }
+
+export function getLiveDataDetailBySql(liveId) {
+  return request({
+    url: '/liveData/liveData/getLiveDataDetailBySql?liveId=' + liveId,
+    method: 'get'
+  })
+}
+
+export function getLiveUserDetailListBySql(liveId) {
+  return request({
+    url: '/liveData/liveData/getLiveUserDetailListBySql?liveId=' + liveId,
+    method: 'get'
+  })
+}
+
+export function getLiveDataDetailByServer(liveId) {
+  return request({
+    url: '/liveData/liveData/getLiveDataDetailByServer?liveId=' + liveId,
+    method: 'get'
+  })
+}
+
+export function getLiveUserDetailListByServer(liveId) {
+  return request({
+    url: '/liveData/liveData/getLiveUserDetailListByServer?liveId=' + liveId,
+    method: 'get'
+  })
+}
+
+// 导出直播间用户详情数据
+export function exportLiveUserDetail(liveId) {
+  return request({
+    url: '/liveData/liveData/exportLiveUserDetail?liveId=' + liveId,
+    method: 'get'
+  })
+}

+ 8 - 0
src/api/live/liveOrder.js

@@ -85,6 +85,14 @@ export function exportLiveOrderZm(query) {
     params: query
   })
 }
+export function exportZmNew(query) {
+  return request({
+    url: '/live/liveOrder/exportZmNew',
+    method: 'get',
+    params: query
+  })
+}
+
 
 export function getExpress(data) {
   return request({

+ 64 - 0
src/api/live/mergedOrder.js

@@ -0,0 +1,64 @@
+import request from '@/utils/request'
+
+// 查询合并订单列表
+export function listMergedOrder(query) {
+  return request({
+    url: '/order/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 导出合并订单
+export function exportMergedOrder(query) {
+  return request({
+    url: '/order/export',
+    method: 'get',
+    params: query
+  })
+}
+
+// 导出合并订单明细
+export function exportMergedOrderItems(query) {
+  return request({
+    url: '/order/exportItems',
+    method: 'get',
+    params: query
+  })
+}
+
+// 导出合并订单(明文)
+export function exportMergedOrderDetails(query) {
+  return request({
+    url: '/order/exportDetails',
+    method: 'get',
+    params: query
+  })
+}
+
+// 导出合并订单明细(明文)
+export function exportMergedOrderItemsDetails(query) {
+  return request({
+    url: '/order/exportItemsDetails',
+    method: 'get',
+    params: query
+  })
+}
+
+// 导出发货单
+export function exportMergedShipping(query) {
+  return request({
+    url: '/order/exportShipping',
+    method: 'get',
+    params: query
+  })
+}
+
+// 导入物流单号模板下载
+export function importDeliveryNoteExpressTemplate() {
+  return request({
+    url: '/order/importDeliveryNoteTemplate',
+    method: 'get'
+  })
+}
+

+ 31 - 1
src/api/login.js

@@ -50,4 +50,34 @@ export function getCodeImg() {
     method: 'get',
     timeout: 20000
   })
-}
+}
+
+export function getWechatQrCode(data) {
+  return request({
+    url: '/getWechatQrCode',
+    method: 'post',
+    data: data
+  })
+}
+
+export function checkWechatScan(ticket) {
+  return request({
+    url: '/checkWechatScan',
+    method: 'get',
+    params: { ticket }
+  })
+}
+
+export function checkIsNeedCheck(username, password, code, uuid) {
+  const data = {
+    username,
+    password,
+    code,
+    uuid
+  }
+  return request({
+    url: '/checkIsNeedCheck',
+    method: 'post',
+    data: data
+  })
+}

+ 53 - 0
src/api/merchantAppConfig/merchantAppConfig.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询商户应用配置列表
+export function listMerchantAppConfig(query) {
+  return request({
+    url: '/his/merchantAppConfig/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询商户应用配置详细
+export function getMerchantAppConfig(id) {
+  return request({
+    url: '/his/merchantAppConfig/' + id,
+    method: 'get'
+  })
+}
+
+// 新增商户应用配置
+export function addMerchantAppConfig(data) {
+  return request({
+    url: '/his/merchantAppConfig',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改商户应用配置
+export function updateMerchantAppConfig(data) {
+  return request({
+    url: '/his/merchantAppConfig',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除商户应用配置
+export function delMerchantAppConfig(id) {
+  return request({
+    url: '/his/merchantAppConfig/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出商户应用配置
+export function exportMerchantAppConfig(query) {
+  return request({
+    url: '/his/merchantAppConfig/export',
+    method: 'get',
+    params: query
+  })
+}

+ 86 - 0
src/api/qw/applyIpad.js

@@ -0,0 +1,86 @@
+import request from '@/utils/request'
+
+// 查询分配记录列表
+export function listRecords(query) {
+  return request({
+    url: '/qw/records/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询分配记录详细
+export function getRecords(id) {
+  return request({
+    url: '/qw/records/' + id,
+    method: 'get'
+  })
+}
+
+// 新增分配记录
+export function addRecords(data) {
+  return request({
+    url: '/qw/records',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改分配记录
+export function updateRecords(data) {
+  return request({
+    url: '/qw/records',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除分配记录
+export function delRecords(id) {
+  return request({
+    url: '/qw/records/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出分配记录
+export function exportRecords(query) {
+  return request({
+    url: '/qw/records/export',
+    method: 'get',
+    params: query
+  })
+}
+
+export function apply(applyCount) {
+  return request({
+    url: '/qw/records/apply',
+    method: 'get',
+    params: applyCount
+  })
+}
+// 新增分配记录
+//@PostMapping("/batchUpdate")
+// public AjaxResult batchUpdate(@RequestBody Long[] ids)
+//后端接收结构
+export function batchUpdate(data) {
+  return request({
+    url: '/qw/records/batchUpdate',
+    method: 'post',
+    data: data
+  })
+}
+// 获取服务器信息
+export function getServerInfo(id) {
+  return request({
+    url: '/qw/records/server/' + id,
+    method: 'get'
+  })
+}
+export function release(data) {
+  return request({
+    url: '/qw/records/release',
+    method: 'post',
+    data: data
+  })
+}

+ 65 - 0
src/api/qw/externalContactInfo.js

@@ -0,0 +1,65 @@
+import request from '@/utils/request'
+
+// 查询外部联系人信息表列表
+export function listExternalContactInfo(query) {
+  return request({
+    url: '/qw/externalContactInfo/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询外部联系人信息表详细
+export function getExternalContactInfo(id) {
+  return request({
+    url: '/qw/externalContactInfo/' + id,
+    method: 'get'
+  })
+}
+
+// 新增外部联系人信息表
+export function addExternalContactInfo(data) {
+  return request({
+    url: '/qw/externalContactInfo',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改外部联系人信息表
+export function updateExternalContactInfo(data) {
+  return request({
+    url: '/qw/externalContactInfo',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除外部联系人信息表
+export function delExternalContactInfo(id) {
+  return request({
+    url: '/qw/externalContactInfo/' + id,
+    method: 'delete'
+  })
+}
+export function editTalk(id) {
+  return request({
+    url: '/qw/externalContactInfo/editTalk/' + id,
+    method: 'put'
+  })
+}
+
+export function editAllTalk(id) {
+  return request({
+    url: '/qw/externalContactInfo/editAllTalk/' + id,
+    method: 'put'
+  })
+}
+// 导出外部联系人信息表
+export function exportExternalContactInfo(query) {
+  return request({
+    url: '/qw/externalContactInfo/export',
+    method: 'get',
+    params: query
+  })
+}

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

@@ -0,0 +1,10 @@
+import request from '@/utils/request'
+
+// 查询好友欢迎语列表
+export function listFriendWelcome(query) {
+  return request({
+    url: '/qw/friendWelcome/list',
+    method: 'get',
+    params: query
+  })
+}

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

@@ -50,4 +50,13 @@ export function exportQwIpadServer(query) {
     method: 'get',
     params: query
   })
+}
+
+// 新增ipad服务器
+export function release(data) {
+  return request({
+    url: '/qw/records/release',
+    method: 'post',
+    data: data
+  })
 }

+ 4 - 4
src/api/qw/sop.js

@@ -4,8 +4,8 @@ import request from '@/utils/request'
 export function listSop(query) {
   return request({
     url: '/qw/sop/list',
-    method: 'get',
-    params: query
+    method: 'post',
+    data: query
   })
 }
 // 查询企微sop模板列表
@@ -98,8 +98,8 @@ export function updateStatus(ids) {
 export function exportSop(query) {
   return request({
     url: '/qw/sop/export',
-    method: 'get',
-    params: query
+    method: 'post',
+    data: query
   })
 }
 

+ 4 - 4
src/api/qw/sopTemp.js

@@ -4,8 +4,8 @@ import request from '@/utils/request'
 export function listSopTemp(query) {
   return request({
     url: '/qw/sopTemp/list',
-    method: 'get',
-    params: query
+    method: 'post',
+    data: query
   })
 }
 // 查询sop模板列表
@@ -136,8 +136,8 @@ export function shareSopTemp(data) {
 export function exportSopTemp(query) {
   return request({
     url: '/qw/sopTemp/export',
-    method: 'get',
-    params: query
+    method: 'post',
+    data: query
   })
 }
 

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

@@ -264,3 +264,11 @@ export function selectCloudAP(data) {
     data: data
   })
 }
+
+export function getQwAllUserList(query) {
+  return request({
+    url: '/qw/user/getQwAllUserList',
+    method: 'get',
+    params: query
+  })
+}

+ 8 - 0
src/api/system/user.js

@@ -150,3 +150,11 @@ export function isAdmin() {
   })
 }
 
+export function unBind(userId) {
+  return request({
+    url: '/system/user/unBind',
+    method: 'post',
+    data: { userId: userId }
+  })
+}
+

二進制
src/assets/logo/cfryt.png


二進制
src/assets/logo/gzzdy_logo.png


二進制
src/assets/logo/hsyy.png


二進制
src/assets/logo/jnsyj.png


+ 493 - 0
src/components/City/indexZm.vue

@@ -0,0 +1,493 @@
+<template>
+  <el-dialog :close-on-click-modal="false"
+             :visible.sync="addressView"
+             append-to-body
+             class="modal"
+             title="选择城市" width="950px">
+    <el-row :gutter="24" type="flex">
+      <el-col :xl="24" :lg="24" :md="24" :sm="24" :xs="24" class="item">
+        <div class="check-btn">
+          <el-checkbox v-model="iSselect" @change="allCheckbox">全选</el-checkbox>
+          <div class="empty" @click="empty">清空</div>
+        </div>
+      </el-col>
+    </el-row>
+    <el-row  :gutter="24"  :loading="loading" >
+      <el-col  :xl="6" :lg="6" :md="6" :sm="8" :xs="6" class="item"  v-for="(item,index) in cityList" :key="index">
+        <div @mouseenter="enter(index)" @mouseleave="leave()" v-if="item.level==1">
+          <el-checkbox
+            v-model="item.checked"
+            :label="item.cityName"
+            :disabled="item.disabled"
+            @change="checkedClick(index)"
+            :class="{ 'disabled-checkbox': item.disabled }"
+          >{{item.cityName}}</el-checkbox>
+          <div class="city" v-show="activeCity===index">
+            <div class="checkBox">
+              <div class="arrow"></div>
+              <div>
+                <el-checkbox
+                  v-model="subitem.checked"
+                  :label="subitem.cityName"
+                  :disabled="subitem.disabled"
+                  @change="primary(index,subindex)"
+                  class="itemn"
+                  v-for="(subitem,subindex) in item.children"
+                  :key="subindex"
+                  :class="{ 'disabled-checkbox': subitem.disabled }"
+                >{{subitem.cityName}}</el-checkbox>
+              </div>
+            </div>
+          </div>
+        </div>
+      </el-col>
+    </el-row>
+    <div slot="footer">
+      <el-button @click="close">取消</el-button>
+      <el-button type="primary" @click="confirm">确定</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import {getAllList} from "@/api/hisStore/city";
+
+export default {
+  name: 'CityZm',
+  props: {
+    type: {
+      type: Number,
+      default: 0
+    },
+    selectedCities: {
+      type: Array,
+      default: () => []
+    }
+  },
+  data() {
+    return {
+      iSselect: false,
+      addressView: false,
+      cityList: [],
+      activeCity: -1,
+      loading: false
+    }
+  },
+  methods: {
+    enter(index) {
+      this.activeCity = index;
+    },
+    leave() {
+      this.activeCity = null;
+    },
+    getCityList() {
+      this.loading = true;
+      getAllList().then(res => {
+        this.loading = false;
+        console.log(res.data)
+        var data = res.data;
+        this.cityList = data.filter(item => item.level === 1)
+
+        this.cityList.forEach((item, index, arr) => {
+          // 加载市的数据
+          var subData = data.filter(subitem => subitem.parentId === item.cityId && subitem.level === 2)
+          console.log(subData)
+          item.children = subData;
+
+          // 加载县的数据到每个市下
+          item.children.forEach((city, cityIndex) => {
+            var countyData = data.filter(county => county.parentId === city.cityId && county.level === 3);
+            if (countyData && countyData.length > 0) {
+              city.children = countyData;
+            }
+          });
+
+          // 标记已选择的城市
+          this.markSelectedCities(item);
+        });
+      })
+    },
+    // 标记已选择的城市为禁用状态
+    markSelectedCities(province) {
+      let that = this;
+      if (!that.selectedCities || that.selectedCities.length === 0) {
+        return;
+      }
+
+      // 检查是否选择了整个省(children为空数组或不存在)
+      let selectedProvince = that.selectedCities.find(city => {
+        if (city.cityId === province.cityId) {
+          // 如果没有children属性,或者children是空数组,说明选择了整个省
+          return !city.children || city.children.length === 0;
+        }
+        return false;
+      });
+
+      if (selectedProvince) {
+        // 整个省已选择,禁用省和所有市
+        that.$set(province, 'disabled', true);
+        if (province.children && province.children.length > 0) {
+          province.children.forEach((city, cityIndex) => {
+            that.$set(province.children[cityIndex], 'disabled', true);
+            // 如果市下有县,也禁用所有县
+            if (city.children && city.children.length > 0) {
+              city.children.forEach((county, countyIndex) => {
+                that.$set(province.children[cityIndex].children[countyIndex], 'disabled', true);
+              });
+            }
+          });
+        }
+      } else {
+        // 检查是否有部分市被选择
+        let selectedCityMap = new Map(); // 存储已选择的市及其县信息
+        that.selectedCities.forEach(selectedCity => {
+          if (selectedCity.cityId === province.cityId && selectedCity.children && selectedCity.children.length > 0) {
+            // 该省下有选择的市
+            selectedCity.children.forEach(child => {
+              if (!selectedCityMap.has(child.cityId)) {
+                selectedCityMap.set(child.cityId, new Set());
+              }
+              // 如果市下有选择的县,记录县的ID
+              if (child.children && child.children.length > 0) {
+                child.children.forEach(county => {
+                  selectedCityMap.get(child.cityId).add(county.cityId);
+                });
+              }
+            });
+          }
+        });
+
+        if (selectedCityMap.size > 0) {
+          // 检查该省下所有市是否都被选择
+          let allCitiesSelected = true;
+          if (province.children && province.children.length > 0) {
+            province.children.forEach(city => {
+              if (!selectedCityMap.has(city.cityId)) {
+                allCitiesSelected = false;
+              }
+            });
+          } else {
+            allCitiesSelected = false;
+          }
+
+          // 如果所有市都被选择,禁用整个省
+          if (allCitiesSelected) {
+            that.$set(province, 'disabled', true);
+          }
+
+          // 标记已选择的市为禁用,并检查市下的县
+          if (province.children && province.children.length > 0) {
+            province.children.forEach((city, cityIndex) => {
+              if (selectedCityMap.has(city.cityId)) {
+                // 该市已被选择
+                let selectedCountyIds = selectedCityMap.get(city.cityId);
+
+                // 检查是否选择了整个市(没有选择具体的县,或者县列表为空)
+                let citySelectedData = null;
+                that.selectedCities.forEach(selectedCity => {
+                  if (selectedCity.cityId === province.cityId && selectedCity.children) {
+                    let foundCity = selectedCity.children.find(c => c.cityId === city.cityId);
+                    if (foundCity && (!foundCity.children || foundCity.children.length === 0)) {
+                      citySelectedData = foundCity;
+                    }
+                  }
+                });
+
+                if (citySelectedData) {
+                  // 选择了整个市,禁用该市和所有县
+                  that.$set(province.children[cityIndex], 'disabled', true);
+                  if (city.children && city.children.length > 0) {
+                    city.children.forEach((county, countyIndex) => {
+                      that.$set(province.children[cityIndex].children[countyIndex], 'disabled', true);
+                    });
+                  }
+                } else if (city.children && city.children.length > 0 && selectedCountyIds.size > 0) {
+                  // 检查该市下所有县是否都被选择
+                  let allCountiesSelected = true;
+                  city.children.forEach(county => {
+                    if (!selectedCountyIds.has(county.cityId)) {
+                      allCountiesSelected = false;
+                    }
+                  });
+
+                  // 如果所有县都被选择,禁用该市
+                  if (allCountiesSelected) {
+                    that.$set(province.children[cityIndex], 'disabled', true);
+                  }
+
+                  // 标记已选择的县为禁用
+                  city.children.forEach((county, countyIndex) => {
+                    if (selectedCountyIds.has(county.cityId)) {
+                      that.$set(province.children[cityIndex].children[countyIndex], 'disabled', true);
+                    }
+                  });
+                } else {
+                  // 选择了整个市(没有县的数据或没有选择县),禁用该市
+                  that.$set(province.children[cityIndex], 'disabled', true);
+                }
+              }
+            });
+          }
+        }
+      }
+    },
+    /**
+     * 全选或者反选
+     * @param checked
+     */
+    allCheckbox: function () {
+      let that = this, checked = this.iSselect;
+      that.cityList.forEach(function (item, key) {
+        // 跳过已禁用的省
+        if (item.disabled) {
+          return;
+        }
+        that.$set(that.cityList[key], 'checked', checked);
+        if (checked) {
+          // 只计算未禁用的市的数量
+          let enabledCount = that.cityList[key].children.filter(city => !city.disabled).length;
+          that.$set(that.cityList[key], 'count', enabledCount);
+        } else {
+          that.$set(that.cityList[key], 'count', 0);
+        }
+        that.cityList[key].children.forEach(function (val, k) {
+          // 跳过已禁用的市
+          if (!val.disabled) {
+            that.$set(that.cityList[key].children[k], 'checked', checked);
+          }
+        })
+      });
+    },
+    // 清空;
+    empty() {
+      let that = this;
+      that.cityList.forEach(function (item, key) {
+        // 跳过已禁用的省
+        if (item.disabled) {
+          return;
+        }
+        that.$set(that.cityList[key], 'checked', false);
+        that.cityList[key].children.forEach(function (val, k) {
+          // 跳过已禁用的市
+          if (!val.disabled) {
+            that.$set(that.cityList[key].children[k], 'checked', false);
+          }
+        });
+        that.$set(that.cityList[key], 'count', 0);
+      });
+      this.iSselect = false;
+    },
+    /**
+     * 点击省
+     * @param index
+     */
+    checkedClick: function (index) {
+      let that = this;
+      // 如果省被禁用,不允许操作
+      if (that.cityList[index].disabled) {
+        return;
+      }
+      if (that.cityList[index].checked) {
+        // 只选择未禁用的市
+        let enabledCount = 0;
+        that.cityList[index].children.forEach(function (item, key) {
+          if (!item.disabled) {
+            that.$set(that.cityList[index].children[key], 'checked', true);
+            enabledCount++;
+          }
+        });
+        that.$set(that.cityList[index], 'count', enabledCount);
+      } else {
+        that.$set(that.cityList[index], 'count', 0);
+        that.$set(that.cityList[index], 'checked', false);
+        that.cityList[index].children.forEach(function (item, key) {
+          // 只取消未禁用的市的选中状态
+          if (!item.disabled) {
+            that.$set(that.cityList[index].children[key], 'checked', false);
+          }
+        });
+        that.iSselect = false;
+      }
+    },
+    /**
+     * 点击市区
+     * @param index
+     * @param ind
+     */
+    primary: function (index, ind) {
+      // 如果市被禁用,不允许操作
+      if (this.cityList[index].children[ind].disabled) {
+        return;
+      }
+      let checked = false, count = 0;
+      this.cityList[index].children.forEach(function (item, key) {
+        console.log("item:" + item.checked)
+        if (item.checked) {
+          checked = true;
+          count++;
+        }
+      });
+      this.$set(this.cityList[index], 'count', count);
+      this.$set(this.cityList[index], 'checked', checked);
+    },
+    // 确定;
+    confirm() {
+      let that = this;
+      // 被选中的省市;
+      let selectList = [];
+      that.cityList.forEach(function (item, key) {
+        // 跳过已禁用的省
+        if (item.disabled) {
+          return;
+        }
+        let data = {};
+        if (item.checked) {
+          data = {
+            name: item.cityName,
+            cityId: item.cityId,
+            children: []
+          };
+
+        }
+        that.cityList[key].children.forEach(function (i, k) {
+          // 只添加未禁用且选中的市
+          if (i.checked && !i.disabled) {
+            let cityData = {
+              cityId: i.cityId
+            };
+
+            // 如果市下有县,检查是否有选中的县
+            if (i.children && i.children.length > 0) {
+              let selectedCounties = [];
+              i.children.forEach(function (county, countyIndex) {
+                if (county.checked && !county.disabled) {
+                  selectedCounties.push({
+                    cityId: county.cityId
+                  });
+                }
+              });
+
+              // 如果有选中的县,添加到市的children中
+              if (selectedCounties.length > 0) {
+                cityData.children = selectedCounties;
+              }
+            }
+
+            data.children.push(cityData);
+          }
+        });
+        if (data.cityId !== undefined) {
+          selectList.push(data);
+        }
+      });
+      console.log(selectList);
+      if (selectList.length === 0) {
+        return this.$message({
+          message: '至少选择一个省份或者城市',
+          type: 'error'
+        });
+      } else {
+        this.$emit('selectCity', selectList, this.type);
+        that.addressView = false;
+        this.cityList = []
+      }
+    },
+    close() {
+      this.addressView = false;
+      this.cityList = [];
+      // 重置选中状态
+      this.iSselect = false;
+    }
+  },
+  mounted() {
+  }
+}
+</script>
+
+<style scoped>
+
+.modal .item {
+  position: relative;
+  margin-bottom: 20px;
+}
+
+.modal .item .city {
+  position: absolute;
+  z-index: 9;
+  top: 17px;
+  width: 100%;
+  padding-top: 18px;
+}
+
+.modal .item .city .checkBox {
+  width: 97%;
+  padding: 10px;
+  border: 1px solid #eee;
+  background-color: #fff;
+  max-height: 100px;
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+
+.modal .item .city .checkBox .arrow {
+  position: absolute;
+  top: 3px;
+  width: 0;
+  height: 0;
+  border: 8px solid transparent;
+  border-bottom-color: #ddd;
+}
+
+.modal .item .city .checkBox .arrow:before {
+  position: absolute;
+  bottom: -8px;
+  right: -7px;
+  content: "";
+  width: 0;
+  height: 0;
+  border: 7px solid transparent;
+  border-bottom-color: #fff;
+}
+
+.modal .item .city .checkBox .itemn {
+  margin-bottom: 10px;
+}
+
+.radio {
+  padding: 5px 0;
+  font-size: 14px !important;
+}
+
+.red {
+  color: #ff0000;
+}
+
+.empty {
+  cursor: pointer;
+  margin-left: 10px
+}
+
+.check-btn {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: flex-end;
+}
+
+/* 禁用状态的复选框样式 */
+.disabled-checkbox {
+  opacity: 0.5;
+  cursor: not-allowed !important;
+}
+
+.disabled-checkbox /deep/ .el-checkbox__input.is-disabled .el-checkbox__inner {
+  background-color: #f5f7fa;
+  border-color: #e4e7ed;
+  cursor: not-allowed;
+}
+
+.disabled-checkbox /deep/ .el-checkbox__input.is-disabled + .el-checkbox__label {
+  color: #c0c4cc;
+  cursor: not-allowed;
+}
+</style>

+ 139 - 0
src/components/Editor/wangZm.vue

@@ -0,0 +1,139 @@
+<template>
+  <div>
+    <div ref='editor1' class="myedit"></div>
+  </div>
+</template>
+
+<script>
+import E from 'wangeditor'
+export default {
+  name: 'editoritem',
+  data() {
+    return {
+      uploadUrl: process.env.VUE_APP_BASE_API + "/common/uploadWang",
+      editor: null,
+      selectedImageCount: 0, // 记录选择的图片数量
+      uploadedImageCount: 0  // 记录已上传的图片数量
+    }
+  },
+  beforeDestroy() {
+    if (this.editor != null) {
+      this.editor.destroy()
+      this.editor = null
+    }
+  },
+  methods: {
+    initEditor() {
+      const that = this;
+      if (this.editor == null) {
+        this.editor = new E(that.$refs.editor1)
+        this.editor.config.uploadImgServer = this.uploadUrl;
+        this.editor.config.uploadImgMaxSize = 6 * 1024 * 1024 // 2M
+        this.editor.config.uploadImgAccept = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']
+        this.editor.config.uploadFileName = 'fileName'
+        this.editor.config.zIndex = 1
+
+        // 关键配置:允许多选,串行上传
+        this.editor.config.uploadImgMultiple = true;
+        this.editor.config.uploadImgMaxLength = 15;
+        this.editor.config.uploadImgConcurrent = 1;
+
+        this.editor.config.customUploadImg = function (files, insertImgFn) {
+          // 获取选择的图片数量
+          that.selectedImageCount = files.length;
+          that.uploadedImageCount = 0;
+          console.log(`已选择 ${that.selectedImageCount} 张图片,准备开始上传`);
+
+          that.$emit('image-selected', that.selectedImageCount);
+
+          const uploadNext = (index) => {
+            if (index >= files.length) {
+              console.log(`所有 ${files.length} 张图片上传处理完毕`);
+              that.$emit('all-images-uploaded', that.uploadedImageCount);
+              return;
+            }
+
+            const formData = new FormData();
+            formData.append(that.editor.config.uploadFileName, files[index]);
+
+            const xhr = new XMLHttpRequest();
+            xhr.open('POST', that.uploadUrl);
+
+            xhr.onload = function () {
+              if (xhr.status >= 200 && xhr.status < 300) {
+                const result = JSON.parse(xhr.responseText);
+                if (result.errno === 0 && result.data && result.data[0] && result.data[0].url) {
+                  insertImgFn(result.data[0].url);
+                  that.uploadedImageCount++;
+                  that.$emit('image-uploaded', that.uploadedImageCount, that.selectedImageCount);
+                } else {
+                  console.error(`第 ${index+1} 张图片上传失败:`, result);
+                  that.$emit('image-upload-error', index+1);
+                }
+              } else {
+                console.error(`第 ${index+1} 张图片上传请求失败:`, xhr.statusText);
+                that.$emit('image-upload-error', index+1);
+              }
+              uploadNext(index + 1);
+            };
+
+            xhr.onerror = function () {
+              console.error(`第 ${index+1} 张图片上传出错`);
+              that.$emit('image-upload-error', index+1);
+              uploadNext(index + 1);
+            };
+
+            // 发送请求
+            xhr.send(formData);
+          };
+
+          // 开始上传第一张
+          uploadNext(0);
+        };
+
+        this.editor.config.menus = [
+          'head', 'bold', 'fontSize', 'fontName', 'italic', 'underline',
+          'strikeThrough', 'indent', 'lineHeight', 'foreColor', 'backColor',
+          'link', 'list', 'todo', 'justify', 'quote', 'emoticon', 'image',
+          'table', 'code', 'splitLine', 'undo', 'redo'
+        ]
+
+        this.editor.config.onchange = function (newHtml) {
+          that.$emit("on-text-change", newHtml);
+        }
+
+        this.editor.config.pasteFilterStyle = false
+        this.editor.config.onchangeTimeout = 500
+
+        this.editor.create()
+      }
+      this.editor.txt.html("");
+    },
+
+    setText(text) {
+      if (this.editor == null) {
+        this.initEditor()
+      }
+      this.editor.txt.html(text || "");
+    },
+
+    getSelectedImageCount() {
+      return this.selectedImageCount;
+    },
+
+    getUploadedImageCount() {
+      return this.uploadedImageCount;
+    }
+  }
+}
+</script>
+
+<style scoped>
+.myedit {
+  min-height: 300px;
+  z-index: 1 !important;
+}
+.w-e-toolbar, .w-e-text-container {
+  z-index: 1 !important;
+}
+</style>

+ 18 - 8
src/store/modules/user.js

@@ -1,4 +1,4 @@
-import { login, logout, getInfo } from '@/api/login'
+import {login, logout, getInfo, checkIsNeedCheck} from '@/api/login'
 import { getToken, setToken, removeToken } from '@/utils/auth'
 
 const user = {
@@ -48,13 +48,23 @@ const user = {
       const code = userInfo.code
       const uuid = userInfo.uuid
       return new Promise((resolve, reject) => {
-        login(username, password, code, uuid).then(res => {
-          setToken(res.token)
-          commit('SET_TOKEN', res.token)
-          resolve()
-        }).catch(error => {
-          reject(error)
-        })
+        checkIsNeedCheck(username,password,code,uuid).then(resp => {
+          console.log("检查是否需要验证", resp)
+          if (!resp){
+            // 不需要短信验证,直接登录
+            login(username, password, code, uuid).then(res => {
+              setToken(res.token)
+              commit('SET_TOKEN', res.token)
+              resolve({needSms: false})
+            }).catch(error => {
+              reject(error)
+            })
+          } else {
+            // 需要短信,交给页面去弹窗
+            resolve({ needSms: true })
+          }
+        }).catch(error => reject(error))
+
       })
     },
 

+ 92 - 0
src/utils/hsy.js

@@ -0,0 +1,92 @@
+import TTUploader from 'tt-uploader'
+import { HsyAssumeRoleService } from '@/api/course/userVideo'
+const  spaceName = process.env.VUE_APP_HSY_SPACE
+export const uploadToHSY = async (file, onProgress, type, callBackUp) => {
+  try {
+    const res = await HsyAssumeRoleService()
+    //console.log('火山云 STS 凭证:', res)
+    const credentials = res.data.result.credentials
+    //console.log('火山云 credentials 凭证:', credentials)
+
+    if (!credentials) {
+      throw new Error('未获取到火山云 STS 凭证')
+    }
+
+    const uploader = new TTUploader({
+      appId: '917052',
+      userId: '68185444',
+      videoConfig: {
+        spaceName: spaceName,
+      }
+    })
+
+    const date = new Date();
+    const yyyy = date.getFullYear();
+    const MM = String(date.getMonth() + 1).padStart(2, '0');
+    const dd = String(date.getDate()).padStart(2, '0');
+    const datePath = `${yyyy}${MM}${dd}`;
+
+
+    const fileName = `${Date.now()}.mp4`;
+
+    const remoteFileName = `course/${datePath}/${fileName}`;
+
+    const fileKey = uploader.addFile({
+      file,
+      type: 'video',
+      fileName:remoteFileName,
+      stsToken: {
+        CurrentTime: credentials.currentTime,
+        ExpiredTime: credentials.expiredTime,
+        SessionToken: credentials.sessionToken,
+        AccessKeyID: credentials.accessKeyId,
+        SecretAccessKey: credentials.secretAccessKey,
+      },
+    })
+
+    return new Promise((resolve, reject) => {
+
+      // 上传进度
+      uploader.on('progress', (info) => {
+        onProgress && onProgress({
+          percent: info.percent,
+        })
+      })
+
+      // 上传完成
+      uploader.on('complete', (info) => {
+        resolve({
+          ...info.uploadResult,
+          fileKey,
+        })
+      })
+
+      // 上传失败
+      uploader.on('error', (info) => {
+        reject(info)
+      })
+
+      // 取消上传支持
+      if (callBackUp) {
+        callBackUp({
+          uploader,
+          fileKey,
+          cancel: () => {
+            try {
+              uploader.removeFile(fileKey)
+              reject(new Error('Upload cancelled by user'))
+            } catch (e) {
+              reject(e)
+            }
+          }
+        })
+      }
+
+      uploader.start(fileKey)
+    })
+
+  } catch (error) {
+    console.error('火山云上传失败:', error)
+    throw error
+  }
+}

+ 6 - 1
src/utils/obs.js

@@ -39,7 +39,11 @@ export const uploadToOBS = async (file, progressCallback, type, cancelCallback)
           },
         })
       }
-
+      //四福堂专属配置
+   /*   resolve({
+        "RequestId": "",
+        "urlPath": ""
+      })*/
       obsClient.putObject(
         {
           Bucket: process.env.VUE_APP_OBS_BUCKET,
@@ -65,6 +69,7 @@ export const uploadToOBS = async (file, progressCallback, type, cancelCallback)
           }
         },
       )
+      //注释到这里【四福堂】
     })
   } catch (error) {
     console.error("Error during upload:", error)

+ 83 - 0
src/views/WechatLoginDialog.vue

@@ -0,0 +1,83 @@
+<!--<template>-->
+<!--  <el-dialog title="微信扫码验证" :visible.sync="visible" width="300px">-->
+<!--    <div class="flex flex-col items-center justify-center">-->
+<!--      &lt;!&ndash; 直接用 qrcode-vue 生成二维码 &ndash;&gt;-->
+<!--      <qrcode-vue :value="qrUrl" :size="200" v-if="qrUrl" />-->
+<!--      <p v-if="status==='waiting'">请使用微信扫码确认</p>-->
+<!--      <p v-if="status==='success'">验证成功,正在跳转...</p>-->
+<!--    </div>-->
+<!--  </el-dialog>-->
+<!--</template>-->
+
+<script>
+import { getWechatQrCode, checkWechatScan } from "@/api/login";
+
+
+export default {
+  name: "WechatLoginDialog",
+  props: {
+    visible: Boolean,
+    username: String,
+    redirect: String
+  },
+  data() {
+    return {
+      qrUrl: "",     // 微信扫码登录URL(用来生成二维码内容)
+      ticket: "",
+      status: "waiting",
+      timer: null,
+      errorShown: false
+    };
+  },
+  watch: {
+    visible(newVal) {
+      if (newVal && this.username) this.open(this.username);
+    }
+  },
+  methods: {
+    open(username) {
+      getWechatQrCode({ username }).then(res => {
+        this.ticket = res.data.state;
+        const win = window.open(res.data.url); // 新开窗口扫码
+        this.startPolling(win); // 传入窗口对象
+      });
+    },
+    startPolling(win) {
+      this.timer = setInterval(() => {
+        checkWechatScan(this.ticket)
+          .then(res => {
+            if (res.code === 200 && res.data) {
+              this.status = "success";
+              clearInterval(this.timer);
+              console.log("扫码成功,准备 emit 事件", res.data);
+
+              this.$emit("update:visible", false);
+              this.$emit("loginSuccess", res.data);
+
+              if (win && !win.closed) {
+                win.close(); // 扫码完成后自动关闭窗口
+              }
+            }
+          })
+          .catch(err => {
+            clearInterval(this.timer);
+            this.$emit("update:visible", false);
+
+            if (!this.errorShown) {
+              this.errorShown = true;
+              this.$message.error(err.response?.data?.msg);
+            }
+
+            if (win && !win.closed) {
+              win.close(); // 异常也关闭窗口
+            }
+          });
+      }, 800);
+    }
+
+  },
+  beforeDestroy() {
+    if (this.timer) clearInterval(this.timer);
+  }
+};
+</script>

+ 318 - 0
src/views/company/companyRedPacketBalanceLogs/index.vue

@@ -0,0 +1,318 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="ID" prop="logsId">
+        <el-input
+          v-model="queryParams.logsId"
+          placeholder="请输入ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <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="logsType">
+        <el-select v-model="queryParams.logsType" placeholder="请选择类型" clearable size="small">
+          <el-option
+            v-for="dict in logsTypeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="创建时间">
+        <el-date-picker
+          v-model="daterangeCreateTime"
+          size="small"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['company:companyRedPacketBalanceLogs:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="companyRedPacketBalanceLogsList" @selection-change="handleSelectionChange">
+      <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="remark" />
+      <el-table-column label="类型" align="center" prop="logsType">
+        <template slot-scope="scope">
+          <dict-tag :options="logsTypeOptions" :value="scope.row.logsType"/>
+        </template>
+      </el-table-column>
+      <el-table-column v-if="false" label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['company:companyRedPacketBalanceLogs:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['company:companyRedPacketBalanceLogs: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="企业ID" prop="companyId">
+          <el-input v-model="form.companyId" placeholder="请输入企业ID" />
+        </el-form-item>
+        <el-form-item label="金额" prop="money">
+          <el-input v-model="form.money" placeholder="请输入金额" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="请输入备注" />
+        </el-form-item>
+        <el-form-item label="余额" prop="balance">
+          <el-input v-model="form.balance" placeholder="请输入余额" />
+        </el-form-item>
+        <el-form-item label="类型 字典字段" prop="logsType">
+          <el-select v-model="form.logsType" placeholder="请选择类型 字典字段">
+            <el-option
+              v-for="dict in logsTypeOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="parseInt(dict.dictValue)"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listCompanyRedPacketBalanceLogs, getCompanyRedPacketBalanceLogs, delCompanyRedPacketBalanceLogs, addCompanyRedPacketBalanceLogs, updateCompanyRedPacketBalanceLogs, exportCompanyRedPacketBalanceLogs } from "@/api/company/companyRedPacketBalanceLogs";
+import { getCompanyList } from '@/api/company/company'
+
+export default {
+  name: "CompanyRedPacketBalanceLogs",
+  data() {
+    return {
+      companys:[], // 公司列表
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 企业红包余额记录表格数据
+      companyRedPacketBalanceLogsList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 创建时间时间范围
+      daterangeCreateTime: [],
+      // 类型 字典字段字典
+      logsTypeOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        logsId: null,
+        companyId: null,
+        createTime: null,
+        logsType: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+
+    this.getDicts("company_red_packet_balance_type").then(response => {
+      this.logsTypeOptions = response.data;
+    });
+    getCompanyList().then(response => {
+      this.companys = response.data;
+    });
+    this.getList();
+
+  },
+  methods: {
+    /** 查询企业红包余额记录列表 */
+    getList() {
+      this.loading = true;
+      this.queryParams.params = {};
+      if (null != this.daterangeCreateTime && '' != this.daterangeCreateTime) {
+        this.queryParams.params["beginCreateTime"] = this.daterangeCreateTime[0];
+        this.queryParams.params["endCreateTime"] = this.daterangeCreateTime[1];
+      }
+      listCompanyRedPacketBalanceLogs(this.queryParams).then(response => {
+        this.companyRedPacketBalanceLogsList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        logsId: null,
+        companyId: null,
+        money: null,
+        remark: null,
+        createTime: null,
+        balance: null,
+        logsType: null,
+        status: 0
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.daterangeCreateTime = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.logsId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加企业红包余额记录";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const logsId = row.logsId || this.ids
+      getCompanyRedPacketBalanceLogs(logsId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改企业红包余额记录";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.logsId != null) {
+            updateCompanyRedPacketBalanceLogs(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addCompanyRedPacketBalanceLogs(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const logsIds = row.logsId || this.ids;
+      this.$confirm('是否确认删除企业红包余额记录编号为"' + logsIds + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delCompanyRedPacketBalanceLogs(logsIds);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有企业红包余额记录数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportCompanyRedPacketBalanceLogs(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 248 - 4
src/views/components/course/userCourseCatalogDetails.vue

@@ -83,6 +83,12 @@
       <el-table-column label="红包金额" align="center" prop="redPacketMoney"/>
       <el-table-column label="排序" align="center" prop="courseSort"/>
       <el-table-column label="上传时间" align="center" prop="createTime"/>
+      <el-table-column label="是否上架" align="center" prop="isOnPut">
+        <template slot-scope="{ row }">
+          <el-tag v-if="row.isOnPut == 0">是</el-tag>
+          <el-tag type="danger" v-if="row.isOnPut == 1">否</el-tag>
+        </template>
+      </el-table-column>
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
@@ -157,6 +163,89 @@
         </el-form-item>
         <el-form-item label="红包金额" prop="redPacketMoney">
           <el-input-number v-model="form.redPacketMoney" :min="0.1" :max="200" :step="0.1"></el-input-number>
+        </el-form-item>
+         <!-- v-if="!!form.randomRedPacketRulesArr" -->
+        <el-form-item v-if="!!enableRandomRedPacket" label="随机红包金额"  >
+          <template >
+          <div v-for="(rule, index) in form.randomRedPacketRulesArr" :key="index" class="form-row">
+           <el-form-item
+            label="随机红包金额区间"
+            :prop="`randomRedPacketRulesArr.${index}.minAmount`"
+            :rules="[
+              { required: true, message: '请输入最小金额', trigger: 'blur' },
+              { validator: validateMinAmount, trigger: 'blur', index: index }
+            ]"
+            class="form-item-amount"
+          >
+            <el-input
+              v-model.number="rule.minAmount"
+              type="number"
+              :min="0.01"
+              :precision="2"
+              :step="0.01"
+              placeholder="最小金额"
+              size="small"
+              class="amount-input"
+              @input="handleAmountInput(rule, 'minAmount')"
+            ></el-input>
+            <span class="separator">-</span>
+            <el-input
+              v-model.number="rule.maxAmount"
+              type="number"
+              :min="rule.minAmount || 0.01"
+              :precision="2"
+              :step="0.01"
+              placeholder="最大金额"
+              size="small"
+              class="amount-input"
+              @input="handleAmountInput(rule, 'maxAmount')"
+            ></el-input>
+            <span class="suffix">元</span>
+          </el-form-item>
+              <el-form-item
+                label="随机权重"
+                :prop="`randomRedPacketRulesArr.${index}.weight`"
+                :rules="[
+                  { required: true, message: '请输入权重', trigger: 'blur' },
+                  { type: 'integer', message: '权重必须为整数', trigger: 'blur' },
+                ]"
+                class="form-item-weight"
+              >
+                <el-input
+                  v-model.number="rule.weight"
+                  type="number"
+                  :min="1"
+                  placeholder="权重"
+                  size="small"
+                ></el-input>
+              </el-form-item>
+              <el-tooltip class="item" effect="dark" content="权重越高,被随机到的概率越大" placement="top">
+                <i class="el-icon-question"></i>
+              </el-tooltip>
+              <div class="action-buttons">
+                <el-button
+                  icon="el-icon-plus"
+                  size="mini"
+                  type="text"
+                  @click="addRule(index)"
+                  class="add-btn"
+                >
+                  新增
+                </el-button>
+                <el-button
+                  icon="el-icon-delete"
+                  size="mini"
+                  type="text"
+                  @click="deleteRule(index)"
+                  :disabled="form.randomRedPacketRulesArr.length <= 1"
+                  class="delete-btn"
+                >
+                  删除
+                </el-button>
+              </div>
+          </div>
+        </template>
+
         </el-form-item>
         <el-form-item label="是否关联商品">
           <el-radio v-model="form.isProduct" :label=0>否</el-radio>
@@ -168,6 +257,18 @@
             <el-radio :label="0">否</el-radio>
           </el-radio-group>
         </el-form-item>
+        <el-form-item label="是否启用倍速" prop="isSpeed">
+          <el-radio-group v-model="form.isSpeed">
+            <el-radio :label="1">是</el-radio>
+            <el-radio :label="0">否</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="是否上架" prop="isOnPut">
+          <el-radio-group v-model="form.isOnPut">
+            <el-radio :label="0">上架</el-radio>
+            <el-radio :label="1">下架</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">
@@ -355,10 +456,21 @@ import {getByIds} from '@/api/course/courseQuestionBank'
 import CourseWatchComment from "./courseWatchComment.vue";
 import {getCateListByPid, getCatePidList} from '@/api/course/userCourseCategory'
 import draggable from 'vuedraggable'
+import { getConfigByKey } from '@/api/system/config'
 
 export default {
   name: "userCourseCatalog",
   components: {VideoUpload, QuestionBank, CourseWatchComment, CourseProduct, draggable},
+  watch:{
+    // 深度监听 rules 数组的变化,以更新总权重
+    "form.randomRedPacketRulesArr": {
+      handler(val) {
+        // this.calculateTotalWeight();
+        this.validateRules();
+      },
+      deep: true,
+    },
+  },
   data() {
     return {
       duration: null,
@@ -454,7 +566,16 @@ export default {
       openVideoSort: false,
       // 表单参数
       form: {
-        courseProducts: []
+        isOnPut: 0,
+        courseProducts: [],
+        randomRedPacketRules:null,
+        randomRedPacketRulesArr:[
+           {
+            minAmount: 0.01,
+            maxAmount: 0.01,
+            weight: 100,
+          }
+        ]
       },
       updateBatchData: {
         open: false,
@@ -477,12 +598,25 @@ export default {
         videoId: null,
         title: ""
       },
+      enableRandomRedPacket:false
     }
   },
   created() {
     this.getDicts("sys_course_temp_type").then(response => {
       this.typeOptions = response.data;
     });
+        getConfigByKey('randomRedpacket:config').then(res=>{
+        let configData = res.data;
+        if(!!configData && !!configData.configValue){
+           let configValue = JSON.parse(configData.configValue);
+           if(!!configValue.enableRandomRedpacket){
+            this.enableRandomRedPacket = configValue.enableRandomRedpacket;
+            console.log("this.enableRandomRedPacket ::" + this.enableRandomRedPacket)
+           }
+        }
+    }).catch(res=>{
+
+    })
   },
   methods: {
     getPickerOptions() {
@@ -711,8 +845,18 @@ export default {
         transcodeFileKey: null,
         isProduct: 0,
         isFirst: 0,
+        isSpeed: 0,
+        isOnPut: 0,
         listingStartTime: null,
         listingEndTime: null,
+        randomRedPacketRules:null,
+        randomRedPacketRulesArr:[
+          {
+            minAmount: 0.01,
+            maxAmount: 0.01,
+            weight: 100,
+          }
+        ]
       };
       this.videoURL = '';
       this.progress = 0;
@@ -765,10 +909,24 @@ export default {
     /** 修改按钮操作 */
     handleUpdate(row) {
       this.reset();
+      this.form.isOnPut=row.isOnPut
       this.packageList = [];
       const videoId = row.videoId || this.ids
       getUserCourseVideo(videoId).then(response => {
+        console.log(response);
         this.form = response.data;
+        this.$set(this.form, 'isOnPut', response.data.isOnPut !== undefined ? response.data.isOnPut : 0);
+        if(!!this.form.randomRedPacketRules){
+           this.$set(this.form, 'randomRedPacketRulesArr', JSON.parse(this.form.randomRedPacketRules)) ;
+          // this.form.randomRedPacketRulesArr = JSON.parse(this.form.randomRedPacketRules);
+        }else{
+          //处理初始值
+         this.form.randomRedPacketRulesArr = [{
+            minAmount: 0.01,
+            maxAmount: 0.01,
+            weight: 100,
+          }]
+        }
         if (response.data.videoUrl != null && response.data.videoUrl !== '') {
           this.videoUrl = response.data.videoUrl;
         }
@@ -813,7 +971,7 @@ export default {
             });
             return
           }
-          if (this.form.isProduct != null && this.form.isProduct == 1 && this.form.courseProducts.length < 1) {
+          if (this.form.isProduct != null && this.form.isProduct == 1 && (this.form.courseProducts == null || this.form.courseProducts.length < 1)) {
             this.$message({
               message: '请选择关联商品',
               type: 'warning'
@@ -829,6 +987,10 @@ export default {
           if (this.form.courseProducts != null) {
             this.form.productId = this.form.courseProducts.map(item => item.id).join(',');
           }
+          if(!!this.form.randomRedPacketRulesArr){
+            let rulesJson = JSON.stringify(this.form.randomRedPacketRulesArr);
+            this.form.randomRedPacketRules =  rulesJson;
+          }
           if (this.form.videoId != null) {
             updateUserCourseVideo(this.form).then(response => {
               this.msgSuccess("修改成功");
@@ -888,7 +1050,7 @@ export default {
         return syncTemplate(courseId);
       }).then(() => {
         this.getList();
-        this.msgSuccess("同步成功");
+        this.msgSuccess("正在同步模板中!!请稍后!");
       }).catch(() => {
       });
     },
@@ -981,7 +1143,15 @@ export default {
       this.redData.loading = true;
       this.redData.queryParams.courseId = this.courseId;
       getVideoListByCourseId(this.redData.queryParams).then(response => {
-        this.redData.list = response.rows;
+        if(!!response.rows && response.rows.length >0){
+          for(let i = 0; i < response.rows.length; i++){
+            if(!!response.rows[i].randomRedPacketRules){
+             this.$set(response.rows[i], 'randomRedPacketRulesArr', JSON.parse(response.rows[i].randomRedPacketRules)) ;
+            }
+          }
+        }
+         this.redData.list = response.rows;
+         console.log(this.redData.list);
         this.redData.loading = false;
       });
     },
@@ -998,6 +1168,80 @@ export default {
       this.commentDialog.title = `查看评论 - ${row.title}`;
       this.commentDialog.open = true;
     },
+    // 实时过滤金额输入,只允许两位小数
+    handleAmountInput(rule, field) {
+      let value = rule[field];
+      if (value === null || value === undefined) return;
+
+      // 转换为字符串处理
+      let str = value.toString();
+
+      // 移除除数字和小数点外的所有字符
+      str = str.replace(/[^0-9.]/g, '');
+
+      // 只保留一个小数点
+      const dotIndex = str.indexOf('.');
+      if (dotIndex !== -1) {
+        str = str.substring(0, dotIndex + 1) + str.substring(dotIndex + 1).replace(/\./g, '');
+      }
+
+      // 限制小数点后最多两位
+      if (dotIndex !== -1 && str.length > dotIndex + 3) {
+        str = str.substring(0, dotIndex + 3);
+      }
+
+      // 转换回数字并更新
+      rule[field] = parseFloat(str) || 0;
+    },
+      deleteRule(index) {
+      this.$confirm("确定要删除这个区间吗?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      }).then(() => {
+        this.form.randomRedPacketRulesArr.splice(index, 1);
+        this.$message({
+          type: "success",
+          message: "删除成功!",
+        });
+      });
+    },
+      addRule(index) {
+      // 在当前行的后面插入一个新行
+      this.form.randomRedPacketRulesArr.splice(index + 1, 0, {
+        minAmount: 0.01,
+        maxAmount: 0.01,
+        weight: 100,
+      });
+    },
+       // 自定义校验规则:确保最大金额大于最小金额
+    validateMinAmount(rule, value, callback) {
+      // debugger;
+      // const maxAmount = this.form29.rules[].maxAmount
+
+      const index = rule.index;
+      const maxAmount = this.form.randomRedPacketRulesArr[index].maxAmount;
+
+      if (value > maxAmount) {
+        callback(new Error("最小金额不能大于最大金额"));
+      } else {
+        callback();
+      }
+    },
+      validateRules() {
+      this.form.randomRedPacketRulesArr.forEach((rule) => {
+        if (rule.minAmount === undefined || rule.minAmount < 0.01) {
+          rule.minAmount = 0.01;
+        }
+        if (rule.maxAmount === undefined || rule.maxAmount < rule.minAmount) {
+          rule.maxAmount = rule.minAmount;
+        }
+        if (rule.weight === undefined || rule.weight < 1) {
+          rule.weight = 1;
+        }
+      });
+    },
+
   }
 }
 </script>

+ 75 - 2
src/views/components/his/integralOrderDetails.vue

@@ -106,6 +106,27 @@
 
       </el-table>
     </div>
+    
+    <!-- 操作记录 -->
+    <div class="contentx" v-if="item != null" style="padding-bottom: 70px;">
+      <div class="desct">
+        操作记录
+      </div>
+      <el-table :data="orderLogs" border style="width: 100%; margin-top: 20px;" v-loading="logsLoading">
+        <!-- <el-table-column prop="changeType" label="操作类型" align="center" width="120">
+        </el-table-column> -->
+        <el-table-column prop="changeTime" label="操作时间" align="center" width="180">
+          <template slot-scope="scope">
+            {{ parseTime(scope.row.changeTime) }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="changeMessage" label="操作备注" align="center">
+        </el-table-column>
+        <!-- <el-table-column prop="operator" label="操作员" align="center" width="120">
+        </el-table-column> -->
+        
+      </el-table>
+    </div>
     <el-dialog width="35%" title="发货" :visible.sync="sendVisible" append-to-body @close="sendCancel">
       <el-form ref="form" :model="form" label-width="120px">
         <el-form-item label="快递名称" prop="deliveryName">
@@ -179,7 +200,10 @@
     </el-dialog>
 
     <el-dialog :title="expressDialog.title" :visible.sync="expressDialog.open" width="600px" append-to-body>
-      <el-table style="margin-top: 20px;width: 100%" ref="orderHistoryTable" :data="traces" border>
+      <div style="margin-bottom: 10px; text-align: right;">
+        <el-button type="primary" size="small" @click="syncExpressInfo" :loading="syncLoading">同步物流信息</el-button>
+      </div>
+      <el-table style="margin-top: 20px;width: 100%" ref="orderHistoryTable" :data="traces" border v-loading="tableLoading">
         <el-table-column label="操作时间" width="160" align="center">
           <template slot-scope="scope">
             {{ scope.row.AcceptTime }}
@@ -345,7 +369,7 @@
 </template>
 
 <script>
-import { getExpress,mandatoryRefunds,getCitys,finishOrder, listIntegralOrder, sendgoods, getIntegralOrder, delIntegralOrder, addIntegralOrder, updateIntegralOrder, exportIntegralOrder, getOrderUserPhone } from "@/api/his/integralOrder";
+import { getExpress,mandatoryRefunds,getCitys,finishOrder, listIntegralOrder, sendgoods, getIntegralOrder, delIntegralOrder, addIntegralOrder, updateIntegralOrder, exportIntegralOrder, getOrderUserPhone, getOrderLogs } from "@/api/his/integralOrder";
 import { getExpressList } from "@/api/his/express";
 import { listAccount } from "@/api/his/dfAccount";
 export default {
@@ -429,6 +453,11 @@ export default {
       selectedDistrict: null, // 选中的区
       detailAddress: '', // 详细地址
       deliveryTypeOptions:[],
+      // 操作记录相关数据
+      orderLogs: [], // 订单操作记录
+      logsLoading: false, // 操作记录加载状态
+      syncLoading: false, // 同步物流信息按钮加载状态
+      tableLoading: false // 物流信息表格加载状态
     }
   },
   created() {
@@ -726,13 +755,31 @@ export default {
     },
     showExpress() {
       this.expressDialog.open = true;
+      this.loadExpressInfo();
+    },
+    // 加载物流信息
+    loadExpressInfo() {
+      this.tableLoading = true;
       getExpress(this.item.orderId).then(response => {
         this.express = response.data;
         if (this.express != null && this.express.Traces != null) {
           this.traces = this.express.Traces
+        } else {
+          this.traces = [];
         }
+        this.tableLoading = false;
+      }).catch(error => {
+        this.traces = [];
+        this.tableLoading = false;
+        console.error('获取物流信息失败:', error);
       });
     },
+    // 同步物流信息
+    syncExpressInfo() {
+      this.syncLoading = true;
+      this.loadExpressInfo();
+      this.syncLoading = false;
+    },
     sendGoods() {
       // 手动验证所有必填字段
       if (!this.selectedRow) {
@@ -772,9 +819,12 @@ export default {
     },
     getDetails(orderId) {
       this.item = null;
+      this.orderLogs = []; // 清空操作记录
       getIntegralOrder(orderId).then(response => {
         this.item = response.data;
         this.prod = [JSON.parse(this.item.itemJson)][0];
+        // 获取操作记录
+        this.getOrderLogsData();
       });
     },
     // 代服账号选择变化
@@ -884,6 +934,29 @@ export default {
         console.error('完成订单失败:', error);
       });
     },
+    // 获取订单操作记录
+    getOrderLogsData() {
+      if (!this.item || !this.item.orderId) {
+        return;
+      }
+      
+      this.logsLoading = true;
+      getOrderLogs(this.item.orderId).then(response => {
+        if (response.code === 200) {
+          // 按照时间升序排列
+          this.orderLogs = response.data.sort((a, b) => {
+            return new Date(a.changeTime) - new Date(b.changeTime);
+          });
+        } else {
+          this.orderLogs = [];
+        }
+        this.logsLoading = false;
+      }).catch(error => {
+        this.orderLogs = [];
+        this.logsLoading = false;
+        console.error('获取操作记录失败:', error);
+      });
+    }
   }
 }
 </script>

+ 25 - 13
src/views/components/his/storeOrderDetails.vue

@@ -6,7 +6,8 @@
 <div class="contentx" v-if="item!=null">
   <div class="desct"></div>
 <div class="order-status" v-if="item!=null" >
-          <el-steps  :active="item.status==4?item.status:item.status-1" align-center finish-status="success">
+         <!-- 7为金牛药师待确认状态-->
+          <el-steps  :active="item.status==7?1:(item.status==4?item.status:item.status-1)" align-center finish-status="success">
             <el-step title="待支付"></el-step>
             <el-step title="待发货"></el-step>
             <el-step title="待收货"></el-step>
@@ -303,6 +304,8 @@
                          <el-option key="JD"  label="京东" value="JD" />
                          <el-option key="DBL"  label="德邦" value="DBL" />
 						              <el-option key="YD"  label="韵达" value="YD" />
+                         <el-option key="JTSD"  label="极兔" value="JTSD" />
+                         <el-option key="YTO"  label="圆通" value="YTO" />
                        </el-select>
                      </el-form-item>
                     <el-form-item label="物流单号" prop="deliverySn"  >
@@ -351,7 +354,7 @@
                       v-model="payMoney"
                       :precision="2"
                       :step="0.1"
-                      disabled   
+                      disabled
                     />
                   </el-form-item>
                   <el-form-item label="物流代收金额">
@@ -446,7 +449,7 @@
                 >
                 <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>
@@ -467,10 +470,10 @@
 
                   <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" 
+                      <el-input-number
+                        v-model="scope.row.money"
+                        :precision="2"
+                        :step="0.1"
                         :min="0"
                         size="mini"
                       />
@@ -479,17 +482,17 @@
 
                   <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"   
+                      <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;">
@@ -707,6 +710,15 @@ import {getCitys} from "@/api/store/city";
             });
 
     },
+    watch: {
+      'editForm.status': function(newVal, oldVal) {
+        if (newVal == 2) {
+          // 状态改为待发货时,物流状态设置为"暂无轨迹信息"(值0)
+          this.editForm.deliveryType = "";
+          this.editForm.deliveryStatus = "0"; // 对应"暂无轨迹信息"
+        }
+      }
+    },
     computed: {
        // 应收金额 = 实收金额 + 代收金额
       payPrice() {
@@ -1067,7 +1079,7 @@ import {getCitys} from "@/api/store/city";
         } else {
           this.refund(); //正常退款
         }
-        
+
       },
       submitRefundForm(){
         if(this.refundForm.refundAmount<=0){

+ 2 - 0
src/views/components/his/storeOrderDetails2.vue

@@ -298,8 +298,10 @@
                         <el-option key="SF"  label="顺丰" value="SF" />
                         <el-option key="EMS"  label="邮政" value="EMS" />
                          <el-option key="ZTO"  label="中通" value="ZTO" />
+                         <el-option key="STO"  label="申通" value="STO" />
                          <el-option key="JD"  label="京东" value="JD" />
                          <el-option key="DBL"  label="德邦" value="DBL" />
+                         <el-option key="JTSD"  label="极兔" value="JTSD" />
 						              <el-option key="YD"  label="韵达" value="YD" />
 						              <el-option key="STO"  label="申通" value="STO" />
                        </el-select>

+ 2313 - 0
src/views/components/index/statisticsDashboard.vue

@@ -0,0 +1,2313 @@
+<template>
+  <div class="statistics-dashboard">
+    <!-- 数据概览 (Data Overview) -->
+    <el-card class="overview-section" shadow="never">
+      <el-row :gutter="20">
+        <el-col :xs="24" :sm="24" :md="16" :lg="16" :xl="16" class="companybox">
+          <img src="@/assets/images/topbg.png" alt="" class="topimg">
+          <img src="@/assets/images/topbg.png" alt="" class="bottomimg">
+          <div class="companyboxtitle">
+            企业数据
+          </div>
+          <div class="companyflex">
+            <div class="topbg companycard cardafter">
+              <div class="card-title1">
+                <img src="@/assets/images/tab_company.png" alt="" class="icon-img">
+                分公司数量
+              </div>
+
+              <div class="card-value highlight1">
+                <count-to :start-val="0" :end-val="dealderCount" :duration="3600"
+                          class="card-panel-num companynumber" />
+              </div>
+            </div>
+            <div class="companycard cardafter">
+              <div class="card-title1">
+                <img src="@/assets/images/salesperson.png" alt="" class="icon-img">
+                销售数量
+              </div>
+              <div class="card-value highlight1">
+                <count-to :start-val="0" :end-val="groupMgrCount" :duration="3600"
+                          class="card-panel-num companynumber" />
+              </div>
+            </div>
+            <div class="companycard cardafter">
+              <div class="card-title1">
+                <img src="@/assets/images/member.png" alt="" class="icon-img">
+                会员数量
+              </div>
+              <div class="card-value highlight1">
+                <count-to :start-val="0" :end-val="memberCount" :duration="3600" class="card-panel-num companynumber" />
+                <span class="highlight-today-add companyadd">+{{todayIncreaseUserNum}}</span>
+              </div>
+
+            </div>
+            <div class="cardafter companycard">
+              <div class="card-title1">
+                <img src="@/assets/images/tab_enterprise.png" alt="" class="icon-img">
+                企微数量
+              </div>
+              <div class="card-value highlight1">
+                <count-to :start-val="0" :end-val="qwMemberNum" :duration="3600" class="card-panel-num companynumber" />
+              </div>
+            </div>
+            <div class="botttombg companycard">
+              <div class="card-title1">
+                <svg-icon icon-class="phone" />
+                pad使用情况
+              </div>
+              <div class="card-value highlight1">
+                <count-to :start-val="0" :end-val="padUsedNum" :duration="3600" class="card-panel-num companynumber" />
+                /
+                <template v-if="typeof padTotalNum === 'number'">
+                  <count-to :start-val="0" :end-val="padTotalNum" :duration="1800" class="card-panel-num companynumber" />
+                </template>
+                <template v-else>
+                  <span class="card-panel-num companynumber">{{ padTotalNum }}</span>
+                </template>
+              </div>
+            </div>
+          </div>
+        </el-col>
+
+
+        <el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="8" class="propertyboxtitle">
+          <div class="property_title">
+            资产概览
+          </div>
+          <div class="propertyboxflex">
+            <div class="property-card propertyline">
+              <div class="property-title">
+                <i class="el-icon-money"></i>
+                企业资产(元)
+              </div>
+              <div class="card-value highlight">
+                <count-to :start-val="0" :end-val="balance" :duration="3600" class="card-panel-num" />
+              </div>
+            </div>
+            <div class="property-card propertyline">
+              <div class="property-title">
+                <i class="el-icon-money"></i>
+                润天余额(元)
+              </div>
+              <div class="card-value highlight">
+                <count-to :start-val="0" :end-val="runTianBalance" :duration="3600" class="card-panel-num" />
+              </div>
+            </div>
+            <div class="property-card">
+              <div class="property-title">
+                <span>今日消耗 (元)</span>
+              </div>
+              <div class="card-value highlight" style="color: rgba(32, 33, 36, 1);margin-top: 10px;">
+                <count-to :start-val="0" :end-val="todayComsumption" :duration="3600" class="card-panel-num" />
+              </div>
+              <div class="card-compare">
+                较昨日 <span>+1</span>
+              </div>
+            </div>
+          </div>
+
+        </el-col>
+      </el-row>
+
+      <el-row :gutter="20">
+        <el-col :xs="24" :sm="24" :md="16" :lg="16" :xl="16">
+          <div class="operatetitle">
+            经营数据
+          </div>
+          <div class="operatetitle-col">
+            <div class="operatetitle-card">
+              <div class="card-title">
+                <i class="el-icon-shopping-cart-full"></i>
+                收款总数
+              </div>
+              <div class="operate-value highlight">
+                <count-to :start-val="0" :end-val="recvTotalNum" :duration="3600" class="card-panel-num" />
+                <div class="yesterdaybox">
+                  较昨日 <span class="highlight-today-add2">+{{recvTodayNum}}</span>
+                </div>
+              </div>
+              <div class="card-badge">
+              </div>
+            </div>
+            <div class="operatetitle-card">
+              <div class="card-title">
+                <i class="el-icon-shopping-cart-full"></i>
+                订单总数
+              </div>
+              <div class="operate-value highlight">
+                <count-to :start-val="0" :end-val="orderTotalNum" :duration="3600" class="card-panel-num" />
+                <div class="yesterdaybox">
+                  较昨日 <span class="highlight-today-add2">+{{todayOrderNum}}</span>
+                </div>
+
+              </div>
+              <div class="card-badge">
+              </div>
+
+            </div>
+            <div class="operatetitle-card">
+              <div class="card-title">
+                平台今日看课人数
+              </div>
+              <div class="operate-value highlight">
+                <count-to :start-val="0" :end-val="todayWatchUserCount" :duration="3600" class="card-panel-num" />
+              </div>
+              <div class="card-sub">
+                <span>配额上限</span>
+                <span class="sub-value">
+                  <count-to :start-val="0" :end-val="todayWatchUserCount" :duration="3600" class="card-panel-num"
+                            style="color: rgba(49, 185, 154, 1);" />
+                  /
+                  <count-to :start-val="0" :end-val="versionLimit" :duration="3600" class="card-panel-num" />
+                </span>
+              </div>
+              <el-progress :percentage="versionLimitPercent" :show-text="false"
+                           color="#409EFF"></el-progress>
+            </div>
+            <div class="operatetitle-card">
+              <div class="card-title">
+                <i class="el-icon-shopping-cart-full"></i>
+                商品总数
+              </div>
+              <div class="operate-value highlight">
+                <count-to :start-val="0" :end-val="goodsTotalNum" :duration="3600" class="card-panel-num" />
+                <div class="yesterdaybox">
+                  较昨日 <span class="highlight-today-add2">+{{todayGoodsNum}}</span>
+                </div>
+
+              </div>
+              <div class="card-badge">
+              </div>
+            </div>
+          </div>
+
+        </el-col>
+
+
+        <el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="8" style="padding-left: 15px;">
+
+          <div class="internetbox">
+            <div class="internet-cardtop">
+              <div class="cardinnerbox">
+                <div class="cardtopimg">
+                  <img src="@/assets/images/liuliang.png" alt=""><span>剩余流量</span>
+                </div>
+                <div class="cardtopnumber">
+                  <span>{{formatBytes(this.trafficCount)}}</span>
+                </div>
+              </div>
+              <div class="progress">
+                <el-progress :percentage="90" :show-text="false" define-back-color="#000">
+
+                </el-progress>
+              </div>
+              <div class="cardinnerbox2">
+                <div>
+                  今日消耗 <span>{{formatBytes(this.todayTraffic)}}</span>
+                </div>
+                <div>
+                  本月 <span>{{formatBytes(this.thisMonthTraffic)}}</span>
+                </div>
+              </div>
+            </div>
+
+            <div class="internetbox-messge">
+              <div class="internet-card">
+                <img src="@/assets/images/message.png" alt="">
+
+                <span class="internet-title">
+                  短信剩余条数 (条)
+                </span>
+              </div>
+              <div class="internet-number">
+                0
+              </div>
+            </div>
+          </div>
+        </el-col>
+      </el-row>
+    </el-card>
+    <!-- 分析概览 (Analysis Overview) -->
+    <div class="analysis-section" shadow="never">
+      <div slot="header" class="header">
+        <div>分析概览</div>
+        <div class="tab-group">
+          <el-radio-group v-model="queryTime" size="medium" @change="handleAnalysis">
+            <el-radio-button label="今日"></el-radio-button>
+            <el-radio-button label="昨日"></el-radio-button>
+            <el-radio-button label="本周"></el-radio-button>
+            <el-radio-button label="本月"></el-radio-button>
+            <el-radio-button label="上月"></el-radio-button>
+          </el-radio-group>
+        </div>
+        <div class="action-group">
+          <div v-if="this.$store.state.user.medicalMallConfig.statics">
+            <!-- 选择部门 -->
+            <el-select v-model="deptId" placeholder="请选择部门" size="small" @change="handleDeptChange" style="width: 150px">
+              <el-option
+                v-for="company in deptOptions"
+                :key="company.deptId"
+                :label="company.deptName"
+                :value="company.deptId"
+              />
+            </el-select>
+            <!-- 选择销售公司 -->
+            <el-select  v-model="companyId" placeholder="请选择销售公司" size="small" clearable @change="handleCompanyChange" style="width: 180px" >
+              <el-option
+                v-for="company in companyOptions"
+                :key="company.companyId"
+                :label="company.companyName"
+                :value="company.companyId"
+              />
+            </el-select>
+          </div>
+          <el-radio-group v-model="userTypeText" @change="handleUserType">
+            <el-radio-button label="会员"></el-radio-button>
+            <el-radio-button label="企微"></el-radio-button>
+          </el-radio-group>
+
+          <el-dropdown @command="handleAutoRefresh" trigger="click">
+            <el-button size="small" plain>
+              自动刷新
+              <i class="el-icon-arrow-down el-icon--right"></i>
+            </el-button>
+            <el-dropdown-menu slot="dropdown">
+              <el-dropdown-item :command="0" :class="{ 'is-active': !autoRefreshInterval }">关闭</el-dropdown-item>
+              <el-dropdown-item :command="5" :class="{ 'is-active': autoRefreshInterval === 5 }">5分钟</el-dropdown-item>
+              <el-dropdown-item :command="10"
+                                :class="{ 'is-active': autoRefreshInterval === 10 }">10分钟</el-dropdown-item>
+              <el-dropdown-item :command="15"
+                                :class="{ 'is-active': autoRefreshInterval === 15 }">15分钟</el-dropdown-item>
+            </el-dropdown-menu>
+          </el-dropdown>
+          <el-button size="small" plain icon="el-icon-refresh" type="primary" @click="manualRefresh">手动刷新</el-button>
+        </div>
+      </div>
+    </div>
+    <div>
+      <el-row :gutter="20">
+        <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12" style="position: relative">
+          <div class="analysis-card-check" :class="selectedDiv===0?'analysis-card-check-selected color':''"
+               @click="handleToggleDiv(0)">
+            <div class="analysis-card">
+              <img class="card-icon" src="@/assets/images/cishu_views.png"></img>
+              <div class="card-content">
+                <div class="card-row">
+                  <span>观看人数</span>
+                  <span class="highlight">
+                    <count-to :start-val="0" :end-val="watchUserCount" :duration="3600" class="card-panel-num" />
+                  </span>
+                </div>
+                <div class="card-row">
+                  <span>完播人数</span>
+                  <span class="highlight">
+                    <count-to :start-val="0" :end-val="completedUserCount" :duration="3600" class="card-panel-num" />
+                  </span>
+                </div>
+                <div class="card-row">
+                  <span>完播率</span>
+                  <span class="highlight">{{completedRate}}%</span>
+                </div>
+              </div>
+            </div>
+            <div class="analysis-card">
+              <img class="card-icon" src="@/assets/images/number_views.png"></img>
+              <div class="card-content">
+                <div class="card-row">
+                  <span>观看次数</span>
+                  <span class="highlight-red">
+                    <count-to :start-val="0" :end-val="watchCount" :duration="3600" class="card-panel-num" /></span>
+                </div>
+                <div class="card-row">
+                  <span>完播次数</span>
+                  <span class="highlight-red">
+                    <count-to :start-val="0" :end-val="completedCount" :duration="3600" class="card-panel-num" />
+                  </span>
+                </div>
+                <div class="card-row">
+                  <span>视频完播率</span>
+                  <span class="highlight-red">{{watchRate}}%</span>
+                </div>
+              </div>
+            </div>
+          </div>
+        </el-col>
+
+        <el-col :xs="24" :sm="12" :md="6" :lg="6" :xl="6" style="position: relative">
+          <div class="analysis-card-check" :class="selectedDiv===1?'analysis-card-check-selected color':''"
+               @click="handleToggleDiv(1)">
+            <div class="analysis-card">
+              <img class="card-icon" src="@/assets/images/renshu_views.png"></img>
+              <div class="card-content">
+                <div class="card-row">
+                  <span>答题人数</span>
+                  <span class="highlight-black">
+                    <count-to :start-val="0" :end-val="answerMemberCount" :duration="3600" class="card-panel-num" />
+                  </span>
+                </div>
+                <div class="card-row">
+                  <span>正确人数</span>
+                  <span class="highlight-black">
+                    <count-to :start-val="0" :end-val="correctUserCount" :duration="3600" class="card-panel-num" />
+                  </span>
+                </div>
+                <div class="card-row">
+                  <span>正确率</span>
+                  <span class="highlight-black">{{correctRate}}%</span>
+                </div>
+              </div>
+            </div>
+          </div>
+        </el-col>
+
+        <el-col :xs="24" :sm="12" :md="6" :lg="6" :xl="6"  style="position: relative">
+          <div class="analysis-card-check" :class="selectedDiv===2?'analysis-card-check-selected color':''"
+               @click="handleToggleDiv(2)">
+            <div class="analysis-card">
+              <img class="card-icon" src="@/assets/images/hongbao_views.png"></img>
+              <div class="card-content">
+                <div class="card-row">
+                  <span>答题红包个数</span>
+                  <span class="highlight-black">
+                    <count-to :start-val="0" :end-val="rewardCount" :duration="3600" class="card-panel-num" />
+                  </span>
+                </div>
+                <div class="card-row">
+                  <span>答题红包金额(元)</span>
+                  <span class="highlight-black">
+                    <count-to :start-val="0" :end-val="rewardMoney" :duration="3600" class="card-panel-num" /></span>
+                </div>
+              </div>
+            </div>
+          </div>
+        </el-col>
+      </el-row>
+    </div>
+
+    <!-- 图表区域 (Charts Area) -->
+    <transition name="fade">
+      <el-row :gutter="20" class="charts-section" v-show="selectedDiv===0">
+        <el-col :span="12">
+          <el-card shadow="never">
+            <div slot="header" class="chart-header">
+              <span>会员观看、完播人数趋势图</span>
+              <div class="legend">
+                <div class="legend-item">
+                  <span class="dot viewer-dot"></span>
+                  <span>观看人数</span>
+                </div>
+                <div class="legend-item">
+                  <span class="dot complete-dot"></span>
+                  <span>完播人数</span>
+                </div>
+              </div>
+              <!--              <el-button size="small" plain class="view-more">平台每日统计 <i class="el-icon-arrow-right"></i></el-button>-->
+            </div>
+            <div ref="viewerChart" class="chart-container"></div>
+          </el-card>
+        </el-col>
+
+
+        <el-col :span="12">
+          <el-card shadow="never">
+            <div slot="header" class="chart-header">
+              <span>经销商看客统计</span>
+              <div class="legend">
+                <div class="legend-item">
+                  <span class="dot viewer-dot"></span>
+                  <span>观看人数</span>
+                </div>
+                <div class="legend-item">
+                  <span class="dot complete-dot"></span>
+                  <span>完播人数</span>
+                </div>
+              </div>
+            </div>
+            <div ref="dealerChartNew" class="chart-container"></div>
+          </el-card>
+        </el-col>
+
+        <!--        <el-col :span="12">-->
+        <!--          <el-card shadow="never">-->
+        <!--            <div slot="header" class="chart-header">-->
+        <!--              <span>经销商会员观看TOP10</span>-->
+        <!--              <div class="legend">-->
+        <!--                <el-radio-group v-model="viewerType" size="small" @change="handleDealerChartData">-->
+        <!--                  <el-radio-button label="0">按观看人数</el-radio-button>-->
+        <!--                  <el-radio-button label="1">按完播人数</el-radio-button>-->
+        <!--                </el-radio-group>-->
+        <!--              </div>-->
+        <!--              &lt;!&ndash;              <el-button size="small" plain class="view-more">经销商统计 <i class="el-icon-arrow-right"></i></el-button>&ndash;&gt;-->
+        <!--            </div>-->
+        <!--            <div ref="dealerChart" class="chart-container"></div>-->
+        <!--          </el-card>-->
+        <!--        </el-col>-->
+      </el-row>
+    </transition>
+    <transition name="fade">
+      <el-row :gutter="20" class="charts-section" v-show="selectedDiv===1">
+        <el-card shadow="never">
+          <div slot="header" class="chart-header">
+            <span>课程观看TOP10</span>
+            <div class="legend">
+              <el-radio-group v-model="viewerType" size="small" @change="handleCourseWatchChart">
+                <el-radio-button label="0">按观看人数</el-radio-button>
+                <el-radio-button label="1">按完播人数</el-radio-button>
+                <el-radio-button label="2">按答题人数</el-radio-button>
+                <el-radio-button label="3">按正确人数</el-radio-button>
+              </el-radio-group>
+            </div>
+            <div class="legend">
+              <el-radio-group v-model="delerSort" @change="handleCourseWatchChart">
+                <el-radio label="DESC">前10名</el-radio>
+                <el-radio label="ASC">倒数10名</el-radio>
+              </el-radio-group>
+            </div>
+            <div class="legend">
+              <div class="legend-item">
+                <span class="dot viewer-dot"></span>
+                <span>观看人数</span>
+              </div>
+              <div class="legend-item">
+                <span class="dot complete-dot"></span>
+                <span>完播人数</span>
+              </div>
+              <div class="legend-item">
+                <span class="dot" style="background-color: #E6A23C"></span>
+                <span>答题人数</span>
+              </div>
+              <div class="legend-item">
+                <span class="dot" style="background-color: #F56C6C"></span>
+                <span>正确人数</span>
+              </div>
+            </div>
+            <!--            <el-button size="small" plain class="view-more">经销商统计 <i class="el-icon-arrow-right"></i></el-button>-->
+          </div>
+          <div ref="courseWatchChart" class="chart-container"></div>
+        </el-card>
+      </el-row>
+    </transition>
+
+    <transition name="fade">
+      <el-row :gutter="20" class="charts-section" v-show="selectedDiv===2">
+        <el-col :span="12">
+          <el-card shadow="never">
+            <div slot="header" class="chart-header">
+              <span>答题红包金额TOP10</span>
+              <div class="legend">
+                <el-radio-group v-model="dataType" size="small" @change="handleAnswerRedPackViewerChart">
+                  <el-radio-button label="0">按经销商排行</el-radio-button>
+                  <el-radio-button label="1">按课程排行</el-radio-button>
+                </el-radio-group>
+              </div>
+              <!--              <el-button size="small" plain class="view-more">红包记录 <i class="el-icon-arrow-right"></i></el-button>-->
+            </div>
+            <div ref="answerRedPackViewerChart" class="chart-container"></div>
+          </el-card>
+        </el-col>
+        <el-col :span="12">
+          <el-card shadow="never">
+            <div slot="header" class="chart-header">
+              <span>答题红包金额趋势图</span>
+              <div class="legend">
+                <div class="legend-item">
+                  <span class="dot viewer-dot"></span>
+                  <span>答题红包金额</span>
+                </div>
+              </div>
+              <!--              <el-button size="small" plain class="view-more">红包记录 <i class="el-icon-arrow-right"></i></el-button>-->
+            </div>
+            <div ref="answerRedPackMoneyViewerChart" class="chart-container"></div>
+          </el-card>
+        </el-col>
+      </el-row>
+    </transition>
+    <el-row :gutter="20" class="charts-section">
+      <el-col :span="12">
+        <el-card shadow="never">
+          <div slot="header" class="chart-header">
+            <span>本月订单数</span>
+            <div class="legend">
+              <div class="legend-item">
+                <span class="dot viewer-dot"></span>
+                <span>订单数</span>
+              </div>
+              <div class="legend-item">
+                <span class="dot complete-dot"></span>
+                <span>订单金额</span>
+              </div>
+            </div>
+          </div>
+          <div ref="viewerOrderChart" class="chart-container"></div>
+        </el-card>
+      </el-col>
+      <el-col :span="12">
+        <el-card shadow="never">
+          <div slot="header" class="chart-header">
+            <span>本月收款数</span>
+            <div class="legend">
+              <div class="legend-item">
+                <span class="dot viewer-dot"></span>
+                <span>收款数</span>
+              </div>
+              <div class="legend-item">
+                <span class="dot complete-dot"></span>
+                <span>收款金额</span>
+              </div>
+            </div>
+          </div>
+          <div ref="viewerReceiveChart" class="chart-container"></div>
+        </el-card>
+      </el-col>
+    </el-row>
+    <br/>
+  </div>
+</template>
+
+<script>
+import * as echarts from 'echarts'
+import CountTo from "vue-count-to";
+import {
+  analysisPreview,
+  authorizationInfo,
+  dealerAggregated, deaMemberTopTen, rechargeComsumption, rewardMoneyTopTen, rewardMoneyTrend,
+  smsBalance, thisMonthOrderCount, thisMonthRecvCount, trafficLog,
+  watchCourseTopTen, watchEndPlayTrend,getWatchCourseStatisticsData
+} from "@/api/statistics/statistics";
+import dayjs from 'dayjs';
+import { listDept } from '@/api/system/dept'
+import { listCompany } from '@/api/his/company'
+
+
+const viewCharOption = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    }
+  },
+  grid: {
+    left: '3%',
+    right: '4%',
+    bottom: '3%',
+    containLabel: true
+  },
+  xAxis: {
+    type: 'category',
+    data: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23']
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      name: '观看人数',
+      type: 'bar',
+      data: [],
+      itemStyle: {
+        color: '#409EFF'
+      }
+    },
+    {
+      name: '完播人数',
+      type: 'bar',
+      data: [],
+      itemStyle: {
+        color: '#67C23A'
+      }
+    }
+  ]
+}
+
+const dealerOptionNew = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    }
+  },
+  grid: {
+    left: '3%',
+    right: '4%',
+    bottom: '3%',
+    containLabel: true
+  },
+  xAxis: {
+    type: 'category',
+    axisLabel: {
+      rotate: 30, // 设置标签倾斜45度
+      // fontSize: 12, // 减小字体大小
+      interval: 0, // 显示所有标签
+      // 可选:限制标签宽度并截断
+      width: 80,
+      overflow: 'truncate',
+      // 可选:设置标签的对齐方式
+      margin: 20,
+      fontWeight: 'bold' // 设置字体加粗
+    }
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      name: '观看人数',
+      type: 'bar',
+      data: [],
+      itemStyle: {
+        color: '#409EFF'
+      }
+    },
+    {
+      name: '完播人数',
+      type: 'bar',
+      data: [],
+      itemStyle: {
+        color: '#67C23A'
+      }
+    }
+  ]
+}
+
+const thisMonthOrderCountOption = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    }
+  },
+  grid: {
+    left: '3%',
+    right: '4%',
+    bottom: '3%',
+    containLabel: true
+  },
+  xAxis: {
+    type: 'category',
+    data: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23']
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      name: '订单数',
+      type: 'line',
+      data: [],
+      itemStyle: {
+        color: '#409EFF'
+      }
+    },
+    {
+      name: '订单金额',
+      type: 'line',
+      data: [],
+      itemStyle: {
+        color: '#67C23A'
+      }
+    }
+  ]
+}
+
+const thisMonthRecvCountOption = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    }
+  },
+  grid: {
+    left: '3%',
+    right: '4%',
+    bottom: '3%',
+    containLabel: true
+  },
+  xAxis: {
+    type: 'category',
+    data: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23']
+  },
+  yAxis: {
+    type: 'value'
+  },
+  series: [
+    {
+      name: '收款数',
+      type: 'line',
+      data: [],
+      itemStyle: {
+        color: '#409EFF'
+      }
+    },
+    {
+      name: '收款金额',
+      type: 'line',
+      data: [],
+      itemStyle: {
+        color: '#67C23A'
+      }
+    }
+  ]
+}
+const dealerOption = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    }
+  },
+  grid: {
+    left: '3%',
+    right: '4%',
+    bottom: '3%',
+    containLabel: true
+  },
+  xAxis: {
+    type: 'value'
+  },
+  yAxis: {
+    type: 'category',
+    data: []
+  },
+  series: [
+    {
+      name: '观看人数',
+      type: 'bar',
+      data: [],
+      itemStyle: {
+        color: '#409EFF'
+      }
+    }
+  ]
+}
+
+const courseWatchOption = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    }
+  },
+  grid: {
+    left: '3%',
+    right: '4%',
+    bottom: '8%',
+    top: '3%',
+    containLabel: true
+  },
+  xAxis: {
+    type: 'category',
+    data: [],
+    axisLabel: {
+      interval: 0,
+      rotate: 30,
+      fontSize: 10,
+      width: 100,
+      overflow: 'truncate'
+    }
+  },
+  yAxis: {
+    type: 'value',
+    splitLine: {
+      lineStyle: {
+        type: 'dashed'
+      }
+    }
+  },
+  series: [
+    {
+      name: '观看人数',
+      type: 'bar',
+      data: [],
+      itemStyle: {
+        color: '#409EFF'
+      }
+    },
+    {
+      name: '完播人数',
+      type: 'bar',
+      data: [],
+      itemStyle: {
+        color: '#67C23A'
+      }
+    },
+    {
+      name: '答题人数',
+      type: 'bar',
+      data: [],
+      itemStyle: {
+        color: '#E6A23C'
+      }
+    },
+    {
+      name: '正确人数',
+      type: 'bar',
+      data: [],
+      itemStyle: {
+        color: '#F56C6C'
+      }
+    }
+  ]
+}
+
+const lineChartOption = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'cross' // 改为 'cross' 更适合折线图
+    }
+  },
+  grid: {
+    left: '3%',
+    right: '4%',
+    bottom: '8%', // 如果x轴标签旋转,可能需要更大的 bottom
+    top: '5%',    // 增加一点顶部空间给可能的 Y 轴名称
+    containLabel: true
+  },
+  xAxis: {
+    type: 'time', // X轴类型改为 'time'
+    // data: [], // 时间轴不需要单独设置 data,数据在 series 中提供
+    axisLabel: {
+      // interval: 0, // 时间轴通常自动处理间隔,可以先移除或注释掉
+      rotate: 30,   // 保留旋转,如果标签可能重叠
+      fontSize: 10,
+      // width: 100, // width 和 overflow 对于时间轴可能行为不同,按需调整
+      // overflow: 'truncate',
+      formatter: null // ECharts 会自动格式化时间,如需特定格式可用 function 或字符串模板
+    }
+  },
+  yAxis: {
+    type: 'value',
+    name: '金额 (元)', // 添加 Y 轴名称
+    nameLocation: 'end', // 名称位置
+    nameTextStyle: {
+      align: 'right',
+      padding: [0, 10, 0, 0] // 调整名称与轴线的距离
+    },
+    splitLine: {
+      lineStyle: {
+        type: 'dashed'
+      }
+    },
+    axisLabel: {
+      formatter: '{value} 元' // 可选:给 Y 轴刻度添加单位
+    }
+  },
+  series: [
+    {
+      name: '答题红包金额',
+      type: 'line', // 系列类型改为 'line'
+      data: [
+      ],
+      itemStyle: { // 控制数据点(标记)的样式
+        color: '#409EFF'
+      },
+      lineStyle: { // 控制线的样式
+        color: '#409EFF'
+      },
+      smooth: false, // 是否平滑曲线,可设为 true
+      symbol: 'circle', // 数据点标记形状,'emptyCircle', 'rect', 'roundRect', 'triangle', 'diamond', 'pin', 'arrow', 'none'
+      symbolSize: 4   // 数据点标记大小
+    }
+  ]
+};
+
+
+const redPackageOption = {
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    }
+  },
+  grid: {
+    left: '3%',
+    right: '4%',
+    bottom: '8%',
+    top: '3%',
+    containLabel: true
+  },
+  xAxis: {
+    type: 'category',
+    data: [],
+    axisLabel: {
+      interval: 0,
+      rotate: 30,
+      fontSize: 10,
+      width: 100,
+      overflow: 'truncate'
+    }
+  },
+  yAxis: {
+    type: 'value',
+    splitLine: {
+      lineStyle: {
+        type: 'dashed'
+      }
+    }
+  },
+  series: [
+    {
+      name: '答题红包金额',
+      type: 'bar',
+      data: [],
+      itemStyle: {
+        color: '#409EFF'
+      }
+    }
+  ]
+}
+export default {
+  name: 'StatisticsDashboard',
+  components: {CountTo},
+  data() {
+    return {
+      deptInitOptions:[],
+      deptOptions:[],
+      intiDeptId:this.$store.state.user.user.deptId,
+      deptId:this.$store.state.user.user.deptId,
+      staticParam : {companyId:null,deptId:this.$store.state.user.user.deptId},
+      companyIntiOptions:[],
+      companyOptions:[],
+      companyId:null,
+      percentage: 0,
+      // 预测message
+      remainMessage: '',
+      // 当天使用流量
+      todayTraffic: 0,
+      trafficCount: 0,
+      // 当月使用流量
+      thisMonthTraffic: 0,
+      dataType: '0',
+      delerSort: 'DESC',
+      smsRemainCount: 0,
+      viewerType: '0',
+      viewerChart: null,
+      dealerChartNew: null,
+      userTypeText: process.env.VUE_APP_COURSE_DEFAULT==1?"会员":"企微",
+      userType: process.env.VUE_APP_COURSE_DEFAULT,
+      dealerChart: null,
+      // 分公司数量
+      dealderCount: 0,
+      // 销售数量
+      groupMgrCount: 0,
+      // 会员总数量
+      memberCount: 0,
+      // 企微数量
+      qwMemberNum: 0,
+      // pad使用情况
+      padTotalNum: 0,
+      // pad使用情况
+      padUsedNum: 0,
+      // 正常会员数量
+      normalNum: 0,
+      // 黑名单会员数量
+      blackNum: 0,
+      // 观看人数
+      watchUserCount: 0,
+      // 完播人数
+      completedUserCount: 0,
+      // 完播率
+      completedRate: 0,
+      // 观看次数
+      watchCount:0,
+      // 完播次数
+      completedCount: 0,
+      // 视频完播率
+      watchRate: 0,
+      // 答题人数
+      answerMemberCount: 0,
+      // 正确人数
+      correctUserCount: 0,
+      correctRate: 0.0,
+      // 答题红包个数
+      rewardCount: 0,
+      // 答题红包金额
+      rewardMoney: 0.0,
+      queryTime: '今日',
+      todayWatchUserCount: 0,
+      versionLimit: 0,
+      versionLimitPercent : 0.0,
+      /// 选中的分析概览
+      selectedDiv: 0,
+      filterType: 0,
+      answerRedPackViewerChart: null,
+      answerRedPackMoneyViewerChart: null,
+      todayComsumption: 0,
+      yesterdayComsumption: 0,
+      balance: 0,
+      runTianBalance: 0,
+      autoRefreshInterval: null,
+      // 今日新增用户数
+      todayIncreaseUserNum: 0,
+      // 订单总数
+      orderTotalNum: 0,
+      // 今日新增订单数
+      todayOrderNum: 0,
+      // 收款总数
+      recvTotalNum: 0,
+      // 今日收款总数
+      recvTodayNum: 0,
+      // 商品总数
+      goodsTotalNum: 0,
+      // 今日商品总数
+      todayGoodsNum: 0
+    }
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.initViewerChart();
+      this.initDealerChartNew();
+      this.initDealerChart();
+      this.initCourseWatchChart();
+      this.initAnswerRedPackViewerChart();
+      this.initAnswerRedPackMoneyViewerChart();
+      this.initThisMonthOrderChart();
+      this.initThisMonthRecvChart();
+
+
+      // 监听窗口大小变化,重新渲染图表
+      window.addEventListener('resize', () => {
+        this.viewerChart && this.viewerChart.resize()
+        this.dealerChart && this.dealerChart.resize()
+        this.dealerChartNew && this.dealerChartNew.resize()
+      })
+    })
+  },
+  created() {
+    this.refresh();
+    listDept().then(res => {
+      this.deptInitOptions = res.data;
+      listCompany().then(res => {
+        this.companyIntiOptions = res.rows;
+        this.getDeptOptions(this.intiDeptId);
+        this.getCompanyOptions(this.intiDeptId);
+      });
+    });
+  },
+  methods: {
+    getDeptOptions(deptId) {
+      const deptInitOptions = this.deptInitOptions;
+      // 部门本身节点
+      let deptNode = deptInitOptions.filter(item => item.deptId === deptId);
+
+      // 递归查找所有子节点
+      function findChildren(parentId) {
+        //部门的子部门
+        let deptChildren = deptInitOptions.filter(item => item.parentId === parentId);
+        //添加子部门
+        deptChildren.forEach(child => {
+          deptNode.push(child);
+          findChildren(child.deptId); // 递归查找子节点的子节点
+        });
+      }
+
+      // 从目标节点开始查找子节点
+      findChildren(deptId);
+      this.deptOptions = deptNode;
+    },
+    getCompanyOptions(deptId) {
+      this.companyId = null;
+      //修改选择后清空查询参数
+      this.staticParam.companyId = null;
+      this.staticParam.deptId = deptId;
+      const deptInitOptions = this.deptInitOptions;
+      const companyInitOptions = this.companyIntiOptions;
+      // 部门下的公司
+      let companyNode = companyInitOptions.filter(item => item.deptId === deptId);
+
+      // 递归查找所有子节点
+      function findChildren(parentId) {
+        //部门的子部门
+        let deptChildren = deptInitOptions.filter(item => item.parentId === parentId);
+        //添加子部门
+        deptChildren.forEach(child => {
+          //子部门下的销售公司
+          let companyChildren = companyInitOptions.filter(item => item.deptId === child.deptId);
+          companyChildren.forEach(companyChild => {
+            companyNode.push(companyChild);
+          })
+          findChildren(child.deptId); // 递归查找子节点的子节点
+        });
+      }
+
+      // 从目标节点开始查找子节点
+      findChildren(deptId);
+      this.companyOptions = companyNode;
+    },
+    //首页统计选择部门、销售公司
+    handleDeptChange() {
+      this.getCompanyOptions(this.deptId);
+      this.refresh();
+    },
+    handleCompanyChange() {
+      this.staticParam.companyId = this.companyId;
+      this.refresh();
+    },
+    handleUserType() {
+      if (this.userTypeText === '会员') {
+        this.userType = 1
+      } else {
+        this.userType = 2
+      }
+
+      this.refresh()
+    },
+    /**
+     * 计算余额预计可持续的天数
+     * @param {number} balance - 当前账户余额
+     * @param {number} runTianBalance - 润天账户余额
+     * @param {number} todayConsumption - 今日消耗金额
+     * @param {number} yesterdayConsumption - 昨日消耗金额
+     * @return {Object} 包含天数和进度百分比的对象
+     */
+    calculateRemainingDays(balance, todayConsumption, yesterdayConsumption) {
+      // 如果今日和昨日消耗都为0,则无法预测(避免除以0)
+      if (todayConsumption === 0 && yesterdayConsumption === 0) {
+        return {
+          days: Infinity,
+          percentage: 0,
+          message: '暂无消耗数据'
+        };
+      }
+
+      // 计算每日平均消耗量
+      const avgDailyConsumption = (todayConsumption + yesterdayConsumption) / 2;
+
+      // 如果平均消耗为0,则无法预测
+      if (avgDailyConsumption === 0) {
+        return {
+          days: Infinity,
+          percentage: 0,
+          message: '暂无消耗数据'
+        };
+      }
+
+      // 计算剩余天数(向下取整)
+      const remainingDays = Math.floor(balance / avgDailyConsumption);
+
+      // 计算进度条百分比,最大为100
+      // 这里假设100天是满值,可以根据需要调整
+      const maxDays = 100;
+      const percentage = Math.min(100, Math.max(0, Math.round((remainingDays / maxDays) * 100)));
+
+      let message = '';
+      if (remainingDays > 365) {
+        message = '预测余额充足';
+      } else {
+        message = `预测不足${remainingDays}天`;
+      }
+
+      return {
+        days: remainingDays,
+        percentage: 100 - percentage,
+        message: message
+      };
+    },
+    /**
+     * 将字节数转换为合适的单位表示(Byte、KB、MB、GB、TB)
+     * @param {number} bytes - 字节数
+     * @param {number} [decimals=2] - 小数点后保留的位数
+     * @returns {string} 格式化后的字符串,包含数值和单位
+     */
+    formatBytes(bytes, decimals = 2) {
+      const isNegative = bytes < 0;  // 判断是否为负数
+      bytes = Math.abs(bytes);  // 获取绝对值
+
+      if (bytes === 0) return '0 Byte';
+
+      const k = 1024;
+      const sizes = ['Byte', 'KB', 'MB', 'GB', 'TB'];
+
+      // 计算合适的单位级别
+      let i = Math.floor(Math.log(bytes) / Math.log(k));
+
+      // 转换为对应单位的值
+      const value = bytes / Math.pow(k, i);
+
+
+      if(this.deptId !== 1 ||  this.companyId !== null){
+        i += 1;
+      }
+      // 格式化为指定小数位的字符串
+      const result = parseFloat(value.toFixed(decimals)) + ' ' + sizes[Math.min(i, sizes.length - 1)];
+
+      // 如果是负数,返回带负号的值
+      return isNegative ? `-${result}` : result;
+    },
+    // 手动刷新
+    manualRefresh() {
+      this.refresh();
+    },
+    // 处理自动刷新选项
+    handleAutoRefresh(command) {
+      // 清除之前的定时器
+      if (this.timer) {
+        clearInterval(this.timer);
+        this.timer = null;
+      }
+
+      // 设置新的刷新间隔
+      this.autoRefreshInterval = parseInt(command);
+
+      // 如果间隔大于0,设置新的定时器
+      if (this.autoRefreshInterval > 0) {
+        this.timer = setInterval(() => {
+          this.refresh();
+        }, this.autoRefreshInterval * 60 * 1000); // 转换为毫秒
+
+        this.$message.success(`已设置${this.autoRefreshInterval}分钟自动刷新`);
+      } else {
+        this.$message.info('已关闭自动刷新');
+      }
+    },
+    refresh() {
+      rechargeComsumption(this.staticParam).then(res => {
+        console.log(res);
+        if (res.code === 200) {
+          this.balance = res.data.balance;
+          this.runTianBalance = res.data.runTianBalance;
+          this.todayComsumption = res.data.todayComsumption;
+          this.yesterdayComsumption = res.data.yesterdayComsumption;
+          let calculateRemainingDays1 = this.calculateRemainingDays(this.balance, this.todayComsumption, this.yesterdayComsumption);
+          this.percentage = calculateRemainingDays1.percentage;
+          this.remainMessage = calculateRemainingDays1.message;
+        }
+      });
+
+      trafficLog(this.staticParam).then(res => {
+        if (res.code === 200) {
+          this.todayTraffic = res.data.today;
+          this.thisMonthTraffic = res.data.thisMonth;
+          this.trafficCount = res.data.traffic;
+        }
+      })
+
+      dealerAggregated(this.staticParam).then(res => {
+        if (res.code === 200) {
+          this.dealderCount = res.data.dealderCount ?? 0;
+          this.groupMgrCount = res.data.groupMgrCount ?? 0;
+          this.memberCount = res.data.memberCount ?? 0;
+          this.qwMemberNum = res.data.qwMemberNum ?? 0;
+          const totalNum = res.data.padTotalNum;
+          //-1 不限 null 未设置
+          if(totalNum != null && totalNum !== -1 && totalNum > 0){
+            this.padTotalNum = totalNum;
+          }else{
+            this.padTotalNum = '不限';
+          }
+          this.padUsedNum = res.data.padUsedNum ?? 0;
+          this.padInfo = res.data.padInfo;
+          this.normalNum = res.data.normalNum ?? 0;
+          this.blackNum = res.data.blackNum ?? 0;
+          this.todayIncreaseUserNum = res.data.todayIncreaseUserNum ?? 0;
+          this.orderTotalNum = res.data.orderTotalNum ?? 0;
+          this.todayOrderNum = res.data.todayOrderNum ?? 0;
+          this.recvTotalNum = res.data.recvTotalNum ?? 0;
+          this.recvTodayNum = res.data.recvTodayNum ?? 0;
+          this.goodsTotalNum = res.data.goodsTotalNum ?? 0;
+          this.todayGoodsNum = res.data.todayGoodsNum ?? 0;
+        }
+      })
+      let param = this.getParam();
+
+      // 获取当前日期时间
+      const today = dayjs();
+      param.startTime = this.formatDate(today);
+      param.endTime = this.formatDate(today);
+      analysisPreview(param).then(res => {
+        if (res.code === 200) {
+          this.watchUserCount = res.data.watchUserCount;
+          this.completedUserCount = res.data.completedUserCount;
+          this.completedRate = res.data.completedRate;
+          this.watchCount = res.data.watchCount;
+          this.completedCount = res.data.completedCount;
+          this.answerMemberCount = res.data.answerMemberCount;
+          this.correctUserCount = res.data.correctUserCount;
+          this.correctRate = res.data.correctRate;
+          this.rewardCount = res.data.rewardCount;
+          this.rewardMoney = res.data.rewardMoney;
+          this.watchRate = res.data.watchRate;
+        }
+      })
+      smsBalance(this.staticParam).then(res => {
+        if (res.code === 200) {
+          if (res.data == null) {
+            this.smsRemainCount = 0;
+          } else {
+            this.smsRemainCount = res.data;
+          }
+        }
+      })
+      authorizationInfo(this.staticParam).then(res => {
+        if (res.code === 200 && res.data != null) {
+          this.todayWatchUserCount = res.data.todayWatchUserCount;
+          this.versionLimit = res.data.versionLimit;
+          if(this.versionLimit){
+            this.versionLimitPercent = this.todayWatchUserCount/this.versionLimit;
+          }
+        }
+      })
+
+      this.handleCourseWatchChart()
+      this.handleViewChartData()
+      this.handleDealerChartDataNew()
+
+      // 经销商会员观看TOP10
+      this.handleDealerChartData()
+
+      this.handleAnswerRedPackViewerChart()
+
+      this.handleAnswerRedPackMoneyViewerChart()
+
+      this.handleThisMonthRecvCount();
+      this.handleThisMonthOrderCount();
+
+    },
+    /**
+     * 将数字添加千位分隔符
+     * @param {number|string} num - 需要格式化的数字
+     * @return {string} 添加千位分隔符后的字符串
+     */
+    formatNumberWithCommas(num) {
+      if (num === null || num === undefined || isNaN(Number(num))) {
+        return '0';
+      }
+
+      const numStr = String(num);
+
+      // 处理负数
+      const isNegative = numStr.startsWith('-');
+      const absNumStr = isNegative ? numStr.slice(1) : numStr;
+
+      // 分离整数部分和小数部分
+      const parts = absNumStr.split('.');
+      const integerPart = parts[0];
+      const decimalPart = parts.length > 1 ? '.' + parts[1] : '';
+
+      const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
+
+      return (isNegative ? '-' : '') + formattedInteger + decimalPart;
+    },
+    handleToggleDiv(selected) {
+      this.selectedDiv = selected;
+
+      if (selected === 1) {
+        this.$nextTick(() => {
+          if (this.courseWatchChart) {
+            this.courseWatchChart.resize();
+          } else {
+          }
+        });
+      } else if (selected === 0) {
+        this.$nextTick(() => {
+          if (this.viewerChart) this.viewerChart.resize();
+          if (this.dealerChart) this.dealerChart.resize();
+        });
+      } else if (selected === 2) {
+        this.$nextTick(() => {
+          if (this.answerRedPackViewerChart) this.answerRedPackViewerChart.resize();
+          if (this.answerRedPackMoneyViewerChart) this.answerRedPackMoneyViewerChart.resize();
+        });
+      }
+      if (this.selectedDiv === 0) {
+        this.handleViewChartData()
+        this.handleDealerChartData()
+        this.handleDealerChartDataNew()
+      } else if (this.selectedDiv === 1) {
+        this.handleCourseWatchChart()
+      } else if (this.selectedDiv === 2) {
+        this.handleAnswerRedPackViewerChart()
+        this.handleAnswerRedPackMoneyViewerChart()
+      }
+    },
+    formatDate(date) {
+      return dayjs(date).format('YYYY-MM-DD');
+    },
+
+    getParam() {
+      let param = {
+        startTime: '',
+        endTime: '',
+        userType: this.userType,
+        companyId: this.companyId,
+        deptId: this.deptId
+      };
+      // 获取当前日期时间
+      const today = dayjs();
+
+      let type = 0;
+      if (this.queryTime === '今日') {
+        param.startTime = this.formatDate(today);
+        param.endTime = this.formatDate(today);
+        type = 0;
+      } else if (this.queryTime === '昨日') {
+        const yesterday = today.subtract(1, 'day');
+        param.startTime = this.formatDate(yesterday);
+        param.endTime = this.formatDate(yesterday);
+        type = 1;
+      } else if (this.queryTime === '本周') {
+        param.startTime = this.formatDate(today.startOf('week'));
+        param.endTime = this.formatDate(today.endOf('week'));
+        type = 2;
+      } else if (this.queryTime === '本月') {
+        param.startTime = this.formatDate(today.startOf('month'));
+        param.endTime = this.formatDate(today.endOf('month'));
+        type = 3;
+      } else if (this.queryTime === '上月') {
+        const lastMonth = today.subtract(1, 'month');
+        param.startTime = this.formatDate(lastMonth.startOf('month'));
+        param.endTime = this.formatDate(lastMonth.endOf('month'));
+        type = 4;
+      } else {
+        console.warn(`未知的 queryTime: ${this.queryTime}, 默认使用今日`);
+        param.startTime = this.formatDate(today);
+        param.endTime = this.formatDate(today);
+      }
+      param.type = type;
+      param.sort = this.delerSort;
+      return param;
+    },
+    // 分析概览
+    handleAnalysis(e) {
+
+      let param = this.getParam();
+      analysisPreview(param).then(res => {
+        if (res.code === 200) {
+          this.watchUserCount = res.data.watchUserCount;
+          this.completedUserCount = res.data.completedUserCount;
+          this.completedRate = res.data.completedRate;
+          this.watchCount = res.data.watchCount;
+          this.completedCount = res.data.completedCount;
+          this.answerMemberCount = res.data.answerMemberCount;
+          this.correctUserCount = res.data.correctUserCount;
+          this.correctRate = res.data.correctRate;
+          this.rewardCount = res.data.rewardCount;
+          this.rewardMoney = res.data.rewardMoney;
+          this.watchRate = res.data.watchRate;
+        }
+      })
+
+      if (this.selectedDiv === 0) {
+        this.handleViewChartData()
+        this.handleDealerChartData()
+        this.handleDealerChartDataNew()
+      } else if (this.selectedDiv === 1) {
+        this.handleCourseWatchChart()
+      } else if (this.selectedDiv === 2) {
+        this.handleAnswerRedPackViewerChart()
+        this.handleAnswerRedPackMoneyViewerChart()
+      }
+    },
+    handleAnswerRedPackViewerChart() {
+      let param = this.getParam();
+      param = { ...param, statisticalType: this.viewerType, dataType: this.dataType };
+      rewardMoneyTopTen(param).then(res => {
+        if (res.code === 200) {
+          let data = res.data;
+          let companyNameList = data.map(e => e.companyName)
+          let courseNameList = data.map(e => e.courseName)
+          let rewardMoneyList = data.map(e => e.rewardMoney)
+          if (this.dataType === '0') {
+            redPackageOption.xAxis.data = companyNameList;
+          } else {
+            redPackageOption.xAxis.data = courseNameList;
+          }
+          redPackageOption.series[0].data = rewardMoneyList;
+
+          this.answerRedPackViewerChart.setOption(redPackageOption)
+        }
+      })
+    },
+    handleAnswerRedPackMoneyViewerChart() {
+      let param = this.getParam();
+      param = { ...param, statisticalType: this.viewerType, dataType: this.dataType };
+      rewardMoneyTrend(param).then(res => {
+        if (res.code === 200) {
+          let data = res.data;
+          let option = data.map(e => [e.x, e.rewardMoney])
+          lineChartOption.series[0].data = option;
+
+          this.answerRedPackMoneyViewerChart.setOption(lineChartOption)
+        }
+      })
+    },
+    handleCourseWatchChart() {
+      let param = this.getParam();
+      param = { ...param, statisticalType: this.viewerType };
+      watchCourseTopTen(param).then(res => {
+        if (res.code === 200) {
+          let data = res.data;
+          let watchUserCountList = data.map(e => e.watchUserCount);
+          let completedUserCountList = data.map(e => e.completedUserCount);
+          let answerUserCountList = data.map(e => e.answerUserCount);
+          let correctUserCountList = data.map(e => e.correctUserCount);
+          let courseNameList = data.map(e => e.courseName);
+          courseWatchOption.xAxis.data = courseNameList;
+          courseWatchOption.series[0].data = watchUserCountList;
+          courseWatchOption.series[1].data = completedUserCountList;
+          courseWatchOption.series[2].data = answerUserCountList;
+          courseWatchOption.series[3].data = correctUserCountList;
+          this.courseWatchChart.setOption(courseWatchOption)
+        }
+      })
+    },
+    handleDealerChartData() {
+      let param = this.getParam();
+
+      // 经销商会员观看TOP10
+      deaMemberTopTen({ ...param, statisticalType: this.viewerType }).then(res => {
+        if (res.code === 200) {
+          let data = res.data;
+          let companyNameList = data.map(e => e.companyName);
+          let watchUserList = data.map(e => e.watchUserCount);
+          dealerOption.yAxis.data = companyNameList;
+          dealerOption.series[0].data = watchUserList;
+
+          this.dealerChart.setOption(dealerOption)
+        }
+      })
+
+    },
+    handleThisMonthOrderCount() {
+      thisMonthOrderCount(this.staticParam).then(res => {
+        if (res.code === 200) {
+          let dates = res.dates;
+          let orderCount = res.orderCount;
+          let payPrice = res.payPrice;
+
+          thisMonthOrderCountOption.series[0].data = orderCount;
+          thisMonthOrderCountOption.series[1].data = payPrice;
+          thisMonthOrderCountOption.xAxis.data = dates;
+
+          this.thisMonthOrderChart.setOption(thisMonthOrderCountOption)
+        }
+      })
+    },
+    handleThisMonthRecvCount() {
+      thisMonthRecvCount(this.staticParam).then(res => {
+        if (res.code === 200) {
+          let dates = res.dates;
+          let orderCount = res.orderCount;
+          let payMoney = res.payMoney;
+
+          thisMonthRecvCountOption.series[0].data = orderCount;
+          thisMonthRecvCountOption.series[1].data = payMoney;
+          thisMonthRecvCountOption.xAxis.data = dates;
+          this.thisMonthRecvChart.setOption(thisMonthRecvCountOption)
+        }
+      })
+    },
+    handleViewChartData() {
+      let param = this.getParam();
+
+      watchEndPlayTrend({ ...param }).then(res => {
+        if (res.code === 200) {
+          let data = res.data;
+          let watchUserCountList = data.map(e => e.watchUserCount);
+          let completedUserCountList = data.map(e => e.completedUserCount);
+          let xAxis = data.map(e => e.x);
+          viewCharOption.series[0].data = watchUserCountList;
+          viewCharOption.series[1].data = completedUserCountList;
+          viewCharOption.xAxis.data = xAxis;
+
+          this.viewerChart.setOption(viewCharOption);
+        }
+      })
+
+    },
+    handleDealerChartDataNew() {
+      let param = this.getParam();
+
+      getWatchCourseStatisticsData({ ...param }).then(res => {
+        if (res.code === 200) {
+          console.log(res.data);
+          // 根据实际数据结构调整
+          let data = res.data;
+          let watchUserCountList = data.map(e => e.watchCount);     // 观看次数
+          let completedUserCountList = data.map(e => e.finishCount); // 完播次数
+          let xAxis = data.map(e => e.companyName);                 // X轴使用公司名称
+
+          // 更新图表配置
+          dealerOptionNew.series[0].data = watchUserCountList;
+          dealerOptionNew.series[1].data = completedUserCountList;
+          dealerOptionNew.xAxis.data = xAxis;
+
+          this.dealerChartNew.setOption(dealerOptionNew);
+
+        }
+      })
+
+    },
+    initThisMonthOrderChart() {
+      this.thisMonthOrderChart = echarts.init(this.$refs.viewerOrderChart)
+      this.thisMonthOrderChart.setOption(thisMonthOrderCountOption)
+    },
+    initThisMonthRecvChart() {
+
+      this.thisMonthRecvChart = echarts.init(this.$refs.viewerReceiveChart)
+      this.thisMonthRecvChart.setOption(thisMonthOrderCountOption)
+    },
+    initViewerChart() {
+      this.viewerChart = echarts.init(this.$refs.viewerChart)
+      this.viewerChart.setOption(viewCharOption)
+    },
+    initDealerChartNew() {
+      this.dealerChartNew = echarts.init(this.$refs.dealerChartNew)
+      this.dealerChartNew.setOption(dealerOptionNew)
+    },
+    initDealerChart() {
+      this.dealerChart = echarts.init(this.$refs.dealerChart)
+
+      this.dealerChart.setOption(dealerOption)
+    },
+    initCourseWatchChart() {
+      this.courseWatchChart = echarts.init(this.$refs.courseWatchChart)
+
+      this.courseWatchChart.setOption(courseWatchOption)
+    },
+    initAnswerRedPackViewerChart() {
+      this.answerRedPackViewerChart = echarts.init(this.$refs.answerRedPackViewerChart)
+
+      this.answerRedPackViewerChart.setOption(redPackageOption)
+    },
+    initAnswerRedPackMoneyViewerChart() {
+      this.answerRedPackMoneyViewerChart = echarts.init(this.$refs.answerRedPackMoneyViewerChart)
+
+      this.answerRedPackMoneyViewerChart.setOption(lineChartOption)
+    }
+  },
+
+  beforeDestroy() {
+    // 组件销毁时清除定时器
+    if (this.timer) {
+      clearInterval(this.timer);
+      this.timer = null;
+    }
+    // window.removeEventListener('resize', this.resizeHandler)
+    this.viewerChart && this.viewerChart.dispose()
+    this.dealerChart && this.dealerChart.dispose()
+    this.dealerChartNew && this.dealerChartNew.dispose()
+  }
+}
+</script>
+
+<style scoped>
+.highlight-today-add {
+  color: green;
+  font-size: 17px;
+  font-weight: normal;
+}
+
+.highlight-today-add2 {
+  color: rgba(49, 185, 154, 1);
+  font-size: 14px;
+  font-weight: normal;
+  transform: scale(.9);
+}
+
+.action-group .el-button + .el-button,
+.action-group .el-dropdown {
+  margin-left: 10px;
+}
+
+.is-active {
+  color: #409EFF;
+  font-weight: bold;
+}
+
+::v-deep .el-radio-button__inner:hover {
+  color: #409EFF;
+  /* 鼠标悬浮时的文字颜色,可以根据需要调整 */
+}
+
+::v-deep .el-radio-button.is-active .el-radio-button__inner {
+  background-color: #409EFF;
+  /* 选中时的背景色 */
+  border-color: #409EFF;
+  /* 选中时的边框色 */
+  color: #FFFFFF;
+  /* 选中时的文字颜色 (通常是白色) */
+  box-shadow: -1px 0 0 0 #409EFF;
+  /* 处理按钮间的连接缝隙 */
+}
+
+/* 如果需要,也可以修改非选中状态下的聚焦(focus)或悬浮(hover)样式 */
+/* 例如,让非选中按钮悬浮时边框和文字也变蓝 */
+::v-deep .el-radio-button:not(.is-active) .el-radio-button__inner:hover {
+  color: #409EFF;
+  /* border-color: #b3d8ff;  Element UI 默认悬浮边框色,可以按需修改 */
+}
+
+/* 聚焦时的外框,如果需要的话 */
+::v-deep .el-radio-button:focus:not(.is-checked) .el-radio-button__inner {
+  /* border-color: #409EFF; */
+  /* Element UI 默认的 focus 颜色通常关联主题色 */
+  /* box-shadow: 0 0 2px 2px rgba(64, 158, 255, 0.2); */
+  /* 示例 focus 光晕 */
+}
+
+.statistics-dashboard {
+  padding: 20px;
+  background-color: #f5f7fa;
+}
+
+.overview-section,
+.analysis-section {
+  margin-bottom: 20px;
+  border-radius: 4px;
+}
+
+.header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  font-size: 16px;
+  font-weight: 500;
+}
+
+.data-card {
+  background-color: #fff;
+  border-radius: 4px;
+  padding: 15px;
+  height: 120px;
+  display: flex;
+  flex-direction: column;
+  position: relative;
+  transition: background-color 0.3s ease-in-out;
+}
+
+.data-card:hover {
+  border: 1px solid #4592ff;
+  background-color: #e7f1ff;
+}
+
+.card-title {
+  color: #606266;
+  font-size: 14px;
+  margin-bottom: 10px;
+}
+
+.card-title1 {
+  color: white;
+  font-size: 14px;
+  margin-bottom: 10px;
+}
+
+.card-value {
+  font-size: 24px;
+  font-weight: bold;
+  margin-top: 20px;
+}
+
+.highlight {
+  color: #409EFF;
+}
+
+.card-sub {
+  display: flex;
+  justify-content: space-between;
+  font-size: 12px;
+  color: #909399;
+  margin-top: 5px;
+}
+
+.card-desc {
+  font-size: 12px;
+  color: #909399;
+  margin-top: 5px;
+}
+
+.card-badge {
+  position: absolute;
+  top: 15px;
+  right: 15px;
+  background: #f0f9eb;
+  color: #67c23a;
+  padding: 2px 5px;
+  border-radius: 4px;
+}
+
+.cdn-label {
+  background-color: #409EFF;
+  color: white;
+  padding: 2px 5px;
+  border-radius: 4px;
+  margin-right: 5px;
+  font-size: 12px;
+}
+
+.tab-group {
+  display: flex;
+  gap: 10px;
+}
+
+.action-group {
+  display: flex;
+  gap: 10px;
+}
+
+.analysis-card {
+  border-radius: 4px;
+  padding: 20px;
+  display: flex;
+  align-items: center;
+}
+
+.card-icon {
+  width: 50px;
+  height: 50px;
+  background-color: rgba(64, 158, 255, 0.1);
+  border-radius: 8px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  font-size: 24px;
+  color: #409EFF;
+  margin-right: 20px;
+}
+
+.card-content {
+  display: flex;
+}
+
+.card-row {
+  display: flex;
+  justify-content: center;
+  justify-items: center;
+  flex-direction: column;
+  padding: 10px;
+
+  .highlight {
+    text-align: center;
+    margin-top: 1em;
+
+    font-family: BebasNeue;
+    color: #1677ff;
+    font-size: 21px;
+    line-height: 42px;
+    font-weight: 600;
+    margin-top: 8px;
+  }
+
+  font-size: 15px;
+  color: #000;
+
+}
+
+.charts-section {
+  margin-top: 20px;
+}
+
+.chart-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.view-more {
+  font-size: 12px;
+}
+
+.legend {
+  display: flex;
+  gap: 15px;
+}
+
+.legend-item {
+  display: flex;
+  align-items: center;
+  font-size: 12px;
+}
+
+.dot {
+  width: 10px;
+  height: 10px;
+  border-radius: 50%;
+  margin-right: 5px;
+}
+
+.viewer-dot {
+  background-color: #409EFF;
+}
+
+.complete-dot {
+  background-color: #67C23A;
+}
+
+.chart-container {
+  height: 350px;
+  width: 100%;
+}
+
+.analysis-card-check {
+  display: flex;
+  flex-direction: row;
+  border: 1px solid transparent;
+  background-color: #fff;
+  border-radius: 4px;
+}
+
+.analysis-card-check:hover {
+  cursor: pointer;
+}
+
+.analysis-card-check-selected:after {
+  content: "";
+  display: block;
+  border-width: 15px;
+  position: absolute;
+  bottom: -30px;
+  left: 50%;
+  margin-left: -32px;
+  border-style: solid dashed dashed solid;
+  border-color: #4592FF transparent transparent transparent;
+  font-size: 0;
+  line-height: 0;
+  z-index: 1;
+}
+
+.analysis-card-check-selected:before {
+  content: "";
+  display: block;
+  border-width: 15px;
+  position: absolute;
+  bottom: -30px;
+  left: 50%;
+  margin-left: -32px;
+  border-style: solid dashed dashed solid;
+  border-color: #4592FF transparent transparent transparent;
+  font-size: 0;
+  line-height: 0;
+  z-index: 1;
+}
+
+.analysis-card-check-selected {
+  border: 1px solid #4592FF;
+  background-color: #e7f1ff;
+}
+
+.color {
+  position: relative;
+  border: 1px solid #4592FF;
+  background-color: #e7f1ff;
+}
+
+.color:after {
+  bottom: -27px;
+  border-color: #E7F1FF transparent transparent transparent;
+}
+
+.companybox {
+  color: white;
+  background-color: #006CFF;
+  padding: 10px 10px 40px 10px;
+  box-sizing: border-box;
+  position: relative;
+  border-radius: 6px;
+
+  .topimg {
+    width: 100px;
+    height: 80px;
+    position: absolute;
+    top: 0px;
+    left: 0;
+  }
+
+  .bottomimg {
+    width: 100px;
+    height: 80px;
+    position: absolute;
+    bottom: -10px;
+    right: 0;
+    transform: rotate(180deg);
+  }
+
+  .companyboxtitle {
+    height: 30px;
+    margin-bottom: 20px;
+    font-weight: 600;
+  }
+
+  .companyflex {
+    display: flex;
+    justify-content: space-around;
+  }
+}
+
+
+.companynumber {
+  color: white;
+}
+
+.companycard {
+
+  width: 25%;
+}
+
+.companyadd {
+  color: white;
+}
+
+.cardafter {
+  position: relative;
+
+}
+
+.cardafter::after {
+  content: "";
+  height: 60px;
+  border-right: 1px solid rgba(255, 255, 255, 0.20);
+  position: absolute;
+  right: 30px;
+  top: 0px;
+}
+
+.highlight1 {
+  margin-top: 10px;
+  margin-left: 20px;
+}
+
+
+.propertyboxtitle {
+  background-image: url(~@/assets/images/zcgl_bg.png);
+  height: 100px;
+}
+
+.propertyboxflex {
+  display: flex;
+  background-color: white;
+  justify-content: space-between;
+}
+
+.property-card {
+  width: 48%;
+  border-radius: 4px;
+  padding: 15px;
+  height: 100px;
+  display: flex;
+  flex-direction: column;
+  position: relative;
+  transition: background-color 0.3s ease-in-out;
+
+}
+
+.property_title {
+  height: 40px;
+  line-height: 40px;
+  color: rgba(32, 33, 36, 1);
+  box-sizing: border-box;
+  padding-left: 10px;
+  font-weight: 600;
+}
+
+.card-compare {
+  margin-top: 5px;
+  font-size: 14px;
+  color: rgba(92, 95, 102, 1);
+
+  span {
+    font-size: 13px;
+    transform: scale(.8);
+    color: rgba(49, 185, 154, 1);
+  }
+}
+
+.propertyline {
+  position: relative;
+}
+
+.propertyline::after {
+  position: absolute;
+  content: "";
+  height: 80px;
+  border-right: 1px solid rgba(237, 239, 242, 1);
+  right: 0;
+}
+
+.operatetitle {
+  font-weight: 600;
+  height: 50px;
+  line-height: 50px;
+}
+
+.operatetitle-col {
+  display: flex;
+  justify-content: space-between;
+  padding-bottom: 20px;
+  padding-right: 5px;
+
+  .operatetitle-card {
+    width: 24%;
+    border: 1px solid transparent;
+    background-color: rgba(245, 247, 250, 1);
+    border-radius: 4px;
+    padding: 15px;
+    display: flex;
+    flex-direction: column;
+    position: relative;
+    transition: background-color 0.3s ease-in-out;
+
+    .operate-value {
+      font-size: 24px;
+      font-weight: bold;
+    }
+  }
+}
+
+.yesterdaybox {
+  font-size: 14px;
+  color: rgba(92, 95, 102, 1);
+  font-weight: 200;
+  margin-top: 10px;
+}
+
+.internetbox {
+  background: linear-gradient(to right, rgba(255, 99, 0, 1), rgba(255, 159, 1, 1));
+  border-radius: 6px;
+  padding: 2px 5px 15px 5px;
+  width: 100%;
+
+  .internet-cardtop {
+    background-color: white;
+    border-radius: 3px;
+    margin-top: 5px;
+    justify-content: space-between;
+    padding: 15px;
+    box-sizing: border-box;
+    color: rgba(32, 33, 36, 1);
+
+    .cardinnerbox {
+      display: flex;
+      justify-content: space-between;
+
+      .cardtopimg {
+        display: flex;
+        align-items: center;
+        font-size: 15px;
+
+        img {
+          height: 18px;
+          width: 18px;
+        }
+      }
+
+      .cardtopnumber {
+        font-size: 25px;
+        color: rgba(32, 33, 36, 1);
+        font-weight: bold;
+      }
+
+    }
+
+    .cardinnerbox2 {
+      display: flex;
+      justify-content: space-between;
+      font-size: 14px;
+      color: rgba(92, 95, 102, 1);
+
+
+    }
+
+  }
+
+  .internetbox-messge {
+    color: white;
+    display: flex;
+    justify-content: space-between;
+    padding: 15px 10px 10px 10px;
+
+    .internet-card {
+      display: flex;
+      font-size: 14px;
+      align-items: center;
+
+      img {
+        height: 18px;
+        width: 18px;
+      }
+
+      span {
+        padding-left: 5px;
+      }
+    }
+
+    .internet-number {
+      font-size: 25px;
+
+    }
+  }
+
+  .internetbox {
+    display: flex;
+    color: white;
+
+    .internet-card {
+      width: 100%;
+      display: flex;
+      color: white;
+
+    }
+  }
+
+  .internet-title {
+    font-size: 14px;
+  }
+
+}
+
+.company {
+  background-color: #006CFF;
+}
+
+.highlight-red {
+  text-align: center;
+  margin-top: 1em;
+  font-family: BebasNeue;
+  color: rgba(255, 82, 82, 1);
+  font-size: 21px;
+  line-height: 42px;
+  font-weight: 600;
+  margin-top: 8px;
+}
+
+.highlight-black {
+  text-align: center;
+  margin-top: 1em;
+  font-family: BebasNeue;
+  color: rgba(32, 33, 36, 1);
+  font-size: 21px;
+  line-height: 42px;
+  font-weight: 600;
+  margin-top: 8px;
+
+}
+
+.operatetitle-card:hover {
+  border: 1px solid #4592ff;
+  background-color: #e7f1ff;
+}
+
+.icon-img {
+  height: 14px;
+  width: 14px;
+}
+
+.progress {
+  transform: rotate(180deg);
+  margin-top: 20px;
+}
+
+.progress ::v-deep .el-progress-bar__outer {
+  background-color: rgba(247, 152, 11, 0.2);
+}
+
+::v-deep .el-progress {
+
+  .el-progress-bar {
+    .el-progress-bar__inner {
+      background: linear-gradient(to right, #FF6300, #FF9F01)
+    }
+  }
+}
+</style>

+ 72 - 0
src/views/components/index/welcomePage.vue

@@ -0,0 +1,72 @@
+<template>
+  <div class="app-container welcome-container">
+    <div class="welcome-content">
+      <div class="time-display">{{ currentTime }}</div>
+      <div class="system-name">{{ systemName }}</div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'Welcome',
+  data() {
+    return {
+      currentTime: '',
+      systemName: process.env.VUE_APP_TITLE,
+      timer: null
+    }
+  },
+  mounted() {
+    this.updateTime()
+    this.timer = setInterval(this.updateTime, 1000)
+  },
+  beforeDestroy() {
+    if (this.timer) {
+      clearInterval(this.timer)
+    }
+  },
+  methods: {
+    updateTime() {
+      const now = new Date()
+      this.currentTime = now.toLocaleString('zh-CN', {
+        year: 'numeric',
+        month: '2-digit',
+        day: '2-digit',
+        hour: '2-digit',
+        minute: '2-digit',
+        second: '2-digit',
+        weekday: 'long'
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.welcome-container {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: calc(100vh - 84px); /* 减去头部和padding的高度 */
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+}
+
+.welcome-content {
+  text-align: center;
+  color: white;
+}
+
+.time-display {
+  font-size: 36px;
+  font-weight: 300;
+  margin-bottom: 20px;
+  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
+}
+
+.system-name {
+  font-size: 48px;
+  font-weight: bold;
+  text-shadow: 0 2px 15px rgba(0, 0, 0, 0.4);
+}
+</style>

+ 78 - 22
src/views/course/courseAnswerlogs/index.vue

@@ -1,15 +1,37 @@
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="120px">
-      <el-form-item label="销售公司" prop="companyId">
-        <el-select filterable v-model="queryParams.companyId" clearable placeholder="请选择公司名" size="small">
-          <el-option
-            v-for="item in companys"
-            :key="item.companyId"
-            :label="item.companyName"
-            :value="item.companyId"
-          />
-        </el-select>
+<!--      <el-form-item label="销售公司" prop="companyId">-->
+<!--        <el-select filterable v-model="queryParams.companyId" clearable placeholder="请选择公司名" 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="会员id" prop="userId">
+        <el-input
+          v-model="queryParams.userId"
+          placeholder="请输入会员id"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="公司名" prop="companyId">
+        <select-tree
+          v-model="selectedCompanyList"
+          :raw-data="deptList"
+          placeholder="请选择销售"
+          :parentSelectable="true"
+          :multiple="true"
+          component-width="300px"
+          :max-display-tags="3"
+          :check-strictly="false"
+          :return-leaf-only="false"
+        ></select-tree>
       </el-form-item>
       <el-form-item label="客户电话" prop="phone">
         <el-input
@@ -79,8 +101,8 @@
         </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="timeChange"></el-date-picker>
+        <el-date-picker v-model="createTime" size="small" style="width: 220px" value-format="yyyy-MM-dd HH:mm:ss"
+                        type="datetimerange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="timeChange"></el-date-picker>
 
       </el-form-item>
       <el-form-item>
@@ -106,6 +128,7 @@
 
     <el-table border v-loading="loading" :data="logsList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="小程序会员id" align="center" prop="userId" />
       <el-table-column label="小程序用户名" align="center" prop="userName" />
       <el-table-column label="课程名称" align="center" prop="courseName" />
       <el-table-column label="小节名称" align="center" prop="videoName" />
@@ -135,13 +158,19 @@
 import { listLogs, getLogs, delLogs, addLogs, updateLogs, exportLogs } from "@/api/course/courseAnswerlogs";
 import { courseList, videoList } from '@/api/course/courseRedPacketLog'
 import { getCompanyList } from '@/api/company/company'
+import SelectTree from '@/components/TreeSelect/index.vue'
+import { getDeptData } from '@/api/system/employeeStats'
 
 export default {
   name: "Logs",
+  components: { SelectTree },
   data() {
     return {
+
+      selectedCompanyList: [],
+      deptList: [],
       // 遮罩层
-      loading: true,
+      loading: false,
       // 导出遮罩层
       exportLoading: false,
       // 选中数组
@@ -173,9 +202,11 @@ export default {
       open: false,
       // 查询参数
       queryParams: {
+        logId:null,
         pageNum: 1,
         pageSize: 10,
         phone: null,
+        userId: null,
         phoneMk: null,
         courseId: null,
         videoId: null,
@@ -196,31 +227,45 @@ export default {
   },
   created() {
 
+
+    getDeptData().then(response => {
+      this.deptList = response.data;
+    })
+
     courseList().then(response => {
       this.courseLists = response.list;
     });
 
     getCompanyList().then(response => {
       this.companys = response.data;
-      if(this.companys!=null&&this.companys.length>0){
-        this.companyId=this.companys[0].companyId;
-        this.getTreeselect();
-      }
+      // if(this.companys!=null&&this.companys.length>0){
+      //   this.companyId=this.companys[0].companyId;
+      //   this.getTreeselect();
+      // }
       this.companys.push({companyId:"-1",companyName:"无"})
     });
     this.getDicts("sys_company_or").then(response => {
       this.sysCompanyOr = response.data;
     });
-    this.getList();
+
+    // this.getList();
 
   },
   methods: {
     /** 查询答题日志列表 */
     getList() {
       this.loading = true;
+
+      if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
+        this.queryParams.companyUserIds = this.selectedCompanyList;
+      }else {
+        this.queryParams.companyUserIds = [];
+      }
+
+
       listLogs(this.queryParams).then(response => {
-        this.logsList = response.rows;
-        this.total = response.total;
+        this.logsList = response.data.list;
+        this.total = response.data.total;
         this.loading = false;
       });
     },
@@ -342,12 +387,23 @@ export default {
           cancelButtonText: "取消",
           type: "warning"
         }).then(() => {
-          this.exportLoading = true;
-          return exportLogs(queryParams);
+
+        const loadingInstance = this.$loading({
+          lock: true,
+          text: '正在导出数据,请稍候...',
+          background: 'rgba(0, 0, 0, 0.7)'
+        });
+
+        this.exportLoading = true;
+        return exportLogs(queryParams).finally(res=>{
+          loadingInstance.close();
+        });
         }).then(response => {
           this.download(response.msg);
           this.exportLoading = false;
-        }).catch(() => {});
+        }).catch(() => {}).finally(res=>{
+          this.exportLoading = false;
+      });
     }
   }
 };

+ 43 - 11
src/views/course/courseFinishTemp/index.vue

@@ -1,15 +1,28 @@
 <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  v-model="queryParams.companyId" clearable placeholder="请选择公司名" size="small">
-          <el-option
-            v-for="item in companys"
-            :key="item.companyId"
-            :label="item.companyName"
-            :value="item.companyId"
-          />
-        </el-select>
+<!--      <el-form-item label="销售公司" prop="companyId">-->
+<!--        <el-select filterable  v-model="queryParams.companyId" clearable placeholder="请选择公司名" 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="companyId">
+        <select-tree
+          v-model="selectedCompanyList"
+          :raw-data="deptList"
+          placeholder="请选择销售"
+          :parentSelectable="true"
+          :multiple="true"
+          component-width="300px"
+          :max-display-tags="3"
+          :check-strictly="false"
+          :return-leaf-only="false"
+        ></select-tree>
       </el-form-item>
       <el-form-item label="模板名称" prop="name">
         <el-input
@@ -123,6 +136,8 @@
       <el-table-column label="小节名称" align="center" prop="videoName"/>
       <el-table-column label="创建时间" align="center" prop="createTime"/>
       <el-table-column label="修改时间" align="center" prop="updateTime"/>
+      <el-table-column label="创建人" align="center" prop="createByName"/>
+      <el-table-column label="创建部门" align="center" prop="createByDeptName"/>
       <el-table-column label="全选销售" align="center" prop="isAllCompanyUser">
         <template slot-scope="scope">
           <dict-tag :options="allowSelect" :value="scope.row.isAllCompanyUser"/>
@@ -460,12 +475,16 @@ import {getAllUserlist} from '@/api/company/companyUser'
 import {courseList, videoList} from '@/api/qw/sop'
 import ImageUpload from "@/views/qw/sop/ImageUpload.vue";
 import { getCompanyList } from "@/api/company/company";
+import SelectTree from '@/components/TreeSelect/index.vue'
+import { getDeptData } from '@/api/system/employeeStats'
 
 export default {
   name: "CourseFinishTemp",
-  components: {ImageUpload},
+  components: { SelectTree, ImageUpload},
   data() {
     return {
+      selectedCompanyList: [],
+      deptList: [],
       //上传语音的遮罩层
       voiceLoading: false,
       uploadUrl: process.env.VUE_APP_BASE_API + "/common/uploadOSS2",
@@ -534,7 +553,10 @@ export default {
     };
   },
   created() {
-    this.getList();
+    getDeptData().then(response => {
+      this.deptList = response.data;
+    })
+
 
     getCompanyList().then(response => {
       this.companys = response.data;
@@ -558,6 +580,8 @@ export default {
     courseList().then(response => {
       this.courseList = response.list;
     });
+
+    this.getList();
   },
   methods: {
     courseChange() {
@@ -569,6 +593,13 @@ export default {
     /** 查询完课模板列表 */
     getList() {
       this.loading = true;
+
+      if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
+        this.queryParams.userIds = this.selectedCompanyList;
+      }else {
+        this.queryParams.userIds = [];
+      }
+
       listCourseFinishTemp(this.queryParams).then(response => {
         this.courseFinishTempList = response.rows;
         this.total = response.total;
@@ -744,6 +775,7 @@ export default {
     /** 重置按钮操作 */
     resetQuery() {
       this.resetForm("queryForm");
+      this.selectedCompanyList=[];
       this.handleQuery();
     },
     // 多选框选中数据

+ 266 - 4
src/views/course/coursePlaySourceConfig/index.vue

@@ -39,6 +39,21 @@
           size="small"
           @keyup.enter.native="handleQuery"
         />
+      </el-form-item>
+            <el-form-item label="状态" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="请选择状态"
+          clearable
+          size="small"
+        >
+          <el-option
+            v-for="item in statusOptions"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          />
+        </el-select>
       </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
@@ -142,6 +157,16 @@
           <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="status" width="100px">
+        <template slot-scope="scope">
+          <el-tag
+            :type="scope.row.status === 0 ? 'success' : scope.row.status === 1 ? 'warning' : 'danger'"
+          >
+            {{ getStatusLabel(scope.row.status) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="配置绑定Id" align="center" prop="merchantConfigId" />
       <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">
@@ -166,6 +191,22 @@
             icon="el-icon-setting"
             @click="handleSwitchConfig(scope.row)"
           >是否展示销售</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleBind(scope.row)"
+            v-hasPermi="['course:playSourceConfig:bind']"
+            v-if="!scope.row.merchantConfigId"
+          >绑定</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUnbind(scope.row)"
+            v-hasPermi="['course:playSourceConfig:unbind']"
+            v-if="scope.row.merchantConfigId"
+          >解绑</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -204,6 +245,28 @@
               :value="item.dictValue"
             />
           </el-select>
+        </el-form-item>
+         <el-form-item label="可查看设置公司" prop="setCompanyIdList">
+          <el-select
+            v-model="form.setCompanyIdList"
+            filterable
+            multiple
+            remote
+            reserve-keyword
+            placeholder="请输入公司名称搜索"
+            :remote-method="searchCompanies"
+            :loading="companySearchLoading"
+            style="width: 220px"
+            clearable
+            size="small"
+          >
+            <el-option
+              v-for="item in companyOptions"
+              :key="item.dictValue"
+              :label="item.dictLabel"
+              :value="item.dictValue"
+            />
+          </el-select>
         </el-form-item>
         <el-form-item label="是否是互医/商城小程序" prop="isMall">
           <el-select
@@ -219,6 +282,22 @@
               :value="item.dictValue"
             />
           </el-select>
+        </el-form-item>
+                <el-form-item label="状态" prop="status">
+          <el-select
+            v-model="form.status"
+            placeholder="请选择状态"
+            style="width: 220px"
+            clearable
+            size="small"
+          >
+            <el-option
+              v-for="item in statusOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
         </el-form-item>
         <el-form-item label="图标" prop="img">
           <image-upload v-model="form.img" :file-type='["png", "jpg", "jpeg"]' :limit="1"/>
@@ -260,19 +339,67 @@
       </div>
     </el-dialog>
 
+    <!-- 绑定  -->
+    <el-dialog :title="bindForm.bindTitle" :visible.sync="bindForm.bindShow" width="800px" append-to-body :before-close="handleBindClose">
+      <el-form ref="bindForm" :model="bindForm" :rules="bindRules" label-width="130px">
+        <el-form-item label="商户类型" prop="merchantType">
+          <el-select v-model="bindForm.merchantType" placeholder="请选择商户类型" clearable size="small" @change="changeSysPayModes">
+            <el-option
+              v-for="dict in sysPayModes"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="dict.dictValue"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="商户号" prop="merchantId">
+          <el-select v-model="bindForm.id" placeholder="请选择商户号" clearable size="small">
+            <el-option
+              v-for="dict in merchantAppConfigList"
+              :key="dict.id"
+              :label="dict.merchantId"
+              :value="dict.id"
+            />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitFormBind(bindCurrentRow)" >确 定</el-button>
+        <el-button @click="cancelBind">取 消</el-button>
+      </div>
+    </el-dialog>
+
   </div>
 </template>
 
 <script>
-import {list, get, update, add, del} from '@/api/course/coursePlaySourceConfig'
+import {
+  list,
+  get,
+  update,
+  add,
+  del,
+  updateBindConfig,
+  updateUnbindConfig
+} from '@/api/course/coursePlaySourceConfig'
 import {updateIsTownOn} from "@/api/system/config";
 import { allList } from '@/api/company/company'
 import { resetForm } from '@/utils/common'
+import { listMerchantAppConfig } from "@/api/merchantAppConfig/merchantAppConfig";
 
 export default {
   name: 'CoursePlaySourceConfig',
   data() {
     return {
+      sysPayModes: [],
+      bindCurrentRow: {},
+      bindForm:{
+        bindTitle: '绑定支付配置',
+        bindShow: false,
+        merchantType: null,
+        id:null,
+      },
+      merchantAppConfigList:[],
       switchDialogVisible: false,
       // 公司搜索相关
       companySearchLoading: false,
@@ -286,7 +413,8 @@ export default {
         pageNum: 1,
         pageSize: 10,
         name: null,
-        appid: null
+        appid: null,
+        status: null
       },
       showSearch: true,
       single: true,
@@ -296,6 +424,20 @@ export default {
       list: [],
       total: 0,
       typesOptions: [],
+            statusOptions: [
+        {
+          label: "正常",
+          value: 0
+        },
+        {
+          label: "半封禁",
+          value: 1
+        },
+        {
+          label: "封禁",
+          value: 2
+        }
+      ],
       isMallOptions:[
         {
           dictLabel: "是",
@@ -308,7 +450,17 @@ export default {
       ],
       title: null,
       open: false,
-      form: {},
+      form: {
+        setCompanyIdList: []
+      },
+      bindRules:{
+        merchantType: [
+          { required: true, message: "商户类型不能为空", trigger: "blur" }
+        ],
+        id: [
+          { required: true, message: "商户号不能为空", trigger: "blur" }
+        ]
+      },
       rules: {
         name: [
           { required: true, message: "名称不能为空", trigger: "blur" }
@@ -344,6 +496,9 @@ export default {
     }
   },
   created() {
+    this.getDicts("sys_pay_mode").then(response => {
+      this.sysPayModes = response.data;
+    });
     this.getDicts("play_source_type").then(response => {
       this.typesOptions = response.data.map(item =>  {
         return {
@@ -364,7 +519,89 @@ export default {
       this.companyOptions = [];
       this.open = false;
     },
+    handleUnbind(row) {
+      this.$confirm('是否确认解绑该配置?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        const params = {
+          id: row.id
+        };
+        updateUnbindConfig(params).then(response => {
+          if (response.code === 200) {
+            this.msgSuccess("解绑成功");
+            this.getList();
+          } else {
+            this.msgError("解绑失败: " + response.msg);
+          }
+        }).catch(error => {
+          this.msgError("请求失败: " + error.message);
+        });
+      }).catch(() => {
+        // 用户取消操作
+      });
+    }
+    ,
+    submitFormBind(row) {
+      this.$refs["bindForm"].validate(valid => {
+        if (valid) {
+          // 构造请求参数
+          const params = {
+            id: row.id,  // 使用传入行数据的ID
+            merchantType: this.bindForm.merchantType,
+            merchantConfigId: this.bindForm.id
+          };
 
+          // 调用API更新绑定关系
+          updateBindConfig(params).then(response => {
+            if (response.code === 200) {
+              this.msgSuccess("绑定配置更新成功");
+              this.bindForm.bindShow = false;
+              this.getList(); // 刷新列表数据
+              this.resetForm("bindForm");
+            } else {
+              this.msgError("更新失败: " + response.msg);
+            }
+          }).catch(error => {
+            this.msgError("请求失败: " + error.message);
+          });
+        }
+      });
+    },
+    handleBindClose(done) {
+      this.resetForm("bindForm");
+      this.bindForm.bindShow = false;
+      this.bindForm.id = null;
+      done();
+    },
+    cancelBind(){
+      this.resetForm("bindForm");
+
+      this.bindForm.bindShow = false;  // 关闭对话框
+
+    },
+    // 绑定支付配置
+    handleBind(row) {
+      this.merchantAppConfigList= [];
+      this.bindForm.merchantType = null;
+      this.bindForm.id = null;
+      this.bindCurrentRow = row;  // 保存当前行数据
+      this.bindForm.bindShow = true;
+    },
+    changeSysPayModes(value){
+      console.log(value)
+      const query = {
+        pageNum: 1,
+        pageSize: 100,
+        merchantType: value,
+        isDeleted: 0
+      }
+      listMerchantAppConfig(query).then( response => {
+          this.merchantAppConfigList = response.rows;
+        }
+      )
+    },
 
     // 处理开关配置
     handleSwitchConfig(row) {
@@ -460,6 +697,15 @@ export default {
           ...response.data,
           type: response.data.type.toString()
         }
+        if(!!this.form.setCompanyIds){
+           this.$set(
+            this.form,
+            "setCompanyIdList",
+            this.form.setCompanyIds.split(",").map(str => parseInt(str, 10))
+          );
+          // this.form.setCompanyIdList = this.form.setCompanyIds.split(",").map(str => parseInt(str, 10));
+        }
+        console.log( this.form);
         this.searchCompanies("");
         this.open = true
         this.title = "修改小程序配置"
@@ -486,6 +732,12 @@ export default {
     submitForm() {
       this.$refs["form"].validate(valid => {
         if (valid) {
+          if(!!this.form.setCompanyIdList && this.form.setCompanyIdList.length > 0){
+            this.form.setCompanyIds = this.form.setCompanyIdList.join(',')
+          }else{
+            this.form.setCompanyIds = "";
+          }
+          console.log(this.form);
           if (this.form.id != null) {
             update(this.form).then(response => {
               const {code, msg} = response
@@ -524,12 +776,22 @@ export default {
         secret: null,
         img: null,
         originalId: null,
+        setCompanyIdList: [],
         token: 'cbnd7lJvkripVOpyTFAna6NAWCxCrvC',
         aesKey: 'HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E',
         msgDataFormat: 'JSON',
-        type: '1'
+        type: '1',
+        status: 0
       }
       this.resetForm("form");
+          },
+    getStatusLabel(status) {
+      const statusMap = {
+        0: '正常',
+        1: '半封禁',
+        2: '封禁'
+      };
+      return statusMap[status] || '未知';
     }
   },
 }

+ 165 - 45
src/views/course/courseRedPacketLog/index.vue

@@ -1,30 +1,53 @@
 <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  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="companyId">-->
+<!--		     <el-select filterable  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="companyId">
+        <select-tree
+          v-model="selectedCompanyList"
+          :raw-data="deptList"
+          placeholder="请选择销售"
+          :parentSelectable="true"
+          :multiple="true"
+          component-width="300px"
+          :max-display-tags="3"
+          :check-strictly="false"
+          :return-leaf-only="false"
+        ></select-tree>
+      </el-form-item>
+<!--    <el-form-item label="部门" prop="type">-->
+<!--      <TreeselectVue-->
+<!--        style="width: 220px"-->
+<!--        :clearable="false"-->
+<!--        v-model="queryParams.deptId"-->
+<!--        :options="deptOptions"-->
+<!--        clearable-->
+<!--        :show-count="true"-->
+<!--        placeholder="请选择归属部门"-->
+<!--      />-->
+<!--    </el-form-item>-->
 		<el-form-item label="员工" prop="companyUserName">
 		  <el-input
 		    v-model="queryParams.companyUserName"
-		    placeholder="员工"
+		    placeholder="所属员工"
 		    clearable
 		    size="small"
 		    @keyup.enter.native="handleQuery"
 		  />
 		</el-form-item>
-
-      <el-form-item label="用户ID" prop="userId">
+      <el-form-item label="会员ID" prop="userId">
         <el-input
           v-model="queryParams.userId"
-          placeholder="请输入用户ID"
+          placeholder="请输入会员ID"
           clearable
           size="small"
           @keyup.enter.native="handleQuery"
@@ -49,6 +72,28 @@
 	      @keyup.enter.native="handleQuery"
 	    />
 	  </el-form-item>
+
+      <el-form-item label="营期" prop="courseId">
+        <el-select
+          v-model="queryParams.periodId"
+          placeholder="请选择课程"
+          filterable
+          clearable
+          size="small"
+          remote
+          :remote-method="remoteMethod"
+          :loading="loadingPeriod"
+          @focus="handleFocus"
+        >
+          <el-option
+            v-for="dict in periodLists"
+            :key="dict.periodId"
+            :label="dict.periodName"
+            :value="parseInt(dict.periodId)"
+          />
+        </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
@@ -70,7 +115,7 @@
      </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"
+	           <el-date-picker v-model="createTime" size="small" style="width: 220px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
                              range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
 	 </el-form-item>
 
@@ -101,7 +146,7 @@
     </el-tabs>
     <el-table border v-loading="loading" :data="courseRedPacketLogList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="记录编号" align="center" prop="logId" />
+<!--      <el-table-column label="记录编号" align="center" prop="logId" />-->
       <el-table-column label="批次单号" align="center" prop="outBatchNo" />
       <el-table-column label="课程名称" align="center" prop="courseId" >
         <template slot-scope="scope">
@@ -110,9 +155,11 @@
       </el-table-column>
       <el-table-column label="小节名称" align="center" prop="title" />
       <el-table-column label="会员id" align="center" prop="userId" />
+      <el-table-column label="会员名称" align="center" prop="fsNickName" />
       <el-table-column label="会员电话" align="center" prop="phone" />
-      <el-table-column label="所属销售" align="center" prop="companyUserName" />
+      <el-table-column label="所属员工" align="center" prop="companyUserName" />
       <el-table-column label="所属公司" align="center" prop="companyName" />
+      <el-table-column label="员工部门" align="center" prop="deptName" />
       <el-table-column label="转帐金额" align="center" prop="amount" />
       <el-table-column label="状态" align="center" prop="status" >
         <template slot-scope="scope">
@@ -138,14 +185,14 @@
         <el-form-item label="课程id" prop="courseId">
           <el-input v-model="form.courseId" placeholder="请输入课程id" />
         </el-form-item>
-        <el-form-item label="用户id" prop="userId">
-          <el-input v-model="form.userId" placeholder="请输入用户id" />
+        <el-form-item label="会员id" prop="userId">
+          <el-input v-model="form.userId" placeholder="请输入会员id" />
         </el-form-item>
         <el-form-item label="小节id" prop="videoId">
           <el-input v-model="form.videoId" placeholder="请输入小节id" />
         </el-form-item>
-        <el-form-item label="公司员工id" prop="companyUserId">
-          <el-input v-model="form.companyUserId" placeholder="请输入公司员工id" />
+        <el-form-item label="员工id" prop="companyUserId">
+          <el-input v-model="form.companyUserId" placeholder="请输入员工id" />
         </el-form-item>
         <el-form-item label="公司id" prop="companyId">
           <el-input v-model="form.companyId" placeholder="请输入公司id" />
@@ -166,17 +213,22 @@
 </template>
 
 <script>
-import { courseList,videoList,listCourseRedPacketLog, getCourseRedPacketLog, delCourseRedPacketLog, addCourseRedPacketLog, updateCourseRedPacketLog, exportCourseRedPacketLog } from "@/api/course/courseRedPacketLog";
+import { courseList,videoList,getCourseRedPacketLog, delCourseRedPacketLog, addCourseRedPacketLog, updateCourseRedPacketLog, exportCourseRedPacketLog,listCourseRedPacketLogPage } from "@/api/course/courseRedPacketLog";
 import { getCompanyList } from "@/api/company/company";
+import SelectTree from '@/components/TreeSelect/index.vue'
+import { getDeptData } from '@/api/system/employeeStats'
 
 export default {
   name: "CourseRedPacketLog",
+  components: {SelectTree},
   data() {
     return {
 	  companys:[],
-	  deptOptions:[],
+    selectedCompanyList: [],
+    deptList: [],
       // 遮罩层
       loading: true,
+      loadingPeriod: false,
       // 导出遮罩层
       exportLoading: false,
       // 选中数组
@@ -189,6 +241,7 @@ export default {
       showSearch: true,
       activeName:"00",
       courseLists:[],
+      periodLists:[],
       videoList:[],
       // 总条数
       total: 0,
@@ -198,6 +251,10 @@ export default {
       title: "",
       // 是否显示弹出层
       open: false,
+      queryPeriod: {
+        pageNum: 1,
+        pageSize: 20
+      },
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -214,6 +271,7 @@ export default {
         phoneMk: null,
         sTime:null,
         eTime:null,
+        userIds: null
       },
 	   createTime:null,
       // 表单参数
@@ -231,22 +289,75 @@ export default {
 	  courseList().then(response => {
 	    this.courseLists = response.list;
 	  });
+    getDeptData().then(response => {
+      this.deptList = response.data;
+    })
+    periodList(this.queryPeriod).then(response => {
+	    this.periodLists = response.data;
+	  });
+
+    // this.getList();
   },
   methods: {
-	  handleClick(tab, event) {
+    // 远程搜索方法
+    async remoteMethod(query) {
+      this.searchKeyword = query
+      if (query !== '') {
+        this.loadingPeriod = true
+        await this.getPeriodList(query)
+        this.loadingPeriod = false
+      } else {
+        // 如果输入为空,可以清空列表或加载默认数据
+        this.periodLists = []
+      }
+    },
+
+    // 获取营期列表
+    async getPeriodList(keyword = '') {
+      try {
+        const params = {
+          periodName: keyword, // 搜索关键词
+          pageNum: 1,
+          pageSize: 50 // 根据需求调整
+        }
+
+        const response = await periodList(params)
+        this.periodLists = response.data.list || response.data || []
+      } catch (error) {
+        console.error('获取营期列表失败:', error)
+        this.periodLists = []
+      }
+    },
+    // 下拉框获取焦点时加载数据
+    async handleFocus() {
+      if (this.periodLists.length === 0) {
+        this.getPeriodList();
+      }
+    },
+
+
+    handleClick(tab, event) {
 	    this.activeName=tab.name;
-	    this.queryParams.status=tab.name
-	    console.log(this.queryParams.status)
-	    this.getList();
+      if(tab.name == "00") {
+        this.queryParams.status = null;
+      } else {
+        this.queryParams.status = tab.name;
+      }
+        this.getList();
 	  },
     /** 查询短链课程看课记录列表 */
     getList() {
       this.loading = true;
-      listCourseRedPacketLog(this.queryParams).then(response => {
-        this.courseRedPacketLogList = response.rows;
-        this.total = response.total;
+      if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
+        this.queryParams.userIds = this.selectedCompanyList;
+      }else {
+        this.queryParams.userIds = [];
+      }
+      listCourseRedPacketLogPage(this.queryParams).then(response => {
+        this.courseRedPacketLogList = response.data.list;
+        this.total = response.data.total;
         this.loading = false;
-      });
+      })
     },
 	change(){
 	      if(this.createTime!=null){
@@ -259,7 +370,6 @@ export default {
 
 	    },
 	courseChange(row){
-
 		if(row==""){
 			this.videoList=[]
 			this.queryParams.videoId=null
@@ -302,6 +412,10 @@ export default {
 	   this.createTime=null;
 	  this.queryParams.sTime=null;
 	  this.queryParams.eTime=null;
+      this.selectedCompanyList = [];
+      this.queryParams.pageNum = 1;    // Reset to first page
+      this.queryParams.pageSize = 10;  // Reset to default page size
+	  this.queryParams.periodId=null;
       this.handleQuery();
     },
     // 多选框选中数据
@@ -360,30 +474,36 @@ export default {
           this.msgSuccess("删除成功");
         }).catch(() => {});
     },
-	getSubCateList(pid){
-	  this.form.subCateId=null;
-	  if(pid == ''){
-	    this.subCategoryOptions=[];
-	    return
-	  }
-	  getCateListByPid(pid).then(response => {
-	    this.subCategoryOptions = response.data;
-	  });
-	},
     /** 导出按钮操作 */
     handleExport() {
+      if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
+        this.queryParams.userIds = this.selectedCompanyList;
+      }else {
+        this.queryParams.userIds = [];
+      }
       const queryParams = this.queryParams;
       this.$confirm('是否确认导出所有短链课程看课记录数据项?', "警告", {
           confirmButtonText: "确定",
           cancelButtonText: "取消",
           type: "warning"
         }).then(() => {
-          this.exportLoading = true;
-          return exportCourseRedPacketLog(queryParams);
+        const loadingInstance = this.$loading({
+          lock: true,
+          text: '正在导出数据,请稍候...',
+          background: 'rgba(0, 0, 0, 0.7)'
+        });
+
+        this.exportLoading = true;
+          // return exportCourseRedPacketLog(queryParams);
+        return exportCourseRedPacketLog(queryParams).finally(res=>{
+          loadingInstance.close();
+        })
         }).then(response => {
           this.download(response.msg);
           this.exportLoading = false;
-        }).catch(() => {});
+        }).catch(() => {}).finally(res=>{
+
+      });
     }
   }
 };

+ 38 - 2
src/views/course/courseTrafficLog/index.vue

@@ -52,12 +52,13 @@
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
         <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
-        <el-button type="warning" plain icon="el-icon-download" size="mini" :loading="exportLoading" @click="handleExport" >导出</el-button>
+        <el-button type="warning" plain icon="el-icon-download" size="mini" :loading="exportLoading" @click="handleExport" v-hasPermi="['course:courseTrafficLog:export']" >导出</el-button>
       </el-form-item>
     </el-form>
 
     <!-- 表格 -->
-    <el-table border v-loading="loading" :data="courseTrafficLogList" @selection-change="handleSelectionChange">
+    <el-table border v-loading="loading" :data="courseTrafficLogList" @selection-change="handleSelectionChange"
+              show-summary :summary-method="getSummaries">
       <el-table-column type="selection" width="55" align="center" />
       <!-- 公司列 -->
       <el-table-column label="公司" align="center" prop="companyName" v-if="activeTab === 'all' || activeTab === 'company'" />
@@ -161,6 +162,40 @@ export default {
     this.getList();
   },
   methods: {
+
+    getSummaries(param) {
+      const { columns, data } = param
+      const sums = []
+
+      columns.forEach((column, index) => {
+        if (index === 0) {
+          // 第一列显示"总计"
+          sums[index] = '总计'
+          return
+        }
+
+        // 如果是流量列
+        if (column.property === 'totalInternetTraffic' ||
+          (column.label === '使用流量' && !column.property)) {
+          const values = data.map(item => Number(item.totalInternetTraffic) || 0)
+          if (!values.every(value => isNaN(value))) {
+            const total = values.reduce((prev, curr) => {
+              const value = Number(curr)
+              return prev + (isNaN(value) ? 0 : value)
+            }, 0)
+            sums[index] = this.formatTrafficData(total)
+          } else {
+            sums[index] = 'N/A'
+          }
+        } else {
+          // 其他列留空
+          sums[index] = ''
+        }
+      })
+
+      return sums
+    },
+
     handleTabClick(tab) {
       this.queryParams.tabType = tab.name;
       this.queryParams.pageNum = 1;
@@ -195,6 +230,7 @@ export default {
       });
     },
     handleQuery() {
+      this.queryParams.tabType = this.activeTab
       this.queryParams.pageNum = 1;
       this.getList();
     },

+ 65 - 5
src/views/course/courseTrafficLog/statistics.vue

@@ -27,8 +27,8 @@
           @change="handleDateData"
         ></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>
@@ -48,10 +48,11 @@
       </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
-    
+
 
     <!-- 表格 -->
-    <el-table border v-loading="loading" :data="courseTrafficLogList" @selection-change="handleSelectionChange">
+    <el-table border v-loading="loading" :data="courseTrafficLogList" @selection-change="handleSelectionChange"
+              show-summary :summary-method="getSummaries">
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="公司" align="center" prop="companyName" />
       <el-table-column v-if="showDept" label="部门" align="center" prop="deptName" />
@@ -61,7 +62,6 @@
       <el-table-column label="金额" align="center" prop="totalAmount">
       </el-table-column>
     </el-table>
-
     <!-- 分页 -->
     <pagination
       v-show="total > 0"
@@ -155,6 +155,66 @@ export default {
     this.getList();
   },
   methods: {
+
+    getSummaries(param) {
+      // 原有的汇总方法
+      const { columns, data } = param;
+      const sums = [];
+
+      columns.forEach((column, index) => {
+        if (index === 0) {
+          sums[index] = '总计';
+          return;
+        }
+
+        if (column.property === 'formattedTotalTraffic') {
+          sums[index] = this.getTotalTraffic();
+        } else if (column.property === 'totalAmount') {
+          sums[index] = '¥' + this.getTotalAmount();
+        } else {
+          sums[index] = '';
+        }
+      });
+
+      return sums;
+    },
+
+
+    // 计算总流量(不四舍五入)
+    getTotalTraffic() {
+      if (!this.courseTrafficLogList || this.courseTrafficLogList.length === 0) {
+        return '0';
+      }
+      let total = 0;
+
+      // 方法B:从格式化字符串中提取数值(如果formattedTotalTraffic类似 "1.23GB")
+      total = this.courseTrafficLogList.reduce((sum, item) => {
+        // 移除非数字字符,只保留数字和小数点
+        if (item.formattedTotalTraffic) {
+          const numStr = item.formattedTotalTraffic.replace(/[^\d.]/g, '');
+          return sum + parseFloat(numStr || 0);
+        }
+        return sum;
+      }, 0);
+
+      // 保留所有小数,不四舍五入
+      return total.toFixed(10).replace(/\.?0+$/, '');
+    },
+
+    // 计算总金额(不四舍五入)
+    getTotalAmount() {
+      if (!this.courseTrafficLogList || this.courseTrafficLogList.length === 0) {
+        return '0';
+      }
+
+      const total = this.courseTrafficLogList.reduce((sum, item) => {
+        return sum + (parseFloat(item.totalAmount) || 0);
+      }, 0);
+
+      // 保留两位小数,不四舍五入
+      return Math.floor(total * 100) / 100;
+    },
+
     handleTabClick(tab) {
       this.queryParams.tabType = tab.name;
       this.queryParams.pageNum = 1;

+ 86 - 22
src/views/course/courseWatchLog/index.vue

@@ -1,15 +1,47 @@
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
-      <el-form-item label="销售公司" prop="companyId">
-        <el-select filterable v-model="queryParams.companyId" clearable placeholder="请选择公司名" size="small">
-          <el-option
-            v-for="item in companyList"
-            :key="item.companyId"
-            :label="item.companyName"
-            :value="item.companyId"
-          />
-        </el-select>
+<!--      <el-form-item label="销售公司" prop="companyId">-->
+<!--        <el-select filterable v-model="queryParams.companyId" clearable placeholder="请选择公司名" size="small">-->
+<!--          <el-option-->
+<!--            v-for="item in companyList"-->
+<!--            :key="item.companyId"-->
+<!--            :label="item.companyName"-->
+<!--            :value="item.companyId"-->
+<!--          />-->
+<!--        </el-select>-->
+<!--      </el-form-item>-->
+      <el-form-item label="记录编号" prop="logId">
+        <el-input
+          v-model="queryParams.logId"
+          placeholder="请输入记录编号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="会员ID" prop="userId">
+        <el-input
+          v-model="queryParams.userId"
+          placeholder="请输入会员ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="员工部门" prop="companyId">
+        <select-tree
+          v-model="selectedCompanyList"
+          :raw-data="deptList"
+          :parentSelectable="true"
+          placeholder="请选择"
+          :multiple="true"
+          component-width="300px"
+          :max-display-tags="3"
+          :check-strictly="false"
+          :return-leaf-only="false"
+          @change="handleMultiChange"
+        ></select-tree>
       </el-form-item>
       <el-form-item label="课程" prop="courseId">
         <el-select filterable  v-model="queryParams.courseId" placeholder="请选择课程"  clearable size="small" @change="courseChange(queryParams.courseId)">
@@ -96,6 +128,7 @@
     <el-table border v-loading="loading" :data="courseWatchLogList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="记录编号" align="center" prop="logId" />
+      <el-table-column label="用户会员id" align="center" prop="userId" />
       <el-table-column label="用户账号" align="center" prop="qwUserName" />
       <el-table-column label="企微客户" align="center" prop="externalUserName">
         <template slot-scope="scope">
@@ -140,6 +173,7 @@
       </el-table-column>
       <el-table-column label="播放时长" align="center" prop="duration" />
       <el-table-column label="所属销售" align="center" prop="companyUserName" />
+      <el-table-column label="销售部门" align="center" prop="deptName" />
 <!--      <el-table-column label="所属公司" align="center" prop="companyName" />-->
 <!--      <el-table-column label="企微员工名称" align="center" prop="qwUserName" />-->
       <el-table-column label="所属发送方式" align="center" prop="sendType" />
@@ -161,16 +195,21 @@
 </template>
 
 <script>
-import { listCourseWatchLog, getCourseWatchLog, delCourseWatchLog, addCourseWatchLog, updateCourseWatchLog, exportCourseWatchLog } from "@/api/course/courseWatchLog";
+import { listCourseWatchLog, getCourseWatchLog, delCourseWatchLog, addCourseWatchLog, updateCourseWatchLog, exportCourseWatchLog,listCourseWatchLogPage } from "@/api/course/courseWatchLog";
 import { allList, getCompanyList } from '@/api/company/company'
 import { courseList,videoList } from '@/api/course/courseRedPacketLog'
 import {getUserList} from "@/api/company/companyUser";
 import {getFsUserList} from "@/api/users/user";
+import {getDeptData} from "@/api/system/employeeStats";
+import SelectTree from "@/components/TreeSelect/index.vue";
 export default {
   name: "CourseWatchLog",
+  components: {SelectTree},
   data() {
     return {
       userSourceTypeOptions: [],
+      selectedCompanyList: [],
+      deptList: [],
       activeName:"00",
       createTime:null,
       updateTime:null,
@@ -204,6 +243,7 @@ export default {
 
       // 查询参数
       queryParams: {
+        logId: null,
         pageNum: 1,
         pageSize: 10,
         userId: null,
@@ -258,7 +298,9 @@ export default {
 
     this.loading = false;
 
-
+    getDeptData().then(response => {
+      this.deptList = response.data;
+    })
   },
   computed: {
     sourceTypeModel: {
@@ -271,7 +313,9 @@ export default {
     }
   },
   methods: {
+    handleMultiChange(e){
 
+    },
     setToday(){
       const today = new Date();
       const todayStart = new Date(today);
@@ -412,7 +456,12 @@ export default {
     },
     /** 查询短链课程看课记录列表 */
     getList() {
-
+      // 在API调用前设置部门参数
+      if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
+        this.queryParams.userIds = this.selectedCompanyList;
+      } else {
+        this.queryParams.userIds = [];
+      }
       // xgb 看课数据量太大必须限制时间if (this.isEmptyArray(this.createTime) &&
       if (this.isEmptyArray(this.createTime) &&
         this.isEmptyArray(this.updateTime) &&
@@ -425,14 +474,11 @@ export default {
         this.queryParams.logType = null;
       }
 
-      listCourseWatchLog(this.queryParams).then(response => {
-        this.courseWatchLogList = response.rows;
-        this.total = response.total;
+      listCourseWatchLogPage(this.queryParams).then(response => {
+        this.courseWatchLogList = response.data.list;
+        this.total = response.data.total;
         this.loading = false;
-      }).catch(() => {
-          this.loading = false;
-        }
-      );
+      })
     },
     // 取消按钮
     cancel() {
@@ -457,6 +503,7 @@ export default {
         courseId: null,
         scheduleStartTime: null,
         scheduleEndTime: null,
+        userIds: null,
       };
       this.scheduleTime=null;
       this.resetForm("form");
@@ -479,6 +526,8 @@ export default {
       this.queryParams.scheduleEndTime = null;
       this.scheduleTime=null;
       this.updateTime=null;
+      this.selectedCompanyList = [];
+      // this.selectedCompanyList = [];
       // 重置时间当天
       this.setToday();
 
@@ -547,6 +596,11 @@ export default {
     },
     /** 导出按钮操作 */
     handleExport() {
+      if(this.selectedCompanyList != null && this.selectedCompanyList.length > 0) {
+        this.queryParams.userIds = this.selectedCompanyList;
+      }else {
+        this.queryParams.userIds = [];
+      }
       // xgb 看课数据量太大必须限制时间
       if (this.isEmptyArray(this.createTime) &&
         this.isEmptyArray(this.updateTime) &&
@@ -560,12 +614,22 @@ export default {
           cancelButtonText: "取消",
           type: "warning"
         }).then(() => {
-          this.exportLoading = true;
-          return exportCourseWatchLog(queryParams);
+        const loadingInstance = this.$loading({
+          lock: true,
+          text: '正在导出数据,请稍候...',
+          background: 'rgba(0, 0, 0, 0.7)'
+        });
+
+        this.exportLoading = true;
+        return exportCourseWatchLog(queryParams).finally(res=>{
+          loadingInstance.close();
+        });
         }).then(response => {
           this.download(response.msg);
           this.exportLoading = false;
-        }).catch(() => {});
+        }).catch(() => {}).finally(res=>{
+          this.exportLoading = false;
+      });
     },
     handleScheduleTimeChange(scheduleTime) {
       if (scheduleTime && scheduleTime.length >= 2) {

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

@@ -50,7 +50,39 @@
       </el-form-item>
     </el-form>
 
-    <el-table border v-loading="loading" :data="courseWatchLogList" @selection-change="handleSelectionChange"  show-summary>
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleStatisExport"
+          v-hasPermi="['course:courseWatchLog:statisticsExport']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-if="'济南联志健康' == this.signProjectName" 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="qwUserName" />
+      <el-table-column label="发课时间" align="center" prop="createTime"/>
+      <el-table-column label="课程名称" align="center" prop="courseName" />
+      <el-table-column label="小节名称" align="center" prop="videoName" />
+      <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-column label="注册用户待看课数" align="center" prop="isUserWaitNumber" />
+      <el-table-column label="未注册用户待看课数" align="center" prop="noUserWaitNumber" />
+      <el-table-column label="上线率" align="center" prop="onLineRate" />
+      <el-table-column label="完课率" align="center" prop="finishedRate" />
+      <el-table-column label="消耗红包金额" align="center" prop="redAmount" />
+    </el-table>
+
+    <el-table v-else border v-loading="loading" :data="courseWatchLogList" @selection-change="handleSelectionChange"  show-summary>
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="企微员工名称" align="center" prop="qwUserName" />
       <el-table-column label="发课时间" align="center" prop="createTime"/>
@@ -79,13 +111,25 @@
 </template>
 
 <script>
-import { listCourseWatchLog, getCourseWatchLog, delCourseWatchLog, addCourseWatchLog, updateCourseWatchLog, exportCourseWatchLog,statisticsList } from "@/api/course/qw/courseWatchLog";
+import {
+  listCourseWatchLog,
+  getCourseWatchLog,
+  delCourseWatchLog,
+  addCourseWatchLog,
+  updateCourseWatchLog,
+  exportCourseWatchLog,
+  statisticsList,
+  getSignProjectName,
+  exportCourseWatchLogStatisticsExport,
+  exportCourseWatchLogStatisticsExportQw
+} from '@/api/course/qw/courseWatchLog'
 import { courseList,videoList } from '@/api/course/courseRedPacketLog'
 import {getCompanyList} from "@/api/company/company";
 export default {
   name: "CourseWatchLog",
   data() {
     return {
+      signProjectName:"",
       companys:[],
       activeName:"00",
       createTime:null,
@@ -140,6 +184,11 @@ export default {
     };
   },
   created() {
+    getSignProjectName().then(res=>{
+      this.signProjectName = res.signProjectName;
+      console.log(this.signProjectName);
+    }).catch(res=>{});
+
     getCompanyList().then(response => {
       this.companys = response.data;
       if(this.companys!=null&&this.companys.length>0){
@@ -156,6 +205,52 @@ export default {
     });
   },
   methods: {
+
+    handleStatisExport(){
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有会员看课统计数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportCourseWatchLogStatisticsExportQw(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
+    },
+    getSummaries(param) {
+        const { columns, data } = param;
+        const sums = [];
+         // 关键改动:创建一个不包含最后一行的新数据数组
+        // 如果数据长度大于1,则截取掉最后一行;否则,使用空数组避免错误
+        const dataToSum = data.length > 1 ? data.slice(0, -1) : [];
+        columns.forEach((column, index) => {
+
+          if (index === 0) {
+            sums[index] = '页总计';
+            return;
+          }
+          const values = dataToSum.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] = 'N/A';
+          }
+        });
+
+        return sums;
+      },
     courseChange(row){
       this.queryParams.videoId=null;
       if(row === ''){

+ 40 - 1
src/views/course/courseWatchLog/statistics.vue

@@ -75,6 +75,21 @@
       </el-form-item>
     </el-form>
 
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleStatisExport"
+          v-hasPermi="['course:courseWatchLog:statisticsExport']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
     <el-table
       border
       v-loading="loading"
@@ -106,7 +121,16 @@
 </template>
 
 <script>
-import { listCourseWatchLog, getCourseWatchLog, delCourseWatchLog, addCourseWatchLog, updateCourseWatchLog, exportCourseWatchLog,statisticsList } from "@/api/course/courseWatchLog";
+import {
+  listCourseWatchLog,
+  getCourseWatchLog,
+  delCourseWatchLog,
+  addCourseWatchLog,
+  updateCourseWatchLog,
+  exportCourseWatchLog,
+  statisticsList,
+  exportCourseWatchLogStatisticsExport
+} from '@/api/course/courseWatchLog'
 import { courseList,videoList } from '@/api/course/courseRedPacketLog'
 import {getUserList} from "@/api/company/companyUser";
 import {getFsUserList} from "@/api/users/user";
@@ -421,6 +445,21 @@ export default {
         this.exportLoading = false;
       }).catch(() => {});
     },
+
+    handleStatisExport(){
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有会员看课统计数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportCourseWatchLogStatisticsExport(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
+    },
     handleScheduleTimeChange(val) {
       if (val) {
         this.queryParams.scheduleStartTime = val[0];

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

@@ -167,7 +167,7 @@
       </el-table-column>
       <el-table-column label="支付时间" align="center" prop="payTime" width="180">
         <template slot-scope="scope">
-          <span>{{ parseTime(scope.row.payTime, '{y}-{m}-{d}') }}</span>
+          <span>{{ parseTime(scope.row.payTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
         </template>
       </el-table-column>
       <el-table-column label="订单状态" align="center" prop="status">
@@ -181,7 +181,7 @@
       </el-table-column>
       <el-table-column label="申请退款时间" align="center" prop="refundTime" width="180">
         <template slot-scope="scope">
-          <span>{{ parseTime(scope.row.refundTime, '{y}-{m}-{d}') }}</span>
+          <span>{{ parseTime(scope.row.refundTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
         </template>
       </el-table-column>
       <el-table-column label="申请退款理由" :show-overflow-tooltip="true" align="center" prop="refundExplain" />

+ 195 - 5
src/views/course/userCourse/index.vue

@@ -108,7 +108,8 @@
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
-    <el-table height="600" border v-loading="loading" :data="userCourseList" @selection-change="handleSelectionChange" style="width: 100%" :fit="true">
+<!--    <el-table height="600" border v-loading="loading" :data="userCourseList" @selection-change="handleSelectionChange" style="width: 100%" :fit="true">-->
+    <el-table max-height="600" border v-loading="loading" :data="userCourseList" @selection-change="handleSelectionChange" style="width: 100%" :fit="true">
       <el-table-column type="selection" width="55" align="center"/>
       <el-table-column label="课程ID" align="center" prop="courseId" width="55"/>
       <el-table-column label="所属项目" align="center" prop="projectName" width="120"/>
@@ -276,6 +277,86 @@
         <el-form-item label="红包金额" prop="redPacketMoney">
           <el-input-number v-model="openRedPage.redPacketMoney" :min="0.1" :max="200" :step="0.1"></el-input-number>
         </el-form-item>
+        <div v-if="!!enableRandomRedPacket" style=" display: flex;
+                  flex-direction: column;">
+             <div v-for="(rule, index) in openRedPage.rules" :key="index" class="form-row">
+           <el-form-item
+            label="随机红包金额区间"
+            :prop="`rules.${index}.minAmount`"
+            :rules="[
+              { required: true, message: '请输入最小金额', trigger: 'blur' },
+              { validator: validateMinAmount, trigger: 'blur', index: index }
+            ]"
+            class="form-item-amount"
+          >
+            <el-input
+              v-model.number="rule.minAmount"
+              type="number"
+              :min="0.01"
+              :precision="2"
+              :step="0.01"
+              placeholder="最小金额"
+              size="small"
+              class="amount-input"
+              @input="handleAmountInput(rule, 'minAmount')"
+            ></el-input>
+            <span class="separator">-</span>
+            <el-input
+              v-model.number="rule.maxAmount"
+              type="number"
+              :min="rule.minAmount || 0.01"
+              :precision="2"
+              :step="0.01"
+              placeholder="最大金额"
+              size="small"
+              class="amount-input"
+              @input="handleAmountInput(rule, 'maxAmount')"
+            ></el-input>
+            <span class="suffix">元</span>
+          </el-form-item>
+              <el-form-item
+                label="随机权重"
+                :prop="`rules.${index}.weight`"
+                :rules="[
+                  { required: true, message: '请输入权重', trigger: 'blur' },
+                  { type: 'integer', message: '权重必须为整数', trigger: 'blur' },
+                ]"
+                class="form-item-weight"
+              >
+                <el-input
+                  v-model.number="rule.weight"
+                  type="number"
+                  :min="1"
+                  placeholder="权重"
+                  size="small"
+                ></el-input>
+              </el-form-item>
+              <el-tooltip class="item" effect="dark" content="权重越高,被随机到的概率越大" placement="top">
+                <i class="el-icon-question"></i>
+              </el-tooltip>
+              <div class="action-buttons">
+                <el-button
+                  icon="el-icon-plus"
+                  size="mini"
+                  type="text"
+                  @click="addRule(index)"
+                  class="add-btn"
+                >
+                  新增
+                </el-button>
+                <el-button
+                  icon="el-icon-delete"
+                  size="mini"
+                  type="text"
+                  @click="deleteRule(index)"
+                  :disabled="openRedPage.rules.length <= 1"
+                  class="delete-btn"
+                >
+                  删除
+                </el-button>
+              </div>
+            </div>
+        </div>
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="submitFormRedPage">确 定</el-button>
@@ -380,7 +461,7 @@ import userCourseCatalogDetails from '../../components/course/userCourseCatalogD
 import {getAllCourseCategoryList, getCatePidList, getCateListByPid} from "@/api/course/userCourseCategory";
 import {allList} from "@/api/company/company";
 import VideoUpload from '@/components/VideoUpload/index.vue'
-
+import { getConfigByKey } from '@/api/system/config'
 export default {
   name: "UserCourse",
   components: {
@@ -388,6 +469,16 @@ export default {
     Treeselect,
     Editor, ImageUpload, userCourseCatalogDetails
   },
+  watch:{
+  // 深度监听 rules 数组的变化,以更新总权重
+    "openRedPage.rules": {
+      handler(val) {
+        // this.calculateTotalWeight();
+        this.validateRules();
+      },
+      deep: true,
+    },
+  },
   data() {
     return {
       talentParam: {
@@ -438,6 +529,14 @@ export default {
         courseId:null,
         courseName:null,
         redPacketMoney:0.1,
+        //随机红包配置
+        rules:[
+           {
+            minAmount: 0.01,
+            maxAmount: 0.01,
+            weight: 100,
+          }
+        ]
       },
       // 查询参数
       queryParams: {
@@ -552,11 +651,26 @@ export default {
             { required: true, message: '支持单位不能为空', trigger: 'blur' }
           ],
         }
-      }
+      },
+      enableRandomRedPacket:false
     };
   },
   created() {
     this.getList();
+    getConfigByKey('randomRedpacket:config').then(res=>{
+        console.log("res::")
+        console.log(res);
+        let configData = res.data;
+        if(!!configData && !!configData.configValue){
+           let configValue = JSON.parse(configData.configValue);
+           console.log(configValue);
+           if(!!configValue.enableRandomRedpacket){
+            this.enableRandomRedPacket = configValue.enableRandomRedpacket;
+           }
+        }
+    }).catch(res=>{
+
+    })
     getCatePidList().then(response => {
       this.categoryOptions = response.data;
     });
@@ -715,6 +829,7 @@ export default {
     /** 重置按钮操作 */
     resetQuery() {
       this.resetForm("queryForm");
+      this.queryParams.companyIdsList = [];
       this.queryParams.isShow = this.activeName
       this.handleQuery();
     },
@@ -809,13 +924,14 @@ export default {
 
       const courseId = this.openRedPage.courseId;
       const redPacketMoney = this.openRedPage.redPacketMoney;
+      let randomRedPacketRules = JSON.stringify( this.openRedPage.rules);
+      console.log(randomRedPacketRules)
       this.$confirm('是否确认将课程id 为"' + courseId + '"的红包批量修改为:【'+redPacketMoney+'】?', "警告", {
         confirmButtonText: "确定",
         cancelButtonText: "取消",
         type: "warning"
       }).then(function () {
-
-        return updateUserCourseRedPage({courseId:courseId,redPacketMoney:redPacketMoney});
+        return updateUserCourseRedPage({courseId:courseId,redPacketMoney:redPacketMoney,randomRedPacketRules:randomRedPacketRules});
       }).then(() => {
         this.getList();
         this.msgSuccess("修改成功");
@@ -985,6 +1101,80 @@ export default {
       this.resetForm('configForm')
       this.configDialog.dialogVisible = false;
     },
+    // 实时过滤金额输入,只允许两位小数
+    handleAmountInput(rule, field) {
+      let value = rule[field];
+      if (value === null || value === undefined) return;
+
+      // 转换为字符串处理
+      let str = value.toString();
+
+      // 移除除数字和小数点外的所有字符
+      str = str.replace(/[^0-9.]/g, '');
+
+      // 只保留一个小数点
+      const dotIndex = str.indexOf('.');
+      if (dotIndex !== -1) {
+        str = str.substring(0, dotIndex + 1) + str.substring(dotIndex + 1).replace(/\./g, '');
+      }
+
+      // 限制小数点后最多两位
+      if (dotIndex !== -1 && str.length > dotIndex + 3) {
+        str = str.substring(0, dotIndex + 3);
+      }
+
+      // 转换回数字并更新
+      rule[field] = parseFloat(str) || 0;
+    },
+      deleteRule(index) {
+      this.$confirm("确定要删除这个区间吗?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      }).then(() => {
+        this.openRedPage.rules.splice(index, 1);
+        this.$message({
+          type: "success",
+          message: "删除成功!",
+        });
+      });
+    },
+      addRule(index) {
+      // 在当前行的后面插入一个新行
+      this.openRedPage.rules.splice(index + 1, 0, {
+        minAmount: 0.01,
+        maxAmount: 0.01,
+        weight: 100,
+      });
+    },
+       // 自定义校验规则:确保最大金额大于最小金额
+    validateMinAmount(rule, value, callback) {
+      // debugger;
+      // const maxAmount = this.form29.rules[].maxAmount
+
+      const index = rule.index;
+      const maxAmount = this.openRedPage.rules[index].maxAmount;
+
+      if (value > maxAmount) {
+        callback(new Error("最小金额不能大于最大金额"));
+      } else {
+        callback();
+      }
+    },
+      validateRules() {
+      this.openRedPage.rules.forEach((rule) => {
+        if (rule.minAmount === undefined || rule.minAmount < 0.01) {
+          rule.minAmount = 0.01;
+        }
+        if (rule.maxAmount === undefined || rule.maxAmount < rule.minAmount) {
+          rule.maxAmount = rule.minAmount;
+        }
+        if (rule.weight === undefined || rule.weight < 1) {
+          rule.weight = 1;
+        }
+      });
+    },
+
   }
 };
 </script>

+ 3 - 2
src/views/course/userCourse/public.vue

@@ -662,9 +662,10 @@ export default {
     },
     handleShow(row) {
       var isShowValue = row.isShow === 0 ? 1 : 0;
-      var course = {courseId: row.courseId, isShow: isShowValue};
+      var course = {courseId: row.courseId, isShow: isShowValue, isPrivate: row.isPrivate};
       updateIsShow(course).then(response => {
-        this.msgSuccess("修改成功");
+        var isShowText = isShowValue === 1 ? "上架成功" : "下架成功";
+        this.msgSuccess(isShowText);
         this.getList();
       });
     },

+ 106 - 29
src/views/course/userCoursePeriod/statistics.vue

@@ -13,6 +13,7 @@
             :loading="courseLoading"
             placeholder="请输入关键词搜索营期课程"
             style="width: 400px"
+            @visible-change="handleCourseDropdownVisible"
           >
             <el-option
               v-for="item in courseOptions"
@@ -20,6 +21,13 @@
               :label="item.videoName"
               :value="item.videoId"
             />
+            <!-- 分页加载更多选项 -->
+            <el-option v-if="hasMoreCourses" key="load-more" disabled class="load-more-option">
+              <div class="load-more" @click="loadMoreCourses">
+                <span>加载更多</span>
+                <i class="el-icon-loading" v-if="loadingMore"></i>
+              </div>
+            </el-option>
           </el-select>
         </el-form-item>
 
@@ -40,6 +48,7 @@
         </el-form-item>
         <el-form-item>
           <el-button type="primary" @click="handleQuery">查询</el-button>
+          <el-button type="info" :loading="exportLoading" @click="exportHandle">导出</el-button>
         </el-form-item>
       </el-form>
 
@@ -132,7 +141,7 @@
 </template>
 
 <script>
-import {getDays, periodCountSelect, getPeriodCompanyList} from "@/api/course/userCoursePeriod";
+import {getDays, periodCountSelect, getPeriodCompanyList,exportInfo} from "@/api/course/userCoursePeriod";
 
 export default {
   name: "CourseStatistics",
@@ -148,13 +157,23 @@ export default {
   },
   data() {
     return {
+      exportLoading: false,
       // 遮罩层
       loading: false,
       courseLoading: false,
+      loadingMore: false,
       // 总条数
       total: 0,
       // 课程选项
       courseOptions: [],
+      courseTotal: 0,
+      courseQueryParams: {
+        pageNum: 1,
+        pageSize: 10, // 默认每页10条
+        videoName: '',
+        periodId: ''
+      },
+      hasMoreCourses: false,
       companyOptions: [],
       // 统计数据
       statistics: {
@@ -184,6 +203,7 @@ export default {
     periodId: {
       handler(newVal) {
         this.queryParams.periodId = newVal;
+        this.courseQueryParams.periodId = newVal;
         if (this.active && !this.initialized) {
           this.initializeData();
         }
@@ -216,53 +236,87 @@ export default {
     },
 
     /** 获取课程选项 */
-    getCourseOptions() {
-      this.courseLoading = true;
-      getDays(this.queryParams).then(r => {
+    getCourseOptions(isLoadMore = false) {
+      if (!isLoadMore) {
+        this.courseLoading = true;
+        this.courseQueryParams.pageNum = 1; // 重置页码
+      } else {
+        this.loadingMore = true;
+      }
+
+      getDays(this.courseQueryParams).then(r => {
         if (r.code === 200) {
-          this.courseOptions = r.rows;
-          this.loading = false;
+          if (isLoadMore) {
+            // 加载更多时,追加数据
+            this.courseOptions = [...this.courseOptions, ...r.rows];
+          } else {
+            // 首次加载或搜索时,替换数据
+            this.courseOptions = r.rows;
+          }
+
+          this.courseTotal = r.total || 0;
+
+          // 计算是否还有更多数据
+          const loadedCount = this.courseOptions.length;
+          this.hasMoreCourses = loadedCount < this.courseTotal;
+
+          this.courseLoading = false;
+          this.loadingMore = false;
         } else {
           this.$message.error(r.msg || '获取数据失败');
+          this.courseLoading = false;
+          this.loadingMore = false;
         }
-        this.courseLoading = false;
       }).catch(() => {
         this.courseLoading = false;
+        this.loadingMore = false;
       });
     },
 
-    /** 营期课程搜索 */
-    handleCourseSearch(query) {
-      if (query !== '') {
-        this.courseLoading = true;
-        // 这里可以根据实际接口调整搜索参数
-        getDays({
-          periodId: this.queryParams.periodId,
-          pageNum: 1,
-          pageSize: 100,
-          videoName: query // 假设接口支持按课程名称搜索
-        }).then(r => {
-          if (r.code === 200) {
-            this.courseOptions = r.rows;
-          } else {
-            this.$message.error(r.msg || '搜索失败');
-          }
-          this.courseLoading = false;
-        }).catch(() => {
-          this.courseLoading = false;
-        });
-      } else {
-        // 如果搜索词为空,重新加载所有课程
+    /** 加载更多课程 */
+    loadMoreCourses() {
+      if (this.loadingMore) return;
+
+      this.courseQueryParams.pageNum += 1;
+      this.getCourseOptions(true);
+    },
+
+    /** 处理下拉框显示/隐藏 */
+    handleCourseDropdownVisible(visible) {
+      if (visible && this.courseOptions.length === 0) {
+        // 当下拉框显示且没有数据时,加载初始数据
         this.getCourseOptions();
       }
     },
 
+    /** 营期课程搜索 */
+    handleCourseSearch(query) {
+      this.courseQueryParams.videoName = query;
+      this.courseQueryParams.pageNum = 1; // 搜索时重置页码
+      this.getCourseOptions();
+    },
+
     /** 查询按钮操作 */
     handleQuery() {
       this.queryParams.pageNum = 1;
       this.getCountList();
     },
 
+    /** 导出 */
+    exportHandle(){
+      this.$confirm('是否确认导出所有课程统计信息数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportInfo(this.queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
+    },
+
     /** 获取列表数据 */
     getCountList() {
       this.loading = true;
@@ -392,4 +446,27 @@ export default {
   font-weight: bold;
   color: #303133;
 }
+
+/* 加载更多选项样式 */
+.load-more-option {
+  text-align: center;
+  padding: 8px 0;
+}
+
+.load-more {
+  color: #409EFF;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 5px;
+}
+
+.load-more:hover {
+  color: #66b1ff;
+}
+
+:deep(.el-select-dropdown__list) {
+  padding-bottom: 0 !important;
+}
 </style>

+ 139 - 35
src/views/course/videoResource/index.vue

@@ -774,7 +774,9 @@ import {getByIds, listCourseQuestionBank} from '@/api/course/courseQuestionBank'
 import {getThumbnail} from "@/api/course/userVideo";
 import {uploadObject} from "@/utils/cos.js";
 import {uploadToOBS} from "@/utils/obs.js";
+import {uploadToHSY} from "@/utils/hsy.js";
 import MinimizableDialog from "@/components/MinimizableDialog"
+import log from "@/views/monitor/job/log.vue";
 
 export default {
   name: 'VideoResource',
@@ -827,6 +829,8 @@ export default {
         typeSubId: null,
         projectIds: [],
         sort: null,
+        hsyVid:null,//火山云上传视频返回vid
+        hsyVodUrl:null,//火山云url
         // 新增上传状态字段
         uploadStatus: 'pending', // pending, uploading, success, failed
         uploadProgress: {
@@ -945,6 +949,7 @@ export default {
       isProcessingBatch: false, // 是否正在处理批次
       currentBatchIndex: 0, // 当前批次索引
       uploadCancellationTokens: new Map(), // Store cancellation functions by video ID
+      currentProject: process.env.VUE_APP_PROJECT
     }
   },
   watch: {
@@ -1107,6 +1112,7 @@ export default {
           this.add = true
 
           const params = Object.assign({}, this.form);
+          console.log("提交素材表单参数",this.form)
           params.projectIds = this.form.projectIds.join(',');
           if (this.form.id != null) {
             updateVideoResource(params).then(response => {
@@ -1301,37 +1307,95 @@ export default {
       }
     },
     //上传华为云Obs
-    async uploadVideoToHwObs(file, form, onProgress) {
+    // async uploadVideoToHwObs(file, form, onProgress) {
+    //   try {
+    //     // 更新线路2状态为上传中
+    //     this.updateUploadProgress('line2Status', 'uploading');
+    //
+    //     const data = await uploadToOBS(file, (progress) => {
+    //       const progressPercent = Math.floor(progress);
+    //       this.updateUploadProgress('line2', progressPercent);
+    //       const progressEvent = { percent: progressPercent, loaded: progress, total: progress, lengthComputable: true };
+    //       onProgress(progressEvent);
+    //     }, 1, (uploadInfo) => {
+    //       if (form.tempId) {
+    //         const tokens = this.uploadCancellationTokens.get(form.tempId) || {};
+    //         tokens.obs = uploadInfo.cancel;
+    //         this.uploadCancellationTokens.set(form.tempId, tokens);
+    //       }
+    //     });
+    //
+    //     form.line2 = `${process.env.VUE_APP_VIDEO_LINE_2}/${data.urlPath}`;
+    //
+    //     // 更新线路2状态为成功
+    //     this.updateUploadProgress('line2Status', 'success');
+    //     this.updateUploadProgress('line2', 100);
+    //
+    //     this.$message.success("线路二上传成功");
+    //     return { success: true, url: form.line2 };
+    //   } catch (error) {
+    //     // 更新线路2状态为失败
+    //     this.updateUploadProgress('line2Status', 'failed');
+    //     this.$message.error("线路二上传失败");
+    //     return { success: false, error: error.message };
+    //   }
+    // },
+    //上传火山云
+    async uploadVideoToHsy(file, form, onProgress) {
       try {
-        // 更新线路2状态为上传中
         this.updateUploadProgress('line2Status', 'uploading');
 
-        const data = await uploadToOBS(file, (progress) => {
-          const progressPercent = Math.floor(progress);
-          this.updateUploadProgress('line2', progressPercent);
-          const progressEvent = { percent: progressPercent, loaded: progress, total: progress, lengthComputable: true };
-          onProgress(progressEvent);
-        }, 1, (uploadInfo) => {
-          if (form.tempId) {
-            const tokens = this.uploadCancellationTokens.get(form.tempId) || {};
-            tokens.obs = uploadInfo.cancel;
-            this.uploadCancellationTokens.set(form.tempId, tokens);
-          }
-        });
+        const data = await uploadToHSY(
+          file,
+          (progress) => {
+            // 火山云的进度是小数0-1
+            if (typeof progress.percent === 'number') {
+              const percent = Math.floor(progress.percent * 100);
+
+              // 更新线路2进度
+              this.updateUploadProgress('line2', percent);
+
+              // 对外统一 progress 事件(模拟 xhr)
+              onProgress?.({
+                percent,
+                loaded: percent,
+                total: 100,
+                lengthComputable: true
+              });
+            }
 
-        form.line2 = `${process.env.VUE_APP_VIDEO_LINE_2}/${data.urlPath}`;
+            // 状态同步(成功 / 失败)
+            if (progress.status === 'success') {
+              this.updateUploadProgress('line2Status', 'success');
+              this.updateUploadProgress('line2', 100);
+            }
 
-        // 更新线路2状态为成功
-        this.updateUploadProgress('line2Status', 'success');
-        this.updateUploadProgress('line2', 100);
+            if (progress.status === 'failed') {
+              this.updateUploadProgress('line2Status', 'failed');
+            }
+          },
+          1,
+          (uploadInfo) => {
+            if (form.tempId) {
+              const tokens = this.uploadCancellationTokens.get(form.tempId) || {};
+              tokens.hsy = uploadInfo.cancel;
+              this.uploadCancellationTokens.set(form.tempId, tokens);
+            }
+          }
+        );
+        console.log("上传火山云返回参数",data)
 
-        this.$message.success("线路二上传成功");
+        form.line2 = `${process.env.VUE_APP_VIDEO_URL}/${data.SourceInfo.FileName}`;
+        this.form.hsyVid = data.Vid
+        this.form.hsyVodUrl = process.env.VUE_APP_VIDEO_URL+"/"+data.SourceInfo.FileName
+        console.log("this.form",this.form)
+        this.$message.success('线路二上传成功');
         return { success: true, url: form.line2 };
+
       } catch (error) {
-        // 更新线路2状态为失败
         this.updateUploadProgress('line2Status', 'failed');
-        this.$message.error("线路二上传失败");
-        return { success: false, error: error.message };
+        this.$message.error('线路二上传失败');
+        return { success: false, error: error?.message || 'upload failed' };
       }
     },
     // 更新上传进度的辅助方法
@@ -1368,7 +1432,8 @@ export default {
         await this.getFirstThumbnail(file, this.form);
         const [line1Result, line2Result] = await Promise.allSettled([
           this.uploadVideoToTxPcdn(file, this.form, options.onProgress),
-          this.uploadVideoToHwObs(file, this.form, options.onProgress)
+          //this.uploadVideoToHwObs(file, this.form, options.onProgress)
+          this.uploadVideoToHsy(file, this.form, options.onProgress)
         ]);
 
         const line1Success = line1Result.status === 'fulfilled' && line1Result.value.success;
@@ -1470,6 +1535,7 @@ export default {
     },
     /** 批量修改 */
     submitBatchUpdate() {
+      console.log("批量上传表单提交参数",this.form)
       this.$refs["form"].validate(valid => {
         if (valid) {
           if (this.batchUpdateForm.ids.length === 0) {
@@ -1503,6 +1569,7 @@ export default {
       }
 
       // 检查是否所有选中的视频都已上传完成
+      console.log("videoList",this.videoList)
       const incompleteVideos = this.videoList.filter(item => (item.progress || 0) < 100);
       if (incompleteVideos.length > 0) {
         this.$message.warning('有未完成上传的视频,请先完成上传');
@@ -1661,14 +1728,24 @@ export default {
     /** 显示上传面板 */
     showUploadPanel() {
       this.showUpload = true;
-      this.batchUploadForm = {
-        typeId: null,
-        typeSubId: null,
-        projectIds: [],
-        files: []
-      };
+
+      if (this.currentProject === 'myhk') {
+        this.batchUploadForm = {
+          ...this.batchUploadForm,
+          projectIds: [],
+          files: []
+        };
+      } else {
+        this.batchUploadForm = {
+          typeId: null,
+          typeSubId: null,
+          projectIds: [],
+          files: []
+        };
+        this.subTypeList = []
+      }
+
       this.batchFileList = [];
-      this.subTypeList = []
       if (this.$refs.batchVideoUpload) {
         this.$refs.batchVideoUpload.clearFiles();
       }
@@ -1776,6 +1853,7 @@ export default {
       this.isProcessingBatch = false;
       this.isUploading = false;
       this.$message.success('所有视频上传队列处理完成!');
+      console.log("批量上传form",this.form)
     },
 
     async uploadSingleVideo(tempVideo) {
@@ -1786,7 +1864,9 @@ export default {
         // 并行上传到两个服务器
         const [line1Result, line2Result] = await Promise.allSettled([
           this.uploadVideoToTxPcdnBatch(tempVideo.file, tempVideo),
-          this.uploadVideoToHwObsBatch(tempVideo.file, tempVideo)
+          // this.uploadVideoToHwObsBatch(tempVideo.file, tempVideo)
+          this.uploadVideoToHSYBatch(tempVideo.file, tempVideo),
+
         ]);
 
         // 检查上传结果
@@ -2110,9 +2190,31 @@ export default {
       }
     },
     // 批量上传 - 华为云
-    async uploadVideoToHwObsBatch(file, tempVideo) {
+    // async uploadVideoToHwObsBatch(file, tempVideo) {
+    //   try {
+    //     const data = await uploadToOBS(file, (progress) => {
+    //       const progressPercent = Math.floor(progress);
+    //       const index = this.videoList.findIndex(item => item.tempId === tempVideo.tempId);
+    //       if (index !== -1) {
+    //         this.videoList[index].uploadDetails.line2 = progressPercent;
+    //         this.videoList[index].uploadDetails.line2Status = 'uploading';
+    //         this.updateBatchProgress(index);
+    //       }
+    //     }, 1, (uploadInfo) => {
+    //       const tokens = this.uploadCancellationTokens.get(tempVideo.tempId) || {};
+    //       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) {
+    //     return { success: false, error: error.message };
+    //   }
+    // },
+    async uploadVideoToHSYBatch(file, tempVideo) {
       try {
-        const data = await uploadToOBS(file, (progress) => {
+        const data = await uploadToHSY(file, (progress) => {
           const progressPercent = Math.floor(progress);
           const index = this.videoList.findIndex(item => item.tempId === tempVideo.tempId);
           if (index !== -1) {
@@ -2125,9 +2227,11 @@ export default {
           tokens.obs = uploadInfo.cancel;
           this.uploadCancellationTokens.set(tempVideo.tempId, tokens);
         });
+        console.log("批量上传返回参数",data)
+        tempVideo.line2 = `${process.env.VUE_APP_VIDEO_URL}/${data.SourceInfo.FileName}`;
+        tempVideo.hsyVid = data.Vid;
 
-        tempVideo.line2 = `${process.env.VUE_APP_VIDEO_LINE_2}/${data.urlPath}`;
-        return { success: true, url: tempVideo.line2 };
+        return { success: true, url: tempVideo.line2};
       } catch (error) {
         return { success: false, error: error.message };
       }

+ 9 - 1
src/views/his/adv/index.vue

@@ -109,6 +109,7 @@
         </template>
       </el-table-column>
       <el-table-column label="地址" show-overflow-tooltip align="center" prop="advUrl" width="150px" />
+      <el-table-column label="跳转小程序原始id" show-overflow-tooltip align="center" prop="originalId" width="150px" />
 
       <el-table-column label="排序" align="center" prop="sort" />
       <el-table-column label="类型" align="center" prop="advType" width="130px">
@@ -199,6 +200,9 @@
        <el-form-item label="APP地址" prop="advUrl" v-if="form.showType==2||form.showType==4 ">
          <el-input v-model="form.appAdvUrl" placeholder="请输入APP地址" />
        </el-form-item>
+        <el-form-item label="跳转小程序原始id" prop="advUrl" v-if="form.showType==2||form.showType==4 ">
+          <el-input v-model="form.originalId" placeholder="请输入跳转小程序原始id" />
+        </el-form-item>
        <el-form-item label="文章内容" v-show="form.showType==3">
          <editor ref="myeditor" @on-text-change="updateText" />
        </el-form-item>
@@ -297,6 +301,9 @@ export default {
         showType: [
           { required: true, message: "显示类别不能为空", trigger: "blur" }
         ],
+        activeId: [
+          { required: true, message: "活动不能为空", trigger: "blur" }
+        ],
       }
     };
   },
@@ -368,7 +375,8 @@ export default {
         sort: null,
         advType: null,
         showType: null,
-        activeId: null
+        activeId: null,
+        originalId: null
       };
       this.resetForm("form");
     },

+ 21 - 8
src/views/his/company/index.vue

@@ -145,6 +145,7 @@
       <el-table-column label="到期时间" align="center" prop="limitTime" width="180"/>
       <el-table-column label="创建时间" align="center" prop="createTime" width="180"/>
       <el-table-column label="更新时间" align="center" prop="updateTime" width="180"/>
+      <el-table-column v-if="'济南联志健康'==signProjectName"  align="center" width="180" label="分公司配置商户号" prop="mchId" />
       <!--      <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="220px">
         <template slot-scope="scope">
@@ -189,6 +190,7 @@
           >扣款
           </el-button>
           <el-button
+            v-if="showRedPacket"
             size="mini"
             type="text"
             icon="el-icon-edit"
@@ -197,6 +199,7 @@
           >红包充值
           </el-button>
           <el-button
+            v-if="showRedPacket"
             size="mini"
             type="text"
             icon="el-icon-edit"
@@ -732,11 +735,12 @@ import { cateList } from '@/api/his/packageCate'
 import { getConfigByKey } from '@/api/system/config'
 import { listDept } from '@/api/system/dept'
 import { listAll } from '@/api/course/coursePlaySourceConfig'
-
+import{ getSignProjectName } from '@/api/course/qw/courseWatchLog'
 export default {
   name: 'Company',
   data() {
     return {
+      signProjectName:"",
       redSubmit: false,
       //分账参数
       revenue:{
@@ -764,6 +768,7 @@ export default {
         open: false,
         title: '红包充值'
       },
+      showRedPacket: false,
       // 遮罩层
       loading: true,
       // 导出遮罩层
@@ -916,6 +921,11 @@ export default {
     }
   },
   created() {
+    getSignProjectName()
+    .then(res=>{
+      this.signProjectName = res.signProjectName;
+    })
+    .catch(res=>{console.log("getSignProjectName Err")})
     this.getList()
     this.getDicts('sys_company_status').then(response => {
       this.statusOptions = response.data
@@ -935,13 +945,16 @@ export default {
     listDept().then(response => {
       this.deptOptions = response.data
     })
-    // getConfigByKey("courseMa.config").then(response => {
-    //   if(response.data && response.data.configValue) {
-    //     this.miniAppList = JSON.parse(response.data.configValue);
-    //   } else {
-    //     this.miniAppList = [];
-    //   }
-    // });
+    getConfigByKey("course.config").then(response => {
+      if(response.data && response.data.configValue) {
+        const  config = JSON.parse(response.data.configValue);
+        if( config.isRedPackageBalanceDeduction && config.isRedPackageBalanceDeduction==1){
+          this.showRedPacket=true
+        }
+      } else {
+        this.showRedPacket = false;
+      }
+    });
     docList().then(response => {
       this.doctor = response.rows
     })

+ 285 - 9
src/views/his/integralOrder/index.vue

@@ -1,14 +1,60 @@
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="订单编号" prop="orderCode">
-        <el-input
-          v-model="queryParams.orderCode"
-          placeholder="请输入订单编号"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
+      <el-form-item label="订单编号" prop="orderCodes">
+        <div class="tag-input-container">
+          <!-- 标签显示区域 -->
+          <div class="tags-wrapper" @click="focusInput">
+            <!-- 已添加的订单号标签 -->
+            <el-tag
+              v-for="(code, index) in queryParams.orderCodes"
+              :key="index"
+              closable
+              size="small"
+              @close="removeOrderCode(index)"
+              class="order-tag"
+              :class="{ 'tag-error': false }"
+            >
+              {{ code }}
+            </el-tag>
+
+            <!-- 输入框 -->
+            <el-input
+              ref="tagInput"
+              v-model="currentInput"
+              v-show="inputVisible || queryParams.orderCodes.length === 0"
+              :placeholder="queryParams.orderCodes.length === 0 ? '请输入订单号,按回车或逗号分隔' : '继续输入...'"
+              size="small"
+              class="tag-input"
+              @keydown.native="handleKeyDown"
+              @keyup.native="handleKeyUp"
+              @blur="handleInputConfirm"
+              @focus="inputVisible = true"
+              clearable
+            />
+
+            <!-- 添加按钮(当没有输入时显示) -->
+            <el-button
+              v-if="!inputVisible && queryParams.orderCodes.length > 0"
+              class="button-new-tag"
+              size="small"
+              @click="showInput"
+              icon="el-icon-plus"
+              type="text"
+            >
+              添加订单号
+            </el-button>
+          </div>
+
+          <!-- 输入提示 -->
+          <div class="input-tips">
+            <span class="tip-text">
+              支持:回车、逗号、空格分隔 |
+              已添加 {{ queryParams.orderCodes.length }} 个订单号
+              <span v-if="maxOrderCodes > 0"> (最多{{ maxOrderCodes }}个)</span>
+            </span>
+          </div>
+        </div>
       </el-form-item>
       <el-form-item label="用户名称" prop="userName">
         <el-input
@@ -174,6 +220,20 @@
       <el-table-column label="ERP账号" align="center" prop="loginAccount" />
       <el-table-column label="ERP电话" align="center" prop="erpPhone" />
       <el-table-column label="订单编号" align="center" prop="orderCode" />
+      <el-table-column label="商品名称" align="center" width="200">
+        <template slot-scope="scope">
+          <div style="display: flex; align-items: center; justify-content: center;">
+            <span>{{ scope.row.goodsName }}</span>
+            <el-image
+              v-if="scope.row.goodsImage"
+              :src="scope.row.goodsImage"
+              style="width: 40px; height: 40px; margin-left: 8px;"
+              fit="cover"
+              :preview-src-list="[scope.row.goodsImage]"
+            />
+          </div>
+        </template>
+      </el-table-column>
       <el-table-column label="用户名称" align="center" prop="userName" />
       <el-table-column label="用户电话" align="center" prop="userPhone" />
       <el-table-column label="用户地址" align="center" prop="userAddress" show-overflow-tooltip />
@@ -528,6 +588,7 @@ export default {
         pageNum: 1,
         pageSize: 10,
         orderCode: null,
+        orderCodes: [], // 添加订单号数组
         userName: null,
         userPhone: null,
         integral: null,
@@ -541,6 +602,15 @@ export default {
         companyId:null,
         loginAccount: null  // 添加ERP账号筛选字段
       },
+      // 最大订单号数量限制
+      maxOrderCodes: {
+        type: Number,
+        default: 50
+      },
+      // 输入框是否可见
+      inputVisible: false,
+      // 当前输入值
+      currentInput: '',
        createTime:null,
       qwCompanyList:[],
       companyUserNameList:[],
@@ -691,10 +761,57 @@ export default {
     /** 查询积分商品订单列表 */
     getList() {
       this.loading = true;
+      
+      // 直接传递订单编号数组给后端
       listIntegralOrder(this.queryParams).then(response => {
-        this.integralOrderList = response.rows;
+        // 解析itemJson字段,提取goodsName和图片
+        const processedData = response.rows.map(item => {
+          let goodsName = '';
+          let goodsImage = '';
+          try {
+            if (item.itemJson) {
+              const itemData = JSON.parse(item.itemJson);
+              // 如果itemJson是数组格式,取第一个商品的名称和图片
+              if (Array.isArray(itemData) && itemData.length > 0) {
+                goodsName = itemData[0].goodsName || '';
+                // 提取图片,优先使用imgUrl,如果没有则使用images的第一张
+                if (itemData[0].imgUrl) {
+                  goodsImage = itemData[0].imgUrl;
+                } else if (itemData[0].images && itemData[0].images.split(',').length > 0) {
+                  goodsImage = itemData[0].images.split(',')[0];
+                }
+              }
+              // 如果itemJson是对象格式,直接取goodsName和图片
+              else if (itemData.goodsName) {
+                goodsName = itemData.goodsName;
+                // 提取图片,优先使用imgUrl,如果没有则使用images的第一张
+                if (itemData.imgUrl) {
+                  goodsImage = itemData.imgUrl;
+                } else if (itemData.images && itemData.images.split(',').length > 0) {
+                  goodsImage = itemData.images.split(',')[0];
+                }
+              }
+            }
+          } catch (error) {
+            console.error('解析itemJson失败:', error);
+            goodsName = '';
+            goodsImage = '';
+          }
+          
+          return {
+            ...item,
+            goodsName: goodsName,
+            goodsImage: goodsImage
+          };
+        });
+        
+        this.integralOrderList = processedData;
         this.total = response.total;
         this.loading = false;
+      }).catch(error => {
+        console.error('查询订单列表失败:', error);
+        this.loading = false;
+        this.$message.error('查询订单列表失败');
       });
     },
     // 取消按钮
@@ -739,6 +856,12 @@ export default {
       this.queryParams.qwUserId=null;
       this.queryParams.companyId=null;
       this.queryParams.companyUserId=null;
+      
+      // 清除订单号标签
+      this.queryParams.orderCodes = [];
+      this.currentInput = '';
+      this.inputVisible = false;
+      
       this.handleQuery();
 
     },
@@ -1093,6 +1216,159 @@ export default {
     submitOrderStatusFileForm(){
       this.$refs.uploadStatus.submit();
     },
+    // 处理键盘按下事件
+    handleKeyDown(event) {
+      const { key, target } = event
+      
+      // 处理退格键删除标签
+      if (key === 'Backspace' && !target.value && this.queryParams.orderCodes.length > 0) {
+        event.preventDefault()
+        this.removeOrderCode(this.queryParams.orderCodes.length - 1)
+      }
+      
+      // 处理分隔符
+      if ([',', ',', ' ', 'Enter'].includes(key)) {
+        event.preventDefault()
+        this.handleInputConfirm()
+      }
+    },
+
+    // 处理键盘抬起事件(实时分割输入)
+    handleKeyUp(event) {
+      const value = event.target.value
+      
+      // 检查是否包含分隔符
+      if (/[,,\s]/.test(value)) {
+        this.handleInputConfirm()
+      }
+    },
+
+    // 确认输入
+    handleInputConfirm() {
+      const inputValue = this.currentInput.trim()
+      
+      if (inputValue) {
+        // 分割多个订单号
+        const codes = inputValue.split(/[,,\s]+/).filter(code => code.trim())
+        
+        codes.forEach(code => {
+          this.addOrderCode(code.trim())
+        })
+      }
+      
+      this.currentInput = ''
+    },
+
+    // 添加订单号
+    addOrderCode(code) {
+      if (!code) return
+      
+      // 检查数量限制
+      if (this.maxOrderCodes > 0 && this.queryParams.orderCodes.length >= this.maxOrderCodes) {
+        this.$message.warning(`最多只能添加 ${this.maxOrderCodes} 个订单号`)
+        return
+      }
+      
+      // 检查重复
+      if (this.queryParams.orderCodes.includes(code)) {
+        this.$message.warning(`订单号 "${code}" 已存在`)
+        return
+      }
+      
+      // 添加到列表
+      this.queryParams.orderCodes.push(code)
+    },
+
+    // 删除订单号
+    removeOrderCode(index) {
+      this.queryParams.orderCodes.splice(index, 1)
+    },
+
+    // 显示输入框
+    showInput() {
+      this.inputVisible = true
+      this.$nextTick(() => {
+        this.$refs.tagInput.focus()
+      })
+    },
+    // 聚焦输入框
+    focusInput() {
+      if (!this.inputVisible) {
+        this.showInput()
+      }
+    },
   }
 };
 </script>
+
+<style scoped>
+.tag-input-container {
+  min-width: 445px;
+}
+
+.tags-wrapper {
+  min-height: 32px;
+  padding: 4px 8px;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  cursor: text;
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  gap: 4px;
+  transition: border-color 0.2s;
+}
+
+.tags-wrapper:hover {
+  border-color: #c0c4cc;
+}
+
+.tags-wrapper:focus-within {
+  border-color: #409eff;
+  box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
+}
+
+.order-tag {
+  margin: 2px;
+  flex-shrink: 0;
+}
+
+.tag-error {
+  background-color: #fef0f0;
+  border-color: #fbc4c4;
+  color: #f56c6c;
+}
+
+.tag-input {
+  border: none;
+  outline: none;
+  flex: 1;
+  min-width: 120px;
+}
+
+.tag-input >>> .el-input__inner {
+  border: none;
+  padding: 0;
+  height: 24px;
+  line-height: 24px;
+}
+
+.button-new-tag {
+  height: 24px;
+  line-height: 22px;
+  padding: 0 8px;
+  margin: 2px;
+}
+
+.input-tips {
+  margin-top: 4px;
+  font-size: 12px;
+  color: #909399;
+}
+
+.tip-text {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+</style>

+ 738 - 0
src/views/his/merchantAppConfig/index.vue

@@ -0,0 +1,738 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <!--   主键ID   -->
+      <el-form-item label="主键ID" prop="id">
+        <el-input v-model="queryParams.id" placeholder="请输入主键ID" clearable size="small" @keyup.enter.native="handleQuery" />
+      </el-form-item>
+      <el-form-item label="商户类型" prop="merchantType">
+        <el-select v-model="queryParams.merchantType" placeholder="请选择商户类型" clearable size="small">
+          <el-option
+            v-for="dict in sysPayModes"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <!--  商户号    -->
+      <el-form-item label="商户号" prop="merchantId">
+        <el-input v-model="queryParams.merchantId" placeholder="请输入商户号" clearable size="small" @keyup.enter.native="handleQuery" />
+      </el-form-item>
+<!--      <el-form-item label="应用ID" prop="appIds">-->
+<!--        <el-select-->
+<!--          v-model="queryParams.appIds"-->
+<!--          placeholder="请选择应用ID"-->
+<!--          clearable-->
+<!--          size="small"-->
+<!--        >-->
+<!--          <el-option-->
+<!--            v-for="dict in appIdOptions"-->
+<!--            :key="dict.appid"-->
+<!--            :label="dict.name"-->
+<!--            :value="dict.appid"-->
+<!--          />-->
+<!--        </el-select>-->
+<!--      </el-form-item>-->
+<!--      <el-form-item label="创建时间">-->
+<!--        <el-date-picker-->
+<!--          v-model="daterangeCreatedTime"-->
+<!--          size="small"-->
+<!--          style="width: 240px"-->
+<!--          value-format="yyyy-MM-dd"-->
+<!--          type="daterange"-->
+<!--          range-separator="-"-->
+<!--          start-placeholder="开始日期"-->
+<!--          end-placeholder="结束日期"-->
+<!--        ></el-date-picker>-->
+<!--      </el-form-item>-->
+      <el-form-item label="状态" prop="isDeleted">
+        <el-select v-model="queryParams.isDeleted" placeholder="请选择状态" clearable size="small">
+          <el-option
+            v-for="dict in isDeletedOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['merchantAppConfig:merchantAppConfig: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="['merchantAppConfig:merchantAppConfig: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="['merchantAppConfig:merchantAppConfig: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="['merchantAppConfig:merchantAppConfig:export']"-->
+<!--        >导出</el-button>-->
+<!--      </el-col>-->
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="merchantAppConfigList" @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="merchantId" />
+      <el-table-column label="商户类型" align="center" prop="merchantType">
+        <template slot-scope="scope">
+          <dict-tag :options="sysPayModes" :value="scope.row.merchantType"/>
+        </template>
+      </el-table-column>
+
+      <!--   appId 转化 appIdOptions   -->
+      <el-table-column label="应用名称" align="center" prop="appId">
+        <template slot-scope="scope">
+          <span v-if="scope.row.appId">
+            {{ getAppNames(scope.row.appId) }}
+          </span>
+        </template>
+      </el-table-column>
+      <el-table-column label="应用ID" align="center" prop="appId">
+        <template slot-scope="scope">
+          <span>{{ scope.row.appId }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="回调地址" align="center" prop="callbackUrl" />
+      <el-table-column label="配置详情" align="center" prop="dataJson">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleView(scope.row)"
+          >详情</el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createdTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createdTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="修改时间" align="center" prop="updatedTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.updatedTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="isDeleted">
+        <template slot-scope="scope">
+          <dict-tag :options="isDeletedOptions" :value="scope.row.isDeleted"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['merchantAppConfig:merchantAppConfig:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['merchantAppConfig:merchantAppConfig: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="dialogVisible" width="800px" append-to-body>
+      <el-form ref="form" :model="form" :rules="!isViewMode ? rules : {}" label-width="160px" :disabled="isViewMode">
+        <el-form-item label="商户类型" prop="merchantType">
+          <el-select
+            v-model="form.merchantType"
+            placeholder="请选择商户类型"
+            :disabled="form.id !== null"
+            @change="handleMerchantTypeChange"
+          >
+            <el-option
+              v-for="dict in sysPayModes"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="dict.dictValue"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="应用ID" prop="appIds">
+          <el-select
+            v-model="form.appIds"
+            placeholder="请选择应用ID"
+            clearable
+            size="small"
+            multiple
+          >
+            <el-option
+              v-for="dict in appIdOptions"
+              :key="dict.appid"
+              :label="dict.name"
+              :value="dict.appid"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-divider></el-divider>
+        </el-form-item>
+
+
+        <!-- 动态渲染不同商户类型的配置表单 -->
+        <div v-if="form.merchantType">
+          <!-- 易宝支付配置 -->
+          <div v-if="form.merchantType === 'yb'">
+            <el-form-item label="易宝商户号" prop="ybAccount">
+              <el-input v-model="ybConfig.ybAccount" placeholder="请输入易宝商户号"></el-input>
+            </el-form-item>
+            <el-form-item label="易宝Key" prop="ybKey">
+              <el-input v-model="ybConfig.ybKey" placeholder="请输入易宝Key"></el-input>
+            </el-form-item>
+            <el-form-item label="易宝回调地址" prop="ybNotifyUrl">
+              <el-input v-model="ybConfig.ybNotifyUrl" placeholder="易宝回调地址"></el-input>
+            </el-form-item>
+          </div>
+
+          <!-- 台州银行配置 -->
+          <div v-else-if="form.merchantType === 'tz'">
+            <el-form-item label="台州商户号" prop="tzPlatMerCstNo">
+              <el-input v-model="tzConfig.tzPlatMerCstNo" placeholder="请输入台州商户号"></el-input>
+            </el-form-item>
+            <el-form-item label="台州appSecret" prop="tzAppSecret">
+              <el-input v-model="tzConfig.tzAppSecret" placeholder="请输入台州appSecret"></el-input>
+            </el-form-item>
+            <el-form-item label="台州私钥" prop="tzPrivateKey">
+              <el-input v-model="tzConfig.tzPrivateKey" placeholder="请输入台州私钥"></el-input>
+            </el-form-item>
+            <el-form-item label="台州平台公钥" prop="tzPlatformPublicKey">
+              <el-input v-model="tzConfig.tzPlatformPublicKey" placeholder="请输入台州平台公钥"></el-input>
+            </el-form-item>
+            <el-form-item label="台州appKey" prop="tzAppKey">
+              <el-input v-model="tzConfig.tzAppKey" placeholder="请输入台州appKey"></el-input>
+            </el-form-item>
+            <el-form-item label="台州支付回调地址" prop="tzPayDecrypt">
+              <el-input v-model="tzConfig.tzPayDecrypt" placeholder="请输入台州支付回调地址"></el-input>
+            </el-form-item>
+            <el-form-item label="退款回调地址" prop="tzRefundDecrypt">
+              <el-input v-model="tzConfig.tzRefundDecrypt" placeholder="请输入退款回调地址"></el-input>
+            </el-form-item>
+            <el-form-item label="分账回调地址" prop="tzOrderShareDecrypt">
+              <el-input v-model="tzConfig.tzOrderShareDecrypt" placeholder="请输入台州分账回调地址"></el-input>
+            </el-form-item>
+          </div>
+
+          <!-- 微信支付配置 -->
+            <div v-else-if="form.merchantType === 'wx'">
+            <el-form-item label="微信商户号" prop="wxMchId">
+              <el-input v-model="wxConfig.wxMchId" placeholder="请输入微信商户号"></el-input>
+            </el-form-item>
+            <el-form-item label="微信Key" prop="wxMchKey">
+              <el-input v-model="wxConfig.wxMchKey" placeholder="请输入微信Key"></el-input>
+            </el-form-item>
+            <el-form-item label="微信商户V3密钥" prop="wxApiV3Key">
+              <el-input v-model="wxConfig.wxApiV3Key" placeholder="请输入商户V3密钥"></el-input>
+            </el-form-item>
+            <el-form-item label="微信回调地址(scrm)" prop="notifyUrlScrm">
+              <el-input v-model="wxConfig.notifyUrlScrm" placeholder="请输入商城微信回调地址"></el-input>
+            </el-form-item>
+            <el-form-item label="p12证书路径" prop="keyPath">
+              <el-input v-model="wxConfig.keyPath" placeholder="请输入p12证书文件的绝对路径"></el-input>
+            </el-form-item>
+          </div>
+
+          <!-- 汇付支付配置 -->
+          <div v-else-if="form.merchantType === 'hf'">
+            <el-form-item label="汇付产品号" prop="hfProductId">
+              <el-input v-model="hfConfig.hfProductId" placeholder="汇付产品号"></el-input>
+            </el-form-item>
+            <el-form-item label="系统号" prop="hfSysId">
+              <el-input v-model="hfConfig.hfSysId" placeholder="系统号Key"></el-input>
+            </el-form-item>
+            <el-form-item label="商户号" prop="hfHuifuId">
+              <el-input v-model="hfConfig.huifuId" placeholder="商户号"></el-input>
+            </el-form-item>
+            <el-form-item label="商户私钥" prop="hfRsaPrivateKey">
+              <el-input v-model="hfConfig.hfRsaPrivateKey" placeholder="商户私钥"></el-input>
+            </el-form-item>
+            <el-form-item label="汇付公钥" prop="hfRsaPublicKey">
+              <el-input v-model="hfConfig.hfRsaPublicKey" placeholder="汇付公钥"></el-input>
+            </el-form-item>
+            <el-form-item label="汇付支付回调地址" prop="hfPayNotifyUrl">
+              <el-input v-model="hfConfig.hfPayNotifyUrl" placeholder="汇付支付回调地址"></el-input>
+            </el-form-item>
+            <el-form-item label="大额支付回调地址" prop="hfPayOnlineNotifyUrl">
+              <el-input v-model="hfConfig.hfPayOnlineNotifyUrl" placeholder="汇付支付回调地址"></el-input>
+            </el-form-item>
+            <el-form-item label="汇付退款回调地址" prop="hfRefundNotifyUrl">
+              <el-input v-model="hfConfig.hfRefundNotifyUrl" placeholder="汇付退款回调地址"></el-input>
+            </el-form-item>
+            <el-form-item label="汇付大额退款回调地址" prop="hfOnlineRefundNotifyUrl">
+              <el-input v-model="hfConfig.hfOnlineRefundNotifyUrl" placeholder="汇付分账回调地址"></el-input>
+            </el-form-item>
+          </div>
+        </div>
+      </el-form>
+
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm" v-if="!isViewMode">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+import { listMerchantAppConfig, getMerchantAppConfig, delMerchantAppConfig, addMerchantAppConfig, updateMerchantAppConfig, exportMerchantAppConfig } from "@/api/merchantAppConfig/merchantAppConfig";
+import { listAll } from "@/api/course/coursePlaySourceConfig";
+
+export default {
+  name: "MerchantAppConfig",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 商户应用配置表格数据
+      merchantAppConfigList: [],
+      // 弹出层标题
+      title: "",
+      // 创建时间时间范围
+      daterangeCreatedTime: [],
+      // 删除状态:0-正常,1-已删除字典
+      isDeletedOptions: [],
+      sysPayModes: [],
+      detailOpen: false,  // 详情对话框开关
+      isViewMode: false,  // 是否为查看模式
+      dialogVisible: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        merchantType: null,
+        appIds: null,
+        createdTime: null,
+        isDeleted: "0",
+        id: null
+      },
+      appIdOptions:[],
+      ybConfig: {}, // 易宝配置
+      tzConfig: {}, // 台州银行配置
+      wxConfig: {}, // 微信配置
+      hfConfig: {}, // 汇付配置
+      // 表单参数
+      form: {
+        id: null,
+        merchantType: null,
+        appIds: [],
+        callbackUrl: null,
+        dataJson: null,
+        createdTime: null,
+        updatedTime: null,
+        isDeleted: null,
+        createdBy: null,
+        updatedBy: null
+      },
+      // 表单校验
+      rules: {
+        merchantType: [
+          { required: true, message: "商户类型不能为空", trigger: "change" }
+        ],
+        isDeleted: [
+          { required: true, message: "删除状态:0-正常,1-已删除不能为空", trigger: "change" }
+        ],
+        createdBy: [
+          { required: true, message: "创建人ID或用户名不能为空", trigger: "blur" }
+        ],
+        updatedBy: [
+          { required: true, message: "修改人ID或用户名不能为空", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+
+    this.getDicts("sys_normal_disable").then(response => {
+      this.isDeletedOptions = response.data;
+    });
+    this.getDicts("sys_pay_mode").then(response => {
+      this.sysPayModes = response.data;
+    });
+    listAll().then(response => {
+      this.appIdOptions=response.data;
+    });
+    this.getList();
+
+  },
+  methods: {
+    /** 详情按钮操作 */
+    handleView(row) {
+      this.isViewMode = true;
+      this.dialogVisible = true;  // 改为设置 dialogVisible
+      this.title = "查看商户应用配置";
+
+      // 加载数据(复用修改逻辑)
+      getMerchantAppConfig(row.id).then(response => {
+        // 先设置基础数据
+        Object.keys(response.data).forEach(key => {
+          if (key !== 'appIds') { // appIds单独处理
+            this.$set(this.form, key, response.data[key]);
+          }
+        });
+
+        // 单独处理 appIds,确保它是响应式的数组
+        let appIdsArray = [];
+        if (response.data.appId) {
+          if (typeof response.data.appId === 'string') {
+            appIdsArray = response.data.appId.split(',').map(item => item.trim()).filter(item => item);
+          } else if (Array.isArray(response.data.appId)) {
+            appIdsArray = [...response.data.appId];
+          }
+        }
+
+        // 使用 $set 确保响应式
+        this.$set(this.form, 'appIds', appIdsArray);
+
+        // 解析配置详情JSON
+        if (this.form.dataJson) {
+          try {
+            const configData = JSON.parse(this.form.dataJson);
+            switch(this.form.merchantType) {
+              case 'yb':
+                this.ybConfig = { ...configData };
+                break;
+              case 'tz':
+                this.tzConfig = { ...configData };
+                break;
+              case 'wx':
+                this.wxConfig = { ...configData };
+                break;
+              case 'hf':
+                this.hfConfig = { ...configData };
+                break;
+            }
+          } catch (e) {
+            console.error('解析配置详情失败:', e);
+          }
+        }
+      });
+    }
+    ,
+    /** 关闭详情对话框 */
+    closeDetailView() {
+      this.detailOpen = false;
+      this.isViewMode = false;
+      this.reset();
+    },
+    getAppNames(appIds) {
+      if (!appIds) return '';
+
+      // 处理逗号分隔的字符串
+      const appIdArray = typeof appIds === 'string' ? appIds.split(',') : Array.isArray(appIds) ? appIds : [appIds];
+
+      // 根据 appIdOptions 查找对应的应用名称
+      const names = appIdArray
+        .map(id => {
+          const option = this.appIdOptions.find(opt => opt.appid === id.trim());
+          return option ? option.name : id;
+        })
+        .filter(name => name); // 过滤掉空值
+
+      return names.join(', ');
+    },
+    /** 商户类型变化处理 */
+    handleMerchantTypeChange(value) {
+      // 清空之前的选择
+      this.ybConfig = {};
+      this.tzConfig = {};
+      this.wxConfig = {};
+      this.hfConfig = {};
+    },
+
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          // 构建配置详情JSON
+          let configData = {};
+          switch(this.form.merchantType) {
+            case 'yb':
+              configData = { ...this.ybConfig };
+              break;
+            case 'tz':
+              configData = { ...this.tzConfig };
+              break;
+            case 'wx':
+              configData = { ...this.wxConfig };
+              break;
+            case 'hf':
+              configData = { ...this.hfConfig };
+              break;
+          }
+
+          // 正确处理多选应用ID转字符串
+          if (this.form.appIds && Array.isArray(this.form.appIds) && this.form.appIds.length > 0) {
+            this.form.appId = this.form.appIds.join(',');
+          } else {
+            this.form.appId = '';
+          }
+
+          // 将配置转换为JSON字符串
+          this.form.dataJson = JSON.stringify(configData);
+
+          if (this.form.id != null) {
+            updateMerchantAppConfig(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.dialogVisible = false;
+              this.getList();
+            });
+          } else {
+            addMerchantAppConfig(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.dialogVisible = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+
+    /** 修改按钮操作 */
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids;
+      getMerchantAppConfig(id).then(response => {
+        // 先设置基础数据
+        Object.keys(response.data).forEach(key => {
+          if (key !== 'appIds') { // appIds单独处理
+            this.$set(this.form, key, response.data[key]);
+          }
+        });
+
+        // 单独处理 appIds,确保它是响应式的数组
+        let appIdsArray = [];
+        if (response.data.appId) {
+          if (typeof response.data.appId === 'string') {
+            appIdsArray = response.data.appId.split(',').map(item => item.trim()).filter(item => item);
+          } else if (Array.isArray(response.data.appId)) {
+            appIdsArray = [...response.data.appId];
+          }
+        }
+
+        // 使用 $set 确保响应式
+        this.$set(this.form, 'appIds', appIdsArray);
+
+        // 解析配置详情JSON
+        if (this.form.dataJson) {
+          try {
+            const configData = JSON.parse(this.form.dataJson);
+            switch(this.form.merchantType) {
+              case 'yb':
+                this.ybConfig = { ...configData };
+                break;
+              case 'tz':
+                this.tzConfig = { ...configData };
+                break;
+              case 'wx':
+                this.wxConfig = { ...configData };
+                break;
+              case 'hf':
+                this.hfConfig = { ...configData };
+                break;
+            }
+          } catch (e) {
+            console.error('解析配置详情失败:', e);
+          }
+        }
+
+        this.isViewMode = false; // 添加此行
+        this.dialogVisible = true; // 替代 this.open = true
+        this.title = "修改商户应用配置";
+      });
+    }
+
+    ,
+    /** 查询商户应用配置列表 */
+    getList() {
+      this.loading = true;
+      // if (this.queryParams.appIds && this.queryParams.appIds.length > 0) {
+      //   this.queryParams.appIds = this.queryParams.appIds.join(',');
+      // }
+      this.queryParams.params = {};
+      if (null != this.daterangeCreatedTime && '' != this.daterangeCreatedTime) {
+        this.queryParams.params["beginCreatedTime"] = this.daterangeCreatedTime[0];
+        this.queryParams.params["endCreatedTime"] = this.daterangeCreatedTime[1];
+      }
+      listMerchantAppConfig(this.queryParams).then(response => {
+        this.merchantAppConfigList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.dialogVisible = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        merchantType: null,
+        appId: null,  // 应该删除这一行
+        appIds: [],   // 初始化为空数组而不是null
+        callbackUrl: null,
+        dataJson: null,
+        createdTime: null,
+        updatedTime: null,
+        isDeleted: null,
+        createdBy: null,
+        updatedBy: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.daterangeCreatedTime = [];
+      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.isViewMode = false; // 添加此行
+      this.dialogVisible = true; // 替代 this.open = true
+      this.title = "添加商户应用配置";
+    },
+    // /** 修改按钮操作 */
+    // handleUpdate(row) {
+    //   this.reset();
+    //   const id = row.id || this.ids
+    //   getMerchantAppConfig(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) {
+    //         updateMerchantAppConfig(this.form).then(response => {
+    //           this.msgSuccess("修改成功");
+    //           this.open = false;
+    //           this.getList();
+    //         });
+    //       } else {
+    //         addMerchantAppConfig(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 delMerchantAppConfig(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有商户应用配置数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          this.exportLoading = true;
+          return exportMerchantAppConfig(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 15 - 4
src/views/his/packageOrder/index.vue

@@ -51,10 +51,19 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="员工" prop="companyUserName">
+      <el-form-item label="员工账号" prop="companyUserName">
         <el-input
           v-model="queryParams.companyUserName"
-          placeholder="员工"
+          placeholder="员工账号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="员工昵称" prop="companyNickName">
+        <el-input
+          v-model="queryParams.companyNickName"
+          placeholder="员工昵称"
           clearable
           size="small"
           @keyup.enter.native="handleQuery"
@@ -156,7 +165,8 @@
       <el-table-column type="selection" width="55" align="center" />
       <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="companyUserName" />
+      <el-table-column label="员工昵称" align="center" prop="companyNickName" />
       <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"/>
@@ -377,6 +387,7 @@ export default {
         endStartTime:null,
         endEndTime:null,
         companyUserName:null,
+        companyNickName:null,
         companyName:null,
         deptId:null,
         source:null,
@@ -423,7 +434,7 @@ export default {
     this.getDicts("sys_package_sub_type").then(response => {
       this.packageSubTypeOptions = response.data;
     });
-    
+
     // 获取小程序选项列表
     this.getAppMallOptions();
   },

+ 423 - 0
src/views/his/redPacketConfig/index.vue

@@ -0,0 +1,423 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+
+      <el-form-item label="公众号appId" prop="appId">
+        <el-input
+          v-model="queryParams.appId"
+          placeholder="请输入公众号appId"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="小程序appId" prop="miniappId">
+        <el-input
+          v-model="queryParams.miniappId"
+          placeholder="请输入小程序appId"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="商户号" prop="mchId">
+        <el-input
+          v-model="queryParams.mchId"
+          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="['redPacket:more: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="['redPacket:more: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="['redPacket:more:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-tag
+          type="primary"
+          size="large"
+          style="font-size: 16px;"
+        >
+          当前使用的商户号:{{this.redPacketMchId}}
+        </el-tag>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="small"
+          @click="handleEditRedPacket"
+          v-hasPermi="['redPacket:more:editRedPacket']"
+        >修改当前发送的红包的商户号</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="moreList" @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="isNew" >
+        <template slot-scope="scope">
+          {{ scope.row.isNew === 0 ? '老商户' : '新商户' }}
+        </template>
+      </el-table-column>
+      <el-table-column label="公众号appId" align="center" prop="appId" />
+      <el-table-column label="小程序appId" align="center" prop="miniappId" />
+      <el-table-column label="商户号" align="center" prop="mchId" />
+      <el-table-column label="商户密钥" align="center" prop="mchKey" />
+      <el-table-column label="p12证书文件" align="center" prop="keyPath" />
+      <el-table-column label="apiclient_key.pem证书" align="center" prop="privateKeyPath" />
+      <el-table-column label="apiclient_cert.pem证书" align="center" prop="privateCertPath" />
+      <el-table-column label="apiV3" align="center" prop="apiV3Key" />
+      <el-table-column label="公钥ID" align="center" prop="publicKeyId" />
+      <el-table-column label="pub_key.pem证书" align="center" prop="publicKeyPath" />
+      <el-table-column label="回调地址" align="center" prop="notifyUrl" />
+      <el-table-column label="回调地址" align="center" prop="notifyUrlScrm" />
+      <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="['redPacket:more:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['redPacket:more: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="isNew">
+          <el-radio-group v-model="form.isNew">
+            <el-radio :label="0">商家转账到零钱(旧)</el-radio>
+            <el-radio :label="1">商家转账(新)</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="公众号appId" prop="appId">
+          <el-input v-model="form.appId" placeholder="请输入公众号appId" />
+        </el-form-item>
+        <el-form-item label="小程序appId" prop="miniappId">
+          <el-input v-model="form.miniappId" placeholder="请输入小程序appId" />
+        </el-form-item>
+        <el-form-item label="商户号" prop="mchId">
+          <el-input v-model="form.mchId" placeholder="请输入商户号" />
+        </el-form-item>
+        <el-form-item label="商户密钥" prop="mchKey">
+          <el-input v-model="form.mchKey" placeholder="请输入商户密钥" />
+        </el-form-item>
+        <el-form-item label="p12证书文件" prop="keyPath">
+          <el-input v-model="form.keyPath" placeholder="请输入p12证书文件的绝对路径或者以classpath:开头的类路径." />
+        </el-form-item>
+        <el-form-item label="apiclient_key证书地址" prop="privateKeyPath">
+          <el-input v-model="form.privateKeyPath" placeholder="请输入apiclient_key.pem证书文件的绝对路径或者以classpath:开头的类路径." />
+        </el-form-item>
+        <el-form-item label="apiclient_cert证书地址" prop="privateCertPath">
+          <el-input v-model="form.privateCertPath" placeholder="请输入apiclient_cert.pem证书文件的绝对路径或者以classpath:开头的类路径." />
+        </el-form-item>
+        <el-form-item label="apiV3秘钥" prop="apiV3Key">
+          <el-input v-model="form.apiV3Key" placeholder="请输入apiV3 秘钥值." />
+        </el-form-item>
+        <el-form-item label="公钥ID" prop="publicKeyId">
+          <el-input v-model="form.publicKeyId" placeholder="请输入公钥ID" />
+        </el-form-item>
+        <el-form-item label="pub_key.pem证书地址" prop="publicKeyPath">
+          <el-input v-model="form.publicKeyPath" placeholder="请输入pub_key.pem证书文件的绝对路径或者以classpath:开头的类路径." />
+        </el-form-item>
+        <el-form-item label="回调地址" prop="notifyUrl">
+          <el-input v-model="form.notifyUrl" placeholder="请输入回调地址notifyUrl" />
+        </el-form-item>
+        <el-form-item label="回调地址" prop="notifyUrlScrm">
+          <el-input v-model="form.notifyUrlScrm" placeholder="请输入回调地址notifyUrlScrm" />
+        </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="redPacketOpen.title" :visible.sync="redPacketOpen.open" width="600px" append-to-body>
+      <el-form ref="redPacketOpen" :model="redPacketOpen" label-width="110px">
+        <el-form-item label="商户号" prop="cateId">
+          <el-select v-model="redPacketOpen.newChangeMchId" placeholder="请选择" clearable size="small">
+            <el-option
+              v-for="dict in moreList"
+              :key="dict.mchId"
+              :label="dict.mchId"
+              :value="dict.mchId"
+            />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitFormChangeMchId">确 定</el-button>
+        <el-button @click="cancelChangeMchId">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  listMore,
+  getMore,
+  delMore,
+  addMore,
+  updateMore,
+  getRedPacketMchId,
+  updateChangeMchId
+} from '@/api/his/redPacketConfig'
+
+export default {
+  name: "redPacketConfig",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      redPacketMchId: null,
+      redPacketOpen:{
+        open:false,
+        title:null,
+        oldChangeMchId:null,
+        newChangeMchId:null,
+      },
+      // 多商户配置表格数据
+      moreList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        isNew: null,
+        appId: null,
+        miniappId: null,
+        mchId: null,
+        mchKey: null,
+        keyPath: null,
+        privateKeyPath: null,
+        privateCertPath: null,
+        apiV3Key: null,
+        publicKeyId: null,
+        publicKeyPath: null,
+        notifyUrl: null,
+        notifyUrlScrm: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {},
+      redPacketOpenRule:{
+        newChangeMchId:[{ required: true, trigger: "blur", message: "商户号不能为空" }]
+      },
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询多商户配置列表 */
+    getList() {
+      this.loading = true;
+      listMore(this.queryParams).then(response => {
+        console.log("response.rows",response.rows)
+        this.moreList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+      getRedPacketMchId().then(res=>{
+        this.redPacketMchId=res.data
+      })
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    cancelChangeMchId() {
+      this.redPacketOpen.open=false;
+      this.redPacketOpen.title=false;
+      this.redPacketOpen.oldChangeMchId=false;
+      this.redPacketOpen.newChangeMchId=false;
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        isNew: null,
+        appId: null,
+        miniappId: null,
+        mchId: null,
+        mchKey: null,
+        keyPath: null,
+        privateKeyPath: null,
+        privateCertPath: null,
+        apiV3Key: null,
+        publicKeyId: null,
+        publicKeyPath: null,
+        notifyUrl: null,
+        notifyUrlScrm: 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
+      getMore(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改多商户配置";
+      });
+    },
+    handleEditRedPacket(){
+      this.redPacketOpen.open= true;
+      this.redPacketOpen.title="修改发送红包的商户号";
+
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateMore(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addMore(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+
+    /** 提交修改发送红包的商户号- */
+    submitFormChangeMchId() {
+      this.$refs["redPacketOpen"].validate(valid => {
+        if (valid) {
+            this.redPacketOpen.oldChangeMchId=this.redPacketMchId;
+            if (this.redPacketOpen.newChangeMchId==null){
+              return this.$message.error("修改的商户号不能为空")
+            }
+
+            updateChangeMchId(this.redPacketOpen).then(response => {
+              this.msgSuccess("修改成功");
+              this.cancelChangeMchId();
+              this.getList();
+            });
+
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除多商户配置编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delMore(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+  }
+};
+</script>

+ 143 - 142
src/views/his/storeOrder/order1.vue

@@ -50,7 +50,7 @@
             >
               {{ code }}
             </el-tag>
-            
+
             <!-- 输入框 -->
             <el-input
               ref="tagInput"
@@ -65,7 +65,7 @@
               @focus="inputVisible = true"
               clearable
             />
-            
+
             <!-- 添加按钮(当没有输入时显示) -->
             <el-button
               v-if="!inputVisible && queryParams.orderCodes.length > 0"
@@ -78,11 +78,11 @@
               添加订单号
             </el-button>
           </div>
-          
+
           <!-- 输入提示 -->
           <div class="input-tips">
             <span class="tip-text">
-              支持:回车、逗号、空格分隔 | 
+              支持:回车、逗号、空格分隔 |
               已添加 {{ queryParams.orderCodes.length }} 个订单号
               <span v-if="maxOrderCodes > 0"> (最多{{ maxOrderCodes }}个)</span>
             </span>
@@ -220,7 +220,7 @@
                 />
               </el-select>
       </el-form-item>
-	 
+
       <el-form-item label="是否首次进线" prop="isFirst">
         <el-select filterable v-model="queryParams.isFirst" placeholder="状态" clearable size="small">
                 <el-option
@@ -318,7 +318,7 @@
       <el-form-item label="入账时间" prop="tuiMoneyTime">
             <el-date-picker v-model="tuiMoneyTime" 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 label="ERP账户" prop="erpAccount" v-if="SFDFopen">
+      <el-form-item label="ERP账户" prop="erpAccount" v-if="SFDFopen && (this.actName !=='1' && this.actName !== '7') ">
         <el-select v-model="queryParams.erpAccount" placeholder="ERP账户" clearable size="small">
           <el-option
             v-for="dict in erpAccountQueryList"
@@ -328,7 +328,7 @@
           />
         </el-select>
       </el-form-item>
-      <el-form-item label="ERP电话" prop="erpPhoneNumber" v-if="SFDFopen">
+      <el-form-item label="ERP电话" prop="erpPhoneNumber" v-if="SFDFopen && (this.actName !=='1' && this.actName !== '7')">
         <el-input
           v-model="queryParams.erpPhoneNumber"
           placeholder="ERP电话"
@@ -414,7 +414,7 @@
               plain
               icon="el-icon-phone"
               size="mini"
-              
+
               @click="setErpPhone"
               v-hasPermi="['his:storeOrder:createErpOrder']"
             >设置推送手机</el-button>
@@ -480,7 +480,7 @@
       </el-row>
       <el-tabs type="card" v-model="actName" @tab-click="handleClickX">
         <el-tab-pane label="全部订单" name="10"></el-tab-pane>
-        <el-tab-pane v-for="(item,index) in orderOptions" :label="item.dictLabel" :name="item.dictValue"></el-tab-pane>
+        <el-tab-pane v-for="(item,index) in orderOptions" :key="index" :label="item.dictLabel" :name="item.dictValue"></el-tab-pane>
       </el-tabs>
       <el-table ref="orderTable" height="500" v-loading="loading" border :data="orderList" @selection-change="handleSelectionChange"
         @sort-change="handleSortChange" :default-sort="{prop: 'createTime', order: 'descending'}">
@@ -572,12 +572,12 @@
       <div v-if="currentSort.prop" class="sort-info">
         <el-tag size="small" type="info" closable @close="clearSort">
           <i class="el-icon-sort"></i>
-          当前排序:{{ getSortLabel(currentSort.prop) }} 
+          当前排序:{{ getSortLabel(currentSort.prop) }}
           {{ currentSort.order === 'ascending' ? '升序' : '降序' }}
         </el-tag>
-          <el-button 
-            type="text" 
-            size="mini" 
+          <el-button
+            type="text"
+            size="mini"
             @click="clearSort"
             style="margin-left: 8px; color: #909399;"
           >
@@ -675,7 +675,7 @@
         <el-button @click="uploadStatus.open = false">取 消</el-button>
       </div>
     </el-dialog>
-    
+
     <!-- 设置推送手机对话框 -->
     <el-dialog :title="erpPhone.title" :visible.sync="erpPhone.open" width="600px" append-to-body>
       <div style="margin-bottom: 20px;">
@@ -684,9 +684,9 @@
       <el-table :data="phoneList" border style="width: 100%">
         <el-table-column prop="phone" label="手机号" align="center">
           <template slot-scope="scope">
-            <el-input 
-              v-if="scope.row.editing" 
-              v-model="scope.row.phone" 
+            <el-input
+              v-if="scope.row.editing"
+              v-model="scope.row.phone"
               placeholder="请输入手机号"
               @blur="validatePhone(scope.row)"
               @keyup.enter.native="handleSavePhone(scope.$index)"
@@ -696,27 +696,27 @@
         </el-table-column>
         <el-table-column label="操作" align="center" width="300">
           <template slot-scope="scope">
-            <el-button 
-              v-if="scope.row.editing" 
-              type="success" 
-              size="mini" 
+            <el-button
+              v-if="scope.row.editing"
+              type="success"
+              size="mini"
               @click="handleSavePhone(scope.$index)"
             >保存</el-button>
-            <el-button 
-              v-if="scope.row.editing" 
-              type="info" 
-              size="mini" 
+            <el-button
+              v-if="scope.row.editing"
+              type="info"
+              size="mini"
               @click="handleCancelEdit(scope.$index)"
             >取消</el-button>
-            <el-button 
-              v-if="!scope.row.editing" 
-              type="primary" 
-              size="mini" 
+            <el-button
+              v-if="!scope.row.editing"
+              type="primary"
+              size="mini"
               @click="handleEditPhone(scope.$index)"
             >修改</el-button>
-            <el-button 
-              type="danger" 
-              size="mini" 
+            <el-button
+              type="danger"
+              size="mini"
               @click="handleDeletePhone(scope.$index)"
             >删除</el-button>
           </template>
@@ -747,9 +747,9 @@
       <div v-loading="erpAccountDialog.loading">
         <el-form :model="erpAccountForm" label-width="100px">
           <el-form-item label="ERP账户" required>
-            <el-select 
-              v-model="erpAccountForm.selectedAccount" 
-              placeholder="请选择ERP账户" 
+            <el-select
+              v-model="erpAccountForm.selectedAccount"
+              placeholder="请选择ERP账户"
               style="width: 100%"
               filterable
             >
@@ -765,7 +765,7 @@
             </el-select>
           </el-form-item>
         </el-form>
-        
+
         <!-- 订单统计信息 -->
         <div class="order-summary" v-if="orderSummary">
           <el-divider content-position="left">订单统计</el-divider>
@@ -791,11 +791,11 @@
           </el-row>
         </div>
       </div>
-      
+
       <div slot="footer" class="dialog-footer">
         <el-button @click="cancelErpAccountDialog">取 消</el-button>
-        <el-button 
-          type="primary" 
+        <el-button
+          type="primary"
           @click="confirmCreateErpOrder"
           :disabled="!erpAccountForm.selectedAccount"
           :loading="erpAccountDialog.submitting"
@@ -811,12 +811,12 @@
           <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" 
+              <el-checkbox
+                v-model="field.checked"
                 :label="field.label"
                 style="margin-bottom: 12px; width: 100%;"
               >
@@ -825,7 +825,7 @@
             </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">
@@ -837,11 +837,11 @@
           </span>
         </div>
       </div>
-      
+
       <div slot="footer" class="dialog-footer">
         <el-button @click="cancelExportFieldDialog">取 消</el-button>
-        <el-button 
-          type="primary" 
+        <el-button
+          type="primary"
           @click="confirmExportFields"
         >确认导出</el-button>
       </div>
@@ -880,11 +880,11 @@ export default {
         prop: null,
         order: null
       },
-      
+
       // 排序字段映射
       sortFieldMap: {
         'companyUserName': '员工',
-        'packageName': '套餐名称', 
+        'packageName': '套餐名称',
         'payPrice': '应收金额',
         'payMoney': '实收金额',
         'createTime': '下单时间'
@@ -898,7 +898,7 @@ export default {
       },
       // 输入框是否可见
       inputVisible: false,
-      
+
       // 无效订单号对话框
       showInvalidDialog: false,
       // 当前输入值
@@ -937,7 +937,7 @@ export default {
               title:"订单详情",
               open:false,
             },
-	  sourceOptions:[],		
+	  sourceOptions:[],
       importExpress: {
               // 是否显示弹出层
               open: false,
@@ -1047,7 +1047,8 @@ export default {
         { key: 'sex', label: '性别', checked: false },
         { key: 'erpPhone', label: 'ERP电话', checked: false },
         { key: 'erpAccount', label: 'ERP账号', checked: false },
-        { key: 'source', label: '订单来源', checked: false }
+        { key: 'source', label: '订单来源', checked: false },
+        { key: 'countGoods', label: '统计商品数量', checked: false }
       ],
       // 已选择的导出字段
       selectedExportFields: [],
@@ -1226,13 +1227,13 @@ export default {
     // 新增排序处理方法
     handleSortChange({ column, prop, order }) {
       console.log('排序变化:', { column, prop, order });
-      
+
       // 更新当前排序状态
       this.currentSort = {
         prop: prop,
         order: order
       };
-      
+
       // 更新查询参数
       if (order) {
         this.queryParams.sortField = prop;
@@ -1241,11 +1242,11 @@ export default {
         this.queryParams.sortField = null;
         this.queryParams.sortOrder = null;
       }
-      
+
       // 重新查询数据
       this.queryParams.pageNum = 1; // 重置到第一页
       this.getList();
-      
+
       // 显示排序提示
       if (order) {
         const fieldLabel = this.getSortLabel(prop);
@@ -1253,12 +1254,12 @@ export default {
         this.$message.success(`已按${fieldLabel}${orderLabel}排序`);
       }
     },
-    
+
     // 获取排序字段的中文标签
     getSortLabel(prop) {
       return this.sortFieldMap[prop] || prop;
     },
-    
+
     // 清除排序
     clearSort() {
       this.currentSort = {
@@ -1281,38 +1282,38 @@ export default {
     // 修改查询列表方法,添加排序参数
     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
@@ -1322,16 +1323,16 @@ export default {
         this.queryParams.companyId = this.companyId
         this.queryParams.companyIds = null;
       }
-      
+
       // 处理订单号数组
       if (this.queryParams.orderCodes && this.queryParams.orderCodes.length > 0) {
         this.queryParams.orderCodeList = this.queryParams.orderCodes.join(',');
       } else {
         this.queryParams.orderCodeList = null;
       }
-      
+
       console.log('查询参数:', this.queryParams);
-      
+
       listOrder(this.queryParams).then(response => {
         this.orderList = response.rows;
         this.total = response.total;
@@ -1346,15 +1347,15 @@ export default {
           this.payRemainTotal = "0"
           this.productInfo = response.productInfo;
         }
-        
+
         this.loading = false;
-        
+
         if(response.msg == 'jnmy'){
           this.SFDFopen = true;
         } else{
           this.SFDFopen = false;
         }
-        
+
         // 如果有排序,显示排序结果提示
         if (this.currentSort.prop) {
           const fieldLabel = this.getSortLabel(this.currentSort.prop);
@@ -1370,72 +1371,72 @@ export default {
     // 处理键盘按下事件
     handleKeyDown(event) {
       const { key, target } = event
-      
+
       // 处理退格键删除标签
       if (key === 'Backspace' && !target.value && this.queryParams.orderCodes.length > 0) {
         event.preventDefault()
         this.removeOrderCode(this.queryParams.orderCodes.length - 1)
       }
-      
+
       // 处理分隔符
       if ([',', ',', ' ', 'Enter'].includes(key)) {
         event.preventDefault()
         this.handleInputConfirm()
       }
     },
-    
+
     // 处理键盘抬起事件(实时分割输入)
     handleKeyUp(event) {
       const value = event.target.value
-      
+
       // 检查是否包含分隔符
       if (/[,,\s]/.test(value)) {
         this.handleInputConfirm()
       }
     },
-    
+
     // 确认输入
     handleInputConfirm() {
       const inputValue = this.currentInput.trim()
-      
+
       if (inputValue) {
         // 分割多个订单号
         const codes = inputValue.split(/[,,\s]+/).filter(code => code.trim())
-        
+
         codes.forEach(code => {
           this.addOrderCode(code.trim())
         })
       }
-      
+
       this.currentInput = ''
     },
-    
+
     // 添加订单号
     addOrderCode(code) {
       if (!code) return
-      
+
       // 检查数量限制
       if (this.maxOrderCodes > 0 && this.queryParams.orderCodes.length >= this.maxOrderCodes) {
         this.$message.warning(`最多只能添加 ${this.maxOrderCodes} 个订单号`)
         return
       }
-      
+
       // 检查重复
       if (this.queryParams.orderCodes.includes(code)) {
         this.$message.warning(`订单号 "${code}" 已存在`)
         return
       }
-      
+
       // 添加到列表
       this.queryParams.orderCodes.push(code)
-      
+
     },
-    
+
     // 删除订单号
     removeOrderCode(index) {
       this.queryParams.orderCodes.splice(index, 1)
     },
-    
+
     // 清空所有标签
     clearAllTags() {
       this.$confirm('确认清空所有订单号吗?', '提示', {
@@ -1476,7 +1477,7 @@ export default {
       this.erpSettingType = 'push'
       this.calculateOrderSummary();
     },
-    
+
     //获取ERP账户列表
     async getErpAccountList() {
       try {
@@ -1494,7 +1495,7 @@ export default {
           this.$message.error(response.msg || '获取ERP账户列表失败');
           this.erpAccountList = [];
         }
-        
+
       } catch (error) {
         console.error('获取ERP账户列表失败:', error);
         this.$message.error('获取ERP账户列表失败');
@@ -1503,13 +1504,13 @@ export default {
         this.erpAccountDialog.loading = false;
       }
     },
-    
+
     // 新增:计算订单统计信息
     calculateOrderSummary() {
       let selectedCount = 0;
       let totalAmount = 0;
       let queryCount = this.total || 0;
-      
+
       if (this.ids.length > 0) {
         // 如果有选中的订单,统计选中的订单
         selectedCount = this.ids.length;
@@ -1525,14 +1526,14 @@ export default {
           totalAmount += parseFloat(order.payMoney || 0);
         });
       }
-      
+
       this.orderSummary = {
         selectedCount,
         totalAmount: totalAmount.toFixed(2),
         queryCount
       };
     },
-    
+
     //确认创建ERP订单
     confirmCreateErpOrder() {
       if (!this.erpAccountForm.selectedAccount) {
@@ -1542,8 +1543,8 @@ export default {
       console.log("-----------------",this.erpSettingType)
       if(this.erpSettingType == 'set'){
         this.$confirm(
-          `确认将订单设置ERP账户为"${this.erpAccountForm.selectedAccount}"吗?`, 
-          '确认', 
+          `确认将订单设置ERP账户为"${this.erpAccountForm.selectedAccount}"吗?`,
+          '确认',
           {
             confirmButtonText: '确定',
             cancelButtonText: '取消',
@@ -1554,8 +1555,8 @@ export default {
         });
       } else if(this.erpSettingType == 'push'){
         this.$confirm(
-          `确认将订单推送到ERP账户"${this.erpAccountForm.selectedAccount}"吗?`, 
-          '确认推送', 
+          `确认将订单推送到ERP账户"${this.erpAccountForm.selectedAccount}"吗?`,
+          '确认推送',
           {
             confirmButtonText: '确定推送',
             cancelButtonText: '取消',
@@ -1569,12 +1570,12 @@ export default {
 
     async executSetErpOrder() {
       this.erpAccountDialog.submitting = true;
-      
+
       try {
         let param = {
           loginAccount: this.erpAccountForm.selectedAccount
         };
-        
+
         if (this.ids.length > 0) {
           // 如果有选中的订单,只推送选中的
           param.orderIds = this.ids;
@@ -1605,11 +1606,11 @@ export default {
           } else {
             this.queryParams.qwSubject = null;
           }
-          
+
           // 合并查询参数
           param = { ...param, ...this.queryParams };
         }
-        
+
         const response = await batchSetErpOrder(param);
         if (response.code === 200) {
           this.$message.success('订单ERP账号设置成功');
@@ -1626,16 +1627,16 @@ export default {
         this.erpAccountDialog.submitting = false;
       }
     },
-    
+
     //执行创建ERP订单
     async executeCreateErpOrder() {
       this.erpAccountDialog.submitting = true;
-      
+
       try {
         let param = {
           loginAccount: this.erpAccountForm.selectedAccount
         };
-        
+
         if (this.ids.length > 0) {
           // 如果有选中的订单,只推送选中的
           param.orderIds = this.ids;
@@ -1666,11 +1667,11 @@ export default {
           } else {
             this.queryParams.qwSubject = null;
           }
-          
+
           // 合并查询参数
           param = { ...param, ...this.queryParams };
         }
-        
+
         const response = await batchCreateErpOrder(param);
         if (response.code === 200) {
           this.$message.success('ERP订单创建成功');
@@ -1687,7 +1688,7 @@ export default {
         this.erpAccountDialog.submitting = false;
       }
     },
-    
+
     // 新增:取消ERP账户选择对话框
     cancelErpAccountDialog() {
       this.erpAccountDialog.open = false;
@@ -1737,7 +1738,7 @@ export default {
         param = this.queryParams;
         param.erpPhone=this.erpPhoneValue;
       }
-      
+
       editErpPhone(param).then(response=>{
         this.msgSuccess("修改成功");
         this.setPhoneOpen = false;
@@ -1764,7 +1765,7 @@ export default {
             originalPhone: phone.trim()
           }));
         }
-        
+
         // 保存原始数据用于取消操作
         this.originalPhoneList = this.phoneList;
       });
@@ -1795,7 +1796,7 @@ export default {
         return;
       }
       // 检查是否重复
-      const duplicateIndex = this.phoneList.findIndex((item, idx) => 
+      const duplicateIndex = this.phoneList.findIndex((item, idx) =>
         idx !== index && item.phone === phone
       );
       if (duplicateIndex !== -1) {
@@ -1846,17 +1847,17 @@ export default {
         this.$message.error('请先保存正在编辑的手机号');
         return;
       }
-      
+
       // 检查是否有空的手机号
       const emptyPhone = this.phoneList.find(item => !item.phone.trim());
       if (emptyPhone) {
         this.$message.error('存在空的手机号,请删除或填写完整');
         return;
       }
-      
+
       // 构造手机号列表
       const phoneList = this.phoneList.map(item => item.phone);
-      
+
       // 调用保存接口
       saveErpPhone(phoneList).then(response => {
         if (response.code === 200) {
@@ -1876,7 +1877,7 @@ export default {
       this.phoneList = JSON.parse(JSON.stringify(this.originalPhoneList));
       this.erpPhone.open = false;
     },
-    
+
     handleImportExpress() {
           this.importExpress.title = "导入";
           this.importExpress.open = true;
@@ -1911,7 +1912,7 @@ export default {
           this.$alert(response.msg, "导入结果", { dangerouslyUseHTMLString: true });
           this.getList();
         },
-        
+
         // 提交上传文件
         submitFileFormExpress() {
           this.$refs.importExpress.submit();
@@ -2108,7 +2109,7 @@ export default {
       };
       this.queryParams.sortField = null;
       this.queryParams.sortOrder = null;
-      
+
       // 清除订单号标签
       this.queryParams.orderCodes = [];
       this.currentInput = '';
@@ -2120,7 +2121,7 @@ export default {
           this.$refs.orderTable.clearSort();
         }
       });
-      
+
       this.handleQuery();
     },
     // 多选框选中数据
@@ -2223,7 +2224,7 @@ export default {
         }).then(response => {
 			console.log(response)
 			if(response.code==200){
-			
+
 			that.msgSuccess(response.msg);
 			that.taskId=response.data;
 			that.time=setInterval(function(){
@@ -2245,7 +2246,7 @@ export default {
       // 打开字段选择对话框
       this.exportFieldDialog.open = true;
     },
-    
+
     // 导出字段选择相关方法
     // 全选字段
     selectAllFields() {
@@ -2253,22 +2254,22 @@ export default {
         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', 
+      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)) {
@@ -2276,22 +2277,22 @@ export default {
         }
       });
     },
-    
+
     // 获取已选择字段数量
     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参数)
@@ -2300,51 +2301,51 @@ export default {
         // 如果选择了字段,则只导出选中的字段
         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 {
         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
       }
-      
+
       const queryParams = this.queryParams;
-      
+
       // 根据是否选择字段显示不同的确认消息
       let confirmMessage = '';
       if (selectedFields === null) {
@@ -2353,21 +2354,21 @@ export default {
         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)
@@ -2414,7 +2415,7 @@ export default {
           this.getTreeselect();
         }
       }
-      
+
     },
     // companyChange(val){
     //   console.log(val);
@@ -2578,15 +2579,15 @@ export default {
     min-width: auto;
     width: 100%;
   }
-  
+
   .tags-wrapper {
     min-height: 40px;
   }
-  
+
   .quick-actions {
     flex-direction: column;
     align-items: flex-start;
     gap: 8px;
   }
 }
-</style>
+</style>

+ 28 - 8
src/views/his/user/indexProject.vue

@@ -11,11 +11,21 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="会员昵称" prop="nickname">
+      <el-form-item label="会员昵称(模糊)" prop="nickname" label-width="130px">
         <el-input
 
           v-model="queryParams.nickname"
-          placeholder="请输入会员昵称"
+          placeholder="请输入会员昵称(模糊搜索)"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="会员昵称(精确)" prop="nicknameExact" label-width="130px">
+        <el-input
+
+          v-model="queryParams.nicknameExact"
+          placeholder="请输入会员昵称(精确搜索)"
           clearable
           size="small"
           @keyup.enter.native="handleQuery"
@@ -64,7 +74,9 @@
       <el-form-item label="所属销售" prop="companyUserNickName">
 
         <el-select
-          v-model="queryParams.companyUserId"
+          v-model="queryParams.companyUserIds"
+          multiple
+          collapse-tags
           placeholder="请选择所属销售"
           clearable
           filterable
@@ -439,6 +451,7 @@ export default {
         idCard: null,
         mark: null,
         nickname: null,
+        nicknameExact: null,
         avatar: null,
         phone: null,
         lastIp: null,
@@ -461,7 +474,9 @@ export default {
         endCreateTime: null,
         companyId: null,
         companyUserNickName: null,
-        userId: null
+        userId: null,
+        companyUserIds: [], //销售id 多选数组
+        companyUserIdMulti: null, //销售id 用于传到后端
       },
       // 表单参数
       form: {},
@@ -549,8 +564,9 @@ export default {
 
 
     /** 查询用户列表 */
-    getList() {
+    async getList() {
       this.loading = true;
+      this.queryParams.companyUserIdMulti =this.queryParams.companyUserIds.join(",");
       listUserByProject(this.queryParams).then(response => {
         this.userList = response.rows;
         this.total = response.total;
@@ -721,7 +737,11 @@ export default {
     },
 
     // 解绑会员
-    handleUnbind() {
+    async handleUnbind() {
+      // 解绑前先主动搜索一下
+      this.queryParams.pageNum = 1;
+      await this.getList();
+
       // 检查是否有勾选列表行
       if (this.selectedUser.length > 0) {
         // 有勾选行,获取选中的userId列表
@@ -736,7 +756,7 @@ export default {
         }).then(() => {
           this.msgSuccess("解绑成功");
           this.getList();
-        }).catch(function() {
+        }).catch(function () {
           this.$message.error('解绑失败');
         });
       } else {
@@ -751,7 +771,7 @@ export default {
         }).then(() => {
           this.msgSuccess("解绑成功");
           this.getList();
-        }).catch(function() {
+        }).catch(function () {
           this.$message.error('解绑失败');
         });
       }

+ 22 - 0
src/views/his/userIntegralLogs/index.vue

@@ -27,6 +27,16 @@
           size="small"
           @keyup.enter.native="handleQuery"
         />
+      </el-form-item>
+      <el-form-item label="类别" prop="logType">
+        <el-select v-model="queryParams.logType" placeholder="请选择类别" clearable size="small">
+          <el-option
+            v-for="dict in intefralLogTypeOptions"
+            :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>
@@ -38,6 +48,17 @@
     </el-form>
 
     <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['his:userIntegralLogs:remove']"
+        >删除</el-button>
+      </el-col>
       <el-col :span="1.5">
         <el-button
           type="warning"
@@ -53,6 +74,7 @@
     </el-row>
 
     <el-table v-loading="loading" border :data="userIntegralLogsList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
       <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" />

+ 21 - 0
src/views/hisStore/adv/index.vue

@@ -392,6 +392,27 @@ export default {
         this.form.status = response.data.status.toString();
         this.form.advType = response.data.advType.toString();
         this.form.showType = response.data.showType ? response.data.showType.toString() : "";
+        // 根据 imageUrl 判断 urlType
+        if (this.form.imageUrl) {
+          // 可以根据文件扩展名判断是图片还是视频
+          const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp'];
+          const videoExtensions = ['.mp4', '.avi', '.mov', '.wmv', '.flv', '.mkv'];
+
+          const lowerImageUrl = this.form.imageUrl.toLowerCase();
+          let isImage = imageExtensions.some(ext => lowerImageUrl.includes(ext));
+          let isVideo = videoExtensions.some(ext => lowerImageUrl.includes(ext));
+
+          if (isImage) {
+            this.form.urlType = 1; // 图片
+          } else if (isVideo) {
+            this.form.urlType = 2; // 视频
+          } else {
+            this.form.urlType = 1; // 默认图片
+          }
+        } else {
+          this.form.urlType = 1; // 默认图片
+        }
+        console.log('urlType:', this.form.urlType, typeof this.form.urlType);
         this.open = true;
         this.title = "修改广告";
         setTimeout(() => {

+ 21 - 0
src/views/hisStore/components/productAfterSalesOrder.vue

@@ -43,6 +43,11 @@
                   {{afterSales.refundAmount}}
                 </span>
             </el-descriptions-item>
+            <el-descriptions-item label="运费"  >
+                <span v-if="order!=null">
+                  {{order.payPostage}}
+                </span>
+            </el-descriptions-item>
             <el-descriptions-item label="申请类型"  >
                 <span v-if="afterSales!=null">
                   <el-tag  v-for="(item, index) in serviceTypeOptions"    v-if="afterSales.serviceType==item.dictValue" >{{item.dictLabel}}</el-tag>
@@ -145,6 +150,11 @@
             </template>
           </el-table-column>
         </el-table>
+        <div style="margin-top: 12px; text-align: right;" v-if="order">
+          <div>订单金额:¥{{ goodsTotal.toFixed(2) }}</div>
+          <div>运费金额:¥{{ (order.payPostage || 0).toFixed(2) }}</div>
+          <div>实付金额:¥{{ (goodsTotal + (order.payPostage || 0)).toFixed(2) }}</div>
+        </div>
         <div style="margin-top: 20px">
           <svg-icon icon-class="marker" style="color: #606266"></svg-icon>
           <span class="font-small">操作信息</span>
@@ -265,6 +275,17 @@ export default {
 
     };
   },
+  computed: {
+    goodsTotal() {
+      if (!this.items || this.items.length === 0) return 0;
+      return this.items.reduce((sum, it) => {
+        const info = JSON.parse(it.jsonInfo || "{}");
+        const num = Number(it.num != null ? it.num : info.num) || 0;
+        const price = Number(info.price) || 0;
+        return sum + num * price;
+      }, 0);
+    }
+  },
   created() {
     this.getDicts("store_after_sales_sales_status").then((response) => {
         this.salesStatusOptions = response.data;

+ 4 - 0
src/views/hisStore/components/productOrder.vue

@@ -402,8 +402,12 @@
             <el-option key="SF"  label="顺丰" value="SF" />
             <el-option key="EMS"  label="邮政" value="EMS" />
              <el-option key="ZTO"  label="中通" value="ZTO" />
+             <el-option key="STO"  label="申通" value="STO" />
              <el-option key="JD"  label="京东" value="JD" />
              <el-option key="DBL"  label="德邦" value="DBL" />
+             <el-option key="JTSD"  label="极兔" value="JTSD" />
+             <el-option key="YD"  label="韵达" value="YD" />
+             <el-option key="YTO"  label="圆通" value="YTO" />
            </el-select>
          </el-form-item>
         <el-form-item label="物流单号" prop="deliveryId"  >

+ 3 - 1
src/views/hisStore/menu/index.vue

@@ -207,7 +207,9 @@ export default {
         {"dictLabel": "养生有道",
           "dictValue": "2"},
         {"dictLabel": "个人中心",
-          "dictValue": "3"}
+          "dictValue": "3"},
+        {"dictLabel": "主菜单-热销榜",
+          "dictValue": "4"}
       ],
       statusOptions:[],
       imageArr:[],

+ 23 - 6
src/views/hisStore/shippingTemplates/index.vue

@@ -131,7 +131,7 @@
                 </el-table-column>
                 <el-table-column  label="操作">
                   <template slot-scope="scope">
-                    <a v-if="scope.row.regionName!=='默认全国'" @click="delCity(scope.row.index,1)">删除</a>
+                    <a  @click="delCity(scope.$index,1)">删除</a>
                   </template>
                 </el-table-column>
 
@@ -175,7 +175,7 @@
                 </el-table-column>
                 <el-table-column  label="操作">
                   <template slot-scope="scope">
-                    <a v-if="scope.row.regionName!=='默认全国'" @click="delCity(scope.row.index,2)">删除</a>
+                    <a  @click="delCity(scope.$index ,2)">删除</a>
                   </template>
                 </el-table-column>
 
@@ -197,17 +197,17 @@
         <el-button @click="cancel">取 消</el-button>
       </div>
     </el-dialog>
-    <city ref="city" @selectCity="selectCity" :type="type"></city>
+    <CityZm ref="city" @selectCity="selectCity" :type="type"></CityZm>
   </div>
 </template>
 
 <script>
 import { listShippingTemplates, getShippingTemplates, delShippingTemplates, addShippingTemplates, updateShippingTemplates, exportShippingTemplates } from "@/api/hisStore/shippingTemplates";
-import City from '@/components/City'
+import CityZm from '@/components/City/indexZm'
 export default {
   name: "ShippingTemplates",
   components: {
-    City
+    CityZm
   },
   data() {
     return {
@@ -267,7 +267,6 @@ export default {
   },
   methods: {
     delCity (index,type) {
-      console.log(index)
       if (type === 1) {
         this.templateList.splice(index, 1);
       } else {
@@ -301,8 +300,26 @@ export default {
     },
     // 单独添加配送区域
     addCity (type) {
+      // 获取已选择的城市数据
+      let selectedCities = [];
+      if (type === 1) {
+        // 配送区域
+        this.templateList.forEach(item => {
+          if (item.region && item.region.length > 0) {
+            selectedCities = selectedCities.concat(item.region);
+          }
+        });
+      } else {
+        // 指定包邮
+        this.appointList.forEach(item => {
+          if (item.place && item.place.length > 0) {
+            selectedCities = selectedCities.concat(item.place);
+          }
+        });
+      }
       this.$refs.city.addressView = true;
       this.type = type;
+      this.$refs.city.selectedCities = selectedCities;
       this.$refs.city.getCityList()
     },
     /** 查询运费模板列表 */

+ 1 - 1
src/views/hisStore/store/audit.vue

@@ -63,7 +63,7 @@
           size="mini"
           :loading="exportLoading"
           @click="handleExport"
-          v-hasPermi="['his:store:export']"
+          v-hasPermi="['store:his:store:export']"
         >导出</el-button>
       </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>

+ 12 - 7
src/views/hisStore/store/index.vue

@@ -71,7 +71,7 @@
           icon="el-icon-plus"
           size="mini"
           @click="handleAdd"
-          v-hasPermi="['his:store:add']"
+          v-hasPermi="['store:his:store:add']"
         >新增</el-button>
       </el-col>
       <el-col :span="1.5">
@@ -82,7 +82,7 @@
           size="mini"
           :disabled="single"
           @click="handleUpdate"
-          v-hasPermi="['his:store:edit']"
+          v-hasPermi="['store:his:store:edit']"
         >修改</el-button>
       </el-col>
       <el-col :span="1.5">
@@ -93,7 +93,7 @@
           size="mini"
           :disabled="multiple"
           @click="handleDelete"
-          v-hasPermi="['his:store:remove']"
+          v-hasPermi="['store:his:store:remove']"
         >删除</el-button>
       </el-col>
       <el-col :span="1.5">
@@ -104,7 +104,7 @@
           size="mini"
           :loading="exportLoading"
           @click="handleExport"
-          v-hasPermi="['his:store:export']"
+          v-hasPermi="['store:his:store:export']"
         >导出</el-button>
       </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
@@ -173,13 +173,14 @@
             type="text"
             icon="el-icon-edit"
             @click="handleUpdate(scope.row)"
-            v-hasPermi="['his:store:edit']"
+            v-hasPermi="['store:his:store:edit']"
           >修改</el-button>
           <el-button
             size="mini"
             type="text"
             icon="el-icon-s-promotion"
             @click="handledetails(scope.row)"
+            v-hasPermi="['store:his:store:query']"
           >详情
           </el-button>
           <el-button
@@ -187,14 +188,14 @@
             type="text"
             icon="el-icon-delete"
             @click="handleDelete(scope.row)"
-            v-hasPermi="['his:store:remove']"
+            v-hasPermi="['store:his:store:remove']"
           >删除</el-button>
           <el-button
             size="mini"
             type="text"
             icon="el-icon-refresh"
             @click="handleRefresh(scope.row)"
-            v-hasPermi="['his:store:refresh']"
+            v-hasPermi="['store:his:store:refresh']"
           >重置密码</el-button>
         </template>
       </el-table-column>
@@ -903,6 +904,10 @@ export default {
         this.form = response.data;
         this.open = true;
         this.title = "修改店铺";
+        // 移除 phone 字段的验证规则
+        const newRules = Object.assign({}, this.rules);
+        delete newRules.phone;
+        this.rules = newRules;
         let str = this.form.shippingType
         this.form.shippingType = str.split(",")
         this.form.cityIds = ((this.form.cityIds).split(",")).map(Number)

+ 44 - 5
src/views/hisStore/storeAfterSales/index.vue

@@ -25,10 +25,10 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="员工姓名" prop="companyUserNickName">
+      <el-form-item label="销售名称" prop="companyUserNickName">
         <el-input
           v-model="queryParams.companyUserNickName"
-          placeholder="请输入员工姓名"
+          placeholder="请输入销售名称"
           clearable
           size="small"
           @keyup.enter.native="handleQuery"
@@ -43,6 +43,15 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
+      <el-form-item label="产品名称" prop="productName">
+        <el-input
+          v-model="queryParams.productName"
+          placeholder="请输入产品名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
 
 
 
@@ -108,8 +117,24 @@
             size="small"
             @keyup.enter.native="handleQuery"/>
        </el-form-item>
+      <el-form-item label="退货物流单号" prop="returnDeliverySn">
+        <el-input
+          v-model="queryParams.returnDeliverySn"
+          placeholder="请输入退货物流单号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
 
-
+      <el-form-item label="汇付商户订单" prop="hfOrderCode" label-width="100">
+          <el-input
+            v-model="queryParams.hfOrderCode"
+            placeholder="请输入汇付商户订单"
+            clearable
+            size="small"
+            @keyup.enter.native="handleQuery"/>
+       </el-form-item>
       <el-form-item label="提交时间" prop="createTime">
         <el-date-picker
           style="width:205.4px"
@@ -145,7 +170,9 @@
       <el-table-column label="所属公司" align="center" prop="companyName" />
       <el-table-column label="所属员工" align="center" prop="companyUserNickName" />
       <el-table-column label="订单单号" align="center" prop="orderCode" />
+      <el-table-column label="支付单号" align="center" prop="payCode" />
       <el-table-column label="会员手机号" align="center" prop="userPhone" />
+      <el-table-column label="产品名称" align="center" prop="productName" :show-overflow-tooltip="true" />
       <el-table-column label="退款金额" align="center" prop="refundAmount" />
        <el-table-column label="退款类型" align="center" prop="serviceType" >
           <template slot-scope="scope">
@@ -267,6 +294,7 @@ export default {
         explainImg: null,
         shipperCode: null,
         deliverySn: null,
+        hfOrderCode:null,
         deliveryName: null,
         status: null,
         salesStatus: null,
@@ -274,7 +302,9 @@ export default {
         userId: null,
         consignee: null,
         phoneNumber: null,
-        address: null
+        address: null,
+        productName: null,
+        returnDeliverySn: null        // 退货物流单号(售后物流单号)
       },
       // 表单参数
       form: {},
@@ -329,7 +359,15 @@ export default {
     /** 查询售后记录列表 */
     getList() {
       this.loading = true;
-      listStoreAfterSales(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+      const params = {
+        ...this.queryParams,
+        deliverySn: this.queryParams.returnDeliverySn || this.queryParams.deliverySn
+      };
+      if(!!params.hfOrderCode && params.hfOrderCode.indexOf("-") > -1){
+        let ss = params.hfOrderCode.split("-");
+        params.hfOrderCode = ss[1];
+      }
+      listStoreAfterSales(this.addDateRange(params, this.dateRange)).then(response => {
         this.storeAfterSalesList = response.rows;
         this.total = response.total;
         this.loading = false;
@@ -352,6 +390,7 @@ export default {
         explainImg: null,
         shipperCode: null,
         deliverySn: null,
+        hfOrderCode:null,
         deliveryName: null,
         status: 0,
         salesStatus: 0,

+ 1 - 0
src/views/hisStore/storeCouponIssue/index.vue

@@ -234,6 +234,7 @@ export default {
     },
     /** 重置按钮操作 */
     resetQuery() {
+      this.dateRange = [];
       this.resetForm("queryForm");
       this.handleQuery();
     },

+ 40 - 12
src/views/hisStore/storeOrder/healthStoreList.vue

@@ -76,6 +76,15 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
+      <el-form-item label="银行交易流水号" prop="bankTransactionId">
+        <el-input
+          v-model="queryParams.bankTransactionId"
+          placeholder="请输入银行交易流水号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
 
       <el-form-item label="手机号" prop="userPhone">
         <el-input
@@ -426,6 +435,7 @@
     @sort-change="handleSortChange" :default-sort="{prop: 'createTime', order: 'descending'}">
       <el-table-column align="center" type="selection" width="55"/>
       <el-table-column align="center" label="订单号" prop="orderCode" width="200px"/>
+      <el-table-column label="银行交易流水号" align="center" prop="bankTransactionId" width="180" />
       <el-table-column label="ERP电话" align="center" prop="erpPhone" width="120px" v-if="SFDFopen"/>
       <el-table-column label="ERP账号" align="center" prop="erpAccount" width="120px" v-if="SFDFopen"/>
       <el-table-column label="小程序名称" align="center" prop="miniProgramName"/>
@@ -463,6 +473,13 @@
             <el-tooltip content="按应收金额排序" placement="top"/>
           </template>
         </el-table-column>
+
+      <el-table-column label="成本价格" align="center" prop="cost" v-if="showFinanceTableField"/>
+      <!-- <el-table-column label="结算价格" align="center" prop="fprice"  v-if="showFinanceTableField"/> -->
+       <el-table-column label="实付金额" align="center" prop="payMoney"  v-if="showFinanceTableField"/>
+      <el-table-column label="额外运费" align="center" prop="payPostage" v-if="showFinanceTableField"/>
+      <el-table-column label="商品编码" align="center" prop="barCode"  v-if="showFinanceTableField"/>
+      <el-table-column label="商品分类" align="center" prop="cateName" v-if="showFinanceTableField"/>
       <el-table-column align="center" label="下单时间" prop="createTime"/>
       <!-- <el-table-column label="支付状态" align="center" prop="paid" /> -->
       <el-table-column align="center" label="支付时间" prop="payTime" width="180">
@@ -976,7 +993,9 @@ import Treeselect from '@riophae/vue-treeselect'
 import '@riophae/vue-treeselect/dist/vue-treeselect.css'
 import { getConfigByKey } from '@/api/system/config'
 import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
+import {checkPermi} from "@/utils/permission";
 
+// 商城订单
 export default {
   components: { productOrder, productSelect, addUser, addUserAddress, Treeselect },
   name: 'HisHealthStoreOrderList',
@@ -1049,26 +1068,30 @@ export default {
       },
       // 可选择的导出字段列表
       exportFieldOptions: [
+
+        { key: 'erpPhone', label: 'ERP电话', checked: false },
+        { key: 'erpAccount', label: 'ERP账号', checked: false },
         { key: 'orderCode', label: '订单号', checked: true },
-        { key: 'miniProgramName', label: '小程序名称', checked: true },
-        { key: 'patientName', label: '就诊人', checked: true },
-        { key: 'productName', label: '编号', checked: true },
-        { key: 'barCode', label: '药品信息', checked: false },
+        { key: 'userId', label: '会员ID', checked: true },
+        { key: 'orderType', label: '订单类型', checked: true },
+        { key: 'companyName', label: '公司名称', checked: true },
+        { key: 'companyUserNickName', label: '所属销售', checked: true },
+        { key: 'realName', label: '收货人姓名', checked: true },
+        { key: 'userPhone', label: '收货人电话', checked: true },
+        { key: 'userAddress', label: '详细地址', checked: true },
         { key: 'payMoney', label: '实收金额', checked: true },
         { key: 'payRemain', label: '物流代收金额', checked: false },
-        { key: 'payType', label: '支付方式', checked: true },
         { key: 'createTime', label: '下单时间', checked: true },
         { key: 'payTime', label: '支付时间', checked: true },
+        { key: 'payType', label: '支付方式', checked: true },
         { key: 'status', label: '订单状态', checked: true },
-        { key: 'userName', label: '收货人姓名', checked: true },
-        { key: 'userPhone', label: '收货人电话', checked: true },
-        { key: 'userAddress', label: '详细地址', checked: true },
-        { key: 'deliveryCode', label: '快递公司编号', checked: false },
+        { key: 'barCode', label: '商品编码', checked: false },
+
+
+        { key: 'deliverySn', label: '快递公司编号', checked: false },
         { key: 'deliveryName', label: '快递公司', checked: false },
-        { key: 'deliverySn', label: '快递单号', checked: false },
+        { key: 'deliveryId', label: '快递单号', checked: false },
         { key: 'remark', label: '备注', checked: false },
-        { key: 'erpPhone', label: 'ERP电话', checked: false },
-        { key: 'erpAccount', label: 'ERP账号', checked: false },
 
       ],
       appMallOptions:[],
@@ -1142,6 +1165,7 @@ export default {
         pageSize: 10,
         orderCode: null,
         orderCodes:[],
+        bankTransactionId: null,
         extendOrderId: null,
         userId: null,
         realName: null,
@@ -1238,6 +1262,7 @@ export default {
       ruleForm:{
         miniAppId: null,
       },
+      showFinanceTableField: false,
     }
   },
   created() {
@@ -1266,6 +1291,9 @@ export default {
     this.getDicts('store_delivery_pay_status').then((response) => {
       this.deliveryPayStatusOptions = response.data
     })
+    if (checkPermi(['his:storeAfterSales:finance'])) {
+      this.showFinanceTableField = true;
+    }
 
     this.getList()
     this.getErpAccountList();

+ 70 - 26
src/views/hisStore/storeOrder/index.vue

@@ -91,6 +91,25 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
+      <el-form-item label="银行交易流水号" prop="bankTransactionId">
+        <el-input
+          v-model="queryParams.bankTransactionId"
+          placeholder="请输入银行交易流水号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="产品名称" prop="productName">
+        <el-input
+          v-model="queryParams.productName"
+          placeholder="请输入产品名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
 
       <el-form-item label="手机号" prop="userPhone">
         <el-input
@@ -110,10 +129,10 @@
           @keyup.enter.native="handleQuery"/>
       </el-form-item>
 
-      <el-form-item label="员工姓名" prop="companyUserNickName">
+      <el-form-item label="销售名称" prop="companyUserNickName">
         <el-input
           v-model="queryParams.companyUserNickName"
-          placeholder="请输入员工姓名"
+          placeholder="请输入销售名称"
           clearable
           size="small"
           @keyup.enter.native="handleQuery"
@@ -433,6 +452,7 @@
     @sort-change="handleSortChange" :default-sort="{prop: 'createTime', order: 'descending'}">
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="订单号" align="center" prop="orderCode" width="200px" />
+      <el-table-column label="银行交易流水号" align="center" prop="bankTransactionId" width="180" />
       <el-table-column label="ERP电话" align="center" prop="erpPhone" width="120px" v-if="SFDFopen "/>
       <el-table-column label="ERP账号" align="center" prop="erpAccount" width="120px" v-if="SFDFopen"/>
       <el-table-column label="所属公司" align="center" prop="companyName" />
@@ -470,6 +490,12 @@
               <span v-if="scope.row.totalPrice!=null">{{scope.row.totalPrice.toFixed(2)}}</span>
           </template>
       </el-table-column>
+
+      <el-table-column label="成本价格" align="center" prop="cost" v-if="showFinanceTableField"/>
+      <!-- <el-table-column label="结算价格" align="center" prop="fprice"  v-if="showFinanceTableField"/> -->
+      <el-table-column label="额外运费" align="center" prop="payPostage" v-if="showFinanceTableField"/>
+      <el-table-column label="商品编码" align="center" prop="barCode"  v-if="showFinanceTableField"/>
+      <el-table-column label="商品分类" align="center" prop="cateName" v-if="showFinanceTableField"/>
        <!-- <el-table-column label="应付金额" align="center" prop="payPrice" >
           <template slot-scope="scope">
               <span v-if="scope.row.payPrice!=null">{{scope.row.payPrice.toFixed(2)}}</span>
@@ -483,8 +509,8 @@
         </el-table-column>
       <el-table-column label="实付金额" align="center" prop="payMoney" >
         <template slot="header" slot-scope="scope">
-          <span>实金额</span>
-          <el-tooltip content="按实金额排序" placement="top"/>
+          <span>实金额</span>
+          <el-tooltip content="按实金额排序" placement="top"/>
         </template>
       </el-table-column>
       <el-table-column label="物流代收金额" align="center" prop="payDelivery" >
@@ -511,7 +537,7 @@
               <el-tag prop="orderMedium" v-for="(item, index) in orderMediumOptions"    v-if="scope.row.orderMedium==item.dictValue">{{item.dictLabel}}</el-tag>
           </template>
       </el-table-column>
-      <el-table-column label="订单产品" align="center" width="200px">
+      <el-table-column label="产品名称" align="center" width="200px">
         <template slot-scope="scope">
           <div v-if="scope.row.items && scope.row.items.length > 0">
             <el-tag
@@ -668,7 +694,7 @@
                     </el-popover>
                   </template>
                 </el-table-column>
-                <el-table-column label="品名称" show-overflow-tooltip align="center" prop="productName" />
+                <el-table-column label="品名称" show-overflow-tooltip align="center" prop="productName" />
                 <el-table-column label="商品规格" align="center" prop="sku" />
                 <el-table-column label="库存" align="center" prop="stock" />
                 <el-table-column label="单价" align="center" prop="price" />
@@ -1013,7 +1039,9 @@ import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 import { getConfigByKey } from '@/api/system/config'
 import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
-
+import {checkPermi} from "@/utils/permission";
+import {getSignProjectName} from "@/api/course/qw/courseWatchLog";
+// 销售订单
 export default {
   components: { productOrder,productSelect,addUser,addUserAddress,Treeselect },
   name: "HisStoreOrder",
@@ -1086,28 +1114,36 @@ export default {
       },
       // 可选择的导出字段列表
       exportFieldOptions: [
+
+        { key: 'erpPhone', label: 'ERP电话', checked: false },
+        { key: 'erpAccount', label: 'ERP账号', checked: false },
         { key: 'orderCode', label: '订单号', checked: true },
-        { key: 'miniProgramName', label: '小程序名称', checked: true },
+        { key: 'userId', label: '会员ID', checked: true },
+        { key: 'orderType', label: '订单类型', checked: true },
         { key: 'companyName', label: '公司名称', checked: true },
         { key: 'companyUserNickName', label: '所属销售', checked: true },
-        { key: 'patientName', label: '就诊人', checked: true },
-        { key: 'productName', label: '编号', checked: true },
-        { key: 'barCode', label: '药品信息', checked: false },
-        { key: 'payMoney', label: '实收金额', checked: true },
-        { key: 'payRemain', label: '物流代收金额', checked: false },
-        { key: 'payType', label: '支付方式', checked: true },
+        { key: 'realName', label: '收货人姓名', checked: true },
+        { key: 'userPhone', label: '收货人电话', checked: true },
+        { key: 'userAddress', label: '详细地址', checked: true },
+        { key: 'packageTitle', label: '套餐名称', checked: true },
+        { key: 'orderItem', label: '商品明细', checked: true },
+        { key: 'totalPrice', label: '商品金额', checked: true },
+        { key: 'payPrice', label: '应付金额', checked: true },
+        { key: 'payMoney', label: '实付金额', checked: true },
+        { key: 'payDelivery', label: '物流代收金额', checked: true },
+        { key: 'deductionPrice', label: '抵扣金额', checked: false },
+        { key: 'couponPrice', label: '优惠券金额', checked: false },
         { key: 'createTime', label: '下单时间', checked: true },
         { key: 'payTime', label: '支付时间', checked: true },
+        { key: 'payType', label: '支付方式', checked: true },
         { key: 'status', label: '订单状态', checked: true },
-        { key: 'userName', label: '收货人姓名', checked: true },
-        { key: 'userPhone', label: '收货人电话', checked: true },
-        { key: 'userAddress', label: '详细地址', checked: true },
-        { key: 'deliveryCode', label: '快递公司编号', checked: false },
+        { key: 'barCode', label: '商品编码', checked: false },
+
+
+        { key: 'deliverySn', label: '快递公司编号', checked: false },
         { key: 'deliveryName', label: '快递公司', checked: false },
-        { key: 'deliverySn', label: '快递单号', checked: false },
+        { key: 'deliveryId', label: '快递单号', checked: false },
         { key: 'remark', label: '备注', checked: false },
-        { key: 'erpPhone', label: 'ERP电话', checked: false },
-        { key: 'erpAccount', label: 'ERP账号', checked: false },
 
       ],
 
@@ -1185,6 +1221,7 @@ export default {
         pageSize: 10,
         orderCode: null,
         orderCodes:[],
+        bankTransactionId: null,
         extendOrderId: null,
         userId: null,
         realName: null,
@@ -1230,7 +1267,7 @@ export default {
         isSysDel: null,
         deptId:null,
         isUpload:null,
-
+        productName:null,
       },
       // 表单参数
       form: {
@@ -1280,9 +1317,17 @@ export default {
       ruleForm:{
         miniAppId: null,
       },
+      showFinanceTableField: false,
+      signProjectName:null,
     };
   },
   created() {
+    getSignProjectName().then(res=>{
+      this.signProjectName = res.signProjectName;
+      console.log(this.signProjectName)
+    }).catch(res=>{
+
+    })
     getCompanyList().then(response => {
         this.companys = response.data;
          if(this.companys!=null&&this.companys.length>0){
@@ -1320,6 +1365,9 @@ export default {
     getTcmScheduleList().then(response => {
       this.scheduleOptions = response.data;
     });
+    if (checkPermi(['his:storeAfterSales:finance'])) {
+      this.showFinanceTableField = true;
+    }
     this.getList();
     this.getItemsNum();
     this.getErpAccountList();
@@ -1444,10 +1492,6 @@ export default {
 
     },
 
-    // 删除订单号
-    removeOrderCode(index) {
-      this.queryParams.orderCodes.splice(index, 1)
-    },
     // 清空所有标签
     clearAllTags() {
       this.$confirm('确认清空所有订单号吗?', '提示', {

+ 25 - 1
src/views/hisStore/storePayment/index.vue

@@ -160,6 +160,15 @@
           @click="handlePayNotify"
           v-hasPermi="['store:storePayment:payNotify']"
         >同步订单状态</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          icon="el-icon-s-order"
+          size="mini"
+          type="success"
+          @click="wxOneClickShipping"
+        >微信一键线下自提发货
+        </el-button>
       </el-col>
 	  <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
@@ -287,7 +296,7 @@
 </template>
 
 <script>
-import { refundStorePayment,listStorePayment, getStorePayment, delStorePayment, addStorePayment, updateStorePayment, exportStorePayment,setPayNotify } from "@/api/hisStore/storePayment";
+import { refundStorePayment,listStorePayment, getStorePayment, delStorePayment, addStorePayment, updateStorePayment, exportStorePayment,setPayNotify, oneClickShipping} from "@/api/hisStore/storePayment";
 import { getCompanyList } from "@/api/company/company";
 import { listLiveOrderPayments,getLivePayment,updateLivePayment,exportLiveOrderPayments } from "@/api/live/liveOrderPayment";
 
@@ -605,6 +614,21 @@ export default {
         }).then(response => {
           this.download(response.msg);
         }).catch(function() {});
+    },
+    wxOneClickShipping(){
+      this.$confirm('是否同步微信线下发货?', '一键发货', {
+        confirmButtonText: '是',
+        cancelButtonText: '否',
+        type: 'warning'
+      }).then(() => {
+        oneClickShipping().then(response => {
+          if(response.code === 200) {
+            this.$message.success("操作成功!")
+            this.getList();
+          }
+        })
+      }).catch(() => {
+      });
     }
   }
 };

+ 17 - 12
src/views/hisStore/storeProduct/index.vue

@@ -553,13 +553,13 @@
           </el-form-item>
         </div>
         </div>
-<!--        <el-row>-->
-<!--          <el-col :span="24">-->
-<!--            <el-form-item label="商品简介" prop="productInfo">-->
-<!--              <el-input v-model="form.productInfo" type="textarea" :rows="2" placeholder="请输入商品简介" />-->
-<!--            </el-form-item>-->
-<!--          </el-col>-->
-<!--        </el-row>-->
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="商品简介" prop="productInfo">
+              <el-input v-model="form.productInfo" type="textarea" :rows="2" placeholder="请输入商品简介" />
+            </el-form-item>
+          </el-col>
+        </el-row>
         <el-form-item label="商品图片" prop="image">
           <Material v-model="imageArr" type="image" :num="1" :width="150" :height="150" />
         </el-form-item>
@@ -985,7 +985,7 @@ export default {
         // 设置上传的请求头部
         headers: { Authorization: "Bearer " + getToken() },
         // 上传的地址
-        url: process.env.VUE_APP_BASE_API + "/store/storeProduct/importData"
+        url: process.env.VUE_APP_BASE_API + "/store/store/storeProduct/importData"
       },
       // 添加药品相关字段
       isDrugOptions: [
@@ -1177,9 +1177,9 @@ export default {
         precautions: [
           { required: true, message: "注意事项不能为空", trigger: "blur" }
         ],
-        // storeId :[
-        //   { required: true, message: "所属店铺不能为空", trigger: "blur"}
-        // ],
+        storeId :[
+          { required: true, message: "所属店铺不能为空", trigger: "blur"}
+        ],
       }
     };
   },
@@ -1684,7 +1684,12 @@ export default {
           }
           addOrEdit(this.form).then(response => {
             if (response.code === 200) {
-              this.msgSuccess("修改成功");
+              // 根据是否有productId判断是新增还是修改
+              if (this.form.productId) {
+                this.msgSuccess("修改成功");
+              } else {
+                this.msgSuccess("新增成功");
+              }
               this.open = false;
               this.getList();
             }

+ 1807 - 0
src/views/hisStore/storeProduct/indexZm.vue

@@ -0,0 +1,1807 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+
+      <el-form-item label="商品分类" prop="cateId">
+        <treeselect  v-model="queryParams.cateId"  style="width:205.4px" :options="categoryOptions" :normalizer="normalizer" placeholder="请选择分类" />
+      </el-form-item>
+
+      <el-form-item label="商品名称" prop="productName">
+        <el-input
+          v-model="queryParams.productName"
+          placeholder="请输入商品名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="商品编号" prop="barCode">
+        <el-input
+          v-model="queryParams.barCode"
+          placeholder="请输入商品编号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+
+      <el-form-item label="商品类型" prop="productType">
+        <el-select   v-model="queryParams.productType" placeholder="请选择商品类型" clearable size="small" >
+          <el-option
+            v-for="item in productTypeOptions"
+            :key="item.dictValue"
+            :label="item.dictLabel"
+            :value="item.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="所属公司">
+        <el-select style="width: 240px" v-model="companyId" multiple placeholder="请选择企业" clearable size="small" >
+          <el-option
+            v-for="item in companyOptions"
+            :key="item.companyId"
+            :label="item.companyName"
+            :value="item.companyId"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="所属店铺" v-if="this.isStores">
+        <el-select style="width: 240px" v-model="queryParams.storeIds" placeholder="请选择店铺" clearable size="small" >
+          <el-option
+            v-for="item in storeOptions"
+            :key="item.storeId"
+            :label="item.storeName"
+            :value="item.storeId"
+          />
+        </el-select>
+      </el-form-item>
+      <div v-if="this.isMedicalMall">
+      <el-form-item label="审核状态">
+        <el-select style="width: 240px" v-model="queryParams.isAudit" placeholder="请选择审核状态" size="small" >
+          <el-option value="0" label="待审核" key="isAudit0">待审核</el-option>
+          <el-option value="1" label="审核通过" key="isAudit1">审核通过</el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="药品注册证书编号" prop="drugRegCertNo">
+        <el-input
+          v-model="queryParams.drugRegCertNo"
+          placeholder="请输入药品注册证书编号"
+          clearable
+          size="small"
+
+        />
+      </el-form-item>
+
+      <el-form-item label="通用名称" prop="commonName">
+        <el-input
+          v-model="queryParams.commonName"
+          placeholder="请输入通用名称"
+          clearable
+          size="small"
+
+        />
+      </el-form-item>
+
+      <el-form-item label="剂型" prop="dosageForm">
+        <el-input
+          v-model="queryParams.dosageForm"
+          placeholder="请输入剂型"
+          clearable
+          size="small"
+
+        />
+      </el-form-item>
+
+      <el-form-item label="单价" prop="unitPrice">
+        <el-input
+          v-model="queryParams.unitPrice"
+          placeholder="请输入单价"
+          clearable
+          size="small"
+
+        />
+      </el-form-item>
+
+      <el-form-item label="批号" prop="batchNumber">
+        <el-input
+          v-model="queryParams.batchNumber"
+          placeholder="请输入批号"
+          clearable
+          size="small"
+
+        />
+      </el-form-item>
+
+      <el-form-item label="上市许可持有人" prop="mah">
+        <el-input
+          v-model="queryParams.mah"
+          placeholder="请输入上市许可持有人"
+          clearable
+          size="small"
+
+        />
+      </el-form-item>
+
+      <el-form-item label="持有人地址" prop="mahAddress">
+        <el-input
+          v-model="queryParams.mahAddress"
+          placeholder="请输入持有人地址"
+          clearable
+          size="small"
+
+        />
+      </el-form-item>
+
+      <el-form-item label="生产企业" prop="manufacturer">
+        <el-input
+          v-model="queryParams.manufacturer"
+          placeholder="请输入生产企业"
+          clearable
+          size="small"
+
+        />
+      </el-form-item>
+
+      <el-form-item label="生产企业地址" prop="manufacturerAddress">
+        <el-input
+          v-model="queryParams.manufacturerAddress"
+          placeholder="请输入生产企业地址"
+          clearable
+          size="small"
+
+        />
+      </el-form-item>
+
+      <el-form-item label="功能主治" prop="indications">
+        <el-input
+          v-model="queryParams.indications"
+          placeholder="请输入功能主治"
+          clearable
+          size="small"
+
+        />
+      </el-form-item>
+
+      <el-form-item label="用法用量" prop="dosage">
+        <el-input
+          v-model="queryParams.dosage"
+          placeholder="请输入用法用量"
+          clearable
+          size="small"
+
+        />
+      </el-form-item>
+
+      <el-form-item label="不良反应" prop="adverseReactions">
+        <el-input
+          v-model="queryParams.adverseReactions"
+          placeholder="请输入不良反应"
+          clearable
+          size="small"
+
+        />
+      </el-form-item>
+
+      <el-form-item label="禁忌" prop="contraindications">
+        <el-input
+          v-model="queryParams.contraindications"
+          placeholder="请输入禁忌"
+          clearable
+          size="small"
+
+        />
+      </el-form-item>
+
+      <el-form-item label="注意事项" prop="precautions">
+        <el-input
+          v-model="queryParams.precautions"
+          placeholder="请输入注意事项"
+          clearable
+          size="small"
+
+        />
+      </el-form-item>
+      </div>
+      <!-- <el-form-item label="状态" prop="isShow">
+         <el-select style="width: 240px" v-model="queryParams.isShow" placeholder="请选择状态" clearable size="small" >
+         <el-option
+                v-for="item in isShowOptions"
+                :key="item.dictValue"
+                :label="item.dictLabel"
+                :value="item.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-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['store:storeProduct:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="multiple"
+          @click="handleUpdate"
+          v-hasPermi="['store:storeProduct:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['store:storeProduct:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="info"
+          plain
+          icon="el-icon-upload2"
+          size="mini"
+          @click="handleImport"
+          v-hasPermi="['store:storeProduct:import']"
+        >导入</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['store:storePayment:export']"
+        >导出</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="multiple"
+          @click="bulkCopy"
+          v-hasPermi="['store:storeProduct:bulkCopy']"
+        >批量复制</el-button>
+      </el-col>
+
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-tabs type="card" v-model="activeName" @tab-click="handleClick">
+      <el-tab-pane label="出售中" name="1"></el-tab-pane>
+      <el-tab-pane label="待上架" name="0"></el-tab-pane>
+    </el-tabs>
+
+    <el-table  height="500" border v-loading="loading" :data="storeProductList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="ID" align="center" prop="productId" />
+      <el-table-column label="商品图片" align="center" width="120">
+        <template slot-scope="scope">
+          <el-popover
+            placement="right"
+            title=""
+            trigger="hover">
+            <img slot="reference" :src="scope.row.image" width="100">
+            <img :src="scope.row.image" style="max-width: 150px;">
+          </el-popover>
+        </template>
+      </el-table-column>
+      <el-table-column label="商品名称" show-overflow-tooltip align="center" prop="productName" />
+      <el-table-column label="分类" align="center" prop="cateName" />
+      <el-table-column label="所属公司" align="center" prop="companyName" />
+      <el-table-column label="所属店铺" align="center" prop="storeName" v-if="this.isStores"/>
+      <el-table-column label="售价" align="center" prop="price" >
+        <template slot-scope="scope" >
+          <span v-if="scope.row.price!=null">{{scope.row.price.toFixed(2)}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="原价" align="center" prop="otPrice" >
+        <template slot-scope="scope" >
+          <span v-if="scope.row.otPrice!=null">{{scope.row.otPrice.toFixed(2)}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="销量" align="center" prop="sales" />
+      <el-table-column label="库存" align="center" prop="stock" />
+      <el-table-column label="类型" align="center" prop="productType" >
+        <template slot-scope="scope">
+          <el-tag prop="productType" v-for="(item, index) in productTypeOptions"    v-if="scope.row.productType==item.dictValue">{{item.dictLabel}}</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="isShow" >
+        <template slot-scope="scope">
+          <el-tag :type="getStatusType(scope.row)" prop="status">
+            {{ getStatusText(scope.row) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['store:storeProduct:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleCopy(scope.row)"
+            v-hasPermi="['store:storeProduct:copy']"
+          >复制</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="showOperLog(scope.row)"
+            v-hasPermi="['store:storeProduct:list']"
+            v-if="scope.row.isAudit===1"
+          >审核记录</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['store:storeProduct: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="open1" width="580px" append-to-body>
+      <el-form ref="form1" :model="form1" :rules="rules" label-width="80px">
+        <el-form-item label="商品状态" prop="status">
+          <el-radio-group v-model="form1.isShow">
+            <el-radio :label="item.dictValue" v-for="item in isShowOptions" >{{item.dictLabel}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="商城展示" prop="isDisplay">
+          <el-radio-group v-model="form1.isDisplay">
+            <el-radio :label="item.dictValue" v-for="item in isDisplayOptions" >{{item.dictLabel}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="所属公司" prop="companyId">
+          <el-select style="width: 220px" filterable multiple v-model="form1.companyId" placeholder="请选择公司名" clearable size="small">
+            <el-option
+              v-for="item in companyOptions"
+              :key="item.companyId"
+              :label="item.companyName"
+              :value="item.companyId"
+            />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm1">确 定</el-button>
+        <el-button @click="cancel1">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 添加或修改商品对话框 -->
+    <el-dialog :title="title" v-if="open" :fullscreen="isFullscreen" :visible.sync="open" width="1000px" append-to-body :show-close="false">
+      <template v-slot:title>
+        <div style="display: flex; justify-content: space-between; align-items: center;">
+          <span>{{ title }}</span>
+          <div>
+            <!-- 全屏按钮 -->
+            <el-button type="text" @click="handleFullScreen" size="middle">
+              <i class="el-icon-full-screen"></i>
+            </el-button>
+            <!--关闭按钮-->
+            <el-button type="text" @click="open = false">
+              <i class="el-icon-close"></i>
+            </el-button>
+          </div>
+        </div>
+      </template>
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+        <el-row >
+          <el-col :span="12">
+            <el-form-item label="商品名称" prop="productName">
+              <el-input v-model="form.productName" placeholder="请输入商品名称" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="商品分类" prop="cateId">
+              <treeselect v-model="form.cateId" :options="categoryOptions" :normalizer="normalizer" placeholder="请选择上级分类" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="关键字" prop="keyword">
+              <el-input v-model="form.keyword" placeholder="请输入关键字" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="单位名" prop="unitName">
+              <el-input v-model="form.unitName" placeholder="请输入单位名" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="品牌" prop="brand">
+              <el-input v-model="form.brand" placeholder="请输入品牌" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="食品生产许可证编码" prop="unitName">
+              <el-input v-model="form.foodProductionLicenseCode" placeholder="请输入食品生产许可证编码" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="生产企业名称" prop="manufacturer">
+              <el-input v-model="form.manufacturer" placeholder="请输入生产企业名称" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="产地" prop="originPlace">
+              <el-input v-model="form.originPlace" placeholder="请输入产地" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="净含量" prop="netContent">
+              <el-input v-model="form.netContent" placeholder="请输入净含量" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="保质期" prop="shelfLife">
+              <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" type="date" v-model="form.shelfLife" placeholder="请输入保质期" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="国产或进口" prop="domesticImported">
+              <el-select v-model="form.domesticImported" style="width: 23%;">
+                <el-option v-for="(item, index) in domesticImportedOptions"
+                           :value="item.dictValue" :key="item.dictValue" :label="item.dictLabel"/>
+              </el-select>
+            </el-form-item>
+          </el-col>
+
+        </el-row>
+        <el-row :gutter="10" v-show="false">
+          <el-col :span="12">
+            <el-form-item label="是否药品" prop="isDrug">
+              <el-radio-group v-model="form.isDrug">
+                <el-radio
+                  v-for="item in isDrugOptions"
+                  :key="item.dictValue"
+                  :label="item.dictValue"
+                >{{ item.dictLabel }}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <div v-if="form.isDrug === '1' ">
+          <el-form-item label="药品展示图" prop="drugImage">
+            <Material v-model="drugImageArr" type="image" :num="1" :width="150" :height="150" />
+          </el-form-item>
+          <div v-if="this.isMedicalMall">
+          <el-row>
+            <el-col :span="12">
+              <el-form-item label="药品注册证书编号" prop="drugRegCertNo">
+                <el-input v-model="form.drugRegCertNo" placeholder="请输入药品注册证书编号" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="通用名称" prop="commonName">
+                <el-input v-model="form.commonName" placeholder="请输入通用名称" />
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row>
+            <el-col :span="12">
+              <el-form-item label="剂型" prop="dosageForm">
+                <el-input v-model="form.dosageForm" placeholder="请输入剂型" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="单价" prop="unitPrice">
+                <el-input v-model="form.unitPrice" placeholder="请输入单价" type="number" />
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row>
+            <el-col :span="12">
+              <el-form-item label="批号" prop="batchNumber">
+                <el-input v-model="form.batchNumber" placeholder="请输入批号" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="规格" prop="prescribeSpec">
+                <el-input v-model="form.prescribeSpec" placeholder="请输入规格" />
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row>
+            <el-col :span="12">
+              <el-form-item label="上市许可持有人" prop="mah">
+                <el-input v-model="form.mah" placeholder="请输入上市许可持有人" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="持有人地址" prop="mahAddress">
+                <el-input v-model="form.mahAddress" placeholder="请输入上市许可持有人地址" />
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row>
+            <el-col :span="12">
+              <el-form-item label="生产企业" prop="manufacturer">
+                <el-input v-model="form.manufacturer" placeholder="请输入生产企业" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="企业地址" prop="manufacturerAddress">
+                <el-input v-model="form.manufacturerAddress" placeholder="请输入生产企业地址" />
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-form-item label="功能主治" prop="indications">
+            <el-input v-model="form.indications" type="textarea" placeholder="请输入功能主治" />
+          </el-form-item>
+
+          <el-form-item label="用法用量" prop="dosage">
+            <el-input v-model="form.dosage" type="textarea" placeholder="请输入用法用量" />
+          </el-form-item>
+
+          <el-form-item label="不良反应" prop="adverseReactions">
+            <el-input v-model="form.adverseReactions" type="textarea" placeholder="请输入不良反应" />
+          </el-form-item>
+
+          <el-form-item label="禁忌" prop="contraindications">
+            <el-input v-model="form.contraindications" type="textarea" placeholder="请输入禁忌" />
+          </el-form-item>
+
+          <el-form-item label="注意事项" prop="precautions">
+            <el-input v-model="form.precautions" type="textarea" placeholder="请输入注意事项" />
+          </el-form-item>
+        </div>
+        </div>
+<!--        <el-row>-->
+<!--          <el-col :span="24">-->
+<!--            <el-form-item label="商品简介" prop="productInfo">-->
+<!--              <el-input v-model="form.productInfo" type="textarea" :rows="2" placeholder="请输入商品简介" />-->
+<!--            </el-form-item>-->
+<!--          </el-col>-->
+<!--        </el-row>-->
+        <el-form-item label="商品图片" prop="image">
+          <Material v-model="imageArr" type="image" :num="1" :width="150" :height="150" />
+        </el-form-item>
+        <!--        <el-form-item label="商品视频" prop="video">
+                  <div>
+                    <el-upload
+                      ref="upload"
+                      class="upload-demo"
+                      :action="uploadUrl"
+                      :on-success="handleSuccess"
+                      :before-upload="beforeUpload"
+                      :limit="1"
+                      :accept="videoAccept"
+                    >
+                      <el-button size="small" type="primary">点击上传视频</el-button>
+                    </el-upload>
+                    <video v-if="form.video" :src="form.video" controls style="max-width: 300px; max-height: 300px; margin-top: 10px"></video>
+                  </div>
+                </el-form-item>-->
+        <el-form-item label="轮播图" prop="sliderImage">
+          <Material v-model="photoArr" type="image" :num="10" :width="150" :height="150" />
+        </el-form-item>
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="商品规格:" props="specType">
+              <el-radio-group v-model="form.specType" >
+                <el-radio :label="0" class="radio">单规格</el-radio>
+                <el-radio :label="1">多规格</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <!-- 多规格添加-->
+          <el-col :span="24" v-if="form.specType === 1" class="noForm" >
+            <el-col :span="24">
+              <el-form-item label="选择规格:" prop="">
+                <div  class="acea-row row-middle">
+                  <el-select v-model="form.selectRule" style="width: 23%;">
+                    <el-option v-for="(item, index) in ruleList" :value="item.ruleName" :key="index">{{ item.ruleName }}</el-option>
+                  </el-select>
+                  <el-button style="margin-left:10px;" type="primary" class="mr20" @click="confirm">确认</el-button>
+                </div>
+              </el-form-item>
+            </el-col>
+
+            <el-col :span="24">
+              <el-form-item v-if="attrs!=null&&attrs.length!==0">
+                <div  v-for="(item, index) in attrs" :key="index">
+                  <div class="acea-row row-middle"><span class="mr5">{{item.value}}</span>
+                    <i class="el-icon-circle-close"  @click="handleRemoveRole(index)"></i>
+                  </div>
+                  <div class="rulesBox">
+                    <el-tag type="dot" closable color="primary" v-for="(j, indexn) in item.detail" :key="indexn" :name="j" class="mr20" @close="handleRemove2(item.detail,indexn)">{{j}}</el-tag>
+                    <el-input placeholder="请输入属性名称" v-model="item.detail.attrsVal"
+                              style="width: 200px">
+                      <el-button slot="append" type="primary" @click="createAttr(item.detail.attrsVal,index)">添加</el-button>
+                    </el-input>
+                  </div>
+                </div>
+              </el-form-item>
+            </el-col>
+
+            <el-col :span="24" v-if="createBnt">
+              <el-form-item>
+                <el-button type="primary" size="small" icon="md-add" @click="addBtn" class="mr15">添加新规格</el-button>
+                <el-button type="success" size="small"  @click="generate">立即生成</el-button>
+              </el-form-item>
+            </el-col>
+            <el-col :span="24" v-if="showIput">
+              <el-col  :xl="6" :lg="9" :md="10" :sm="24" :xs="24" >
+                <el-form-item label="规格:">
+                  <el-input  placeholder="请输入规格" v-model="formDynamic.attrsName"  />
+                </el-form-item>
+              </el-col>
+              <el-col  :xl="6" :lg="9" :md="10" :sm="24" :xs="24">
+                <el-form-item label="规格值:">
+                  <el-input v-model="formDynamic.attrsVal" placeholder="请输入规格值"  />
+                </el-form-item>
+              </el-col>
+              <el-col :xl="6" :lg="5" :md="10" :sm="24" :xs="24" >
+                <el-button type="primary"    @click="createAttrName">确定</el-button>
+                <el-button type="danger" @click="closeAttrName" >取消</el-button>
+              </el-col>
+            </el-col>
+            <!-- 多规格设置-->
+            <el-col :xl="24" :lg="24" :md="24" :sm="24" :xs="24" v-if="manyFormValidate!=null&&manyFormValidate.length">
+              <!-- 多规格表格-->
+              <el-col :span="24">
+                <el-form-item label="商品属性:" class="labeltop">
+
+                  <el-table :data="manyFormValidate" size="small" style="width: 90%;" border>
+                    <el-table-column type="myindex" v-for="(item,index) in form.header" :key="index"  :width="item.minWidth" :label="item.title" :property="item.slot" align="center">
+                      <template slot-scope="scope">
+                        <div v-if="scope.column.property == 'image'" align="center">
+                          <single-img v-model="scope.row[scope.column.property]" type="image" :num="1" :width="60" :height="60" />
+                        </div>
+                        <div v-else-if="scope.column.property.indexOf('value') != -1" align="center">
+                          {{ scope.row[scope.column.property] }}
+                        </div>
+                        <div v-else-if="scope.column.property == 'action'" align="center" >
+                          <a @click="delAttrTable(scope.$index)" align="center">删除</a>
+                        </div>
+                        <div v-else align="center">
+                          <el-input  v-model="scope.row[scope.column.property]" align="center" />
+                        </div>
+                      </template>
+                    </el-table-column>
+                  </el-table>
+
+                </el-form-item>
+              </el-col>
+            </el-col>
+          </el-col>
+
+          <!-- 单规格表格-->
+          <el-col :xl="23" :lg="24" :md="24" :sm="24" :xs="24" v-if="form.specType === 0" style="">
+            <el-form-item >
+              <el-table :data="oneFormValidate"  size="small" border>
+                <el-table-column prop="image" label="图片" align="center">
+                  <template slot-scope="scope">
+                    <single-img v-model="scope.row.image" type="image" :num="1" :width="60" :height="60" />
+                  </template>
+                </el-table-column>
+                <el-table-column prop="price" label="售价" align="center">
+                  <template slot-scope="scope">
+                    <el-input type="text" v-model="scope.row.price"/>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="agentPrice" label="代理价" align="center">
+                  <template slot-scope="scope">
+                    <el-input type="text" v-model="scope.row.agentPrice"/>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="cost" label="成本价" align="center">
+                  <template slot-scope="scope">
+                    <el-input type="text" v-model="scope.row.cost"/>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="otPrice" label="原价" align="center">
+                  <template slot-scope="scope">
+                    <el-input type="text" v-model="scope.row.otPrice"/>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="stock" label="库存" align="center">
+                  <template slot-scope="scope">
+                    <el-input type="text" v-model="scope.row.stock" maxlength="7"/>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="barCode" label="商品编号" width="130px" align="center">
+                  <template slot-scope="scope">
+                    <el-input type="text" v-model="scope.row.barCode"/>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="barCode" label="组合编号" width="130px" align="center">
+                  <template slot-scope="scope">
+                    <el-input type="text" v-model="scope.row.groupBarCode"/>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="weight" label="重量(KG)" align="center">
+                  <template slot-scope="scope">
+                    <el-input type="text" v-model="scope.row.weight"/>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="volume" label="体积(m³)" align="center">
+                  <template slot-scope="scope">
+                    <el-input type="text" v-model="scope.row.volume"/>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="volume" label="所需积分" align="center">
+                  <template slot-scope="scope">
+                    <el-input type="text" v-model="scope.row.integral"/>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="volume" label="一级返佣" align="center">
+                  <template slot-scope="scope">
+                    <el-input type="text" v-model="scope.row.brokerage"/>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="volume" label="二级返佣" align="center">
+                  <template slot-scope="scope">
+                    <el-input type="text" v-model="scope.row.brokerageTwo"/>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="volume" label="三级返佣" align="center">
+                  <template slot-scope="scope">
+                    <el-input type="text" v-model="scope.row.brokerageThree"/>
+                  </template>
+                </el-table-column>
+              </el-table>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="运费模板:" prop="tempId">
+              <div class="acea-row">
+                <el-select v-model="form.tempId"  class="mr20">
+                  <el-option v-for="(item,index) in templateList" :value="item.id" :key="index" :label="item.name">
+                  </el-option>
+                </el-select>
+              </div>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="商品详情" prop="description">
+          <editor ref="myeditor"   @on-text-change="updateText" />
+        </el-form-item>
+        <el-row>
+          <el-col :span="8">
+            <el-form-item label="商品状态" prop="isShow">
+              <el-radio-group v-model="form.isShow">
+                <el-radio :label="item.dictValue" v-for="item in isShowOptions" >{{item.dictLabel}}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="是否热卖" prop="isHot">
+              <el-radio-group v-model="form.isHot">
+                <el-radio :label="item.dictValue" v-for="item in isHotOptions" >{{item.dictLabel}}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="猜你喜欢" prop="isGood">
+              <el-radio-group v-model="form.isGood">
+                <el-radio :label="item.dictValue" v-for="item in isGoodOptions" >{{item.dictLabel}}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="8">
+            <el-form-item label="精品推荐" prop="isBest">
+              <el-radio-group v-model="form.isBest">
+                <el-radio :label="item.dictValue" v-for="item in isBestOptions" >{{item.dictLabel}}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="新品首发" prop="isNew">
+              <el-radio-group v-model="form.isNew">
+                <el-radio :label="item.dictValue" v-for="item in isNewOptions" >{{item.dictLabel}}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="返还积分">
+              <el-input-number  v-model="form.giveIntegral" :min="0" placeholder="请输入积分" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="8">
+            <el-form-item label="商城展示" prop="isDisplay">
+              <el-radio-group v-model="form.isDisplay">
+                <el-radio :label="item.dictValue" v-for="item in isDisplayOptions" >{{item.dictLabel}}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+
+            <el-form-item label="排序" prop="sort">
+              <el-input-number :min="0"  v-model="form.sort" placeholder="请输入排序" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="销量" prop="sales">
+              <el-input-number :min="0"  v-model="form.sales" placeholder="请输入销量" />
+            </el-form-item>
+          </el-col>
+
+        </el-row>
+        <el-form-item label="推广分类" prop="tuiCateId">
+          <el-select style="width: 240px" v-model="form.tuiCateId" placeholder="请选择推广分类" clearable size="small" >
+            <el-option
+              v-for="item in productTuiCateOptions"
+              :key="item.dictValue"
+              :label="item.dictLabel"
+              :value="item.dictValue"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="商品类型" prop="productType">
+          <el-select style="width: 240px" v-model="form.productType" placeholder="请选择商品类型" clearable size="small">
+            <el-option
+              v-for="item in productTypeOptions"
+              :key="item.dictValue"
+              :label="item.dictLabel"
+              :value="item.dictValue"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="所属公司">
+          <el-select style="width: 240px" v-model="form.companyIds" multiple placeholder="请选择企业" clearable size="small" >
+            <el-option
+              v-for="item in companyOptions"
+              :key="item.companyId"
+              :label="item.companyName"
+              :value="item.companyId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="所属店铺" prop="storeId" v-if="this.isStores">
+          <el-select style="width: 240px" v-model="form.storeId" placeholder="请选择店铺" clearable size="small" >
+            <el-option
+              v-for="item in storeOptions"
+              :key="item.storeId"
+              :label="item.storeName"
+              :value="item.storeId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="退货地址" prop="returnAddress">
+          <el-input v-model="form.returnAddress" type="textarea" :rows="1" placeholder="请输入退货地址" />
+        </el-form-item>
+        <el-form-item label="国药准字" v-if="form.productType==2" prop="prescribeCode">
+          <el-input v-model="form.prescribeCode" placeholder="请输入国药准字" />
+        </el-form-item>
+        <el-form-item label="规格" v-if="form.productType==2" prop="prescribeSpec">
+          <el-input v-model="form.prescribeSpec" placeholder="请输入规格" />
+        </el-form-item>
+        <el-form-item label="生产厂家" v-if="form.productType==2" prop="prescribeFactory">
+          <el-input v-model="form.prescribeFactory" placeholder="请输入生产厂家" />
+        </el-form-item>
+        <el-form-item label="处方名" v-if="form.productType==2" prop="prescribeName">
+          <el-input v-model="form.prescribeName" 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="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
+      <el-upload
+        ref="upload"
+        :limit="1"
+        accept=".xlsx, .xls"
+        :headers="upload.headers"
+        :action="upload.url + '?updateSupport=' + upload.updateSupport"
+        :disabled="upload.isUploading"
+        :on-progress="handleFileUploadProgress"
+        :on-success="handleFileSuccess"
+        :auto-upload="false"
+        drag
+      >
+        <i class="el-icon-upload"></i>
+        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
+        <div class="el-upload__tip text-center" slot="tip">
+          <div class="el-upload__tip" slot="tip">
+            <!--     <el-checkbox v-model="upload.updateSupport" /> 是否更新已经存在的数据 -->
+          </div>
+          <span>仅允许导入xls、xlsx格式文件。</span>
+          <el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;" @click="importTemplate">下载模板</el-link>
+        </div>
+      </el-upload>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitFileForm">确 定</el-button>
+        <el-button @click="upload.open = false">取 消</el-button>
+      </div>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+import {
+  genFormatAttr,
+  listStoreProduct,
+  getStoreProduct,
+  delStoreProduct,
+  copyStoreProduct,
+  addOrEdit,
+  exportStoreProduct,
+  importTemplate,
+  batchModify,bulkCopy
+} from "@/api/hisStore/storeProduct";
+import { getAllStoreProductCategory } from "@/api/hisStore/storeProductCategory";
+import { getAllStoreProductRule } from "@/api/hisStore/storeProductRule";
+import { getAllShippingTemplates } from "@/api/hisStore/shippingTemplates";
+import { getToken } from "@/utils/auth";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import Editor from '@/components/Editor/wangZm';
+import Material from '@/components/Material'
+import singleImg from '@/components/Material/single'
+import { getCompanyList } from "@/api/company/company";
+import { listStore } from '@/api/hisStore/store'
+export default {
+  name: "HisStoreProduct",
+  components: {
+    Treeselect,
+    Editor,
+    Material,
+    singleImg,
+  },
+  watch: {
+    imageArr: function(val) {
+      this.form.image = val.join(',')
+    },
+    photoArr: function(val) {
+      this.form.sliderImage = val.join(',')
+    },
+    drugImageArr: function(val) {
+      this.form.drugImage = val.join(',');
+    }
+  },
+  data() {
+    return {
+      isMedicalMall: this.$store.state.user.medicalMallConfig.medicalMall,
+      // isStores: this.$store.state.user.medicalMallConfig.stores,
+      isStores: true,
+      companyId: null,
+      storeId: null,
+      isAudit: null,
+      uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
+      //videoAccept:"video/*",
+      upload: {
+        // 是否显示弹出层
+        open: false,
+        // 弹出层标题
+        title: "",
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 设置上传的请求头部
+        headers: { Authorization: "Bearer " + getToken() },
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + "/store/storeProduct/importData"
+      },
+      // 添加药品相关字段
+      isDrugOptions: [
+        { dictValue: "0", dictLabel: "否" },
+        { dictValue: "1", dictLabel: "是" }
+      ],
+      // 添加药品相关字段
+      domesticImportedOptions: [
+        { dictValue: "0", dictLabel: "国产" },
+        { dictValue: "1", dictLabel: "进口" }
+      ],
+
+      // 药品展示图
+      drugImageArr: [],
+
+      productTuiCateOptions:[],
+      showIput: false,
+      createBnt:true,
+      // 规格数据
+      formDynamic: {
+        attrsName: '',
+        attrsVal: ''
+      },
+      open1: false,
+      form1: {},
+      isBtn: false,
+      columns: [],
+      attrs:[],
+      templateList:[],
+      ruleList:[],
+      // 多规格表格data
+      manyFormValidate: [],
+      // 单规格表格data
+      oneFormValidate: [
+        {
+          image: '',
+          price: 0,
+          cost: 0,
+          agentPrice: 0,
+          otPrice: 0,
+          stock: 0,
+          barCode: '',
+          weight: 0,
+          volume: 0,
+          integral: 0
+        }
+      ],
+      photoArr:[],
+      imageArr:[],
+      activeName:"1",
+      productTypeOptions:[],
+      isDisplayOptions:[],
+      isGoodOptions:[],
+      isNewOptions:[],
+      isBestOptions:[],
+      isHotOptions:[],
+      isShowOptions:[],
+      categoryOptions:[],
+      // 企业列表
+      companyOptions:[],
+      storeOptions:[],
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: false,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      isFullscreen: false,
+      // 总条数
+      total: 0,
+      // 商品表格数据
+      storeProductList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        productName: null,
+        productType: null,
+        isShow: "1",
+        barCode:null,
+        companyIds: null,
+        storeIds: null,
+        drugRegCertNo: null,
+        commonName: null,
+        dosageForm: null,
+        unitPrice: null,
+        batchNumber: null,
+        mah: null,
+        mahAddress: null,
+        manufacturer: null,
+        manufacturerAddress: null,
+        indications: null,
+        dosage: null,
+        adverseReactions: null,
+        contraindications: null,
+        precautions: null
+      },
+      // 表单参数
+      form: {},
+      storeForm: {isAudit:1,status:1},
+      // 表单校验
+      rules: {
+        image: [
+          { required: true, message: "商品图片不能为空", trigger: "blur" }
+        ],
+        sliderImage: [
+          { required: true, message: "轮播图不能为空", trigger: "blur" }
+        ],
+        productName: [
+          { required: true, message: "商品名称不能为空", trigger: "blur" }
+        ],
+        // productInfo: [
+        //   { required: true, message: "商品简介不能为空", trigger: "blur" }
+        // ],
+        // unitName: [
+        //   { required: true, message: "单位名不能为空", trigger: "blur" }
+        // ],
+        // keyword: [
+        //   { required: true, message: "关键字不能为空", trigger: "blur" }
+        // ],
+        cateId: [
+          { required: true, message: "分类id不能为空", trigger: "blur" }
+        ],
+        price: [
+          { required: true, message: "商品价格不能为空", trigger: "blur" }
+        ],
+        prescribeCode: [
+          { required: true, message: "国药准字不能为空", trigger: "blur" }
+        ],
+        prescribeSpec: [
+          { required: true, message: "规格不能为空", trigger: "blur" }
+        ],
+        prescribeFactory: [
+          { required: true, message: "生产厂家不能为空", trigger: "blur" }
+        ],
+        prescribeName: [
+          { required: true, message: "处方药不能为空", trigger: "blur" }
+        ],
+        companyIds: [
+          { required: true, message: "销售公司不能为空", trigger: "blur" }
+        ],
+        // 药品相关字段校验(仅在是药品时必填)
+        drugImage: [
+          { required: true, message: "药品展示图不能为空", trigger: "blur" }
+        ],
+        drugRegCertNo: [
+          { required: true, message: "药品注册证书编号不能为空", trigger: "blur" }
+        ],
+        commonName: [
+          { required: true, message: "通用名称不能为空", trigger: "blur" }
+        ],
+        dosageForm: [
+          { required: true, message: "剂型不能为空", trigger: "blur" }
+        ],
+        unitPrice: [
+          { required: true, message: "单价不能为空", trigger: "blur" }
+        ],
+        batchNumber: [
+          { required: true, message: "批号不能为空", trigger: "blur" }
+        ],
+        mah: [
+          { required: true, message: "上市许可持有人不能为空", trigger: "blur" }
+        ],
+        mahAddress: [
+          { required: true, message: "上市许可持有人地址不能为空", trigger: "blur" }
+        ],
+        // manufacturer: [
+        //   { required: true, message: "生产企业不能为空", trigger: "blur" }
+        // ],
+        manufacturerAddress: [
+          { required: true, message: "生产企业地址不能为空", trigger: "blur" }
+        ],
+        indications: [
+          { required: true, message: "功能主治不能为空", trigger: "blur" }
+        ],
+        dosage: [
+          { required: true, message: "用法用量不能为空", trigger: "blur" }
+        ],
+        adverseReactions: [
+          { required: true, message: "不良反应不能为空", trigger: "blur" }
+        ],
+        contraindications: [
+          { required: true, message: "禁忌不能为空", trigger: "blur" }
+        ],
+        precautions: [
+          { required: true, message: "注意事项不能为空", trigger: "blur" }
+        ],
+        // storeId :[
+        //   { required: true, message: "所属店铺不能为空", trigger: "blur"}
+        // ],
+      }
+    };
+  },
+  created() {
+    this.getDicts("store_product_tui_cate").then((response) => {
+      this.productTuiCateOptions = response.data;
+    });
+    this.getDicts("store_product_enable").then((response) => {
+      this.isNewOptions = response.data;
+      this.isBestOptions = response.data;
+      this.isHotOptions = response.data;
+      this.isGoodOptions=response.data;
+      this.isDisplayOptions=response.data;
+    });
+    this.getDicts("store_product_type").then((response) => {
+      this.productTypeOptions = response.data;
+      if(!this.isMedicalMall &&
+      this.productTypeOptions.length === 4){
+        //删除后两项
+        this.productTypeOptions.splice(2,2);
+      }
+    });
+    this.getDicts("store_product_is_show").then((response) => {
+      this.isShowOptions = response.data;
+    });
+    getAllShippingTemplates().then(response => {
+      this.templateList =response.data;
+    });
+    getAllStoreProductRule().then(response => {
+      this.ruleList =response.data;
+    });
+    getCompanyList().then(response => {
+      this.companyOptions = response.data;
+    });
+    listStore(this.storeForm).then(response => {
+      this.storeOptions = response.rows;
+    });
+    this.getTreeselect();
+    this.getList();
+  },
+  methods: {
+    getStatusText(row) {
+      console.log()
+      if (row.isAudit == 0) {
+        return '待审核';
+      }
+      const option = this.isShowOptions.find(item => item.dictValue == row.isShow);
+      return option ? option.dictLabel : '未知状态';
+    },
+
+    getStatusType(row) {
+      console.log(row)
+      if (row.isAudit == 0) {
+        return 'warning';
+      }
+      // 根据你的业务逻辑返回不同的类型,如:success, danger, info等
+      return row.isShow == 1 ? 'success' : 'info';
+    },
+    cancel1(){
+      this.open1 = false;
+    },
+    submitForm1(){
+      let param = {}
+      param.productId = this.ids;
+      param.goodsStatus = this.form1.isShow;
+      param.goodsIsShow = this.form1.isDisplay;
+      param.companyIds = this.form1.companyId.join(',');
+      batchModify(param).then(res=>{
+        if(res.code === 200){
+          this.$message.success("批量修改成功");
+          this.getList();
+        }
+      }).finally(()=>{
+        this.open1 = false;
+        this.form1.isShow = null;
+        this.form1.isDisplay = null;
+        this.form1.companyId = null;
+      })
+    },
+    handleFullScreen(){
+      this.isFullscreen = !this.isFullscreen;
+    },
+    handleSuccess(response, file) {
+      // 上传成功后的回调函数
+      this.myloading.close();
+      //this.form.video = response.url;
+      this.$refs.upload.clearFiles();
+    },
+    beforeUpload(file) {
+      // 上传前的钩子函数,可以在这里对文件进行处理
+      // 返回 false 则取消上传
+
+      // 例如限制文件大小
+      const isLt2M = file.size / 1024 / 1024 < 200;
+      if (!isLt2M) {
+        this.$message.error('上传视频文件大小不能超过 200MB!');
+        return false;
+      }
+      this.myloading = this.$loading({
+        lock: true,
+        text: '上传中',
+        spinner: 'el-icon-loading',
+        background: 'rgba(0, 0, 0, 0.7)'
+      });
+
+    },
+    // 提交上传文件
+    submitFileForm() {
+      this.$refs.upload.submit();
+    },
+    // 文件上传中处理
+    handleFileUploadProgress(event, file, fileList) {
+      this.upload.isUploading = true;
+    },
+    // 文件上传成功处理
+    handleFileSuccess(response, file, fileList) {
+      this.upload.open = false;
+      this.upload.isUploading = false;
+      this.$refs.upload.clearFiles();
+      this.$alert(response.msg, "导入结果", { dangerouslyUseHTMLString: true });
+      this.getList();
+    },
+    handleImport() {
+      this.upload.title = "商品导入";
+      this.upload.open = true;
+    },
+    importTemplate() {
+      importTemplate().then(response => {
+        this.download(response.msg);
+      });
+    },
+    // 删除表格中的属性
+    delAttrTable (index) {
+      this.manyFormValidate.splice(index, 1);
+    },
+    addBtn () {
+      this.clearAttr();
+      this.createBnt = false;
+      this.showIput = true;
+    },
+    //生成SKU
+    generate () {
+      var prodoct = this.form.productId?this.form.productId:0;
+      genFormatAttr(prodoct, { attrs: this.attrs }).then(res => {
+        if(this.form.specType === 0){
+          this.oneFormValidate = res.value;
+          this.form.header = res.header;
+          let header = res.header;
+          header.pop();
+          this.oneFormValidate.map((item) => {
+            if(this.imageArr.length>0){
+              item.image = this.imageArr[0]
+            }
+          });
+        }else if(this.form.specType === 1) {
+          this.manyFormValidate = res.value;
+          let headerdel = {
+            title: '操作',
+            slot: 'action',
+            fixed: 'right',
+            width: 220
+          };
+          res.header.push(headerdel);
+          this.form.header = res.header;
+          let header = res.header;
+          header.pop();
+          // this.manyFormValidate.map((item) => {
+          //   if(this.imageArr.length>0){
+          //     item.image = this.imageArr[0]
+          //   }
+          // });
+        }
+
+      }).catch(res => {
+      })
+    },
+    // 取消添加新规格
+    closeAttrName () {
+      this.showIput = false;
+      this.createBnt = true;
+    },
+    clearAttr () {
+      this.formDynamic.attrsName = '';
+      this.formDynamic.attrsVal = '';
+    },
+    // 删除规格
+    handleRemoveRole (index) {
+      this.attrs.splice(index, 1);
+      this.manyFormValidate.splice(index, 1);
+    },
+    // 删除属性
+    handleRemove2 (item, index) {
+      item.splice(index, 1);
+    },
+    // 添加规则名称
+    createAttrName () {
+      if (this.formDynamic.attrsName && this.formDynamic.attrsVal) {
+        let data = {
+          value: this.formDynamic.attrsName,
+          detail: [
+            this.formDynamic.attrsVal
+          ]
+        };
+        this.attrs.push(data);
+        var hash = {};
+        this.attrs = this.attrs.reduce(function (item, next) {
+          hash[next.value] ? '' : hash[next.value] = true && item.push(next);
+          return item
+        }, [])
+        this.clearAttr();
+        this.showIput = false;
+        this.createBnt = true;
+      } else {
+        this.$message.warning('请添加完整的规格!');
+      }
+    },
+    // 添加属性
+    createAttr (num, idx) {
+      if (num) {
+        this.attrs[idx].detail.push(num);
+        var hash = {};
+        this.attrs[idx].detail = this.attrs[idx].detail.reduce(function (item, next) {
+          hash[next] ? '' : hash[next] = true && item.push(next);
+          return item
+        }, [])
+      } else {
+        this.$message.warning('请添加属性!');
+      }
+    },
+    confirm () {
+      let that = this;
+      that.createBnt = true;
+      if (that.form.selectRule==null||that.form.selectRule.trim().length <= 0) {
+        return this.$message({
+          message:'请选择属性',
+          type: 'error'
+        });
+      }
+      that.ruleList.forEach(function (item, index) {
+        if (item.ruleName === that.form.selectRule) {
+          that.attrs =JSON.parse( item.ruleValue);
+
+        }
+      });
+
+    },
+    updateText(text){
+      this.form.description=text
+    },
+    handleClick(tab, event) {
+      this.queryParams.isShow=tab.name;
+      this.getList();
+    },
+    /** 转换商品分类数据结构 */
+    normalizer(node) {
+      if (node.children && !node.children.length) {
+        delete node.children;
+      }
+      return {
+        id: node.cateId,
+        label: node.cateName,
+        children: node.children
+      };
+    },
+    getTreeselect() {
+      getAllStoreProductCategory().then(response => {
+        this.categoryOptions = [];
+        debugger;
+        const data = this.handleTree(response.data, "cateId", "pid");
+        this.categoryOptions=data;
+      });
+    },
+    /** 查询商品列表 */
+    getList() {
+      this.loading = true;
+      listStoreProduct(this.queryParams).then(response => {
+        this.storeProductList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        productId: null,
+        image: null,
+        video: null,
+        sliderImage: null,
+        productName: null,
+        productInfo: null,
+        keyword: null,
+        barCode: null,
+        cateId: null,
+        price: null,
+        vipPrice: null,
+        otPrice: null,
+        postage: null,
+        unitName: null,
+        sort: null,
+        sales: null,
+        stock: null,
+        isShow: "0",
+        isHot: "0",
+        isBenefit: "0",
+        isBest: "0",
+        isNew: "0",
+        description: null,
+        createTime: null,
+        updateTime: null,
+        isPostage: null,
+        foodProductionLicenseCode: null,
+        brand: null,
+        isDel: null,
+        giveIntegral: null,
+        cost: null,
+        isGood: "0",
+        browse: null,
+        codePath: null,
+        tempId: "",
+        specType: 0,
+        isIntegral: null,
+        integral: null,
+        productType: "1",
+        prescribeCode: null,
+        prescribeSpec: null,
+        prescribeFactory: null,
+        prescribeName: null,
+        isDisplay:"1",
+        companyIds:[],
+        returnAddress: "", // 退货地址
+        isDrug: "0", // 是否药品
+        originPlace: "", // 原产地
+        netContent: "", // 净含量
+        shelfLife: "", // 有效日期
+        domesticImported: "", // 国产或进口
+        drugImage: null, // 药品展示图
+        drugRegCertNo: null, // 药品注册证书编号
+        commonName: null, // 通用名称
+        dosageForm: null, // 剂型
+        unitPrice: null, // 单价
+        batchNumber: null, // 批号
+        mah: null, // 上市许可持有人
+        mahAddress: null, // 上市许可持有人地址
+        manufacturer: null, // 生产企业
+        manufacturerAddress: null, // 生产企业地址
+        indications: null, // 功能主治
+        dosage: null, // 用法用量
+        adverseReactions: null, // 不良反应
+        contraindications: null, // 禁忌
+        precautions: null // 注意事项
+      };
+      // 重置药品展示图
+      this.drugImageArr = [];
+      this.resetForm("form");
+      this.oneFormValidate = [
+        {
+          image: '',
+          price: 0,
+          agentPrice: 0,
+          cost: 0,
+          otPrice: 0,
+          stock: 0,
+          barCode: '',
+          weight: 0,
+          volume: 0,
+          integral: 0,
+          brokerage:0,
+          brokerageTwo:0
+        }
+      ]
+      this.attrs=[];
+      this.photoArr=[];
+      this.imageArr=[];
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.queryParams.companyIds = this.companyId +''
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      const showFlag = this.queryParams.isShow
+      this.queryParams = {
+        pageNum:1,
+        pageSize:10,
+        isShow:showFlag
+      }
+      this.companyId = '';
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.productId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+
+      this.open = true;
+      this.title = "添加商品";
+      setTimeout(() => {
+        this.$refs.myeditor.setText("");
+      }, 500);
+
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      if(this.ids.length > 1){
+        this.title = "批量修改商品";
+        this.open1 = true;
+        return;
+      }
+      var that=this;
+      this.reset();
+      const productId = row.productId || this.ids
+      getStoreProduct(productId).then(response => {
+        this.form = response.data;
+        this.form.isShow = response.data.isShow.toString();
+        this.form.isHot = response.data.isHot.toString();
+        this.form.isGood = response.data.isGood.toString();
+        this.form.isBest = response.data.isBest.toString();
+        this.form.isNew = response.data.isNew.toString();
+        this.form.productType = response.data.productType.toString();
+        this.form.isDisplay = response.data.isDisplay.toString();
+        if(this.form.tuiCateId!=null){
+          this.form.tuiCateId = response.data.tuiCateId.toString();
+        }
+        // this.form.isDrug = response.data.isDrug ? response.data.isDrug.toString() : "1";
+        this.form.isDrug = response.data.isDrug === 0 ? "0" : (response.data.isDrug ? response.data.isDrug.toString() : "1");
+        if (this.form.drugImage != null) {
+          this.drugImageArr = this.form.drugImage.split(",");
+        }
+
+        //组装attrs数据
+        if(response.attrs!=null){
+          this.attrs=[];
+          response.attrs.forEach(function (item, index) {
+            var data={value:item.attrName,detail:item.attrValues.split(',')}
+            that.attrs.push(data);
+          });
+        }
+        // 组装companyIds
+        if (response.data.companyIds != null && response.data.companyIds != undefined && response.data.companyIds.length > 0) {
+          this.form.companyIds = response.data.companyIds.split(',').map(Number);
+        }
+        setTimeout(() => {
+          that.generate();
+        }, 200);
+        if(this.form.specType === 0){
+          that.manyFormValidate = [];
+        }else {
+          that.createBnt = true;
+          that.oneFormValidate = [
+            {
+              image: '',
+              price: 0,
+              agentPrice: 0,
+              cost: 0,
+              otPrice: 0,
+              stock: 0,
+              barCode: '',
+              weight: 0,
+              volume: 0,
+              integral: 0,
+              brokerage:0,
+              brokerageTwo:0
+            }
+          ]
+        }
+        setTimeout(() => {
+          if(this.form.description==null){
+            this.$refs.myeditor.setText("");
+          }
+          else{
+            this.$refs.myeditor.setText(this.form.description);
+          }
+        }, 200);
+        if(this.form.image!=null){
+          this.imageArr=this.form.image.split(",");
+        }
+        if(this.form.sliderImage!=null){
+          this.photoArr=this.form.sliderImage.split(",");
+        }
+        this.open = true;
+        this.title = "修改商品";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if(this.form.specType ===0 ){
+            this.form.items = [];
+            this.form.values = this.oneFormValidate;
+          }else{
+            this.form.items = this.attrs;
+            this.form.values = this.manyFormValidate;
+          }
+          if(this.form.specType === 1 && this.manyFormValidate.length===0){
+            return this.$message.warning('请点击生成规格!');
+          }
+          // 组装companyIds
+          if (this.form.companyIds != null && this.form.companyIds != undefined) {
+            this.form.companyIds = this.form.companyIds.join(',');
+          }
+          addOrEdit(this.form).then(response => {
+            if (response.code === 200) {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            }
+          }).catch(error => {
+            this.$message.error('请求失败: ' + error.message)
+          });
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const productIds = row.productId || this.ids;
+      this.$confirm('是否确认删除商品编号为"' + productIds + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return delStoreProduct(productIds);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(function() {});
+    },
+    /** 复制按钮操作 */
+    handleCopy(row) {
+      const productIds = row.productId || this.ids;
+      this.$confirm('是否确认复制商品编号为"' + productIds + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return copyStoreProduct(productIds);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("复制成功");
+      }).catch(function() {});
+    },
+    /** 复制按钮操作 */
+    bulkCopy(row) {
+      const productIds = row.productId || this.ids;
+      this.$confirm('是否确认复制商品编号为"' + productIds + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return bulkCopy(productIds);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("复制成功");
+      }).catch(function() {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有商品数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return exportStoreProduct(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+      }).catch(function() {});
+    }
+  }
+};
+</script>

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

@@ -1282,6 +1282,14 @@ export default {
     /** 重置按钮操作 */
     resetQuery() {
       this.resetForm("queryForm");
+      this.queryParams = {
+        pageNum:1,
+        pageSize:10,
+        isShow:1,
+        isAudit:0
+      }
+      this.companyId = ''
+      this.storeId = ''
       this.handleQuery();
     },
     // 多选框选中数据

Some files were not shown because too many files changed in this diff