Parcourir la source

Merge branch 'refs/heads/master' into ScrmStore

# Conflicts:
#	src/api/hisStore/city.js
#	src/api/hisStore/store.js
#	src/views/course/coursePlaySourceConfig/index.vue
#	src/views/course/courseTrafficLog/index.vue
#	src/views/hisStore/adv/index.vue
#	src/views/hisStore/store/audit.vue
#	src/views/hisStore/store/index.vue
#	src/views/hisStore/storeProduct/index.vue
chenguo il y a 6 jours
Parent
commit
113979727f
81 fichiers modifiés avec 12935 ajouts et 1074 suppressions
  1. 1 1
      .env.prod-hdt
  2. 40 0
      .env.prod-hyt
  3. 1 1
      .env.prod-jnmy
  4. 1 1
      .env.prod-kyt
  5. 1 1
      .env.prod-sxjz
  6. 1 1
      .env.prod-syysy
  7. 1 0
      package.json
  8. 25 3
      src/api/company/statistics.js
  9. 53 0
      src/api/complaint/category.js
  10. 75 0
      src/api/complaint/complaint.js
  11. 18 0
      src/api/course/courseWatchComment.js
  12. 10 1
      src/api/course/fsCourseProductOrder.js
  13. 8 0
      src/api/course/videoResource.js
  14. 53 0
      src/api/fastGpt/fastGptChatReplaceText.js
  15. 62 0
      src/api/fastGpt/fastGptKeywordSend.js
  16. 53 0
      src/api/fastGpt/fastgptChatArtificialWords.js
  17. 70 0
      src/api/fastGpt/fastgptEventLogTotal.js
  18. 44 0
      src/api/food/record.js
  19. 53 0
      src/api/his/fsFirstDiagnosis.js
  20. 27 0
      src/api/his/inquiryPatient.js
  21. 53 0
      src/api/hisStore/adv.js
  22. 76 0
      src/api/hisStore/express.js
  23. 53 0
      src/api/hisStore/shippingTemplatesFree.js
  24. 53 0
      src/api/hisStore/shippingTemplatesRegion.js
  25. 61 0
      src/api/medical/indicator.js
  26. 64 0
      src/api/medical/report.js
  27. 69 0
      src/api/medical/reportIndicator.js
  28. 61 0
      src/api/medical/unit.js
  29. 69 0
      src/api/recharge/template.js
  30. 49 0
      src/api/saler/competitorInfo.js
  31. 46 0
      src/api/saler/productInfo.js
  32. 8 1
      src/api/system/config.js
  33. 81 0
      src/api/todo/todoItems.js
  34. 53 0
      src/api/user/complaint.js
  35. BIN
      src/assets/logo/hcl.png
  36. BIN
      src/assets/logo/hyt.png
  37. 264 0
      src/components/City/index.vue
  38. 4 0
      src/store/modules/user.js
  39. 92 87
      src/utils/cos.js
  40. 69 52
      src/utils/obs.js
  41. 17 2
      src/views/company/company/index.vue
  42. 260 0
      src/views/components/his/inquiryOrderDetails.vue
  43. 2 2
      src/views/components/his/storeOrderDetails.vue
  44. 99 5
      src/views/course/coursePlaySourceConfig/index.vue
  45. 151 197
      src/views/course/courseTrafficLog/index.vue
  46. 228 95
      src/views/course/courseWatchComment/index.vue
  47. 63 13
      src/views/course/fsCourseProductOrder/index.vue
  48. 6 6
      src/views/course/userCoursePeriod/index.vue
  49. 26 1
      src/views/course/userCoursePeriod/statistics.vue
  50. 527 227
      src/views/course/videoResource/index.vue
  51. 340 0
      src/views/fastGpt/fastGptChatReplaceText/index.vue
  52. 113 0
      src/views/fastGpt/fastGptKeywordSend/fastGptKeyWordDetails.vue
  53. 529 0
      src/views/fastGpt/fastGptKeywordSend/index.vue
  54. 341 0
      src/views/fastGpt/fastgptChatArtificialWords/index.vue
  55. 333 0
      src/views/fastGpt/fastgptEventLogTotal/index.vue
  56. 302 0
      src/views/food/record/index.vue
  57. 30 2
      src/views/his/company/index.vue
  58. 369 0
      src/views/his/fsFirstDiagnosis/index.vue
  59. 252 0
      src/views/his/statistics/ipadStatic.vue
  60. 252 0
      src/views/his/statistics/tokenStatic.vue
  61. 5 71
      src/views/his/user/index.vue
  62. 35 15
      src/views/his/user/indexProject.vue
  63. 207 185
      src/views/hisStore/adv/index.vue
  64. 394 0
      src/views/hisStore/express/index.vue
  65. 443 0
      src/views/hisStore/shippingTemplates/index.vue
  66. 366 0
      src/views/hisStore/shippingTemplatesFree/index.vue
  67. 402 0
      src/views/hisStore/shippingTemplatesRegion/index.vue
  68. 328 0
      src/views/medical/indicator/index.vue
  69. 910 0
      src/views/medical/report/index.vue
  70. 468 0
      src/views/medical/reportIndicator/index.vue
  71. 300 0
      src/views/medical/unit/index.vue
  72. 1 1
      src/views/qw/sopTemp/updateSopTemp.vue
  73. 272 0
      src/views/saler/competitorInfo/index.vue
  74. 296 0
      src/views/saler/productInfo/index.vue
  75. 315 97
      src/views/system/config/config.vue
  76. 4 4
      src/views/system/config/config2.vue
  77. 8 2
      src/views/system/role/index.vue
  78. 619 0
      src/views/todo/todoItems/index.vue
  79. 308 0
      src/views/user/complaint/category/index.vue
  80. 437 0
      src/views/user/complaint/index.vue
  81. 755 0
      src/views/user/rechargeTemplate/index.vue

+ 1 - 1
.env.prod-hdt

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

+ 40 - 0
.env.prod-hyt

@@ -0,0 +1,40 @@
+# 页面标题
+VUE_APP_TITLE =宏医堂互联网医院管理系统
+# 首页菜单标题
+VUE_APP_TITLE_INDEX =宏医堂互联网医院
+# 公司名称
+VUE_APP_COMPANY_NAME =易行健和泰(湖北)健康咨询有限公司
+# ICP备案号
+VUE_APP_ICP_RECORD =鄂ICP备2025116549号-1
+# ICP网站访问地址
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/hyt.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 = hyt-hw079058881
+# 存储桶配置
+VUE_APP_COS_BUCKET = fzhyt-1323137866
+# 存储桶配置
+VUE_APP_COS_REGION = ap-chongqing
+# 线路一地址
+VUE_APP_VIDEO_LINE_1 = https://fzhyttcpv.ylrzcloud.com
+# 线路二地址
+VUE_APP_VIDEO_LINE_2 = https://hytobs.ylrztop.com
+
+# 开发环境配置
+ENV = 'production'
+
+# FS管理系统/开发环境
+VUE_APP_BASE_API = '/prod-api'
+
+#默认 1、会员 2、企微
+VUE_APP_COURSE_DEFAULT = 1
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 1 - 1
.env.prod-jnmy

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

+ 1 - 1
.env.prod-kyt

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

+ 1 - 1
.env.prod-sxjz

@@ -1,7 +1,7 @@
 # 页面标题
 VUE_APP_TITLE =互联网医院管理系统
 # 首页菜单标题
-VUE_APP_TITLE_INDEX =陕西今正
+VUE_APP_TITLE_INDEX =挑宝网
 # 公司名称
 VUE_APP_COMPANY_NAME =银川鑫泰互联网医院有限公司
 # ICP备案号

+ 1 - 1
.env.prod-syysy

@@ -19,7 +19,7 @@ VUE_APP_OBS_SERVER = https://obs.cn-north-4.myhuaweicloud.com
 # 存储桶配置
 VUE_APP_OBS_BUCKET = syysy-hw079058881
 # 存储桶配置
-VUE_APP_COS_BUCKET = syysy -1323137866
+VUE_APP_COS_BUCKET = syysy-1323137866
 # 存储桶配置
 VUE_APP_COS_REGION = ap-chongqing
 # 线路一地址

+ 1 - 0
package.json

@@ -35,6 +35,7 @@
     "build:prod-fby": "vue-cli-service build --mode prod-fby",
     "build:prod-zkzh": "vue-cli-service build --mode prod-zkzh",
     "build:prod-syysy": "vue-cli-service build --mode prod-syysy",
+    "build:prod-hyt": "vue-cli-service build --mode prod-hyt",
     "preview": "node build/index.js --preview",
     "lint": "eslint --ext .js,.vue src"
   },

+ 25 - 3
src/api/company/statistics.js

@@ -100,7 +100,7 @@ export function exportCustomer(query) {
   })
 }
 
- 
+
 export function customerVisit(query) {
   return request({
     url: '/company/statistics/customerVisit',
@@ -116,6 +116,28 @@ export function exportCustomerVisit(query) {
   })
 }
 
-
-
+export function ipadStaticTotal(dateTime) {
+  return request({
+    url: '/company/statistics/ipadStaticTotal/' + dateTime,
+    method: 'get'
+  })
+}
+export function exportIpadStaticByTime(dateTime) {
+  return request({
+    url: '/company/statistics/exportIpadStaticByTime/' + dateTime,
+    method: 'get'
+  })
+}
+export function tokenStaticTotal(dateTime) {
+  return request({
+    url: '/company/statistics/tokenStaticTotal/' + dateTime,
+    method: 'get'
+  })
+}
+export function exportTokenStaticByTime(dateTime) {
+  return request({
+    url: '/company/statistics/exportTokenStaticByTime/' + dateTime,
+    method: 'get'
+  })
+}
 

+ 53 - 0
src/api/complaint/category.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询投诉分类列表
+export function listCategory(query) {
+  return request({
+    url: '/complaint/category/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询投诉分类详细
+export function getCategory(id) {
+  return request({
+    url: '/complaint/category/' + id,
+    method: 'get'
+  })
+}
+
+// 新增投诉分类
+export function addCategory(data) {
+  return request({
+    url: '/complaint/category',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改投诉分类
+export function updateCategory(data) {
+  return request({
+    url: '/complaint/category',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除投诉分类
+export function delCategory(ids) {
+  return request({
+    url: '/complaint/category/' + ids,
+    method: 'delete'
+  })
+}
+
+// 修改投诉分类状态
+export function changeStatus(data) {
+  return request({
+    url: '/complaint/category/status',
+    method: 'put',
+    data: data
+  })
+}

+ 75 - 0
src/api/complaint/complaint.js

@@ -0,0 +1,75 @@
+import request from '@/utils/request'
+
+// 提交投诉
+export function submitComplaint(data) {
+  return request({
+    url: '/complaint',
+    method: 'post',
+    data: data
+  })
+}
+
+// 根据ID查询投诉详情
+export function getComplaintById(id) {
+  return request({
+    url: `/complaint/${id}`,
+    method: 'get'
+  })
+}
+
+// 根据投诉单号查询投诉详情
+export function getComplaintByNo(complaintNo) {
+  return request({
+    url: `/complaint/no/${complaintNo}`,
+    method: 'get'
+  })
+}
+
+// 分页查询投诉列表
+export function getComplaintPage(data) {
+  return request({
+    url: '/complaint/list',
+    method: 'post',
+    data: data
+  })
+}
+
+// 更新投诉信息
+export function updateComplaint(id, data) {
+  return request({
+    url: `/complaint/${id}`,
+    method: 'put',
+    data: {
+      ...data,
+      type: data.categoryId
+    }
+  })
+}
+
+// 删除投诉
+export function deleteComplaint(id) {
+  return request({
+    url: `/complaint/${id}`,
+    method: 'delete'
+  })
+}
+
+// 处理投诉(快捷更新状态为已处理)
+export function handleComplaint(id) {
+  return request({
+    url: `/complaint/${id}`,
+    method: 'put',
+    data: {
+      status: '1' // 假设1表示已处理状态
+    }
+  })
+}
+// 新增:获取所有投诉分类
+export function getAllCategory() {
+  return request({
+    url: '/complaint/queryAllCategory',
+    method: 'post'
+  })
+}
+
+

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

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

+ 10 - 1
src/api/course/fsCourseProductOrder.js

@@ -51,6 +51,15 @@ export function exportFsCourseProductOrder(query) {
     params: query
   })
 }
+// 导出拍单商品订单(解密手机号)
+export function exportFsCourseProductOrderDecodePhone(query) {
+  return request({
+    url: '/course/fsCourseProductOrder/decodeExport',
+    method: 'get',
+    params: query
+  })
+}
+
 
 // 退款拍商品订单
 export function refund(data) {
@@ -67,4 +76,4 @@ export function getOrderUserPhone(courseOrderId) {
     url: '/course/fsCourseProductOrder/queryPhone/' + courseOrderId,
     method: 'get'
   })
-}
+}

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

@@ -52,3 +52,11 @@ export function batchAddVideoResource(data) {
   })
 }
 
+// 批量修改视频资源
+export function batchUpdateVideoResource(data) {
+  return request({
+    url: '/course/videoResource/batchUpdateClass',
+    method: 'post',
+    params: data
+  })
+}

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

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

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

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

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

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询转人工提示词列表
+export function listFastgptChatArtificialWords(query) {
+  return request({
+    url: '/fastGpt/fastgptChatArtificialWords/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询转人工提示词详细
+export function getFastgptChatArtificialWords(id) {
+  return request({
+    url: '/fastGpt/fastgptChatArtificialWords/' + id,
+    method: 'get'
+  })
+}
+
+// 新增转人工提示词
+export function addFastgptChatArtificialWords(data) {
+  return request({
+    url: '/fastGpt/fastgptChatArtificialWords',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改转人工提示词
+export function updateFastgptChatArtificialWords(data) {
+  return request({
+    url: '/fastGpt/fastgptChatArtificialWords',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除转人工提示词
+export function delFastgptChatArtificialWords(id) {
+  return request({
+    url: '/fastGpt/fastgptChatArtificialWords/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出转人工提示词
+export function exportFastgptChatArtificialWords(query) {
+  return request({
+    url: '/fastGpt/fastgptChatArtificialWords/export',
+    method: 'get',
+    params: query
+  })
+}

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

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

+ 44 - 0
src/api/food/record.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询饮食记录列表
+export function listFoodRecord(query) {
+  return request({
+    url: '/food-record/admin/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询饮食记录详细
+export function getFoodRecord(id) {
+  return request({
+    url: '/food-record/getRecordInfo/' + id,
+    method: 'get'
+  })
+}
+
+// 新增饮食记录
+export function addFoodRecord(data) {
+  return request({
+    url: '/food-record/addRecord',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改饮食记录
+export function updateFoodRecord(data) {
+  return request({
+    url: '/food-record/editRecord',
+    method: 'post',
+    data: data
+  })
+}
+
+// 删除饮食记录
+export function delFoodRecord(id) {
+  return request({
+    url: '/food-record/deleteRecord/' + id,
+    method: 'post'
+  })
+}

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

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

+ 27 - 0
src/api/his/inquiryPatient.js

@@ -0,0 +1,27 @@
+import request from '@/utils/request'
+
+// 新增患者问诊信息
+export function addinquiryPatient(data) {
+  return request({
+    url: '/his/inquiryPatientInfo',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改患者问诊信息
+export function updateinquiryPatient(data) {
+  return request({
+    url: '/his/inquiryPatientInfo',
+    method: 'put',
+    data: data
+  })
+}
+
+//获取患者问诊信息详情
+export function detail(inquiryOrderId) {
+  return request({
+    url: '/his/inquiryPatientInfo/detail/'+ inquiryOrderId,
+    method: 'get'
+  })
+}

+ 53 - 0
src/api/hisStore/adv.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询广告列表
+export function listAdv(query) {
+  return request({
+    url: '/his/adv/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询广告详细
+export function getAdv(advId) {
+  return request({
+    url: '/his/adv/' + advId,
+    method: 'get'
+  })
+}
+
+// 新增广告
+export function addAdv(data) {
+  return request({
+    url: '/his/adv',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改广告
+export function updateAdv(data) {
+  return request({
+    url: '/his/adv',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除广告
+export function delAdv(advId) {
+  return request({
+    url: '/his/adv/' + advId,
+    method: 'delete'
+  })
+}
+
+// 导出广告
+export function exportAdv(query) {
+  return request({
+    url: '/his/adv/export',
+    method: 'get',
+    params: query
+  })
+}

+ 76 - 0
src/api/hisStore/express.js

@@ -0,0 +1,76 @@
+import request from '@/utils/request'
+
+// 查询快递公司列表
+export function listExpress(query) {
+  return request({
+    url: '/his/express/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询快递公司详细
+export function getExpress(id) {
+  return request({
+    url: '/his/express/' + id,
+    method: 'get'
+  })
+}
+
+export function getExpressList() {
+  return request({
+    url: '/his/express/getExpressList',
+    method: 'get'
+  })
+}
+
+// 新增快递公司
+export function addExpress(data) {
+  return request({
+    url: '/his/express',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改快递公司
+export function updateExpress(data) {
+  return request({
+    url: '/his/express',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除快递公司
+export function delExpress(id) {
+  return request({
+    url: '/his/express/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出快递公司
+export function exportExpress(query) {
+  return request({
+    url: '/his/express/export',
+    method: 'get',
+    params: query
+  })
+}
+
+//分配快递公司
+export function allotExpress(data,omsCode) {
+  return request({
+    url: '/his/express/allotExpress/'+omsCode,
+    method: 'post',
+    data: data
+  })
+}
+
+export function getCompanyByOmsCode(omsCode) {
+  return request({
+    url: '/his/express/omsCode/' + omsCode,
+    method: 'get'
+  })
+}

+ 53 - 0
src/api/hisStore/shippingTemplatesFree.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询免邮费列表
+export function listShippingTemplatesFree(query) {
+  return request({
+    url: '/store/shippingTemplatesFree/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询免邮费详细
+export function getShippingTemplatesFree(id) {
+  return request({
+    url: '/store/shippingTemplatesFree/' + id,
+    method: 'get'
+  })
+}
+
+// 新增免邮费
+export function addShippingTemplatesFree(data) {
+  return request({
+    url: '/store/shippingTemplatesFree',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改免邮费
+export function updateShippingTemplatesFree(data) {
+  return request({
+    url: '/store/shippingTemplatesFree',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除免邮费
+export function delShippingTemplatesFree(id) {
+  return request({
+    url: '/store/shippingTemplatesFree/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出免邮费
+export function exportShippingTemplatesFree(query) {
+  return request({
+    url: '/store/shippingTemplatesFree/export',
+    method: 'get',
+    params: query
+  })
+}

+ 53 - 0
src/api/hisStore/shippingTemplatesRegion.js

@@ -0,0 +1,53 @@
+import request from '@/utils/request'
+
+// 查询邮费区域列表
+export function listShippingTemplatesRegion(query) {
+  return request({
+    url: '/store/shippingTemplatesRegion/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询邮费区域详细
+export function getShippingTemplatesRegion(id) {
+  return request({
+    url: '/store/shippingTemplatesRegion/' + id,
+    method: 'get'
+  })
+}
+
+// 新增邮费区域
+export function addShippingTemplatesRegion(data) {
+  return request({
+    url: '/store/shippingTemplatesRegion',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改邮费区域
+export function updateShippingTemplatesRegion(data) {
+  return request({
+    url: '/store/shippingTemplatesRegion',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除邮费区域
+export function delShippingTemplatesRegion(id) {
+  return request({
+    url: '/store/shippingTemplatesRegion/' + id,
+    method: 'delete'
+  })
+}
+
+// 导出邮费区域
+export function exportShippingTemplatesRegion(query) {
+  return request({
+    url: '/store/shippingTemplatesRegion/export',
+    method: 'get',
+    params: query
+  })
+}

+ 61 - 0
src/api/medical/indicator.js

@@ -0,0 +1,61 @@
+import request from '@/utils/request'
+
+// 查询医疗指标分页列表
+export function listIndicator(query) {
+  return request({
+    url: '/admin/medical/indicator/page',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询所有启用的指标
+export function listAllEnabled() {
+  return request({
+    url: '/admin/medical/indicator/listEnabled',
+    method: 'get'
+  })
+}
+
+// 根据分类查询指标
+export function listByCategory(category) {
+  return request({
+    url: '/admin/medical/indicator/listByCategory',
+    method: 'get',
+    params: { category }
+  })
+}
+
+// 查询医疗指标详细
+export function getIndicator(indicatorId) {
+  return request({
+    url: '/admin/medical/indicator/' + indicatorId,
+    method: 'get'
+  })
+}
+
+// 新增医疗指标
+export function addIndicator(data) {
+  return request({
+    url: '/admin/medical/indicator/add',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改医疗指标
+export function updateIndicator(data) {
+  return request({
+    url: '/admin/medical/indicator/update',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除医疗指标
+export function delIndicator(indicatorId) {
+  return request({
+    url: '/admin/medical/indicator/' + indicatorId,
+    method: 'delete'
+  })
+}

+ 64 - 0
src/api/medical/report.js

@@ -0,0 +1,64 @@
+import request from '@/utils/request'
+
+// 查询体检报告分页列表
+export function listReport(query) {
+  return request({
+    url: '/admin/medical/report/page',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询体检报告详细
+export function getReport(reportId) {
+  return request({
+    url: '/admin/medical/report/' + reportId,
+    method: 'get'
+  })
+}
+
+// 根据用户ID查询体检报告列表
+export function listReportByUser(userId) {
+  return request({
+    url: '/admin/medical/report/listByUser/' + userId,
+    method: 'get'
+  })
+}
+
+// 根据用户ID和体检日期查询体检报告
+export function getReportByUserAndDate(userId, examDate) {
+  return request({
+    url: '/admin/medical/report/getByUserAndDate',
+    method: 'get',
+    params: {
+      userId: userId,
+      examDate: examDate
+    }
+  })
+}
+
+// 新增体检报告
+export function addReport(data) {
+  return request({
+    url: '/admin/medical/report/add',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改体检报告
+export function updateReport(data) {
+  return request({
+    url: '/admin/medical/report/update',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除体检报告
+export function delReport(reportId) {
+  return request({
+    url: '/admin/medical/report/' + reportId,
+    method: 'delete'
+  })
+}

+ 69 - 0
src/api/medical/reportIndicator.js

@@ -0,0 +1,69 @@
+import request from '@/utils/request'
+
+// 查询报告指标检查结果列表
+export function listResult(query) {
+  return request({
+    url: '/admin/medical/result/page',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询报告指标检查结果详细
+export function getResult(resultId) {
+  return request({
+    url: '/admin/medical/result/' + resultId,
+    method: 'get'
+  })
+}
+
+// 根据报告ID查询所有指标结果
+export function listByReportId(reportId) {
+  return request({
+    url: '/admin/medical/result/listByReport/' + reportId,
+    method: 'get'
+  })
+}
+
+// 根据指标ID查询所有结果
+export function listByIndicatorId(indicatorId) {
+  return request({
+    url: '/admin/medical/result/listByIndicator/' + indicatorId,
+    method: 'get'
+  })
+}
+
+// 新增报告指标检查结果
+export function addResult(data) {
+  return request({
+    url: '/admin/medical/result/add',
+    method: 'post',
+    data: data
+  })
+}
+
+// 批量新增报告指标检查结果
+export function batchAddResult(data) {
+  return request({
+    url: '/admin/medical/result/batchAdd',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改报告指标检查结果
+export function updateResult(data) {
+  return request({
+    url: '/admin/medical/result/update',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除报告指标检查结果
+export function delResult(resultId) {
+  return request({
+    url: '/admin/medical/result/' + resultId,
+    method: 'delete'
+  })
+}

+ 61 - 0
src/api/medical/unit.js

@@ -0,0 +1,61 @@
+import request from '@/utils/request'
+
+// 查询所有计量单位
+export function listAllUnit() {
+  return request({
+    url: '/admin/medical/unit/listAll',
+    method: 'get'
+  })
+}
+
+// 分页查询计量单位列表
+export function listUnit(query) {
+  return request({
+    url: '/admin/medical/unit/page',
+    method: 'get',
+    params: query
+  })
+}
+
+// 根据单位类型查询计量单位
+export function listUnitByType(unitType) {
+  return request({
+    url: '/admin/medical/unit/listByType',
+    method: 'get',
+    params: { unitType }
+  })
+}
+
+// 查询计量单位详细
+export function getUnit(unitId) {
+  return request({
+    url: '/admin/medical/unit/' + unitId,
+    method: 'get'
+  })
+}
+
+// 新增计量单位
+export function addUnit(data) {
+  return request({
+    url: '/admin/medical/unit/add',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改计量单位
+export function updateUnit(data) {
+  return request({
+    url: '/admin/medical/unit/update',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除计量单位
+export function delUnit(unitId) {
+  return request({
+    url: '/admin/medical/unit/' + unitId,
+    method: 'delete'
+  })
+}

+ 69 - 0
src/api/recharge/template.js

@@ -0,0 +1,69 @@
+import request from '@/utils/request'
+
+// 查询充值模板列表
+export function listRechargeTemplate(query) {
+  return request({
+    url: '/recharge-templates/list',
+    method: 'post',
+    data: query
+  })
+}
+
+// 查询充值模板详细
+export function getRechargeTemplate(id) {
+  return request({
+    url: '/recharge-templates/' + id,
+    method: 'get'
+  })
+}
+
+// 新增充值模板
+export function addRechargeTemplate(data) {
+  return request({
+    url: '/recharge-templates',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改充值模板
+export function updateRechargeTemplate(data) {
+  return request({
+    url: '/recharge-templates/' + data.id,
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除充值模板
+export function delRechargeTemplate(id) {
+  return request({
+    url: '/recharge-templates/' + id,
+    method: 'delete'
+  })
+}
+
+// 修改充值模板状态
+export function updateRechargeTemplateStatus(id, status) {
+  return request({
+    url: '/recharge-templates/' + id + '/status',
+    method: 'put',
+    params: {
+      status: status
+    }
+  })
+}
+
+
+/**
+ * 获取优惠券列表
+ * @param {Object} query 查询参数
+ * @returns {Promise} 请求结果
+ */
+export function getCouponList(query) {
+  return request({
+    url: '/recharge-templates/getCouponList',
+    method: 'get',
+    params: query
+  })
+}

+ 49 - 0
src/api/saler/competitorInfo.js

@@ -0,0 +1,49 @@
+import request from '@/utils/request'
+
+// 竞品信息模块请求前缀
+const prefix = '/saler/competitorInfo'
+
+// 查询竞品信息列表
+export function listCompetitorInfo(query) {
+  return request({
+    url: prefix + '/listPage',
+    method: 'post',
+    data: query
+  })
+}
+
+// 查询竞品信息详细
+export function getCompetitorInfo(id) {
+  return request({
+    url: prefix + '/findById',
+    method: 'post',
+    data: { id }
+  })
+}
+
+// 新增竞品信息
+export function addCompetitorInfo(data) {
+  return request({
+    url: prefix + '/save',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改竞品信息
+export function updateCompetitorInfo(data) {
+  return request({
+    url: prefix + '/updateById',
+    method: 'post',
+    data: data
+  })
+}
+
+// 删除竞品信息
+export function delCompetitorInfo(id) {
+  return request({
+    url: prefix + '/deleteById',
+    method: 'post',
+    data: { id }
+  })
+}

+ 46 - 0
src/api/saler/productInfo.js

@@ -0,0 +1,46 @@
+import request from '@/utils/request'
+
+// 查询商品列表
+export function listProductInfo(query) {
+  return request({
+    url: '/saler/serviceGoods/listPage',
+    method: 'post',
+    data: query
+  })
+}
+
+// 查询商品详细
+export function getProductInfo(id) {
+  return request({
+    url: '/saler/serviceGoods/findById',
+    method: 'post',
+    data: { id }
+  })
+}
+
+// 新增商品
+export function addProductInfo(data) {
+  return request({
+    url: '/saler/serviceGoods/save',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改商品
+export function updateProductInfo(data) {
+  return request({
+    url: '/saler/serviceGoods/updateById',
+    method: 'post',
+    data: data
+  })
+}
+
+// 删除商品
+export function delProductInfo(id) {
+  return request({
+    url: '/saler/serviceGoods/deleteById',
+    method: 'post',
+    data: { id }
+  })
+}

+ 8 - 1
src/api/system/config.js

@@ -81,4 +81,11 @@ export function updateConfigByKey(data) {
     method: 'post',
     data: data
   })
-}
+}
+export function updateIsTownOn(query) {
+  return request({
+    url: '/system/config/updateIsTownOn',
+    method: 'get',
+    params: query
+  })
+}

+ 81 - 0
src/api/todo/todoItems.js

@@ -0,0 +1,81 @@
+import request from '@/utils/request'
+
+// 查询待办事项列表
+export function listTodoItems(query) {
+  return request({
+    url: '/todoItems/listPage',
+    method: 'post',
+    data: query
+  })
+}
+
+// 查询待办事项详细
+export function getTodoItems(id) {
+  return request({
+    url: '/todoItems/findById',
+    method: 'post',
+    data: { id: id }
+  })
+}
+
+// 新增待办事项
+export function addTodoItems(data) {
+  return request({
+    url: '/todoItems/add',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改待办事项
+export function updateTodoItems(data) {
+  return request({
+    url: '/todoItems/updateById',
+    method: 'post',
+    data: data
+  })
+}
+
+// 更新待办事项状态
+export function updateTodoItemsStatus(id, status) {
+  return request({
+    url: '/todoItems/updateStatusById',
+    method: 'post',
+    data: { id: id, status: status }
+  })
+}
+
+// 删除待办事项
+export function delTodoItems(id) {
+  return request({
+    url: '/todoItems/removeById',
+    method: 'post',
+    data: { id: id }
+  })
+}
+
+// 分配执行者
+export function assignExecutor(data) {
+  return request({
+    url: '/todoItems/assignExecutor',
+    method: 'post',
+    data: data
+  })
+}
+
+// 获取可分配的执行者列表
+export function getExecutorList() {
+  return request({
+    url: '/todoItems/getExecutorList',
+    method: 'get'
+  })
+}
+
+// 获取执行人员列表(支持分页和公司名称搜索)
+export function getUserList(param) {
+  return request({
+    url: '/todoItems/getUserList',
+    method: 'post',
+    data: param
+  })
+}

+ 53 - 0
src/api/user/complaint.js

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

BIN
src/assets/logo/hcl.png


BIN
src/assets/logo/hyt.png


+ 264 - 0
src/components/City/index.vue

@@ -0,0 +1,264 @@
+<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" @change="checkedClick(index)">{{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" @change="primary(index,subindex)"
+                class="itemn"  v-for="(subitem,subindex) in item.children" :key="subindex"
+                >{{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: 'city',
+    props: {
+      type: {
+        type: Number,
+        default: 0
+      }
+    },
+    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(function(item,index,arr){
+            var subData=data.filter(subitem => subitem.parentId===item.cityId )
+            console.log(subData)
+            item.children=subData;
+          });
+        })
+      },
+      /**
+       * 全选或者反选
+       * @param checked
+       */
+      allCheckbox: function () {
+        let that = this, checked = this.iSselect;
+        that.cityList.forEach(function (item, key) {
+          that.$set(that.cityList[key], 'checked', checked);
+          if (checked) {
+            that.$set(that.cityList[key], 'count', that.cityList[key].children.length);
+          } else {
+            that.$set(that.cityList[key], 'count', 0);
+          }
+          that.cityList[key].children.forEach(function (val, k) {
+            that.$set(that.cityList[key].children[k], 'checked', checked);
+          })
+        });
+      },
+      // 清空;
+      empty () {
+        let that = this;
+        that.cityList.forEach(function (item, key) {
+          that.$set(that.cityList[key], 'checked', false);
+          that.cityList[key].children.forEach(function (val, k) {
+            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].checked) {
+          that.$set(that.cityList[index], 'count', that.cityList[index].children.length);
+          that.cityList[index].children.forEach(function (item, key) {
+            that.$set(that.cityList[index].children[key], 'checked', true);
+          });
+        } else {
+          that.$set(that.cityList[index], 'count', 0);
+          that.$set(that.cityList[index], 'checked', false);
+          that.cityList[index].children.forEach(function (item, key) {
+            that.$set(that.cityList[index].children[key], 'checked', false);
+          });
+          that.iSselect = false;
+        }
+      },
+      /**
+       * 点击市区
+       * @param index
+       * @param ind
+       */
+      primary: function (index, ind) {
+        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) {
+          let data = {};
+          if (item.checked) {
+            data = {
+              name: item.cityName,
+              cityId: item.cityId,
+              children: []
+            };
+
+          }
+          that.cityList[key].children.forEach(function (i, k) {
+            if (i.checked) {
+              data.children.push({
+                cityId: i.cityId
+              })
+            }
+          });
+          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 = []
+      }
+    },
+    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;
+  }
+</style>

+ 4 - 0
src/store/modules/user.js

@@ -29,6 +29,9 @@ const user = {
     },
     SET_PERMISSIONS: (state, permissions) => {
       state.permissions = permissions
+    },
+    SET_ISADMIN: (state, isAdmin) => {
+      state.isAdmin = isAdmin
     }
   },
 
@@ -65,6 +68,7 @@ const user = {
           commit('SET_NAME', user.userName)
           commit('SET_AVATAR', avatar)
           commit('SET_USER', user)
+          commit('SET_ISADMIN', res.isAdmin)
           resolve(res)
         }).catch(error => {
           reject(error)

+ 92 - 87
src/utils/cos.js

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

+ 69 - 52
src/utils/obs.js

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

+ 17 - 2
src/views/company/company/index.vue

@@ -509,9 +509,15 @@ export default {
         this.form = response.data;
         this.form.status = response.data.status.toString();
         this.form.companyType = response.data.companyType.toString();
-        if(this.form.followDoctorIds!=null){
-           this.form.followDoctorIds= JSON.parse(this.form.followDoctorIds)
+
+        if (this.form.followDoctorIds==null || this.form.followDoctorIds.length==0){
+          this.form.followDoctorIds=null;
+        }
+
+        if(this.form.followDoctorIds!=null && this.form.followDoctorIds.length>0){
+          this.form.followDoctorIds= JSON.stringify(this.form.followDoctorIds)
         }
+
         if(this.form.packageIds!=null){
           var packageList=this.form.packageIds.split(",");
           packageList.forEach(element => {
@@ -527,6 +533,15 @@ export default {
     submitForm() {
       this.$refs["form"].validate(valid => {
         if (valid) {
+
+          if (this.form.followDoctorIds==null || this.form.followDoctorIds.length==0){
+            this.form.followDoctorIds=null;
+          }
+
+          if(this.form.followDoctorIds!=null && this.form.followDoctorIds.length>0){
+            this.form.followDoctorIds= JSON.stringify(this.form.followDoctorIds)
+          }
+
           if (this.form.companyId != null) {
             updateCompany(this.form).then(response => {
               if (response.code === 200) {

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

@@ -31,6 +31,9 @@
               <div class="operate-button-container" >
                  <el-button size="mini" @click="handledetails()" v-hasPermi="['his:inquiryOrderReport:query']">咨询报告</el-button>
               </div>
+              <div class="operate-button-container" >
+                 <el-button size="mini" @click="handlePatient()" v-hasPermi="['his:inquiryOrderReport:query']">患者诊断数据</el-button>
+              </div>
 
 
              </div>
@@ -93,6 +96,197 @@
              <el-button type="primary" @click="editStatusOpenOk">确 定</el-button>
            </span>
          </el-dialog>
+
+        <el-dialog
+        title="患者问诊数据"
+        :visible.sync="patientOpen"
+        width="1000px"
+        append-to-body>
+          <el-form ref="patientForm" :model="patientForm" label-width="110px" >
+
+            <el-row>
+              <el-col :span="12">
+                <el-form-item label="患者姓名" prop="patientName">
+                  <el-input disabled v-model="item.patientName"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="患者性别" prop="sex">
+                  <el-select disabled v-model="JSON.parse(item.patientJson).sex">
+                    <el-option label="男" :value = "1"></el-option>
+                    <el-option label="女" :value = "0"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <el-row>
+              <el-col :span="12">
+                <el-form-item label="患者年龄" prop="age">
+                  <el-input disabled v-model="JSON.parse(item.patientJson).age"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="患者电话" prop="mobile">
+                  <el-input disabled v-model="JSON.parse(item.patientJson).mobile"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <el-row>
+              <el-col :span="12">
+                <el-form-item label="患者会员电话" prop="userPhone">
+                  <el-input disabled v-model="patientForm.userPhone"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="客户标签" prop="tag">
+                  <el-input  v-model="patientForm.tag"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <el-row>
+              <el-col :span="12">
+                <el-form-item label="客服姓名" prop="companyUserName">
+                  <el-input disabled v-model="patientForm.companyUserName"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="课程档期" prop="courseName">
+                  <el-input  v-model="patientForm.courseName"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <el-row>
+              <el-col :span="12">
+                <el-form-item label="预约医生" prop="doctorName">
+                  <el-input disabled v-model="item.doctorName"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="会诊时间" prop="subTime">
+                  <el-date-picker
+                  v-model="patientForm.subTime"
+                  type="date"
+                  value-format="yyyy-MM-dd"
+                  placeholder="选择日期">
+                  </el-date-picker>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <el-row>
+              <el-col :span="12">
+                <el-form-item label="就诊状态" prop="sex">
+                  <el-select  v-model="patientForm.diagnosisStatus">
+                    <el-option label="初诊" :value = "1"></el-option>
+                    <el-option label="复诊" :value = "2"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="部门负责人" prop="deptManager">
+                  <el-input v-model="patientForm.deptManager"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <el-form-item label="患者病情主诉">
+              <el-input
+              type="textarea"
+              placeholder="请输入内容"
+              v-model="patientForm.patientCondition">
+              </el-input>
+            </el-form-item>
+
+            <div class="contentx">
+              <div class="desct">
+                医生建议及处置
+              </div>
+            </div>
+            <el-form-item label="诊断">
+              <el-input
+              type="textarea"
+              placeholder="请输入内容"
+              v-model="patientForm.doctorAdviceJson.diagnosis">
+              </el-input>
+            </el-form-item>
+            <el-form-item label="饮食方面">
+              <el-input
+              type="textarea"
+              placeholder="请输入内容"
+              v-model="patientForm.doctorAdviceJson.foodAdvice">
+              </el-input>
+            </el-form-item>
+            <el-form-item label="运动方面">
+              <el-input
+              type="textarea"
+              placeholder="请输入内容"
+              v-model="patientForm.doctorAdviceJson.sportAdvice">
+              </el-input>
+            </el-form-item>
+            <el-form-item label="保健方面">
+              <el-input
+              type="textarea"
+              placeholder="请输入内容"
+              v-model="patientForm.doctorAdviceJson.healthAdvice">
+              </el-input>
+            </el-form-item>
+
+            <el-form-item label="注意禁忌">
+              <el-input
+              type="textarea"
+              placeholder="请输入内容"
+              v-model="patientForm.taboo">
+              </el-input>
+            </el-form-item>
+            <el-form-item label="客户需求">
+              <el-input  v-model="patientForm.customerRequire"></el-input>
+            </el-form-item>
+            <el-row>
+              <el-col :span="12">
+                <el-form-item label="职业医师" prop="age">
+                  <el-input  v-model="patientForm.professionalDoctor"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="医生助理" prop="mobile">
+                  <el-input  v-model="patientForm.assistantDoctor"></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <div class="contentx">
+              <div class="desct">
+                治疗方面
+              </div>
+              </div>
+            <div v-for="(i,index) in patientForm.doctorAdviceJson.treatmentAdvice" :key="index">
+              <el-row>
+                <el-col :span="8">
+                  <el-form-item label="诊断内容" prop="content">
+                    <el-input  v-model="i.content"></el-input>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="8">
+                  <el-form-item label="建议治疗" prop="advice">
+                    <el-input  v-model="i.advice"></el-input>
+                  </el-form-item>
+                </el-col>
+                <el-col :span="8">
+                  <el-button style="margin: 5px;" v-if="index+1 == patientForm.doctorAdviceJson.treatmentAdvice.length" @click="addItem(patientForm.doctorAdviceJson.treatmentAdvice.length)" type="primary" size="mini">+</el-button>
+                  <el-button style="margin: 5px;"  v-if="index !== 0" type="danger" size="mini" @click="delItem(i,index)">-</el-button>
+                </el-col>
+                
+              </el-row>
+            </div>
+          </el-form>
+          <span slot="footer" class="dialog-footer">
+             <el-button @click="patientOpen = false">取 消</el-button>
+             <el-button type="primary" @click="patientInquirySubmit">确 定</el-button>
+          </span>
+        </el-dialog>
  </div>
 
 <div class="contentx" v-if="item!=null">
@@ -259,6 +453,7 @@
 
 <script>
 import { msglist, sendMsg,listinquiryOrder,editStatus, logList,getinquiryOrder, delinquiryOrder, addinquiryOrder, updateinquiryOrder, exportinquiryOrder ,cancelOrder,refundOrder} from "@/api/his/inquiryOrder";
+import {addinquiryPatient, updateinquiryPatient, detail} from "@/api/his/inquiryPatient";
 import {getReportId} from "@/api/his/inquiryOrderReport";
 import msgDetails from '../../components/his/msgDetails.vue';
 import msgServiceDetails from '../../components/his/msgServiceDetails.vue';
@@ -273,6 +468,7 @@ import { js } from "js-beautify";
     components: { inquiryOrderReportDetails,msgDetails ,msgServiceDetails},
     data() {
       return {
+        patientOpen: false,
         logs:[],
         editStatusOpen:false,
         usageJson:{},
@@ -313,6 +509,21 @@ import { js } from "js-beautify";
         doctor:[],
         user:[],
         sexOptions: [],
+        patientForm: {
+          doctorAdviceJson: {
+            diagnosis: '',
+            foodAdvice: '',
+            sportAdvice: '',
+            healthAdvice: '',
+            treatmentAdvice: [
+              //默认一条
+              {
+                content: '',
+                advice: '',
+              }
+            ]
+          }
+        },
       }
     },
     created() {
@@ -340,6 +551,36 @@ import { js } from "js-beautify";
 
     },
     methods: {
+      addItem(length){
+        this.patientForm.doctorAdviceJson.treatmentAdvice.push({
+          content:'',
+          advice:'',
+        })
+      },
+      delItem(item,index){
+        this.patientForm.doctorAdviceJson.treatmentAdvice.splice(index,1)
+      },
+      handlePatient(){
+        this.patientOpen = true;
+        detail(this.item.orderId).then(res => {
+          this.patientForm = res.data;
+          if(!this.patientForm.doctorAdviceJson) {
+            this.patientForm.doctorAdviceJson = {
+              diagnosis: '',
+              foodAdvice: '',
+              sportAdvice: '',
+              healthAdvice: '',
+              treatmentAdvice: [
+                //默认一条
+                {
+                  content: '',
+                  advice: '',
+                }
+              ]
+            }
+          }
+        })
+      },
       cancelorder(){
         var that=this;
         this.$confirm('是否确认取消订单?', "警告", {
@@ -369,6 +610,25 @@ import { js } from "js-beautify";
           });
           });
       },
+      patientInquirySubmit(){
+        this.patientForm.patientId = this.item.patientId;
+        this.patientForm.companyUserId = this.item.companyUserId;
+        this.patientForm.userId = this.item.userId;
+        this.patientForm.inquiryOrderId = this.item.orderId;
+        this.patientForm.subDoctorId = this.item.doctorId;
+        console.log(this.patientForm);
+        if(this.patientForm.id != null) {
+          updateinquiryPatient(this.patientForm).then(res => {
+            this.msgSuccess("更新成功");
+            this.patientOpen = false;
+          })
+        } else {
+          addinquiryPatient(this.patientForm).then(res => {
+            this.msgSuccess("添加成功");
+            this.patientOpen = false;
+          })
+        }
+      },
       msgServiceDetailsClose(){
         this.msgServiceDetails.open = false;
       },

+ 2 - 2
src/views/components/his/storeOrderDetails.vue

@@ -299,11 +299,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="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="YD"  label="韵达" value="YD" />
-						              <el-option key="STO"  label="申通" value="STO" />
                        </el-select>
                      </el-form-item>
                     <el-form-item label="物流单号" prop="deliverySn"  >
@@ -470,6 +469,7 @@ import {getCitys} from "@/api/store/city";
           orderId:null,
           deliveryId:null,
           deliveryCode:null,
+          deliverySn: null
         },
         showList:true,
         edit:{

+ 99 - 5
src/views/course/coursePlaySourceConfig/index.vue

@@ -61,6 +61,36 @@
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
+    <!-- 开关配置对话框 -->
+    <el-dialog title="开关配置" :visible.sync="switchDialogVisible" width="500px" class="switch-dialog">
+      <el-form :model="switchForm" label-width="100px">
+        <el-form-item label="AppId">
+          <el-input v-model="switchForm.appId" :disabled="true"></el-input>
+        </el-form-item>
+        <el-form-item label="开关状态">
+          <el-switch
+            v-model="switchForm.switchStatus"
+            active-text="开启"
+            inactive-text="关闭"
+            active-value="001"
+            inactive-value="002">
+          </el-switch>
+        </el-form-item>
+        <el-form-item label="配置信息" v-if="switchForm.configInfo">
+          <el-input
+            type="textarea"
+            :rows="4"
+            v-model="switchForm.configInfo"
+            :disabled="true">
+          </el-input>
+        </el-form-item>
+      </el-form>
+      <span slot="footer" class="dialog-footer">
+                <el-button @click="switchDialogVisible = false">取 消</el-button>
+                <el-button type="primary" @click="submitSwitchConfig">确 定</el-button>
+            </span>
+    </el-dialog>
+
     <el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange" border>
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="ID" align="center" prop="id" />
@@ -103,6 +133,12 @@
             @click="handleDelete(scope.row)"
             v-hasPermi="['course:playSourceConfig:remove']"
           >删除</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-setting"
+            @click="handleSwitchConfig(scope.row)"
+          >是否展示销售</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -117,7 +153,7 @@
 
     <!-- 添加或修改点播配置对话框 -->
     <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
-      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+      <el-form ref="form" :model="form" :rules="rules" label-width="130px">
         <el-form-item label="名称" prop="name">
           <el-input v-model="form.name" placeholder="请输入名称" />
         </el-form-item>
@@ -166,12 +202,23 @@
 
 <script>
 import {list, get, update, add, del} from '@/api/course/coursePlaySourceConfig'
+import {updateIsTownOn} from "@/api/system/config";
 
 export default {
   name: 'CoursePlaySourceConfig',
   data() {
     return {
-      queryParams: {},
+      switchDialogVisible: false,
+      switchForm: {
+        appId: '',
+        switchStatus: '001',
+      },
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        name: null,
+        appid: null
+      },
       showSearch: true,
       single: true,
       multiple: true,
@@ -225,6 +272,53 @@ export default {
     this.getList();
   },
   methods: {
+
+
+    // 处理开关配置
+    handleSwitchConfig(row) {
+      this.switchForm.appId = row.appid;
+      this.switchForm.switchStatus = "001"; // 默认关闭状态
+
+      // 调用接口获取开关状态
+      this.getSwitchConfig(row.appid);
+      this.switchDialogVisible = true;
+    },
+
+    // 获取开关配置
+    getSwitchConfig(appId) {
+      const params = {
+        appId: this.switchForm.appId
+      };
+      updateIsTownOn(params).then(response=>{
+        if (response.code === 200) {
+          if ( response.date){
+            this.switchForm.switchStatus = response.date;
+          }
+        } else {
+          this.$message.error('获取配置失败: ' + response.msg);
+        }
+      }).catch(error => {
+        this.$message.error('请求失败: ' + error.message);
+      });
+    },
+
+    // 提交开关配置
+    submitSwitchConfig() {
+      const params = {
+        appId: this.switchForm.appId,
+        bock: this.switchForm.switchStatus
+      };
+      updateIsTownOn(params).then(response=>{
+        if (response.code === 200) {
+          this.$message.success('配置更新成功');
+          this.switchDialogVisible = false;
+        } else {
+          this.$message.error('更新失败: ' + response.msg);
+        }
+      })
+    },
+
+
     getList() {
       this.loading = true;
       list(this.queryParams).then(response => {
@@ -244,7 +338,7 @@ export default {
     handleAdd() {
       this.reset()
       this.open = true
-      this.title = "添加点播配置"
+      this.title = "添加小程序配置"
     },
     handleUpdate(row) {
       this.reset()
@@ -255,12 +349,12 @@ export default {
           type: response.data.type.toString()
         }
         this.open = true
-        this.title = "修改点播配置"
+        this.title = "修改小程序配置"
       })
     },
     handleDelete(row) {
       const id = row.id || this.ids
-      this.$confirm('是否确认删除点播配置编号为"' + id + '"的数据项?', "警告", {
+      this.$confirm('是否确认删除小程序配置编号为"' + id + '"的数据项?', "警告", {
         confirmButtonText: "确定",
         cancelButtonText: "取消",
         type: "warning"

+ 151 - 197
src/views/course/courseTrafficLog/index.vue

@@ -1,279 +1,233 @@
 <template>
   <div class="app-container">
+    <!-- Tab 切换 -->
+    <el-tabs v-model="activeTab" @tab-click="handleTabClick">
+      <el-tab-pane label="公司" name="company"></el-tab-pane>
+      <el-tab-pane label="项目" name="project"></el-tab-pane>
+      <el-tab-pane label="课程" name="course"></el-tab-pane>
+      <el-tab-pane label="公开课" name="common"></el-tab-pane>
+    </el-tabs>
+
+    <!-- 查询条件 -->
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="公司名称" prop="companyId" >
-        <el-select v-model="queryParams.companyId" placeholder="请选择所属公司" filterable clearable size="small">
+      <!-- 公司选择 -->
+      <el-form-item label="公司" v-if="activeTab === 'all' || activeTab === 'company'">
+        <el-select v-model="queryParams.companyId" placeholder="请选择公司" filterable clearable size="small">
           <el-option v-for="(option, index) in companyList" :key="index" :value="option.dictValue" :label="option.dictLabel"></el-option>
         </el-select>
       </el-form-item>
-      <el-form-item label="年月" prop="time">
+
+      <!-- 项目选择 -->
+      <el-form-item label="项目" v-if="activeTab === 'all' || activeTab === 'project'">
+        <el-select v-model="queryParams.project" placeholder="请选择项目" filterable clearable size="small">
+          <el-option v-for="dict in projectOptions" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
+        </el-select>
+      </el-form-item>
+
+      <!-- 课程选择 -->
+      <el-form-item label="课程" v-if="activeTab === 'all' || activeTab === 'course'">
+        <el-select v-model="queryParams.courseId" placeholder="请选择课程" filterable clearable size="small">
+          <el-option v-for="dict in courseLists" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="公开课" v-if="activeTab === 'all' || activeTab === 'common'">
+        <el-select v-model="queryParams.courseId" placeholder="请选择课程" filterable clearable size="small">
+          <el-option v-for="dict in courseLists" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
+        </el-select>
+      </el-form-item>
+
+      <!-- 时间选择 -->
+      <el-form-item label="年月">
         <el-date-picker
-          v-model="queryParams.time"
-          type="month"
+          v-model="timeRange"
+          type="daterange"
           placeholder="选择年月"
+          :value-format="'yyyy-MM-dd'"
           :picker-options="pickerOptions"
-          :value-format="'yyyy-MM'"
-          @change="handleTimeChange"
+          @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>
       </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="['course:courseTrafficLog:export']"
-        >导出</el-button>
-      </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-column type="selection" width="55" align="center" />
-      <el-table-column label="公司名称" align="center" prop="companyName" />
-      <el-table-column label="月份" align="center" prop="month" />
+      <!-- 公司列 -->
+      <el-table-column label="公司" align="center" prop="companyName" v-if="activeTab === 'all' || activeTab === 'company'" />
+      <!-- 项目列 -->
+      <el-table-column label="项目" align="center" prop="projectName" v-if="activeTab === 'all' || activeTab === 'project'" />
+      <!-- 课程列 -->
+      <el-table-column label="课程" align="center" prop="courseName" v-if="activeTab === 'all' || activeTab === 'course'||activeTab === 'common'" />
+      <el-table-column label="日期" align="center" prop="month" />
       <el-table-column label="使用流量" align="center">
         <template slot-scope="scope">
           <span>{{ formatTrafficData(scope.row.totalInternetTraffic) }}</span>
         </template>
       </el-table-column>
-      <el-table-column label="费用" align="center">
-        <template slot-scope="scope">
-          <span>{{ formatTrafficMoney(scope.row.totalInternetTraffic) }}</span>
-        </template>
-      </el-table-column>
     </el-table>
 
+    <!-- 分页 -->
     <pagination
-      v-show="total>0"
+      v-show="total > 0"
       :total="total"
       :page.sync="queryParams.pageNum"
       :limit.sync="queryParams.pageSize"
       @pagination="getList"
     />
-
   </div>
 </template>
 
 <script>
-import { listCourseTrafficLog, getCourseTrafficLog, delCourseTrafficLog, addCourseTrafficLog, updateCourseTrafficLog, exportCourseTrafficLog } from "@/api/course/courseTrafficLog";
-import { allList } from '../../../api/company/company'
+import { listCourseTrafficLog, exportCourseTrafficLog } from "@/api/course/courseTrafficLog";
+import { courseList } from "@/api/course/courseRedPacketLog";
+import { allList } from "@/api/company/company";
 
 export default {
-  name: "CourseTrafficLog",
   data() {
     return {
-      companyList:[],
+      activeTab: "company", // 默认 tab
+      timeRange: null, // 时间范围单独绑定
+      companyList: [],
+      projectOptions: [],
       pickerOptions: {
-        shortcuts: [{ text: '本月', onClick: () => this.handleShortcut() }],
+        shortcuts: [
+          {
+            text: '今日',
+            onClick(picker) {
+              const start = new Date();
+              const end = new Date();
+              picker.$emit('pick', [start, end]);
+            }
+          },
+          {
+            text: '昨日',
+            onClick(picker) {
+              const start = new Date();
+              start.setDate(start.getDate() - 1);
+              const end = new Date(start);
+              picker.$emit('pick', [start, end]);
+            }
+          },
+          {
+            text: '本周',
+            onClick(picker) {
+              const now = new Date();
+              const day = now.getDay() || 7;
+              const start = new Date(now);
+              start.setDate(now.getDate() - day + 1);
+              const end = new Date();
+              picker.$emit('pick', [start, end]);
+            }
+          },
+          {
+            text: '本月',
+            onClick(picker) {
+              const start = new Date(new Date().setDate(1));
+              const end = new Date();
+              picker.$emit('pick', [start, end]);
+            }
+          }
+        ]
       },
-      // 遮罩层
-      loading: true,
-      // 导出遮罩层
+      courseLists: [],
+      loading: false,
       exportLoading: false,
-      // 选中数组
-      ids: [],
-      // 非单个禁用
-      single: true,
-      // 非多个禁用
-      multiple: true,
-      // 显示搜索条件
       showSearch: true,
-      // 总条数
       total: 0,
-      // 短链课程流量记录表格数据
       courseTrafficLogList: [],
-      // 弹出层标题
-      title: "",
-      // 是否显示弹出层
-      open: false,
-      // 查询参数
       queryParams: {
+        tabType: "", // 当前 tab 类型
+        startDate: null,
+        endDate: null,
         pageNum: 1,
         pageSize: 10,
-        userId: null,
-        videoId: null,
-        qwExternalContactId: null,
-        internetTraffic: null,
-        qwUserId: null,
-        companyUserId: null,
         companyId: null,
-        courseId: null,
-        time:new Date().getFullYear()+'-'+(new Date().getMonth()+1).toString().padStart(2, '0'),
-        //本月第一天
-        startDate: new Date(new Date().getFullYear(), new Date().getMonth(), 1).toLocaleDateString().replaceAll('/','-'),
-        //本月最后一天
-        endDate: new Date(new Date().getFullYear(), new Date().getMonth()+1, 0).toLocaleDateString().replaceAll('/','-'),
-      },
-      // 表单参数
-      form: {},
-      // 表单校验
-      rules: {
+        project: null,
+        courseId: null
       }
     };
   },
   created() {
-    this.getList();
+    courseList().then(res => this.courseLists = res.list);
+    this.getDicts("sys_course_project").then(res => this.projectOptions = res.data);
     this.getAllCompany();
+    this.getList();
   },
   methods: {
-    getAllCompany() {
-      allList().then(response => {
-        this.companyList = response.rows;
-      });
-    },
-    formatTrafficData(traffic) {
+    handleTabClick(tab) {
+      this.queryParams.tabType = tab.name;
+      this.queryParams.pageNum = 1;
 
-        if (traffic < 1024) { // Less than 1 KB
-          return traffic + ' B';
-        } else if (traffic < 1024 * 1024) { // Less than 1 MB
-          return (traffic / 1024).toFixed(2) + ' KB';
-        } else if (traffic < 1024 * 1024 * 1024) { // Less than 1 GB
-          return (traffic / (1024 * 1024)).toFixed(2) + ' MB';
-        } else { // More than 1 GB
-          return (traffic / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
-        }
+      // 清理互斥参数
+      if (tab.name !== "project") this.queryParams.project = null;
+      if (tab.name !== "course") this.queryParams.courseId = null;
+      if (tab.name !== "company") this.queryParams.companyId = null;
 
-    },
-    formatTrafficMoney(traffic){
-      return (traffic / (1024 * 1024 * 1024) * 0.095).toFixed(2) + ' 元'
+      this.getList();
     },
 
-    handleShortcut() {
-      const now = new Date();
-      this.queryParams.time =  now.getFullYear()+'-'+(now.getMonth() + 1).toString().padStart(2, '0');
-    },
-    handleTimeChange() {
-      if(this.queryParams.time){
-        const year = this.queryParams.time.slice(0, 4);
-        const month = this.queryParams.time.slice(5, 7);
-        this.queryParams.startDate = this.queryParams.time+'-01';
-        const lastDay = new Date(year, month, 0).getDate();
-        this.queryParams.endDate =  this.queryParams.time+'-'+lastDay;
-      }else{
+    handleDateData() {
+      if (this.timeRange) {
+        this.queryParams.startDate = this.timeRange[0];
+        this.queryParams.endDate = this.timeRange[1];
+      } else {
         this.queryParams.startDate = null;
         this.queryParams.endDate = null;
       }
     },
-    /** 查询短链课程流量记录列表 */
+    getAllCompany() {
+      allList().then(res => this.companyList = res.rows);
+    },
     getList() {
       this.loading = true;
-      listCourseTrafficLog(this.queryParams).then(response => {
-        this.courseTrafficLogList = response.rows;
-        this.total = response.total;
+      listCourseTrafficLog(this.queryParams).then(res => {
+        this.courseTrafficLogList = res.rows;
+        this.total = res.total;
+      }).finally(() => {
         this.loading = false;
       });
     },
-    // 取消按钮
-    cancel() {
-      this.open = false;
-      this.reset();
-    },
-    // 表单重置
-    reset() {
-      this.form = {
-        logId: null,
-        userId: null,
-        videoId: null,
-        createTime: null,
-        qwExternalContactId: null,
-        internetTraffic: null,
-        qwUserId: null,
-        companyUserId: null,
-        companyId: null,
-        courseId: 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.logId)
-      this.single = selection.length!==1
-      this.multiple = !selection.length
-    },
-    /** 新增按钮操作 */
-    handleAdd() {
-      this.reset();
-      this.open = true;
-      this.title = "添加短链课程流量记录";
-    },
-    /** 修改按钮操作 */
-    handleUpdate(row) {
-      this.reset();
-      const logId = row.logId || this.ids
-      getCourseTrafficLog(logId).then(response => {
-        this.form = response.data;
-        this.open = true;
-        this.title = "修改短链课程流量记录";
-      });
+      this.timeRange = null;
+      this.queryParams = {
+        ...this.queryParams,
+        startDate: null,
+        endDate: null,
+        companyId: null,
+        project: null,
+        courseId: null,
+        pageNum: 1,
+      };
+      this.getList();
     },
-    /** 提交按钮 */
-    submitForm() {
-      this.$refs["form"].validate(valid => {
-        if (valid) {
-          if (this.form.logId != null) {
-            updateCourseTrafficLog(this.form).then(response => {
-              this.msgSuccess("修改成功");
-              this.open = false;
-              this.getList();
-            });
-          } else {
-            addCourseTrafficLog(this.form).then(response => {
-              this.msgSuccess("新增成功");
-              this.open = false;
-              this.getList();
-            });
-          }
-        }
-      });
+    formatTrafficData(traffic) {
+      if (traffic < 1024) return `${traffic} B`;
+      if (traffic < 1024 ** 2) return `${(traffic / 1024).toFixed(2)} KB`;
+      if (traffic < 1024 ** 3) return `${(traffic / 1024 ** 2).toFixed(2)} MB`;
+      return `${(traffic / 1024 ** 3).toFixed(2)} GB`;
     },
-    /** 删除按钮操作 */
-    handleDelete(row) {
-      const logIds = row.logId || this.ids;
-      this.$confirm('是否确认删除短链课程流量记录编号为"' + logIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delCourseTrafficLog(logIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.logId);
     },
-    /** 导出按钮操作 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有短链课程流量记录数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportCourseTrafficLog(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      this.$confirm("确认导出数据?", "提示").then(() => {
+        this.exportLoading = true;
+        return exportCourseTrafficLog(this.queryParams);
+      }).then(res => {
+        this.download(res.msg);
+      }).finally(() => {
+        this.exportLoading = false;
+      });
     }
   }
 };

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

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

+ 63 - 13
src/views/course/fsCourseProductOrder/index.vue

@@ -10,7 +10,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      
+
       <el-form-item label="用户名称" prop="userName">
         <el-input
           v-model="queryParams.userName"
@@ -29,9 +29,9 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-     
-      
-      
+
+
+
       <el-form-item label="支付状态" prop="isPay">
         <!-- <el-input
           v-model="queryParams.isPay"
@@ -76,10 +76,10 @@
           style="width: 240px"
         />
       </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>
@@ -130,6 +130,17 @@
           v-hasPermi="['course:fsCourseProductOrder:export']"
         >导出</el-button>
       </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleDecodeExport"
+          v-hasPermi="['course:fsCourseProductOrder:decodeExport']"
+        >解密手机号导出</el-button>
+      </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
@@ -146,8 +157,8 @@
       <el-table-column label="课程" align="center" :show-overflow-tooltip="true" prop="courseName" />
       <el-table-column label="视频" align="center" :show-overflow-tooltip="true" prop="title" />
       <el-table-column label="公司名称" align="center"  prop="companyName" />
-      <el-table-column label="销售" align="center"  prop="companyUserName" />  
-      <el-table-column label="企微外部联系人" align="center"  prop="extName" />      
+      <el-table-column label="销售" align="center"  prop="companyUserName" />
+      <el-table-column label="企微外部联系人" align="center"  prop="extName" />
       <el-table-column label="支付状态" align="center" prop="isPay">
         <template slot-scope="scope">
           <el-tag v-if="scope.row.isPay == 0">待支付</el-tag>
@@ -175,7 +186,7 @@
       </el-table-column>
       <el-table-column label="申请退款理由" :show-overflow-tooltip="true" align="center" prop="refundExplain" />
       <el-table-column label="核销码" align="center" prop="verifyCode" />
-      
+
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button
@@ -278,7 +289,17 @@
 </template>
 
 <script>
-import { listFsCourseProductOrder, getFsCourseProductOrder, delFsCourseProductOrder, addFsCourseProductOrder, updateFsCourseProductOrder, exportFsCourseProductOrder, refund, getOrderUserPhone } from "@/api/course/fsCourseProductOrder";
+import {
+  listFsCourseProductOrder,
+  getFsCourseProductOrder,
+  delFsCourseProductOrder,
+  addFsCourseProductOrder,
+  updateFsCourseProductOrder,
+  exportFsCourseProductOrder,
+  refund,
+  getOrderUserPhone,
+  exportFsCourseProductOrderDecodePhone
+} from "@/api/course/fsCourseProductOrder";
 
 export default {
   name: "FsCourseProductOrder",
@@ -466,6 +487,35 @@ export default {
         }).catch(() => {});
     },
     /** 导出按钮操作 */
+    handleDecodeExport() {
+      if (this.payDateRange && this.payDateRange.length === 2) {
+        this.queryParams.payStartTime = this.payDateRange[0];
+        this.queryParams.payEndTime = this.payDateRange[1];
+      } else {
+        this.queryParams.payStartTime = null;
+        this.queryParams.payEndTime = null;
+      }
+      if (this.refundDateRange && this.refundDateRange.length === 2) {
+        this.queryParams.refundStartTime = this.refundDateRange[0];
+        this.queryParams.refundEndTime = this.refundDateRange[1];
+      } else {
+        this.queryParams.refundStartTime = null;
+        this.queryParams.refundEndTime = null;
+      }
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有拍单商品订单数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportFsCourseProductOrderDecodePhone(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
+    },
+    /** 导出按钮操作 */
     handleExport() {
       if (this.payDateRange && this.payDateRange.length === 2) {
         this.queryParams.payStartTime = this.payDateRange[0];
@@ -516,7 +566,7 @@ export default {
     handlePhone(scope) {
       getOrderUserPhone(scope.row.courseOrderId).then(res=>{
         scope.row.userPhone = res.userPhone
-      }) 
+      })
     },
   }
 };

+ 6 - 6
src/views/course/userCoursePeriod/index.vue

@@ -176,7 +176,7 @@
                 type="text"
                 icon="el-icon-edit"
                 @click="handleUpdate(scope.row)"
-                v-hasPermi="['course:period:query']"
+                v-hasPermi="['course:period:edit']"
               >修改</el-button>
     <!--              <el-button-->
     <!--                size="mini"-->
@@ -275,7 +275,7 @@
             start-placeholder="开始日期"
             end-placeholder="结束日期"
             value-format="yyyy-MM-dd"
-            :picker-options="{disabledDate}"
+            :picker-options="{}"
             :clearable="false"
           >
           </el-date-picker>
@@ -287,7 +287,7 @@
             type="date"
             value-format="yyyy-MM-dd"
             placeholder="选择日期"
-            :picker-options="{disabledDate}"
+            :picker-options="{}"
             :clearable="false"
           >
           </el-date-picker>
@@ -1712,9 +1712,9 @@ export default {
       this.updatePeriodDate.form = {id: row.id, dayDate: row.dayDate};
       this.updatePeriodDate.open = true;
     },
-    disabledDate(time) {
-      return time.getTime() < new Date(new Date().setHours(0,0,0,0));
-    },
+    // disabledDate(time) {
+    //   return time.getTime() < new Date(new Date().setHours(0,0,0,0));
+    // },
     getPickerOptions() {
       // 如果已选择看课时间范围,则领取红包时间应在看课时间范围内
       if (this.updateCourse.form.timeRange &&

+ 26 - 1
src/views/course/userCoursePeriod/statistics.vue

@@ -18,6 +18,22 @@
             />
           </el-select>
         </el-form-item>
+
+        <el-form-item label="公司">
+          <el-select
+            v-model="queryParams.companyId"
+            placeholder="请选择公司"
+            clearable
+            style="width: 400px"
+          >
+            <el-option
+              v-for="item in companyOptions"
+              :key="item.companyId"
+              :label="item.companyName"
+              :value="item.companyId"
+            />
+          </el-select>
+        </el-form-item>
         <el-form-item>
           <el-button type="primary" @click="handleQuery">查询</el-button>
         </el-form-item>
@@ -112,7 +128,7 @@
 </template>
 
 <script>
-import {getDays, periodCountSelect} from "@/api/course/userCoursePeriod";
+import {getDays, periodCountSelect, getPeriodCompanyList} from "@/api/course/userCoursePeriod";
 
 export default {
   name: "CourseStatistics",
@@ -134,6 +150,7 @@ export default {
       total: 0,
       // 课程选项
       courseOptions: [],
+      companyOptions: [],
       // 统计数据
       statistics: {
         courseCompleteNum: 0,
@@ -182,8 +199,16 @@ export default {
     initializeData() {
       this.getCourseOptions();
       this.getCountList();
+      this.getCompanyOptions()
       this.initialized = true;
     },
+    getCompanyOptions() {
+      getPeriodCompanyList({
+        periodId: this.periodId
+      }).then(response => {
+        this.companyOptions = response.data || [];
+      });
+    },
     /** 获取课程选项 */
     getCourseOptions() {
       this.loading = true;

Fichier diff supprimé car celui-ci est trop grand
+ 527 - 227
src/views/course/videoResource/index.vue


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

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

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

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

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

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

+ 341 - 0
src/views/fastGpt/fastgptChatArtificialWords/index.vue

@@ -0,0 +1,341 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="类型" prop="type">
+        <el-select v-model="queryParams.type" placeholder="请选择类型" clearable size="small">
+          <el-option
+            v-for="dict in typeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <!--      <el-form-item label="排序" prop="sort">
+              <el-input
+                v-model="queryParams.sort"
+                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="['fastGpt:fastgptChatArtificialWords:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['fastGpt:fastgptChatArtificialWords:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['fastGpt:fastgptChatArtificialWords:remove']"
+        >删除</el-button>
+      </el-col>
+      <!--      <el-col :span="1.5">
+              <el-button
+                type="warning"
+                plain
+                icon="el-icon-download"
+                size="mini"
+                :loading="exportLoading"
+                @click="handleExport"
+                v-hasPermi="['fastGpt:fastgptChatArtificialWords:export']"
+              >导出</el-button>
+            </el-col>-->
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table border v-loading="loading" :data="fastgptChatArtificialWordsList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="id" align="center" prop="id" />
+      <el-table-column label="类型" align="center" prop="type">
+        <template slot-scope="scope">
+          <dict-tag :options="typeOptions" :value="scope.row.type"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="文本" align="center" prop="content" />
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="排序" align="center" prop="sort" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['fastGpt:fastgptChatArtificialWords:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['fastGpt:fastgptChatArtificialWords:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改转人工提示词对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="类型" prop="type">
+          <el-select v-model="form.type" placeholder="请选择类型">
+            <el-option
+              v-for="dict in typeOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="parseInt(dict.dictValue)"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="文本" prop="content">
+          <el-input v-model="form.content" placeholder="请输入文本内容"/>
+        </el-form-item>
+        <el-form-item label="状态">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="parseInt(dict.dictValue)"
+            >{{dict.dictLabel}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="排序" prop="sort">
+          <el-input v-model="form.sort" placeholder="请输入排序" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listFastgptChatArtificialWords, getFastgptChatArtificialWords, delFastgptChatArtificialWords, addFastgptChatArtificialWords, updateFastgptChatArtificialWords, exportFastgptChatArtificialWords } from "@/api/fastGpt/fastgptChatArtificialWords";
+
+export default {
+  name: "FastgptChatArtificialWords",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 转人工提示词表格数据
+      fastgptChatArtificialWordsList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 类型 1报错 2关键词字典
+      typeOptions: [],
+      // 状态字典
+      statusOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        type: null,
+        content: null,
+        status: null,
+        sort: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        type: [
+          { required: true, message: "类型不能为空", trigger: "blur" }
+        ],
+        content: [
+          { required: true, message: "文本不能为空", trigger: "blur" }
+        ],
+        sort: [
+          { required: true, message: "排序不能为空", trigger: "blur" }
+        ],
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_artificial_words_type").then(response => {
+      this.typeOptions = response.data;
+    });
+    this.getDicts("sys_company_status").then(response => {
+      this.statusOptions = response.data;
+    });
+  },
+  methods: {
+    /** 查询转人工提示词列表 */
+    getList() {
+      this.loading = true;
+      listFastgptChatArtificialWords(this.queryParams).then(response => {
+        this.fastgptChatArtificialWordsList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        type: null,
+        content: null,
+        status: 0,
+        sort: null,
+        createTime: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加转人工提示词";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getFastgptChatArtificialWords(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) {
+            updateFastgptChatArtificialWords(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addFastgptChatArtificialWords(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 delFastgptChatArtificialWords(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有转人工提示词数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportFastgptChatArtificialWords(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
+    }
+  }
+};
+</script>

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

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

+ 302 - 0
src/views/food/record/index.vue

@@ -0,0 +1,302 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="用户ID" prop="userId">
+        <el-input
+          v-model="queryParams.userId"
+          placeholder="请输入用户ID"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="用餐日期" prop="recordDate">
+        <el-date-picker clearable
+                        v-model="queryParams.recordDate"
+                        type="date"
+                        value-format="yyyy-MM-dd"
+                        placeholder="请选择用餐日期">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="用餐描述" prop="mealDescription">
+        <el-input
+          v-model="queryParams.mealDescription"
+          placeholder="请输入用餐描述"
+          clearable
+          @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="['food:record: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="['food:record: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="['food:record:remove']"
+        >删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="foodRecordList" @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="username" >
+        <template slot-scope="scope">
+          <span>{{scope.row.username}}</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column label="用餐日期" align="center" prop="recordDate" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.recordDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="记录时间" align="center" prop="recordTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ scope.row.recordTime }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="用餐描述" align="center" prop="mealDescription" :show-overflow-tooltip="true" />
+      <el-table-column label="创建时间" align="center" prop="createdAt" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createdAt, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['food:record:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['food:record: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="userId">
+          <el-input v-model="form.userId" placeholder="请输入用户ID" />
+        </el-form-item>
+        <el-form-item label="用餐日期" prop="recordDate">
+          <el-date-picker clearable
+                          v-model="form.recordDate"
+                          type="date"
+                          value-format="yyyy-MM-dd"
+                          placeholder="请选择用餐日期">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="记录时间" prop="recordTime">
+          <el-time-picker
+            v-model="form.recordTime"
+            value-format="HH:mm:ss"
+            placeholder="请选择记录时间">
+          </el-time-picker>
+        </el-form-item>
+        <el-form-item label="用餐描述" prop="mealDescription">
+          <el-input v-model="form.mealDescription" type="textarea" placeholder="请输入用餐情况描述" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listFoodRecord, getFoodRecord, delFoodRecord, addFoodRecord, updateFoodRecord } from "@/api/food/record";
+import {parseTime} from "../../../utils/common";
+
+export default {
+  name: "FoodRecord",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 饮食记录表格数据
+      foodRecordList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: null,
+        recordDate: null,
+        mealDescription: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        userId: [
+          { required: true, message: "用户ID不能为空", trigger: "blur" }
+        ],
+        recordDate: [
+          { required: true, message: "用餐日期不能为空", trigger: "blur" }
+        ],
+        mealDescription: [
+          { required: true, message: "用餐描述不能为空", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    parseTime,
+    /** 查询饮食记录列表 */
+    getList() {
+      this.loading = true;
+      listFoodRecord(this.queryParams).then(response => {
+        this.foodRecordList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        userId: null,
+        recordDate: null,
+        recordTime: null,
+        mealDescription: null,
+        createdAt: null,
+        updatedAt: 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
+      getFoodRecord(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) {
+            updateFoodRecord(this.form).then(response => {
+              this.$message.success("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addFoodRecord(this.form).then(response => {
+              this.$message.success("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除饮食记录编号为"' + ids + '"的数据项?').then(function() {
+        return delFoodRecord(ids);
+      }).then(() => {
+        this.getList();
+        this.$message.success("删除成功");
+      }).catch(() => {});
+    }
+  }
+};
+</script>

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

@@ -321,7 +321,22 @@
 <!--                              end: '24:00'-->
 <!--                            }"></el-time-select>-->
 <!--      </el-form-item>-->
-        <el-form-item label="服务号点播配置" prop="courseMaAppId">
+      <el-form-item label="自定义小程序" prop="customMiniAppId">
+        <el-select
+          v-model="form.customMiniAppId"
+          placeholder="请选择自定义小程序"
+          clearable
+          size="small"
+        >
+          <el-option
+            v-for="item in customAppList"
+            :key="item.appId"
+            :label="item.appName"
+            :value="item.appId"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="服务号点播配置" prop="courseMaAppId">
           <el-select
             v-model="form.courseMaAppId"
             placeholder="请选择服务号"
@@ -512,9 +527,11 @@ export default {
       // 表单参数
       form: {
         restartTime: '13:10',
+        customMiniAppId:null,
         courseMaAppId: null,
         courseMiniAppId: null,
         miniAppMaster: [],
+        miniAppServer:[],
         miniAppList: [],
       },
       // 表单校验
@@ -587,6 +604,7 @@ export default {
      },
       maAppList: [],
       miniAppList: [],
+      customAppList: [],
     };
   },
   created() {
@@ -783,6 +801,7 @@ export default {
     getAppList() {
       this.maAppList = []
       this.miniAppList = []
+      this.customAppList = []
       const key = "courseMa.config"
       getConfigByKey(key).then(response => {
         const {code,data} = response
@@ -796,6 +815,9 @@ export default {
             this.miniAppList = appList.filter(v => v.type === '1').map(v => {
               return { appId: v.appid, appName: v.name }
             })
+            this.customAppList = appList.filter(v => v.type === '3').map(v => {
+              return { appId: v.appid, appName: v.name }
+            })
           }
         }
       })
@@ -804,9 +826,15 @@ export default {
     submitForm() {
       this.$refs["form"].validate(valid => {
         if (valid) {
-          if(this.form.followDoctorIds!=null){
+
+          if (this.form.followDoctorIds==null || this.form.followDoctorIds.length==0){
+            this.form.followDoctorIds=null;
+          }
+
+          if(this.form.followDoctorIds!=null && this.form.followDoctorIds.length>0){
              this.form.followDoctorIds= JSON.stringify(this.form.followDoctorIds)
           }
+
           if(this.form.packageCateIds!=null){
              this.form.packageCateIds= JSON.stringify(this.form.packageCateIds)
           }

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

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

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

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

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

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

+ 5 - 71
src/views/his/user/index.vue

@@ -1,40 +1,6 @@
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="所属公司" prop="companyName">
-        <el-select
-          v-model="queryCompanyId"
-          placeholder="请选择所属公司"
-          clearable
-          filterable
-          size="small"
-          @change="handleQueryCompanyChange"
-        >
-          <el-option
-            v-for="item in companyQueryOptions"
-            :key="item.companyId"
-            :label="item.companyName"
-            :value="item.companyId">
-          </el-option>
-        </el-select>
-      </el-form-item>
-      <el-form-item label="所属销售" prop="companyUserId">
-
-        <el-select
-          v-model="queryCompanyUserId"
-          placeholder="请选择所属销售"
-          clearable
-          filterable
-          size="small"
-        >
-          <el-option
-            v-for="item in companyQueryUserOptions"
-            :key="item.userId"
-            :label="item.nickName"
-            :value="item.userId">
-          </el-option>
-        </el-select>
-      </el-form-item>
       <el-form-item label="会员ID" prop="userId">
         <el-input
           v-model="queryParams.userId"
@@ -149,8 +115,7 @@
               <dict-tag :options="userOptions" :value="scope.row.status"/>
          </template>
       </el-table-column>
-      <el-table-column label="所属公司" align="center" prop="companyName" />
-      <el-table-column label="所属销售" align="center" prop="companyUserNickName" />
+      <el-table-column label="用户备注" align="center" prop="remark" />
       <el-table-column label="上级昵称" align="center" prop="tuiName" />
       <el-table-column label="app来源" align="center" prop="source" />
       <el-table-column label="登陆设备" align="center" prop="loginDevice" />
@@ -261,10 +226,6 @@ export default {
   components: {userDetails,userDetailsByNew},
   data() {
     return {
-      companyQueryOptions:[],
-      companyQueryUserOptions:[],
-      queryCompanyId:null,
-      queryCompanyUserId:null,
       companyName: null,
       companyUserNickName: null,
       companyOptions: [],
@@ -321,6 +282,7 @@ export default {
         isBuy:null,
         source:null,
         companyName: null,
+        userId: null
       },
       // 表单参数
       form: {},
@@ -368,10 +330,6 @@ export default {
     this.getDicts("sys_company_or").then(response => {
       this.orOptions = response.data;
     });
-    getCompanyList().then(response => {
-        if (response.code === 200) {
-          this.companyQueryOptions = response.data;
-        }});
   },
   methods: {
     /** 销售选择变化 */
@@ -397,26 +355,6 @@ export default {
                  this.$refs.userDetailsByNew.getDetails(row.userId);
             }, 1);
      },
-     handleQueryCompanyChange(companyId){
-      // 清空已选择的销售
-      this.queryCompanyUserId = null;
-      // 根据公司ID获取对应的销售列表
-      if (companyId) {
-        getCompanyUserList({ companyId: companyId }).then(response => {
-          if (response.code === 200) {
-            this.companyQueryUserOptions = response.data;
-          } else {
-            this.$message.error(response.msg || '获取销售列表失败');
-            this.companyQueryUserOptions = [];
-          }
-        }).catch(() => {
-          this.$message.error('获取销售列表失败');
-          this.companyQueryUserOptions = [];
-        });
-      } else {
-        this.companyQueryUserOptions = [];
-      }
-     },
     /** 查询用户列表 */
     getList() {
       this.loading = true;
@@ -459,8 +397,6 @@ export default {
     /** 搜索按钮操作 */
     handleQuery() {
       this.queryParams.pageNum = 1;
-      this.queryParams.companyId = this.queryCompanyId;
-      this.queryParams.companyUserId = this.queryCompanyUserId;
       this.getList();
     },
     /** 重置按钮操作 */
@@ -469,10 +405,6 @@ export default {
        this.createTime=null;
       this.queryParams.sTime=null;
       this.queryParams.eTime=null;
-      this.queryParams.companyName = null;
-      this.queryParams.companyUserNickName = null;
-      this.queryParams.companyId = null;
-      this.queryParams.companyUserId = null;
       this.handleQuery();
     },
     // 多选框选中数据
@@ -574,7 +506,9 @@ export default {
         }).then(response => {
           this.download(response.msg);
           this.exportLoading = false;
-        }).catch(() => {});
+        }).catch(() => {
+          this.exportLoading = false;
+      });
     },
   }
 };

+ 35 - 15
src/views/his/user/indexProject.vue

@@ -30,7 +30,7 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="注册时间" prop="createTimeRange">
+      <el-form-item label="绑定时间" prop="createTimeRange">
         <el-date-picker clearable size="small" style="width: 340px"
                         v-model="dateRange"
                         type="daterange"
@@ -186,7 +186,7 @@
       <el-table-column label="用户余额" align="center" prop="nowMoney" />
       <!--      <el-table-column label="推广佣金" align="center" prop="brokeragePrice" />-->
       <el-table-column label="积分" align="center" prop="integral" />
-      <el-table-column label="会员注册时间" align="center" prop="createTime" />
+      <el-table-column label="绑定时间" align="center" prop="bindTime" width="100" />
       <!--      <el-table-column label="累计消费金额" align="center" prop="totalAmount" />-->
       <!--      <el-table-column label="上次消费时间" align="center" prop="lastBuyTime" />-->
       <!--      <el-table-column label="上次消费金额(元)" align="center" prop="number" />-->
@@ -226,13 +226,13 @@
       </el-table-column>
       <el-table-column label="操作" align="center"  width="150px"   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:user:edit']"
-          >修改</el-button>
+<!--          <el-button-->
+<!--            size="mini"-->
+<!--            type="text"-->
+<!--            icon="el-icon-edit"-->
+<!--            @click="handleUpdate(scope.row)"-->
+<!--            v-hasPermi="['store:user:edit']"-->
+<!--          >修改</el-button>-->
 
           <el-button
             size="mini"
@@ -450,7 +450,8 @@ export default {
         startCreateTime: null,
         endCreateTime: null,
         companyId: null,
-        companyUserNickName: null
+        companyUserNickName: null,
+        userId: null
       },
       // 表单参数
       form: {},
@@ -489,7 +490,7 @@ export default {
     };
   },
   created() {
-    this.getDicts("user_status").then((response) => {
+    this.getDicts("project_user_status").then((response) => {
       this.statusOptions = response.data;
     });
     this.getDicts("user_level").then((response) => {
@@ -598,6 +599,8 @@ export default {
       this.queryParams.companyId = null;
       this.queryParams.companyUserNickName = null;
       this.companyQueryUserOptions = null;
+      this.queryParams.startCreateTime = null
+      this.queryParams.endCreateTime = null
       this.handleQuery();
     },
     /** 处理日期范围变化 */
@@ -629,10 +632,27 @@ export default {
       const userId = row.userId || this.ids
       getUser(userId).then(response => {
         this.form = response.data;
-        this.form.status = response.data.status.toString();
-        this.form.isShow = response.data.isShow.toString();
-        this.form.level = response.data.level.toString();
-        this.form.isPromoter = response.data.isPromoter.toString();
+        if(response.data.status){
+          this.form.status = response.data.status.toString();
+        } else {
+          this.form.status = null;
+        }
+        if(response.data.isShow){
+          this.form.isShow = response.data.isShow.toString();
+        }else {
+          this.form.isShow = null;
+        }
+        if(response.data.level){
+          this.form.level = response.data.level.toString();
+        }else {
+          this.form.level = null;
+        }
+        if(response.data.isPromoter){
+          this.form.isPromoter = response.data.isPromoter.toString();
+        }else {
+          this.form.status = null;
+        }
+
         this.open = true;
         this.title = "修改用户";
       });

+ 207 - 185
src/views/hisStore/adv/index.vue

@@ -1,46 +1,26 @@
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="标题名称" prop="advTitle">
-        <el-input
-          v-model="queryParams.advTitle"
-          placeholder="请输入标题名称"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="状态" prop="status">
-          <el-select v-model="queryParams.status" placeholder="状态" clearable size="small">
-               <el-option
-                 v-for="dict in statusOptions"
-                 :key="dict.dictValue"
-                 :label="dict.dictLabel"
-                 :value="dict.dictValue"
-               />
-             </el-select>
+      <el-form-item label="广告位置" prop="advType">
+        <el-select v-model="queryParams.advType" placeholder="请选择广告位置" clearable size="small">
+          <el-option
+                v-for="item in advTypeOptions"
+                :key="item.dictValue"
+                :label="item.dictLabel"
+                :value="item.dictValue"
+              />
+        </el-select>
       </el-form-item>
       <el-form-item label="显示类型" prop="showType">
-        <el-select v-model="queryParams.showType" placeholder="展示类型" clearable size="small">
-            <el-option
-              v-for="dict in showOptions"
-              :key="dict.dictValue"
-              :label="dict.dictLabel"
-              :value="dict.dictValue"
-            />
-          </el-select>
-        </el-form-item>
-      <el-form-item label="广告类型" prop="advType">
-      <el-select v-model="queryParams.advType" placeholder="广告类型" clearable size="small">
+        <el-select v-model="queryParams.showType" placeholder="请选择显示类型" clearable size="small">
            <el-option
-             v-for="dict in devOptions"
-             :key="dict.dictValue"
-             :label="dict.dictLabel"
-             :value="dict.dictValue"
-           />
-         </el-select>
+                v-for="item in showTypeOptions"
+                :key="item.dictValue"
+                :label="item.dictLabel"
+                :value="item.dictValue"
+              />
+        </el-select>
       </el-form-item>
-
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
         <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
@@ -55,7 +35,7 @@
           icon="el-icon-plus"
           size="mini"
           @click="handleAdd"
-          v-hasPermi="['his:adv:add']"
+          v-hasPermi="['store:adv:add']"
         >新增</el-button>
       </el-col>
       <el-col :span="1.5">
@@ -66,7 +46,7 @@
           size="mini"
           :disabled="single"
           @click="handleUpdate"
-          v-hasPermi="['his:adv:edit']"
+          v-hasPermi="['store:adv:edit']"
         >修改</el-button>
       </el-col>
       <el-col :span="1.5">
@@ -77,73 +57,60 @@
           size="mini"
           :disabled="multiple"
           @click="handleDelete"
-          v-hasPermi="['his:adv:remove']"
+          v-hasPermi="['store:adv:remove']"
         >删除</el-button>
       </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="warning"
-          plain
-          icon="el-icon-download"
-          size="mini"
-          :loading="exportLoading"
-          @click="handleExport"
-          v-hasPermi="['his:adv:export']"
-        >导出</el-button>
-      </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
-    <el-table v-loading="loading" :data="advList" @selection-change="handleSelectionChange" border>
+    <el-table  height="500" border v-loading="loading" :data="advList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="标题名称" align="center" prop="advTitle" width="150px"/>
-      <el-table-column label="图片" align="center" prop="imageUrl" width="150px">
+      <el-table-column label="ID" align="center" prop="advId" />
+      <el-table-column label="广告标题" align="center" prop="advTitle" />
+      <el-table-column label="广告图片" align="center" width="120">
         <template slot-scope="scope">
           <el-popover
             placement="right"
             title=""
-            trigger="hover">
+            trigger="hover"
+          >
             <img slot="reference" :src="scope.row.imageUrl" width="100">
             <img :src="scope.row.imageUrl" style="max-width: 150px;">
           </el-popover>
         </template>
       </el-table-column>
-      <el-table-column label="地址" show-overflow-tooltip align="center" prop="advUrl" width="150px" />
-
+      <el-table-column label="URL地址" show-overflow-tooltip align="center" prop="advUrl" />
       <el-table-column label="排序" align="center" prop="sort" />
-      <el-table-column label="类型" align="center" prop="advType" width="130px">
+      <el-table-column  label="广告位置" align="center" prop="advType">
         <template slot-scope="scope">
-              <dict-tag :options="devOptions" :value="scope.row.advType"/>
-            </template>
+            <el-tag prop="advType" v-for="(item, index) in advTypeOptions"    v-if="scope.row.advType==item.dictValue">{{item.dictLabel}}</el-tag>
+          </template>
       </el-table-column>
-      <el-table-column label="显示类型" align="center" prop="showType" width="130px">
+      <el-table-column  label="显示方式" align="center" prop="showType">
         <template slot-scope="scope">
-              <dict-tag :options="showOptions" :value="scope.row.showType"/>
-            </template>
+             <el-tag prop="showType" v-for="(item, index) in showTypeOptions"    v-if="scope.row.showType==item.dictValue">{{item.dictLabel}}</el-tag>
+          </template>
       </el-table-column>
-      <el-table-column label="状态" align="center" prop="status" >
-           <template slot-scope="scope">
-              <dict-tag :options="statusOptions" :value="scope.row.status"/>
-            </template>
+      <el-table-column  label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+            <el-tag prop="status" v-for="(item, index) in statusOptions"    v-if="scope.row.status==item.dictValue">{{item.dictLabel}}</el-tag>
+        </template>
       </el-table-column>
-        <el-table-column label="创建时间" align="center" prop="createTime" width="150px" />
-        <el-table-column label="修改时间" align="center" prop="updateTime" width="150px" />
-
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="150px">
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button
             size="mini"
             type="text"
             icon="el-icon-edit"
             @click="handleUpdate(scope.row)"
-            v-hasPermi="['his:adv:edit']"
+            v-hasPermi="['store:adv:edit']"
           >修改</el-button>
           <el-button
             size="mini"
             type="text"
             icon="el-icon-delete"
             @click="handleDelete(scope.row)"
-            v-hasPermi="['his:adv:remove']"
+            v-hasPermi="['store:adv:remove']"
           >删除</el-button>
         </template>
       </el-table-column>
@@ -158,56 +125,73 @@
     />
 
     <!-- 添加或修改广告对话框 -->
-    <el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
-      <el-form ref="form" :model="form" :rules="rules" label-width="90px">
-        <el-form-item label="标题名称" prop="advTitle">
+    <el-dialog :title="title" :visible.sync="open" width="680px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="广告标题" prop="advTitle">
           <el-input v-model="form.advTitle" placeholder="请输入广告标题" />
         </el-form-item>
-        <el-form-item label="图片" prop="imageUrl" >
-          <el-upload
-                      v-model="form.imageUrl"
-                      class="avatar-uploader"
-                      :action="uploadUrl"
-                      :show-file-list="false"
-                      :on-success="handleAvatarSuccess"
-                      :before-upload="beforeAvatarUpload">
-                      <img v-if="form.imageUrl" :src="form.imageUrl" class="avatar" width="300px">
-                      <i v-else class="el-icon-plus avatar-uploader-icon"></i>
-          </el-upload>
+        <el-form-item label="展示类型" prop="urlType">
+          <el-radio-group v-model="form.urlType">
+            <el-radio :label="1">图片</el-radio>
+            <el-radio :label="2">视频</el-radio>
+          </el-radio-group>
+        </el-form-item>
+         <el-form-item label="广告图片" prop="imageUrl" v-if="form.urlType==1">
+            <el-upload
+              v-model="form.icon"
+              class="avatar-uploader"
+              :action="uploadUrl"
+              :show-file-list="false"
+              :on-success="handleAvatarSuccess"
+              :before-upload="beforeAvatarUpload">
+              <img v-if="form.imageUrl" :src="form.imageUrl" class="avatar">
+              <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+            </el-upload>
+        </el-form-item>
+        <el-form-item label="广告视频" prop="video" v-if="form.urlType==2">
+          <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.imageUrl" :src="form.imageUrl" controls style="max-width: 300px; max-height: 300px; margin-top: 10px"></video>
+          </div>
         </el-form-item>
-        <el-form-item label="类型" prop="advType">
-          <el-select v-model="form.advType"  placeholder="请选择类型" >
-            <el-option
-              v-for="item in devOptions"
-              :key="item.dictValue"
-              :label="item.dictLabel"
-              :value="item.dictValue"
-            ></el-option>
-          </el-select>
+
+        <el-form-item label="广告位置" prop="advType">
+          <el-radio-group v-model="form.advType">
+            <el-radio :label="item.dictValue" v-for="item in advTypeOptions" >{{item.dictLabel}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="显示方式" prop="showType" v-if="form.urlType==1">
+          <el-radio-group @change="showTypeChange" v-model="form.showType">
+            <el-radio :label="item.dictValue" v-for="item in showTypeOptions" >{{item.dictLabel}}</el-radio>
+          </el-radio-group>
         </el-form-item>
-        <el-form-item label="显示类型" prop="showType">
-         <el-radio-group v-model="form.showType">
-            <el-radio :label="item.dictValue" v-for="item in showOptions" >{{item.dictLabel}}</el-radio>
-         </el-radio-group>
+        <el-form-item label="公众号链接" prop="advUrl" v-if="form.showType==1 && form.urlType==1 " >
+          <el-input v-model="form.advUrl" placeholder="请输入公众号链接" />
         </el-form-item>
-       <el-form-item label="公众号链接" prop="advUrl" v-if="form.showType==1">
-         <el-input v-model="form.advUrl" placeholder="请输入公众号链接" />
-       </el-form-item>
-       <el-form-item label="小程序地址" prop="advUrl" v-if="form.showType==2">
-         <el-input v-model="form.advUrl" placeholder="请输入小程序地址" />
-       </el-form-item>
-       <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="文章内容" v-show="form.showType==3">
-         <editor ref="myeditor" @on-text-change="updateText" />
-       </el-form-item>
-        <el-form-item label="状态">
+        <el-form-item label="小程序地址" prop="advUrl" v-if="form.showType==2 && form.urlType==1 ">
+          <el-input v-model="form.advUrl" placeholder="请输入小程序地址" />
+        </el-form-item>
+        <el-form-item label="文章内容" v-if="form.showType==3 && form.urlType==1 ">
+          <editor ref="myeditor" @on-text-change="updateText" />
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
           <el-radio-group v-model="form.status">
-             <el-radio :label="item.dictValue" v-for="item in statusOptions" >{{item.dictLabel}}</el-radio>
+            <el-radio :label="item.dictValue" v-for="item in statusOptions" >{{item.dictLabel}}</el-radio>
           </el-radio-group>
         </el-form-item>
-
+        <el-form-item label="排序" prop="sort">
+           <el-input-number v-model="form.sort"  :min="1" :max="99" ></el-input-number>
+        </el-form-item>
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="submitForm">确 定</el-button>
@@ -218,18 +202,21 @@
 </template>
 
 <script>
-import { listAdv, getAdv, delAdv, addAdv, updateAdv, exportAdv } from "@/api/his/adv";
+import { listAdv, getAdv, delAdv, addAdv, updateAdv, exportAdv } from "@/api/hisStore/adv";
 import Editor from '@/components/Editor/wang';
 export default {
   name: "Adv",
-  components: { Editor },
+  components: {
+    Editor
+  },
   data() {
     return {
       uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
       baseUrl: process.env.VUE_APP_BASE_API,
-      showOptions: [],
-      devOptions: [],
-      statusOptions: [],
+      videoAccept:"video/*",
+      statusOptions:[],
+      advTypeOptions:[],
+      showTypeOptions:[],
       // 遮罩层
       loading: true,
       // 导出遮罩层
@@ -268,54 +255,78 @@ export default {
       // 表单校验
       rules: {
         advTitle: [
-          { required: true, message: "标题不能为空", trigger: "blur" }
-        ],
-        status: [
-          { required: true, message: "状态不能为空", trigger: "blur" }
-        ],
-        sort: [
-          { required: true, message: "排序不能为空", trigger: "blur" }
-        ],
-        advType: [
-          { required: true, message: "类别不能为空", trigger: "blur" }
+          { required: true, message: "广告标题不能为空", trigger: "blur" }
         ],
-        showType: [
-          { required: true, message: "显示类别不能为空", trigger: "blur" }
+        imageUrl: [
+          { required: true, message: "广告图不能为空", trigger: "blur" }
         ],
+
       }
     };
   },
   created() {
-    this.getList();
-    this.getDicts("sys_company_status").then(response => {
+    this.getDicts("common_status").then((response) => {
       this.statusOptions = response.data;
     });
-    this.getDicts("sys_adv_show").then(response => {
-      this.showOptions = response.data;
+    this.getDicts("adv_adv_type").then((response) => {
+      this.advTypeOptions = response.data;
     });
-    this.getDicts("sys_adv_type").then(response => {
-      this.devOptions = response.data;
+    this.getDicts("adv_show_type").then((response) => {
+      this.showTypeOptions = response.data;
     });
+    this.getList();
   },
   methods: {
+    handleSuccess(response, file) {
+      // 上传成功后的回调函数
+      this.myloading.close();
+      this.form.imageUrl = 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)'
+      });
+
+    },
+    showTypeChange(e){
+      console.log(e)
+      if(e==3){
+        setTimeout(() => {
+          this.$refs.myeditor.setText("");
+        }, 200);
+      }
+    },
     updateText(text){
-        this.form.content=text
-      },
+      this.form.content=text
+    },
     handleAvatarSuccess(res, file) {
-            if(res.code==200){
-              this.form.imageUrl=res.url;
-              self.$forceUpdate()
-            }
-            else{
-              this.msgError(res.msg);
-            }
-        },
+        if(res.code==200){
+          this.form.imageUrl=res.url;
+        }
+        else{
+          this.msgError(res.msg);
+        }
+
+    },
     beforeAvatarUpload(file) {
-          const isLt1M = file.size / 1024 / 1024 < 1;
-          if (!isLt1M) {
-            this.$message.error('上传图片大小不能超过 1MB!');
-          }
-          return   isLt1M;
+      const isLt1M = file.size / 1024 / 1024 < 200;
+      if (!isLt1M) {
+        this.$message.error('上传图片大小不能超过 200MB!');
+      }
+      return   isLt1M;
     },
     /** 查询广告列表 */
     getList() {
@@ -335,14 +346,14 @@ export default {
     reset() {
       this.form = {
         advId: null,
+        urlType:1,
         advTitle: null,
         imageUrl: null,
         advUrl: null,
-        appAdvUrl: null,
         content: null,
         createTime: null,
         updateTime: null,
-        status: "0",
+        status: "1",
         sort: null,
         advType: null,
         showType: null
@@ -370,28 +381,30 @@ export default {
       this.reset();
       this.open = true;
       this.title = "添加广告";
-      setTimeout(() => {
-        this.$refs.myeditor.setText("");
-      }, 100);
     },
     /** 修改按钮操作 */
     handleUpdate(row) {
       this.reset();
       const advId = row.advId || this.ids
+      var that=this;
       getAdv(advId).then(response => {
         this.form = response.data;
+        this.form.status = response.data.status.toString();
+        this.form.advType = response.data.advType.toString();
+        this.form.showType = response.data.showType ? response.data.showType.toString() : "";
         this.open = true;
         this.title = "修改广告";
-        this.form.advType = String(this.form.advType)
-        this.form.showType = String(this.form.showType)
-      setTimeout(() => {
-          if(this.form.content==null){
-            this.$refs.myeditor.setText("");
-          }
-          else{
-            this.$refs.myeditor.setText(this.form.content);
+        setTimeout(() => {
+          if(this.form.showType=="3"){
+            console.log(that.form.content)
+            if(this.form.content==null){
+                that.$refs.myeditor.setText("");
+            }
+            else{
+                that.$refs.myeditor.setText(that.form.content);
+            }
           }
-        }, 1);
+        }, 200);
       });
     },
     /** 提交按钮 */
@@ -446,25 +459,34 @@ export default {
   }
 };
 </script>
-<style>
-   .avatar-uploader .el-upload {
-       border: 1px dashed #d9d9d9;
-       border-radius: 6px;
-       cursor: pointer;
-       position: relative;
-       overflow: hidden;
-     }
-     .avatar-uploader .el-upload:hover {
-       border-color: #409EFF;
-     }
+<style >
+ .avatar-uploader .el-upload {
+    border: 1px dashed #d9d9d9;
+    border-radius: 6px;
+    cursor: pointer;
+    position: relative;
+    overflow: hidden;
+  }
+  .avatar-uploader .el-upload:hover {
+    border-color: #409EFF;
+  }
+</style>
+<style scoped>
+
+  .avatar-uploader-icon {
+    font-size: 28px;
+    color: #8c939d;
+    width: 300px;
+    height: 150px;
+    line-height: 150px;
+    text-align: center;
+  }
+  .avatar {
+    width: 300px;
+    height: 150px;
+    display: block;
+  }
 
-     .avatar-uploader-icon {
-       font-size: 28px;
-       color: #8c939d;
-       width: 150px;
-       height: 150px;
-       line-height: 150px;
-       text-align: center;
-     }
 
 </style>
+

+ 394 - 0
src/views/hisStore/express/index.vue

@@ -0,0 +1,394 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="公司名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入快递公司名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['store:express:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['store:express: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:express:remove']"
+        >删除</el-button>
+      </el-col>
+	  <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table  height="500" border v-loading="loading" :data="expressList" @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="code" />
+      <el-table-column label="快递公司" align="center" prop="name" />
+      <el-table-column label="OMS编号" align="center" prop="omsCode" />
+      <el-table-column label="排序" align="center" prop="sort" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleAllot(scope.row)"
+            v-hasPermi="['store:express:allot']"
+          >分配公司</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['store:express:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['store:express: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="120px">
+        <el-form-item label="快递公司简称" prop="code">
+          <el-input v-model="form.code" placeholder="请输入快递公司简称" />
+        </el-form-item>
+        <el-form-item label="快递公司全称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入快递公司全称" />
+        </el-form-item>
+        <el-form-item label="OMS编号" prop="omsCode">
+          <el-input v-model="form.omsCode" placeholder="请输入快递公司简称" />
+        </el-form-item>
+        <el-form-item label="排序" prop="sort">
+          <el-input-number :min="0"  v-model="form.sort" placeholder="请输入排序" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog :title="allot.title" :visible.sync="allot.open" width="1100px"   append-to-body>
+      <el-transfer
+        filterable
+        width="960px"
+        :filter-method="filterMethod"
+        filter-placeholder="请输入公司名称"
+        v-model="value"
+        :titles="['所有公司', '已选公司']"
+        :right-default-checked="value"
+        :data="allCompanies">
+      </el-transfer>
+      <div slot="footer" class="dialog-footer">
+          <el-button type="primary" @click="handleAllotCompany">分 配</el-button>
+          <el-button @click="cancel1">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listExpress, getExpress, delExpress, addExpress, updateExpress, exportExpress ,allotExpress ,getExpressList,getCompanyByOmsCode} from "@/api/hisStore/express";
+import { getCompanyList} from "@/api/company/company";
+export default {
+  name: "Express",
+  data() {
+    return {
+
+      formId:null,
+        value: [],
+        value2:[],
+        filterMethod(query, item) {
+          return item.label.indexOf(query) > -1;
+        },
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      allCompanies:undefined,
+      allot:{
+        title:"分配公司",
+        open:false,
+      },
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 快递公司表格数据
+      expressList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        code: null,
+        name: null,
+        sort: null,
+        isShow: null,
+        isDel: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        code: [
+          { required: true, message: "快递公司简称不能为空", trigger: "blur" }
+        ],
+        omsCode: [
+          { required: true, message: "OMS编号不能为空", trigger: "blur" }
+        ],
+        name: [
+          { required: true, message: "快递公司全称不能为空", trigger: "blur" }
+        ],
+        sort: [
+          { required: true, message: "排序不能为空", trigger: "blur" }
+        ],
+        isShow: [
+          { required: true, message: "是否显示不能为空", trigger: "blur" }
+        ],
+      }
+    };
+  },
+  created() {
+    this.getList();
+
+  },
+
+  methods: {
+    handleAllotCompany(){
+      console.log(this.value);
+      allotExpress(this.value,this.formId).then(response => {
+      if (response.code === 200) {
+      this.msgSuccess("修改成功");
+      this.allot.open = false;
+      this.getList();
+      }
+      });
+    },
+
+    /** 查询快递公司列表 */
+    getList() {
+      this.loading = true;
+      listExpress(this.queryParams).then(response => {
+        this.expressList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    cancel1() {
+      this.allot.open = false;
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        code: null,
+        omsCode: null,
+        name: null,
+        sort: null,
+        isShow: null,
+        createTime: null,
+        updateTime: null,
+        isDel: 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 = "添加快递公司";
+    },
+    /**分配公司按钮 */
+    handleAllot(row){
+      this.allot.open = true;
+      this.formId = row.omsCode;
+      getCompanyList().then(response => {
+      let data = [];
+      response.data.forEach((item,index) => {
+        data.push({
+          key: item.companyId,
+          label:item.companyName,
+        })
+      });
+      this.allCompanies = data;
+    });
+    const omsCode = row.omsCode;
+    getCompanyByOmsCode(omsCode).then(response => {
+      this.value = response.data2
+      console.log(this.value);
+    });
+
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getExpress(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) {
+            updateExpress(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          } else {
+            addExpress(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除快递公司编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delExpress(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(function() {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有快递公司数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportExpress(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
+    }
+  },
+};
+</script>
+<style scoped lang="scss">
+.container {
+  display: flex;
+  justify-content: space-between;
+  margin-bottom: 20px;
+}
+.box {
+  width: 300px;
+}
+.el-scrollbar {
+  max-height: 300px;
+  overflow-y: auto; /* 添加滚动条 */
+}
+/* 新增样式 */
+.container {
+  display: flex;
+  justify-content: center;
+  align-items: flex-start;
+}
+.box {
+  margin: 0 10px;
+}
+
+/deep/.el-transfer-panel {
+    width:40%;
+}
+/deep/.el-transfer-panel__body{
+  height: 450px;
+}
+/deep/.el-transfer-panel__list.is-filterable {
+   height: 88%;
+}
+
+</style>
+

+ 443 - 0
src/views/hisStore/shippingTemplates/index.vue

@@ -0,0 +1,443 @@
+<template>
+  <div class="app-container">
+
+    <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:shippingTemplates:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['store:shippingTemplates: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:shippingTemplates:remove']"
+        >删除</el-button>
+      </el-col>
+	  <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table  height="500" border v-loading="loading" :data="shippingTemplatesList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="模板ID" align="center" prop="id" />
+      <el-table-column label="模板名称" align="center" prop="name" />
+      <el-table-column label="计费方式" align="center" prop="type" >
+          <template slot-scope="scope">
+              <el-tag prop="type" v-for="(item, index) in typeOptions"    v-if="scope.row.type==item.dictValue">{{item.dictLabel}}</el-tag>
+          </template>
+      </el-table-column>
+      <el-table-column label="指定包邮开关" align="center" prop="appoint" >
+          <template slot-scope="scope">
+              <el-tag prop="type" v-for="(item, index) in appointOptions"    v-if="scope.row.appoint==item.dictValue">{{item.dictLabel}}</el-tag>
+          </template>
+      </el-table-column>
+      <el-table-column label="添加时间" align="center" prop="createTime" />
+      <el-table-column label="排序" align="center" prop="sort" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['store:shippingTemplates:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['store:shippingTemplates:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改运费模板对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="130px">
+        <el-form-item label="模板名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入模板名称" />
+        </el-form-item>
+        <el-form-item label="计费方式" prop="type">
+            <el-radio-group v-model="form.type" >
+               <el-radio :label="item.dictValue" v-for="item in typeOptions" >{{item.dictLabel}}</el-radio>-radio>
+            </el-radio-group>
+        </el-form-item>
+        <el-row :gutter="24" type="flex">
+          <el-col :xl="24" :lg="24" :md="24" :sm="24" :xs="24">
+            <el-form-item class="label" label="配送区域及运费:" props="state">
+              <el-table
+                ref="table"
+                :data="templateList"
+                empty-text="暂无数据"
+                border
+              >
+                <el-table-column prop="regionName" label="可配送区域" width="130" />
+                <el-table-column prop="first" label="首件" width="120">
+                  <template slot="header" slot-scope="scope">
+                    <span v-if="form.type == 1">首件</span>
+                    <span v-else-if="form.type == 2">首件重量(KG)</span>
+                    <span v-else>首件体积(m³)</span>
+                  </template>
+                  <template slot-scope="scope">
+                    <span><el-input type="text" v-model="scope.row.first" /></span>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="price" label="运费(元)" width="110">
+                  <template slot-scope="scope">
+                    <span><el-input type="text" v-model="scope.row.price"/></span>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="_continue" label="续件" width="120">
+                  <template slot="header" slot-scope="scope">
+                    <span v-if="form.type == 1">续件</span>
+                    <span v-else-if="form.type == 2">续件重量(KG)</span>
+                    <span v-else>续件体积(m³)</span>
+                  </template>
+                  <template slot-scope="scope">
+                    <span><el-input type="text" v-model="scope.row.continues"/></span>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="continuePrice" label="续费(元)" width="110">
+                  <template slot-scope="scope">
+                    <span><el-input type="text" v-model="scope.row.continuePrice"/></span>
+                  </template>
+                </el-table-column>
+                <el-table-column  label="操作">
+                  <template slot-scope="scope">
+                    <a v-if="scope.row.regionName!=='默认全国'" @click="delCity(scope.row.index,1)">删除</a>
+                  </template>
+                </el-table-column>
+
+              </el-table>
+              <el-row type="flex" class="addTop">
+                <el-col>
+                  <el-button size="small" type="primary" icon="md-add" @click="addCity(1)">单独添加配送区域</el-button>
+                </el-col>
+              </el-row>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="24" type="flex">
+          <el-col :xl="24" :lg="24" :md="24" :sm="24" :xs="24">
+            <el-form-item label="指定包邮:" prop="appoint">
+              <el-radio-group v-model="form.appoint" >
+                    <el-radio :label="item.dictValue" v-for="item in appointOptions" >{{item.dictLabel}}</el-radio>-radio>
+                  </el-radio-group>
+              <el-table
+                ref="table"
+                :data="appointList"
+                empty-text="暂无数据"
+                border
+                v-if="form.appoint === '1'"
+              >
+                <el-table-column prop="placeName" label="选择地区" />
+                <el-table-column prop="a_num" label="包邮件数" width="120" >
+                  <template slot="header" slot-scope="scope">
+                    <span v-if="form.type == 1">包邮件数</span>
+                    <span v-else-if="form.type == 2">包邮重量(KG)</span>
+                    <span v-else>包邮体积(m³)</span>
+                  </template>
+                  <template slot-scope="scope">
+                    <span><el-input type="text" v-model="scope.row.number"/></span>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="price" label="包邮金额(元)" width="120">
+                  <template slot-scope="scope">
+                    <span><el-input type="text" v-model="scope.row.price"/></span>
+                  </template>
+                </el-table-column>
+                <el-table-column  label="操作">
+                  <template slot-scope="scope">
+                    <a v-if="scope.row.regionName!=='默认全国'" @click="delCity(scope.row.index,2)">删除</a>
+                  </template>
+                </el-table-column>
+
+              </el-table>
+              <el-row type="flex" v-if="form.appoint === '1'">
+                <el-col>
+                  <el-button size="small" type="primary" icon="md-add" @click="addCity(2)">单独指定包邮</el-button>
+                </el-col>
+              </el-row>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="排序" prop="sort">
+          <el-input-number :min="0"  v-model="form.sort" placeholder="请输入排序" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+    <city ref="city" @selectCity="selectCity" :type="type"></city>
+  </div>
+</template>
+
+<script>
+import { listShippingTemplates, getShippingTemplates, delShippingTemplates, addShippingTemplates, updateShippingTemplates, exportShippingTemplates } from "@/api/hisStore/shippingTemplates";
+import City from '@/components/City'
+export default {
+  name: "ShippingTemplates",
+  components: {
+    City
+  },
+  data() {
+    return {
+      type:0,
+      appointList:[],
+      templateList:[],
+      appointOptions:[],
+      typeOptions:[],
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 运费模板表格数据
+      shippingTemplatesList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        name: null,
+        type: null,
+        regionInfo: null,
+        appoint: null,
+        appointInfo: null,
+        isDel: null,
+        sort: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        name: [
+          { required: true, message: "名称不能为空", trigger: "blur" }
+        ],
+      }
+    };
+  },
+  created() {
+    this.getDicts("store_shipping_type").then((response) => {
+      this.typeOptions = response.data;
+    });
+    this.getDicts("store_shipping_appoint").then((response) => {
+      this.appointOptions = response.data;
+    });
+    this.getList();
+  },
+  methods: {
+    delCity (index,type) {
+      console.log(index)
+      if (type === 1) {
+        this.templateList.splice(index, 1);
+      } else {
+        this.appointList.splice(index, 1);
+      }
+    },
+    selectCity: function (data, type) {
+      let cityName = data.map(function (item) {
+        return item.name;
+      }).join(';');
+      switch (type) {
+        case 1:
+          this.templateList.push({
+            region: data,
+            regionName: cityName,
+            first: 1,
+            price: 0,
+            continues: 1,
+            continuePrice: 0
+          });
+          break;
+        case 2:
+          this.appointList.push({
+            place: data,
+            placeName: cityName,
+            number: 0,
+            price: 0
+          });
+          break;
+      }
+    },
+    // 单独添加配送区域
+    addCity (type) {
+      this.$refs.city.addressView = true;
+      this.type = type;
+      this.$refs.city.getCityList()
+    },
+    /** 查询运费模板列表 */
+    getList() {
+      this.loading = true;
+      listShippingTemplates(this.queryParams).then(response => {
+        this.shippingTemplatesList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        name: null,
+        type: "1",
+        appoint: "0",
+        createTime: null,
+        updateTime: null,
+        isDel: null,
+        sort: null
+      };
+      this.templateList = [
+        {
+          region: [
+            {
+              name: '默认全国',
+              cityId: 0
+            }
+          ],
+          regionName: '默认全国',
+          first: 1,
+          price: 0,
+          continues: 1,
+          continuePrice: 0
+        }
+      ];
+      this.appointList=[],
+      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
+      getShippingTemplates(id).then(response => {
+        this.form = response.data;
+        this.form.type = response.data.type.toString();
+        this.form.appoint = response.data.appoint.toString();
+        this.appointList=JSON.parse(this.form.appointInfo)
+        this.templateList=JSON.parse(this.form.regionInfo)
+        this.open = true;
+        this.title = "修改运费模板";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          this.form.regionInfo=this.templateList;
+          this.form.appointInfo=this.appointList;
+          if (this.form.id != null) {
+            updateShippingTemplates(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          } else {
+            addShippingTemplates(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除运费模板编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delShippingTemplates(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(function() {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有运费模板数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportShippingTemplates(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
+    }
+  }
+};
+</script>

+ 366 - 0
src/views/hisStore/shippingTemplatesFree/index.vue

@@ -0,0 +1,366 @@
+<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="tempId">
+        <el-input
+          v-model="queryParams.tempId"
+          placeholder="请输入模板ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="省ID" prop="provinceId">
+        <el-input
+          v-model="queryParams.provinceId"
+          placeholder="请输入省ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="城市ID" prop="cityId">
+        <el-input
+          v-model="queryParams.cityId"
+          placeholder="请输入城市ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="包邮件数" prop="number">
+        <el-input
+          v-model="queryParams.number"
+          placeholder="请输入包邮件数"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="包邮金额" prop="price">
+        <el-input
+          v-model="queryParams.price"
+          placeholder="请输入包邮金额"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="计费方式" prop="type">
+        <el-select v-model="queryParams.type" placeholder="请选择计费方式" clearable size="small">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="产品ID" prop="productId">
+        <el-input
+          v-model="queryParams.productId"
+          placeholder="请输入产品ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['store:shippingTemplatesFree:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['store:shippingTemplatesFree: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:shippingTemplatesFree:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['store:shippingTemplatesFree:export']"
+        >导出</el-button>
+      </el-col>
+	  <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="shippingTemplatesFreeList" @selection-change="handleSelectionChange" border>
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="编号" align="center" prop="id" />
+      <el-table-column label="模板ID" align="center" prop="tempId" />
+      <el-table-column label="省ID" align="center" prop="provinceId" />
+      <el-table-column label="城市ID" align="center" prop="cityId" />
+      <el-table-column label="包邮件数" align="center" prop="number" />
+      <el-table-column label="包邮金额" align="center" prop="price" />
+      <el-table-column label="计费方式" align="center" prop="type" />
+      <el-table-column label="产品ID" align="center" prop="productId" />
+      <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:shippingTemplatesFree:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['store:shippingTemplatesFree: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="tempId">
+          <el-input v-model="form.tempId" placeholder="请输入模板ID" />
+        </el-form-item>
+        <el-form-item label="省ID" prop="provinceId">
+          <el-input v-model="form.provinceId" placeholder="请输入省ID" />
+        </el-form-item>
+        <el-form-item label="城市ID" prop="cityId">
+          <el-input v-model="form.cityId" placeholder="请输入城市ID" />
+        </el-form-item>
+        <el-form-item label="包邮件数" prop="number">
+          <el-input v-model="form.number" placeholder="请输入包邮件数" />
+        </el-form-item>
+        <el-form-item label="包邮金额" prop="price">
+          <el-input v-model="form.price" placeholder="请输入包邮金额" />
+        </el-form-item>
+        <el-form-item label="计费方式" prop="type">
+          <el-select v-model="form.type" placeholder="请选择计费方式">
+            <el-option label="请选择字典生成" value="" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="产品ID" prop="productId">
+          <el-input v-model="form.productId" placeholder="请输入产品ID" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listShippingTemplatesFree, getShippingTemplatesFree, delShippingTemplatesFree, addShippingTemplatesFree, updateShippingTemplatesFree, exportShippingTemplatesFree } from "@/api/hisStore/shippingTemplatesFree";
+
+export default {
+  name: "ShippingTemplatesFree",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 免邮费表格数据
+      shippingTemplatesFreeList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        tempId: null,
+        provinceId: null,
+        cityId: null,
+        number: null,
+        price: null,
+        type: null,
+        productId: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        tempId: [
+          { required: true, message: "模板ID不能为空", trigger: "blur" }
+        ],
+        provinceId: [
+          { required: true, message: "省ID不能为空", trigger: "blur" }
+        ],
+        cityId: [
+          { required: true, message: "城市ID不能为空", trigger: "blur" }
+        ],
+        number: [
+          { required: true, message: "包邮件数不能为空", trigger: "blur" }
+        ],
+        price: [
+          { required: true, message: "包邮金额不能为空", trigger: "blur" }
+        ],
+        type: [
+          { required: true, message: "计费方式不能为空", trigger: "change" }
+        ],
+        productId: [
+          { required: true, message: "产品ID不能为空", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询免邮费列表 */
+    getList() {
+      this.loading = true;
+      listShippingTemplatesFree(this.queryParams).then(response => {
+        this.shippingTemplatesFreeList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        tempId: null,
+        provinceId: null,
+        cityId: null,
+        number: null,
+        price: null,
+        type: null,
+        productId: 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
+      getShippingTemplatesFree(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) {
+            updateShippingTemplatesFree(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          } else {
+            addShippingTemplatesFree(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除免邮费编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delShippingTemplatesFree(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(function() {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有免邮费数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportShippingTemplatesFree(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
+    }
+  }
+};
+</script>

+ 402 - 0
src/views/hisStore/shippingTemplatesRegion/index.vue

@@ -0,0 +1,402 @@
+<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="provinceId">
+        <el-input
+          v-model="queryParams.provinceId"
+          placeholder="请输入省ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="模板ID" prop="tempId">
+        <el-input
+          v-model="queryParams.tempId"
+          placeholder="请输入模板ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="城市ID" prop="cityId">
+        <el-input
+          v-model="queryParams.cityId"
+          placeholder="请输入城市ID"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="首件" prop="first">
+        <el-input
+          v-model="queryParams.first"
+          placeholder="请输入首件"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="首件运费" prop="firstPrice">
+        <el-input
+          v-model="queryParams.firstPrice"
+          placeholder="请输入首件运费"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="续件" prop="continues">
+        <el-input
+          v-model="queryParams.continues"
+          placeholder="请输入续件"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="续件运费" prop="continuePrice">
+        <el-input
+          v-model="queryParams.continuePrice"
+          placeholder="请输入续件运费"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="计费方式" prop="type">
+        <el-select v-model="queryParams.type" placeholder="请选择计费方式" clearable size="small">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="分组唯一值" prop="productId">
+        <el-input
+          v-model="queryParams.productId"
+          placeholder="请输入分组唯一值"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['store:shippingTemplatesRegion:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['store:shippingTemplatesRegion: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:shippingTemplatesRegion:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['store:shippingTemplatesRegion:export']"
+        >导出</el-button>
+      </el-col>
+	  <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="shippingTemplatesRegionList" @selection-change="handleSelectionChange" border>
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="编号" align="center" prop="id" />
+      <el-table-column label="省ID" align="center" prop="provinceId" />
+      <el-table-column label="模板ID" align="center" prop="tempId" />
+      <el-table-column label="城市ID" align="center" prop="cityId" />
+      <el-table-column label="首件" align="center" prop="first" />
+      <el-table-column label="首件运费" align="center" prop="firstPrice" />
+      <el-table-column label="续件" align="center" prop="continues" />
+      <el-table-column label="续件运费" align="center" prop="continuePrice" />
+      <el-table-column label="计费方式" align="center" prop="type" />
+      <el-table-column label="分组唯一值" align="center" prop="productId" />
+      <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:shippingTemplatesRegion:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['store:shippingTemplatesRegion: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="provinceId">
+          <el-input v-model="form.provinceId" placeholder="请输入省ID" />
+        </el-form-item>
+        <el-form-item label="模板ID" prop="tempId">
+          <el-input v-model="form.tempId" placeholder="请输入模板ID" />
+        </el-form-item>
+        <el-form-item label="城市ID" prop="cityId">
+          <el-input v-model="form.cityId" placeholder="请输入城市ID" />
+        </el-form-item>
+        <el-form-item label="首件" prop="first">
+          <el-input v-model="form.first" placeholder="请输入首件" />
+        </el-form-item>
+        <el-form-item label="首件运费" prop="firstPrice">
+          <el-input v-model="form.firstPrice" placeholder="请输入首件运费" />
+        </el-form-item>
+        <el-form-item label="续件" prop="continues">
+          <el-input v-model="form.continues" placeholder="请输入续件" />
+        </el-form-item>
+        <el-form-item label="续件运费" prop="continuePrice">
+          <el-input v-model="form.continuePrice" placeholder="请输入续件运费" />
+        </el-form-item>
+        <el-form-item label="计费方式" prop="type">
+          <el-select v-model="form.type" placeholder="请选择计费方式">
+            <el-option label="请选择字典生成" value="" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="分组唯一值" prop="productId">
+          <el-input v-model="form.productId" placeholder="请输入分组唯一值" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listShippingTemplatesRegion, getShippingTemplatesRegion, delShippingTemplatesRegion, addShippingTemplatesRegion, updateShippingTemplatesRegion, exportShippingTemplatesRegion } from "@/api/hisStore/shippingTemplatesRegion";
+
+export default {
+  name: "ShippingTemplatesRegion",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 邮费区域表格数据
+      shippingTemplatesRegionList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        provinceId: null,
+        tempId: null,
+        cityId: null,
+        first: null,
+        firstPrice: null,
+        continues: null,
+        continuePrice: null,
+        type: null,
+        productId: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        provinceId: [
+          { required: true, message: "省ID不能为空", trigger: "blur" }
+        ],
+        tempId: [
+          { required: true, message: "模板ID不能为空", trigger: "blur" }
+        ],
+        cityId: [
+          { required: true, message: "城市ID不能为空", trigger: "blur" }
+        ],
+        first: [
+          { required: true, message: "首件不能为空", trigger: "blur" }
+        ],
+        firstPrice: [
+          { required: true, message: "首件运费不能为空", trigger: "blur" }
+        ],
+        continues: [
+          { required: true, message: "续件不能为空", trigger: "blur" }
+        ],
+        continuePrice: [
+          { required: true, message: "续件运费不能为空", trigger: "blur" }
+        ],
+        type: [
+          { required: true, message: "计费方式不能为空", trigger: "change" }
+        ],
+        productId: [
+          { required: true, message: "分组唯一值不能为空", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询邮费区域列表 */
+    getList() {
+      this.loading = true;
+      listShippingTemplatesRegion(this.queryParams).then(response => {
+        this.shippingTemplatesRegionList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        provinceId: null,
+        tempId: null,
+        cityId: null,
+        first: null,
+        firstPrice: null,
+        continues: null,
+        continuePrice: null,
+        type: null,
+        productId: 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
+      getShippingTemplatesRegion(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) {
+            updateShippingTemplatesRegion(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("修改成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          } else {
+            addShippingTemplatesRegion(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("新增成功");
+                this.open = false;
+                this.getList();
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除邮费区域编号为"' + ids + '"的数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return delShippingTemplatesRegion(ids);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("删除成功");
+        }).catch(function() {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有邮费区域数据项?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(function() {
+          return exportShippingTemplatesRegion(queryParams);
+        }).then(response => {
+          this.download(response.msg);
+        }).catch(function() {});
+    }
+  }
+};
+</script>

+ 328 - 0
src/views/medical/indicator/index.vue

@@ -0,0 +1,328 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="指标名称" prop="indicatorName">
+        <el-input
+          v-model="queryParams.indicatorName"
+          placeholder="请输入指标名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="分类" prop="category">
+        <el-select v-model="queryParams.category" placeholder="请选择分类" clearable>
+          <el-option
+            v-for="dict in categoryOptions"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </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="['medical:indicator: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="['medical:indicator: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="['medical:indicator:remove']"
+        >删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="indicatorList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="指标ID" align="center" prop="indicatorId" />
+      <el-table-column label="指标名称" align="center" prop="indicatorName" />
+      <el-table-column label="指标代码" align="center" prop="indicatorCode" />
+      <el-table-column label="分类" align="center" prop="category">
+        <template slot-scope="scope">
+          <dict-tag :options="categoryOptions" :value="scope.row.category"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="单位" align="center" prop="unit" />
+      <el-table-column label="正常范围" align="center" prop="normalRange" />
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['medical:indicator:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['medical:indicator:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改医疗指标对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="指标名称" prop="indicatorName">
+          <el-input v-model="form.indicatorName" placeholder="请输入指标名称" />
+        </el-form-item>
+        <el-form-item label="指标代码" prop="indicatorCode">
+          <el-input v-model="form.indicatorCode" placeholder="请输入指标代码" />
+        </el-form-item>
+        <el-form-item label="分类" prop="category">
+          <el-select v-model="form.category" placeholder="请选择分类">
+            <el-option
+              v-for="dict in categoryOptions"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="单位" prop="unit">
+          <el-input v-model="form.unit" placeholder="请输入单位" />
+        </el-form-item>
+        <el-form-item label="正常范围" prop="normalRange">
+          <el-input v-model="form.normalRange" placeholder="请输入正常范围" />
+        </el-form-item>
+        <el-form-item label="描述" prop="description">
+          <el-input v-model="form.description" type="textarea" placeholder="请输入描述" />
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in statusOptions"
+              :key="dict.value"
+              :label="dict.value"
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listIndicator, getIndicator, delIndicator, addIndicator, updateIndicator } from "@/api/medical/indicator";
+
+export default {
+  name: "Indicator",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 医疗指标表格数据
+      indicatorList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 分类字典
+      categoryOptions: [],
+      // 状态字典
+      statusOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        indicatorName: null,
+        category: null,
+        status: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        indicatorName: [
+          { required: true, message: "指标名称不能为空", trigger: "blur" }
+        ],
+        indicatorCode: [
+          { required: true, message: "指标代码不能为空", trigger: "blur" }
+        ],
+        category: [
+          { required: true, message: "分类不能为空", trigger: "change" }
+        ],
+        status: [
+          { required: true, message: "状态不能为空", trigger: "change" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("indicator_category").then(response => {
+      this.categoryOptions = response.data;
+    });
+    this.getDicts("indicator_status").then(response => {
+      this.statusOptions = response.data;
+    });
+  },
+  methods: {
+    /** 查询医疗指标列表 */
+    getList() {
+      this.loading = true;
+      listIndicator(this.queryParams).then(response => {
+        this.indicatorList = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        indicatorId: null,
+        indicatorName: null,
+        indicatorCode: null,
+        category: null,
+        unit: null,
+        normalRange: null,
+        description: null,
+        status: "1"
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.indicatorId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加医疗指标";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const indicatorId = row.indicatorId || this.ids
+      getIndicator(indicatorId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改医疗指标";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.indicatorId != null) {
+            updateIndicator(this.form).then(response => {
+              this.$message.success("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addIndicator(this.form).then(response => {
+              this.$message.success("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const indicatorIds = row.indicatorId || this.ids;
+      this.$confirm('是否确认删除医疗指标编号为"' + indicatorIds + '"的数据项?').then(function() {
+        return delIndicator(indicatorIds);
+      }).then(() => {
+        this.getList();
+        this.$message.success("删除成功");
+      }).catch(() => {});
+    }
+  }
+};
+</script>

+ 910 - 0
src/views/medical/report/index.vue

@@ -0,0 +1,910 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="用户ID" prop="userId">
+        <el-input
+          v-model="queryParams.userId"
+          placeholder="请输入用户ID"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="体检日期" prop="examDate">
+        <el-date-picker clearable
+                        v-model="queryParams.examDate"
+                        type="date"
+                        value-format="yyyy-MM-dd"
+                        placeholder="请选择体检日期">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['medical:report: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="['medical:report: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="['medical:report:remove']"
+        >删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="reportList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="报告ID" align="center" prop="reportId" />
+      <el-table-column label="用户" align="center" prop="userName" />
+      <el-table-column label="销售" align="center" prop="companyUserName" />
+      <el-table-column label="体检日期" align="center" prop="examDate" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.examDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="身高(cm)" align="center" prop="height" />
+      <el-table-column label="体重(kg)" align="center" prop="weight" />
+      <el-table-column label="BMI" align="center" prop="bmi" />
+      <el-table-column label="血压" align="center" prop="bloodPressure" />
+      <el-table-column label="心率" align="center" prop="heartRate" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['medical:report:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['medical:report: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-tabs v-model="activeTab">
+        <el-tab-pane label="身体信息" name="bodyInfo">
+          <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+            <el-row :gutter="20">
+              <el-col :span="12">
+                <el-form-item label="用户ID" prop="userId">
+                  <el-input v-model="form.userId" placeholder="请输入用户ID" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="用户名" prop="userName">
+                  <el-input v-model="form.userName" placeholder="请输入用户名" />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="12">
+                <el-form-item label="销售ID" prop="companyUserId">
+                  <el-input v-model="form.companyUserId" placeholder="请输入销售ID" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="销售名称" prop="companyUserName">
+                  <el-input v-model="form.companyUserName" placeholder="请输入销售名称" />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="12">
+                <el-form-item label="体检日期" prop="examDate">
+                  <el-date-picker clearable
+                                  v-model="form.examDate"
+                                  type="date"
+                                  value-format="yyyy-MM-dd"
+                                  placeholder="请选择体检日期">
+                  </el-date-picker>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="8">
+                <el-form-item label="身高(cm)" prop="height">
+                  <el-input v-model="form.height" placeholder="请输入身高" @input="calculateBMI" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="8">
+                <el-form-item label="体重(kg)" prop="weight">
+                  <el-input v-model="form.weight" placeholder="请输入体重" @input="calculateBMI" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="8">
+                <el-form-item label="BMI指数" prop="bmi">
+                  <el-input v-model="form.bmi" placeholder="BMI自动计算" disabled />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="12">
+                <el-form-item label="腰围(cm)" prop="waistCircumference">
+                  <el-input v-model="form.waistCircumference" placeholder="请输入腰围" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="胸围(cm)" prop="chestCircumference">
+                  <el-input v-model="form.chestCircumference" placeholder="请输入胸围" />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="12">
+                <el-form-item label="血压" prop="bloodPressure">
+                  <el-input v-model="form.bloodPressure" placeholder="请输入血压" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="心率" prop="heartRate">
+                  <el-input v-model="form.heartRate" placeholder="请输入心率" />
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </el-form>
+        </el-tab-pane>
+
+        <el-tab-pane label="指标检查" name="indicators">
+          <div class="indicator-toolbar" style="margin-bottom: 15px;">
+            <el-input
+              placeholder="搜索指标"
+              v-model="indicatorSearch"
+              style="width: 200px; margin-right: 10px;"
+              class="filter-item"
+              @keyup.enter.native="searchIndicators"
+            >
+              <el-button slot="append" icon="el-icon-search" @click="searchIndicators"></el-button>
+            </el-input>
+            <el-select
+              v-model="indicatorCateId"
+              placeholder="选择指标分类"
+              clearable
+              style="width: 180px; margin-right: 10px;"
+              @change="handleIndicatorCateChange"
+            >
+              <el-option
+                v-for="item in indicatorCateOptions"
+                :key="item.dictValue"
+                :label="item.dictLabel"
+                :value="item.dictValue">
+              </el-option>
+            </el-select>
+            <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAddIndicator">添加指标</el-button>
+          </div>
+          <el-table :data="indicatorList" style="width: 100%" v-loading="indicatorLoading">
+            <el-table-column prop="indicatorName" label="指标名称" />
+            <el-table-column prop="testValue" label="检测值" />
+            <el-table-column prop="refRange" label="参考范围" />
+            <el-table-column label="结果评价" align="center">
+              <template slot-scope="scope">
+                <el-tag v-if="scope.row.isAbnormal === 0" type="success">正常</el-tag>
+                <el-tag v-else-if="scope.row.abnormalType === '偏高'" type="danger">偏高</el-tag>
+                <el-tag v-else-if="scope.row.abnormalType === '偏低'" type="warning">偏低</el-tag>
+                <el-tag v-else-if="scope.row.isAbnormal === 1" type="danger">异常</el-tag>
+                <span v-else>-</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="操作" width="150">
+              <template slot-scope="scope">
+                <el-button type="text" size="small" @click="viewIndicatorDetail(scope.row)">查看详情</el-button>
+                <el-button type="text" size="small" @click="editIndicator(scope.row)">编辑</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+          
+          <!-- 指标检查分页 -->
+          <pagination
+            v-show="indicatorTotal > 0"
+            :total="indicatorTotal"
+            :page.sync="indicatorQueryParams.pageNum"
+            :limit.sync="indicatorQueryParams.pageSize"
+            @pagination="loadIndicators"
+            style="margin-top: 15px;"
+          />
+        </el-tab-pane>
+      </el-tabs>
+
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 指标详情对话框 -->
+    <el-dialog title="指标详情" :visible.sync="indicatorDetailVisible" width="600px" append-to-body>
+      <el-descriptions :column="1" border>
+        <el-descriptions-item label="指标名称">{{ currentIndicator.indicatorName }}</el-descriptions-item>
+        <el-descriptions-item label="检测值">{{ currentIndicator.testValue || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="参考范围">{{ currentIndicator.refRange }}</el-descriptions-item>
+        <el-descriptions-item label="结果评价">
+          <el-tag v-if="currentIndicator.isAbnormal === 0" type="success">正常</el-tag>
+          <el-tag v-else-if="currentIndicator.abnormalType === '偏高'" type="danger">偏高</el-tag>
+          <el-tag v-else-if="currentIndicator.abnormalType === '偏低'" type="warning">偏低</el-tag>
+          <el-tag v-else-if="currentIndicator.isAbnormal === 1" type="danger">异常</el-tag>
+          <span v-else>-</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="备注说明">{{ currentIndicator.remarks || '-' }}</el-descriptions-item>
+      </el-descriptions>
+    </el-dialog>
+
+    <!-- 添加指标对话框 -->
+    <el-dialog title="添加指标" :visible.sync="indicatorSelectVisible" width="600px" append-to-body>
+      <div class="search-container" style="margin-bottom: 15px;">
+        <el-input
+          placeholder="搜索指标库"
+          v-model="indicatorLibrarySearch"
+          style="width: 250px; margin-right: 10px;"
+          @keyup.enter.native="searchIndicatorLibrary"
+        >
+          <el-button slot="append" icon="el-icon-search" @click="searchIndicatorLibrary"></el-button>
+        </el-input>
+        <el-select v-model="indicatorCategory" placeholder="选择分类" style="width: 150px;">
+          <el-option
+            v-for="item in indicatorCategoryOptions"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value">
+          </el-option>
+        </el-select>
+      </div>
+
+      <el-table
+        :data="indicatorLibrary"
+        style="width: 100%"
+        height="350px"
+        @selection-change="handleIndicatorSelectionChange">
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="indicatorName" label="指标名称" />
+        <el-table-column prop="indicatorCategory" label="分类" />
+        <el-table-column label="参考范围" align="center">
+          <template slot-scope="scope">
+            {{ formatReferenceRange(scope.row) }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="description" label="描述" />
+      </el-table>
+
+      <div style="margin-top: 15px;">
+        <el-pagination
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+          :current-page="currentPage"
+          :page-sizes="[10, 20, 50, 100]"
+          :page-size="pageSize"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="totalIndicators">
+        </el-pagination>
+      </div>
+
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="addSelectedIndicators">添加所选指标</el-button>
+        <el-button @click="indicatorSelectVisible = false">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 编辑指标结果对话框 -->
+    <el-dialog title="编辑指标结果" :visible.sync="indicatorResultDialogVisible" width="500px" append-to-body>
+      <el-form ref="indicatorResultForm" :model="indicatorResultForm" :rules="indicatorResultRules" label-width="100px">
+        <el-form-item label="指标名称">
+          <span>{{ indicatorResultForm.indicatorName }}</span>
+        </el-form-item>
+        <el-form-item label="参考范围">
+          <span>{{ indicatorResultForm.referenceRange }}</span>
+        </el-form-item>
+        <el-form-item label="检查数值" prop="testValue">
+          <el-input v-model="indicatorResultForm.testValue" placeholder="请输入检查数值" />
+        </el-form-item>
+        <el-form-item label="检查结果" prop="testResult">
+          <el-input v-model="indicatorResultForm.testResult" placeholder="请输入检查结果(文本)" />
+        </el-form-item>
+        <el-form-item label="是否异常">
+          <el-radio-group v-model="indicatorResultForm.isAbnormal">
+            <el-radio :label="0">正常</el-radio>
+            <el-radio :label="1">异常</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="异常类型" v-if="indicatorResultForm.isAbnormal === 1" prop="abnormalType">
+          <el-select v-model="indicatorResultForm.abnormalType" placeholder="请选择异常类型">
+            <el-option label="偏高" value="偏高" />
+            <el-option label="偏低" value="偏低" />
+            <el-option label="其他" value="其他" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="备注说明" prop="remarks">
+          <el-input v-model="indicatorResultForm.remarks" type="textarea" rows="3" placeholder="请输入备注说明" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitIndicatorResult">确 定</el-button>
+        <el-button @click="indicatorResultDialogVisible = false">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listReport, getReport, delReport, addReport, updateReport } from "@/api/medical/report";
+import { parseTime } from "@/utils/common";
+import { getDicts } from "@/api/system/dict/data";
+
+export default {
+  name: "Report",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 体检报告表格数据
+      reportList: [],
+      indicatorCateId: '', // 选中的指标分类ID
+      indicatorCateOptions: [], // 指标分类选项列表
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 当前激活的tab页
+      activeTab: 'bodyInfo',
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: null,
+        examDate: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        userId: [
+          { required: true, message: "用户ID不能为空", trigger: "blur" }
+        ],
+        examDate: [
+          { required: true, message: "体检日期不能为空", trigger: "blur" }
+        ]
+      },
+      // 指标搜索
+      indicatorSearch: '',
+      // 指标列表
+      indicatorList: [],
+      // 肝功能列表
+      liverFunctionList: [],
+      // 指标详情对话框可见性
+      indicatorDetailVisible: false,
+      // 当前查看的指标
+      currentIndicator: {},
+      // 指标选择对话框可见性
+      indicatorSelectVisible: false,
+      // 指标库搜索
+      indicatorLibrarySearch: '',
+      // 指标分类
+      indicatorCategory: '',
+      // 指标分类选项
+      indicatorCategoryOptions: [
+        { value: '', label: '全部' },
+        { value: '肝脏', label: '肝脏' },
+        { value: '血常规', label: '血常规' },
+        { value: '尿常规', label: '尿常规' },
+        { value: '心脏', label: '心脏' },
+        { value: '肾功能', label: '肾功能' },
+        { value: '血脂', label: '血脂' },
+        { value: '其他', label: '其他' }
+      ],
+      // 指标库数据
+      indicatorLibrary: [],
+      // 选中的指标
+      selectedIndicators: [],
+      // 分页
+      currentPage: 1,
+      pageSize: 10,
+      totalIndicators: 0,
+      // 指标结果对话框可见性
+      indicatorResultDialogVisible: false,
+      // 指标结果表单
+      indicatorResultForm: {
+        resultId: null,
+        indicatorName: '',
+        referenceRange: '',
+        testValue: '',
+        testResult: '',
+        isAbnormal: 0,
+        abnormalType: '',
+        remarks: ''
+      },
+      // 指标结果表单校验规则
+      indicatorResultRules: {
+        testValue: [
+          { required: true, message: "检查数值不能为空", trigger: "blur" }
+        ],
+        testResult: [
+          { required: true, message: "检查结果不能为空", trigger: "blur" }
+        ],
+        abnormalType: [
+          { required: true, message: "异常类型不能为空", trigger: "blur" }
+        ]
+      },
+             // 指标检查分页参数
+       indicatorQueryParams: {
+         pageNum: 1,
+         pageSize: 10,
+         reportId: null, // 报告ID
+         indicatorName: '', // 指标名称
+         indicatorCateId: '', // 指标分类ID
+         isAbnormal: null // 是否异常
+       },
+      // 指标检查加载状态
+      indicatorLoading: false,
+      // 指标检查总条数
+      indicatorTotal: 0
+    };
+  },
+  created() {
+    this.getList();
+    this.loadIndicatorCateDict(); // 加载指标分类字典
+  },
+  methods: {
+    /**
+     * 加载指标分类字典数据
+     */
+    loadIndicatorCateDict() {
+      getDicts('user_custom_type').then(response => {
+        this.indicatorCateOptions = response.data || [];
+        console.log('指标分类字典加载成功:', this.indicatorCateOptions);
+      }).catch(error => {
+        console.error("加载指标分类字典失败", error);
+        this.$message.error("加载指标分类字典失败");
+      });
+    },
+    parseTime,
+    /** 查询体检报告列表 */
+    getList() {
+      this.loading = true;
+      listReport(this.queryParams).then(response => {
+        this.reportList = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        reportId: null,
+        userId: null,
+        userName: null,
+        companyUserId: null,
+        companyUserName: null,
+        examDate: null,
+        height: null,
+        weight: null,
+        bmi: null,
+        waistCircumference: null,
+        chestCircumference: null,
+        bloodPressure: null,
+        heartRate: null,
+        generalCondition: null,
+        skinAndMucosa: null,
+        lymphNodes: null,
+        head: null,
+        neck: null,
+        chest: null,
+        heart: null,
+        lungs: null,
+        abdomen: null,
+        examResult: null,
+        doctorAdvice: null
+      };
+      this.resetForm("form");
+      // 重置指标列表
+      this.indicatorList = [];
+      this.liverFunctionList = [];
+      // 重置当前tab
+      this.activeTab = 'bodyInfo';
+      // 重置指标查询参数
+      this.indicatorQueryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        reportId: null,
+        indicatorName: '',
+        indicatorCateId: '',
+        isAbnormal: null
+      };
+      this.indicatorSearch = '';
+      this.indicatorCateId = '';
+      this.indicatorTotal = 0;
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    // 搜索指标
+    searchIndicators() {
+      if (!this.form.reportId) {
+        return;
+      }
+      
+      // 重置到第一页
+      this.indicatorQueryParams.pageNum = 1;
+      this.indicatorQueryParams.reportId = this.form.reportId;
+      this.loadIndicators(this.form.reportId);
+    },
+
+    /**
+     * 指标分类筛选变化处理
+     */
+    handleIndicatorCateChange(value) {
+      this.indicatorCateId = value;
+      this.searchIndicators();
+    },
+
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.reportId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加体检报告";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const reportId = row.reportId || this.ids
+      getReport(reportId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改体检报告";
+        
+        // 设置指标查询参数
+        this.indicatorQueryParams.reportId = reportId;
+        this.indicatorQueryParams.pageNum = 1;
+        
+        // 获取指标数据
+        this.loadIndicators(reportId);
+        // 获取肝功能数据
+        this.loadLiverFunction(reportId);
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.reportId != null) {
+            updateReport(this.form).then(response => {
+              this.$message.success("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addReport(this.form).then(response => {
+              this.$message.success("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const reportIds = row.reportId || this.ids;
+      this.$confirm('是否确认删除体检报告编号为"' + reportIds + '"的数据项?').then(function() {
+        return delReport(reportIds);
+      }).then(() => {
+        this.getList();
+        this.$message.success("删除成功");
+      }).catch(() => {});
+    },
+
+    // 自动计算BMI
+    calculateBMI() {
+      if (this.form.height && this.form.weight) {
+        const height = parseFloat(this.form.height) / 100; // 转换为米
+        const weight = parseFloat(this.form.weight);
+        if (height > 0 && weight > 0) {
+          this.form.bmi = (weight / (height * height)).toFixed(2);
+        }
+      }
+    },
+
+    // 加载指标数据
+    loadIndicators(reportId) {
+      this.indicatorLoading = true; // 开始加载
+      
+      // 如果有reportId参数,更新查询参数
+      if (reportId) {
+        this.indicatorQueryParams.reportId = reportId;
+      }
+      
+      // 调用API从后端获取报告相关的指标检查结果
+      return import('@/api/medical/reportIndicator').then(module => {
+        const { listResult } = module;
+        const query = {
+          reportId: this.indicatorQueryParams.reportId,
+          pageNum: this.indicatorQueryParams.pageNum,
+          pageSize: this.indicatorQueryParams.pageSize,
+          indicatorName: this.indicatorSearch || undefined,
+          indicatorCateId: this.indicatorCateId || undefined,
+          isAbnormal: this.indicatorQueryParams.isAbnormal || undefined
+        };
+        return listResult(query).then(response => {
+          this.indicatorList = response.data.list;
+          this.indicatorTotal = response.data.total;
+          this.indicatorLoading = false; // 结束加载
+          return this.indicatorList; // 返回过滤后的数据
+        });
+      }).catch(error => {
+        console.error("加载指标数据失败", error);
+        this.$message.error("加载指标数据失败");
+        this.indicatorLoading = false; // 结束加载
+        throw error; // 重新抛出错误
+      });
+    },
+
+    // 加载肝功能数据
+    loadLiverFunction(reportId) {
+      // 调用API从后端获取报告相关的肝功能检查结果
+      return import('@/api/medical/reportIndicator').then(module => {
+        const { listResult } = module;
+        const query = {
+          reportId: reportId,
+          pageNum: 1,
+          pageSize: 1000 // 获取足够多的数据
+        };
+        return listResult(query).then(response => {
+          // 过滤出肝功能相关的指标
+          this.liverFunctionList = response.data.list.filter(item => item.category === '肝脏' || item.indicatorCategory === '肝脏');
+          return this.liverFunctionList; // 返回过滤后的数据
+        });
+      }).catch(error => {
+        console.error("加载肝功能数据失败", error);
+        this.$message.error("加载肝功能数据失败");
+        throw error; // 重新抛出错误
+      });
+    },
+
+    // 搜索指标
+    searchIndicators() {
+      if (!this.form.reportId) {
+        return;
+      }
+      
+      // 重置到第一页
+      this.indicatorQueryParams.pageNum = 1;
+      this.indicatorQueryParams.reportId = this.form.reportId;
+      this.loadIndicators(this.form.reportId);
+    },
+
+    /**
+     * 重置指标筛选条件
+     */
+    resetIndicatorFilter() {
+      this.indicatorSearch = '';
+      this.indicatorCateId = '';
+      this.searchIndicators();
+    },
+    // 查看指标详情
+    viewIndicatorDetail(indicator) {
+      this.currentIndicator = indicator;
+      this.indicatorDetailVisible = true;
+    },
+
+    // 添加指标
+    handleAddIndicator() {
+      if (!this.form.reportId) {
+        this.$message.warning("请先保存体检报告,再添加指标");
+        return;
+      }
+
+      // 加载指标库数据
+      this.searchIndicatorLibrary();
+      this.indicatorSelectVisible = true;
+    },
+
+    // 搜索指标库
+    searchIndicatorLibrary() {
+      // 构建查询参数
+      const query = {
+        pageNum: this.currentPage,
+        pageSize: this.pageSize,
+        indicatorName: this.indicatorLibrarySearch || undefined,
+        indicatorCategory: this.indicatorCategory || undefined
+      };
+
+      // 调用API查询指标库
+      import('@/api/medical/indicator').then(module => {
+        const { listIndicator } = module;
+        listIndicator(query).then(response => {
+          this.indicatorLibrary = response.data.list;
+          this.totalIndicators = response.data.total;
+        });
+      }).catch(error => {
+        console.error("搜索指标库失败", error);
+        this.$message.error("搜索指标库失败");
+      });
+    },
+
+    // 分页大小变化
+    handleSizeChange(val) {
+      this.pageSize = val;
+      this.searchIndicatorLibrary();
+    },
+
+    // 分页页码变化
+    handleCurrentChange(val) {
+      this.currentPage = val;
+      this.searchIndicatorLibrary();
+    },
+
+    // 指标选择变化
+    handleIndicatorSelectionChange(selection) {
+      this.selectedIndicators = selection;
+    },
+
+    // 添加选中的指标
+    addSelectedIndicators() {
+      if (this.selectedIndicators.length === 0) {
+        this.$message.warning("请至少选择一个指标");
+        return;
+      }
+
+      // 准备批量添加的数据
+      const batchData = this.selectedIndicators.map(item => ({
+        reportId: this.form.reportId,
+        indicatorId: item.indicatorId,
+        testValue: null,
+        testResult: null,
+        isAbnormal: 0,
+        abnormalType: null,
+        remarks: null
+      }));
+
+      // 调用API批量添加指标结果
+      import('@/api/medical/reportIndicator').then(module => {
+        const { batchAddResult } = module;
+        batchAddResult(batchData).then(() => {
+          this.$message.success("添加指标成功");
+          this.indicatorSelectVisible = false;
+          // 重新加载指标数据
+          this.loadIndicators();
+          // 重新加载肝功能数据
+          this.loadLiverFunction(this.form.reportId);
+        });
+      }).catch(error => {
+        console.error("添加指标失败", error);
+        this.$message.error("添加指标失败");
+      });
+    },
+
+    // 格式化参考范围
+    formatReferenceRange(indicator) {
+      if (indicator.referenceText) {
+        return indicator.referenceText;
+      } else if (indicator.referenceMin !== null && indicator.referenceMax !== null) {
+        return `${indicator.referenceMin}-${indicator.referenceMax}`;
+      } else if (indicator.referenceMin !== null) {
+        return `>${indicator.referenceMin}`;
+      } else if (indicator.referenceMax !== null) {
+        return `<${indicator.referenceMax}`;
+      }
+      return '无参考范围';
+    },
+
+    // 编辑指标结果
+    editIndicator(indicator) {
+      this.indicatorResultForm = {
+        resultId: indicator.resultId,
+        indicatorName: indicator.indicatorName || indicator.name,
+        referenceRange: indicator.refRange || '',
+        testValue: indicator.testValue || '',
+        testResult: indicator.testResult || '',
+        isAbnormal: indicator.isAbnormal || 0,
+        abnormalType: indicator.abnormalType || '',
+        remarks: indicator.remarks || ''
+      };
+      this.indicatorResultDialogVisible = true;
+    },
+
+    // 提交指标结果
+    submitIndicatorResult() {
+      this.$refs.indicatorResultForm.validate(valid => {
+        if (valid) {
+          // 调用API更新指标结果
+          import('@/api/medical/reportIndicator').then(module => {
+            const { updateResult } = module;
+            const data = {
+              resultId: this.indicatorResultForm.resultId,
+              testValue: this.indicatorResultForm.testValue,
+              testResult: this.indicatorResultForm.testResult,
+              isAbnormal: this.indicatorResultForm.isAbnormal,
+              abnormalType: this.indicatorResultForm.abnormalType,
+              remarks: this.indicatorResultForm.remarks
+            };
+
+            updateResult(data).then(() => {
+              this.$message.success("更新指标结果成功");
+              this.indicatorResultDialogVisible = false;
+              // 重新加载指标数据
+              this.loadIndicators();
+              // 重新加载肝功能数据
+              this.loadLiverFunction(this.form.reportId);
+            });
+          }).catch(error => {
+            console.error("更新指标结果失败", error);
+            this.$message.error("更新指标结果失败");
+          });
+        }
+      });
+    }
+  }
+};
+</script>

+ 468 - 0
src/views/medical/reportIndicator/index.vue

@@ -0,0 +1,468 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="报告ID" prop="reportId">
+        <el-input
+          v-model="queryParams.reportId"
+          placeholder="请输入报告ID"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="指标ID" prop="indicatorId">
+        <el-input
+          v-model="queryParams.indicatorId"
+          placeholder="请输入指标ID"
+          clearable
+          @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="['medical:result:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleBatchAdd"
+          v-hasPermi="['medical:result:add']"
+        >批量新增</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="resultList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="结果ID" align="center" prop="resultId" />
+      <el-table-column label="报告ID" align="center" prop="reportId" />
+      <el-table-column label="指标ID" align="center" prop="indicatorId" />
+      <el-table-column label="指标名称" align="center" prop="indicatorName" />
+      <el-table-column label="检查结果" align="center" prop="resultValue" />
+      <el-table-column label="参考范围" align="center" prop="referenceRange" />
+      <el-table-column label="单位" align="center" prop="unit" />
+      <el-table-column label="异常标识" align="center" prop="abnormalFlag">
+        <template slot-scope="scope">
+          <dict-tag :options="abnormalFlagOptions" :value="scope.row.abnormalFlag"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-view"
+            @click="handleDetail(scope.row)"
+            v-hasPermi="['medical:result:query']"
+          >详情</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['medical:result:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['medical:result: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="reportId">
+          <el-input v-model="form.reportId" placeholder="请输入报告ID" />
+        </el-form-item>
+        <el-form-item label="指标ID" prop="indicatorId">
+          <el-input v-model="form.indicatorId" placeholder="请输入指标ID" />
+        </el-form-item>
+        <el-form-item label="指标名称" prop="indicatorName">
+          <el-input v-model="form.indicatorName" placeholder="请输入指标名称" />
+        </el-form-item>
+        <el-form-item label="检查结果" prop="resultValue">
+          <el-input v-model="form.resultValue" placeholder="请输入检查结果" />
+        </el-form-item>
+        <el-form-item label="参考范围" prop="referenceRange">
+          <el-input v-model="form.referenceRange" placeholder="请输入参考范围" />
+        </el-form-item>
+        <el-form-item label="单位" prop="unit">
+          <el-input v-model="form.unit" placeholder="请输入单位" />
+        </el-form-item>
+        <el-form-item label="异常标识" prop="abnormalFlag">
+          <el-select v-model="form.abnormalFlag" placeholder="请选择异常标识">
+            <el-option
+              v-for="dict in abnormalFlagOptions"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 批量新增对话框 -->
+    <el-dialog title="批量新增检查结果" :visible.sync="batchOpen" width="800px" append-to-body>
+      <el-form ref="batchForm" :model="batchForm" label-width="80px">
+        <el-form-item label="报告ID" prop="reportId">
+          <el-input v-model="batchForm.reportId" placeholder="请输入报告ID" />
+        </el-form-item>
+        <el-button type="primary" size="mini" @click="addBatchRow">添加行</el-button>
+        <el-table :data="batchForm.results" style="margin-top: 10px;">
+          <el-table-column label="指标ID" width="100">
+            <template slot-scope="scope">
+              <el-input v-model="scope.row.indicatorId" size="mini" />
+            </template>
+          </el-table-column>
+          <el-table-column label="指标名称" width="120">
+            <template slot-scope="scope">
+              <el-input v-model="scope.row.indicatorName" size="mini" />
+            </template>
+          </el-table-column>
+          <el-table-column label="检查结果" width="100">
+            <template slot-scope="scope">
+              <el-input v-model="scope.row.resultValue" size="mini" />
+            </template>
+          </el-table-column>
+          <el-table-column label="参考范围" width="120">
+            <template slot-scope="scope">
+              <el-input v-model="scope.row.referenceRange" size="mini" />
+            </template>
+          </el-table-column>
+          <el-table-column label="单位" width="80">
+            <template slot-scope="scope">
+              <el-input v-model="scope.row.unit" size="mini" />
+            </template>
+          </el-table-column>
+          <el-table-column label="异常标识" width="100">
+            <template slot-scope="scope">
+              <el-select v-model="scope.row.abnormalFlag" size="mini">
+                <el-option
+                  v-for="dict in abnormalFlagOptions"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+                ></el-option>
+              </el-select>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作" width="80">
+            <template slot-scope="scope">
+              <el-button type="text" size="mini" @click="removeBatchRow(scope.$index)">删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitBatchForm">确 定</el-button>
+        <el-button @click="cancelBatch">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 详情对话框 -->
+    <el-dialog title="检查结果详情" :visible.sync="detailOpen" width="500px" append-to-body>
+      <el-descriptions :column="2" border>
+        <el-descriptions-item label="结果ID">{{ detailData.resultId }}</el-descriptions-item>
+        <el-descriptions-item label="报告ID">{{ detailData.reportId }}</el-descriptions-item>
+        <el-descriptions-item label="指标ID">{{ detailData.indicatorId }}</el-descriptions-item>
+        <el-descriptions-item label="指标名称">{{ detailData.indicatorName }}</el-descriptions-item>
+        <el-descriptions-item label="检查结果">{{ detailData.resultValue }}</el-descriptions-item>
+        <el-descriptions-item label="参考范围">{{ detailData.referenceRange }}</el-descriptions-item>
+        <el-descriptions-item label="单位">{{ detailData.unit }}</el-descriptions-item>
+        <el-descriptions-item label="异常标识">
+          <dict-tag :options="abnormalFlagOptions" :value="detailData.abnormalFlag"/>
+        </el-descriptions-item>
+        <el-descriptions-item label="创建时间" :span="2">
+          {{ parseTime(detailData.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}
+        </el-descriptions-item>
+        <el-descriptions-item label="备注" :span="2">{{ detailData.remark }}</el-descriptions-item>
+      </el-descriptions>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="detailOpen = false">关 闭</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listResult, getResult, delResult, addResult, updateResult, batchAddResult, listByReportId, listByIndicatorId } from "@/api/medical/reportIndicator";
+
+export default {
+  name: "Result",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 报告指标检查结果表格数据
+      resultList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 是否显示批量新增弹出层
+      batchOpen: false,
+      // 是否显示详情弹出层
+      detailOpen: false,
+      // 详情数据
+      detailData: {},
+      // 异常标识字典
+      abnormalFlagOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        reportId: null,
+        indicatorId: null,
+      },
+      // 表单参数
+      form: {},
+      // 批量表单参数
+      batchForm: {
+        reportId: null,
+        results: []        },
+      // 表单校验规则
+      rules: {
+        reportId: [{ required: true, message: '请输入报告ID', trigger: 'blur' }],
+        indicatorId: [{ required: true, message: '请输入指标ID', trigger: 'blur' }],
+        indicatorName: [{ required: true, message: '请输入指标名称', trigger: 'blur' }],
+        resultValue: [{ required: true, message: '请输入检查结果', trigger: 'blur' }],
+        referenceRange: [{ required: true, message: '请输入参考范围', trigger: 'blur' }],
+        unit: [{ required: true, message: '请输入单位', trigger: 'blur' }],
+        abnormalFlag: [{ required: true, message: '请选择异常标识', trigger: 'change' }],
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.loadDictData();
+  },
+  methods: {
+    // 加载异常标识字典数据
+    loadDictData() {
+      // 这里模拟加载字典数据,实际可以根据项目字典接口替换
+      this.abnormalFlagOptions = [
+        { label: '正常', value: '0' },
+        { label: '异常', value: '1' }
+      ];
+    },
+    // 查询列表
+    getList() {
+      this.loading = true;
+      listResult(this.queryParams).then((res) => {
+        if (res && res.data) {
+          this.resultList = res.data.list;
+          this.total = res.data.total;
+        }
+        this.loading = false;
+      }).catch(() => {
+        this.loading = false;
+      });
+    },
+    // 重置搜索条件
+    resetQuery() {
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        reportId: null,
+        indicatorId: null,
+      };
+      this.getList();
+    },
+    // 处理查询按钮点击
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    // 选择项变化
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.resultId);
+      this.single = this.ids.length !== 1;
+      this.multiple = this.ids.length === 0;
+    },
+    // 打开新增弹窗
+    handleAdd() {
+      this.title = "新增检查结果";
+      this.form = {};
+      this.open = true;
+      this.$nextTick(() => {
+        if (this.$refs.form) {
+          this.$refs.form.resetFields();
+        }
+      });
+    },
+    // 打开批量新增弹窗
+    handleBatchAdd() {
+      this.batchForm = {
+        reportId: null,
+        results: []
+      };
+      this.batchOpen = true;
+    },
+    // 添加批量新增表格行
+    addBatchRow() {
+      this.batchForm.results.push({
+        indicatorId: '',
+        indicatorName: '',
+        resultValue: '',
+        referenceRange: '',
+        unit: '',
+        abnormalFlag: '0'
+      });
+    },
+    // 删除批量新增表格行
+    removeBatchRow(index) {
+      this.batchForm.results.splice(index, 1);
+    },
+    // 取消批量新增
+    cancelBatch() {
+      this.batchOpen = false;
+    },
+    // 提交批量新增表单
+    submitBatchForm() {
+      if (!this.batchForm.reportId) {
+        this.$message.error('请输入报告ID');
+        return;
+      }
+      if (this.batchForm.results.length === 0) {
+        this.$message.error('请添加检查结果行');
+        return;
+      }
+      // 给每个结果设置报告ID
+      this.batchForm.results.forEach(item => {
+        item.reportId = this.batchForm.reportId;
+      });
+      batchAddResult(this.batchForm.results).then(res => {
+        if (res.code === 200) {
+          this.$message.success(res.msg || '批量新增成功');
+          this.batchOpen = false;
+          this.getList();
+        } else {
+          this.$message.error(res.msg || '批量新增失败');
+        }
+      });
+    },
+    // 提交新增或修改表单
+    submitForm() {
+      this.$refs.form.validate((valid) => {
+        if (valid) {
+          if (this.form.resultId) {
+            updateResult(this.form).then(res => {
+              if (res.code === 200) {
+                this.$message.success(res.msg || '更新成功');
+                this.open = false;
+                this.getList();
+              } else {
+                this.$message.error(res.msg || '更新失败');
+              }
+            });
+          } else {
+            addResult(this.form).then(res => {
+              if (res.code === 200) {
+                this.$message.success(res.msg || '新增成功');
+                this.open = false;
+                this.getList();
+              } else {
+                this.$message.error(res.msg || '新增失败');
+              }
+            });
+          }
+        }
+      });
+    },
+    // 取消新增或修改
+    cancel() {
+      this.open = false;
+    },
+    // 查看详情
+    handleDetail(row) {
+      getResult(row.resultId).then(res => {
+        if (res.code === 200) {
+          this.detailData = res.data;
+          this.detailOpen = true;
+        } else {
+          this.$message.error(res.msg || '获取详情失败');
+        }
+      });
+    },
+    // 修改
+    handleUpdate(row) {
+      this.title = "修改检查结果";
+      this.form = Object.assign({}, row);
+      this.open = true;
+      this.$nextTick(() => {
+        if (this.$refs.form) {
+          this.$refs.form.clearValidate();
+        }
+      });
+    },
+    // 删除
+    handleDelete(row) {
+      this.$confirm('确定删除该检查结果吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        delResult(row.resultId).then(res => {
+          if (res.code === 200) {
+            this.$message.success(res.msg || '删除成功');
+            this.getList();
+          } else {
+            this.$message.error(res.msg || '删除失败');
+          }
+        });
+      }).catch(() => {});
+    }
+  }
+};
+</script>

+ 300 - 0
src/views/medical/unit/index.vue

@@ -0,0 +1,300 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="单位名称" prop="unitName">
+        <el-input
+          v-model="queryParams.unitName"
+          placeholder="请输入单位名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="单位类型" prop="unitType">
+        <el-select v-model="queryParams.unitType" placeholder="请选择单位类型" clearable>
+          <el-option
+            v-for="dict in unitTypeOptions"
+            :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="['medical:unit: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="['medical:unit: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="['medical:unit:remove']"
+        >删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="unitList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="单位ID" align="center" prop="unitId" />
+      <el-table-column label="单位名称" align="center" prop="unitName" />
+      <el-table-column label="单位符号" align="center" prop="unitSymbol" />
+      <el-table-column label="单位类型" align="center" prop="unitType">
+        <template slot-scope="scope">
+          <dict-tag :options="unitTypeOptions" :value="scope.row.unitType"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" 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="['medical:unit:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['medical:unit:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改计量单位对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="单位名称" prop="unitName">
+          <el-input v-model="form.unitName" placeholder="请输入单位名称" />
+        </el-form-item>
+        <el-form-item label="单位类型" prop="unitType">
+          <el-select v-model="form.unitType" placeholder="请选择单位类型">
+            <el-option
+              v-for="dict in unitTypeOptions"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="单位符号" prop="unitSymbol">
+          <el-input v-model="form.unitSymbol" placeholder="请输入单位符号" />
+        </el-form-item>
+        <el-form-item label="备注" prop="description">
+          <el-input v-model="form.description" type="textarea" placeholder="请输入备注" />
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-select v-model="form.status" placeholder="请选择状态">
+            <el-option
+              v-for="dict in statusOptions"
+              :key="dict.value"
+              :label="dict.label"
+              :value="parseInt(dict.value)"
+            ></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 { listUnit, getUnit, addUnit, updateUnit, delUnit } from "@/api/medical/unit";
+
+export default {
+  name: "Unit",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 计量单位表格数据
+      unitList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 单位类型字典
+      unitTypeOptions: [],
+      // 状态字典
+      statusOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        unitName: null,
+        unitType: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        unitName: [
+          { required: true, message: "单位名称不能为空", trigger: "blur" }
+        ],
+        unitType: [
+          { required: true, message: "单位类型不能为空", trigger: "change" }
+        ],
+        status: [
+          { required: true, message: "状态不能为空", trigger: "change" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("unit_type").then(response => {
+      this.unitTypeOptions = response.data;
+    });
+    this.getDicts("sys_normal_disable").then(response => {
+      this.statusOptions = response.data;
+    });
+  },
+  methods: {
+    /** 查询计量单位列表 */
+    getList() {
+      this.loading = true;
+      listUnit(this.queryParams).then(response => {
+        this.unitList = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        unitId: null,
+        unitName: null,
+        unitType: null,
+        unitSymbol: null,
+        description: null,
+        status: 1
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.unitId);
+      this.single = selection.length !== 1;
+      this.multiple = !selection.length;
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加计量单位";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const unitId = row.unitId || this.ids[0];
+      getUnit(unitId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改计量单位";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.unitId != null) {
+            updateUnit(this.form).then(response => {
+              this.$message.success("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addUnit(this.form).then(response => {
+              this.$message.success("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const unitIds = row.unitId || this.ids;
+      this.$confirm('是否确认删除计量单位编号为"' + unitIds + '"的数据项?').then(function() {
+        return delUnit(unitIds);
+      }).then(() => {
+        this.getList();
+        this.$message.success("删除成功");
+      }).catch(() => {});
+    }
+  }
+};
+</script>

+ 1 - 1
src/views/qw/sopTemp/updateSopTemp.vue

@@ -728,7 +728,7 @@ export default {
       dayList: [],
       ruleList: [],
       ids: [],
-      courseTypeList: ['3', '4', '9'],
+      courseTypeList: ['1','3', '4', '9'],
       sysFsSopWatchStatus: [],
       //消息内容类型 企微版
       sysQwSopContentType: [],

+ 272 - 0
src/views/saler/competitorInfo/index.vue

@@ -0,0 +1,272 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="竞品公司" prop="competitorCompany">
+        <el-input
+          v-model="queryParams.competitorCompany"
+          placeholder="请输入竞品公司"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="产品" prop="product">
+        <el-input
+          v-model="queryParams.product"
+          placeholder="请输入产品名称"
+          clearable
+          @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="['saler:competitorInfo: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="['saler:competitorInfo: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="['saler:competitorInfo:remove']"
+        >删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="competitorInfoList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="ID" align="center" prop="id" v-if="false" />
+      <el-table-column label="竞品公司" align="center" prop="competitorCompany" :show-overflow-tooltip="true" />
+      <el-table-column label="产品" align="center" prop="product" :show-overflow-tooltip="true" />
+      <el-table-column label="价格" align="center" prop="price" />
+      <el-table-column label="服务" align="center" prop="service" :show-overflow-tooltip="true" />
+      <el-table-column label="免费服务次数" align="center" prop="freeServiceTimes" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180" />
+      <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="['saler:competitorInfo:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['saler:competitorInfo: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="120px">
+        <el-form-item label="竞品公司" prop="competitorCompany">
+          <el-input v-model="form.competitorCompany" placeholder="请输入竞品公司" />
+        </el-form-item>
+        <el-form-item label="产品" prop="product">
+          <el-input v-model="form.product" placeholder="请输入产品" />
+        </el-form-item>
+        <el-form-item label="价格" prop="price">
+          <el-input-number v-model="form.price" :precision="2" :step="0.1" :min="0" placeholder="请输入价格" />
+        </el-form-item>
+        <el-form-item label="服务" prop="service">
+          <el-input v-model="form.service" type="textarea" placeholder="请输入服务内容" />
+        </el-form-item>
+        <el-form-item label="免费服务次数" prop="freeServiceTimes">
+          <el-input-number v-model="form.freeServiceTimes" :min="0" placeholder="请输入免费服务次数" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listCompetitorInfo, getCompetitorInfo, addCompetitorInfo, updateCompetitorInfo, delCompetitorInfo } from "@/api/saler/competitorInfo";
+
+export default {
+  name: "CompetitorInfo",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 竞品信息表格数据
+      competitorInfoList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        competitorCompany: null,
+        product: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        competitorCompany: [
+          { required: true, message: "竞品公司不能为空", trigger: "blur" }
+        ],
+        product: [
+          { required: true, message: "产品不能为空", trigger: "blur" }
+        ],
+        price: [
+          { required: true, message: "价格不能为空", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询竞品信息列表 */
+    getList() {
+      this.loading = true;
+      listCompetitorInfo(this.queryParams).then(response => {
+        this.competitorInfoList = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        competitorCompany: null,
+        product: null,
+        price: 0,
+        service: null,
+        freeServiceTimes: 0,
+        remark: 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
+      getCompetitorInfo(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) {
+            updateCompetitorInfo(this.form).then(response => {
+              this.$message.success("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addCompetitorInfo(this.form).then(response => {
+              this.$message.success("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除竞品信息编号为"' + ids + '"的数据项?').then(function() {
+        return delCompetitorInfo(ids);
+      }).then(() => {
+        this.getList();
+        this.$message.success("删除成功");
+      }).catch(() => {});
+    }
+  }
+};
+</script>

+ 296 - 0
src/views/saler/productInfo/index.vue

@@ -0,0 +1,296 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="商品名称" prop="productName">
+        <el-input
+          v-model="queryParams.productName"
+          placeholder="请输入商品名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="会员情况" prop="memberStatus">
+        <el-input
+          v-model="queryParams.memberStatus"
+          placeholder="请输入会员情况"
+          clearable
+          @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="['saler:productInfo: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="['saler:productInfo: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="['saler:productInfo:remove']"
+        >删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="productInfoList" @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="productName" />
+      <el-table-column label="购买数量" align="center" prop="purchaseQuantity" />
+      <el-table-column label="金额" align="center" prop="amount" />
+      <el-table-column label="预计完成时间" align="center" prop="plannedCompletionDate" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.plannedCompletionDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="购买次数" align="center" prop="purchaseTimes" />
+      <el-table-column label="剩余次数" align="center" prop="surplusTimes" />
+      <el-table-column label="会员情况" align="center" prop="memberStatus" />
+      <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-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="['saler:productInfo:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['saler:productInfo: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="120px">
+        <el-form-item label="商品名称" prop="productName">
+          <el-input v-model="form.productName" placeholder="请输入商品名称" />
+        </el-form-item>
+        <el-form-item label="购买数量" prop="purchaseQuantity">
+          <el-input-number v-model="form.purchaseQuantity" :min="0" :max="9999" />
+        </el-form-item>
+        <el-form-item label="金额" prop="amount">
+          <el-input-number v-model="form.amount" :precision="2" :min="0" :step="0.01" />
+        </el-form-item>
+        <el-form-item label="预计完成时间" prop="plannedCompletionDate">
+          <el-date-picker clearable
+                          v-model="form.plannedCompletionDate"
+                          type="date"
+                          value-format="yyyy-MM-dd"
+                          placeholder="请选择预计完成时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="购买次数" prop="purchaseTimes">
+          <el-input-number v-model="form.purchaseTimes" :min="0" :max="9999" />
+        </el-form-item>
+        <el-form-item label="剩余次数" prop="surplusTimes">
+          <el-input-number v-model="form.surplusTimes" :min="0" :max="9999" />
+        </el-form-item>
+        <el-form-item label="会员情况" prop="memberStatus">
+          <el-input v-model="form.memberStatus" placeholder="请输入会员情况" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listProductInfo, getProductInfo, addProductInfo, updateProductInfo, delProductInfo } from "@/api/saler/productInfo";
+
+export default {
+  name: "ProductInfo",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 商品表格数据
+      productInfoList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        productName: null,
+        memberStatus: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        productName: [
+          { required: true, message: "商品名称不能为空", trigger: "blur" }
+        ],
+        purchaseQuantity: [
+          { required: true, message: "购买数量不能为空", trigger: "blur" }
+        ],
+        amount: [
+          { required: true, message: "金额不能为空", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询商品列表 */
+    getList() {
+      this.loading = true;
+      listProductInfo(this.queryParams).then(response => {
+        this.productInfoList = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        productName: null,
+        purchaseQuantity: 0,
+        amount: 0,
+        plannedCompletionDate: null,
+        purchaseTimes: 0,
+        surplusTimes: 0,
+        memberStatus: null,
+        remark: 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[0]
+      getProductInfo(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) {
+            updateProductInfo(this.form).then(response => {
+              this.$message.success("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addProductInfo(this.form).then(response => {
+              this.$message.success("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除商品编号为"' + ids + '"的数据项?').then(function() {
+        return delProductInfo(ids);
+      }).then(() => {
+        this.getList();
+        this.$message.success("删除成功");
+      }).catch(() => {});
+    }
+  }
+};
+</script>

+ 315 - 97
src/views/system/config/config.vue

@@ -344,6 +344,30 @@
           </div>
         </el-form>
     </el-tab-pane>
+
+      <el-tab-pane label="积分比例配置" name="store.integral">
+        <el-form ref="form24" :model="form24" :rules="rules3" label-width="160px">
+          <el-form-item  label="积分抵用比例" prop="integralRatio">
+            <el-tooltip class="item" effect="dark" content="1积分抵多少金额" placement="top-end">
+              <el-input-number  v-model="form24.integralRatio"   ></el-input-number>
+            </el-tooltip>
+          </el-form-item>
+          <el-form-item  label="满多少可以抵扣" prop="integralFull">
+            <el-tooltip class="item" effect="dark" content="消费必须满一定额度才可使用,0代表无限制" placement="top-end">
+              <el-input-number  v-model="form24.integralFull" ></el-input-number>
+            </el-tooltip>
+          </el-form-item>
+          <el-form-item  label="单次最大抵扣积分" prop="integralMax">
+            <el-tooltip class="item" effect="dark" content="限制一次只能使用多少积分,0代表无限制" placement="top-end">
+              <el-input-number  v-model="form24.integralMax" ></el-input-number>
+            </el-tooltip>
+          </el-form-item>
+          <div   class="footer">
+            <el-button type="primary" @click="submitForm24">提  交</el-button>
+          </div>
+        </el-form>
+      </el-tab-pane>
+
     <el-tab-pane label="套餐包" name="his.package" >
         <el-form ref="form8" :model="form8"  label-width="150px">
           <el-form-item  label="物流代收定金比例(%)" prop="payRate">
@@ -513,89 +537,89 @@
           </div>
         </el-form>
     </el-tab-pane>
-      <el-tab-pane label="APP支付配置" name="store.pay">
-        <el-form ref="form23" :model="form23"  label-width="160px">
-          <el-form-item label="支付类型" prop="type">
-            <el-radio-group v-model="form23.type">
-              <el-radio label="yb">易宝</el-radio>
-              <el-radio label="wx">微信</el-radio>
-              <el-radio label="hf">汇付</el-radio>
-            </el-radio-group>
-          </el-form-item>
-          <el-form-item   label="appId" prop="appId">
-            <el-input   v-model="form23.appId"  label="请输入appId"></el-input>
-          </el-form-item>
-          <el-form-item  v-if="form23.type=='yb'" label="易宝商户号" prop="ybAccount">
-            <el-input   v-model="form23.ybAccount"  label="请输入易宝商户号"></el-input>
-          </el-form-item>
-          <el-form-item v-if="form23.type=='yb'" label="易宝Key" prop="ybKey">
-            <el-input  v-model="form23.ybKey" label="请输入易宝Key"></el-input>
-          </el-form-item>
-          <el-form-item v-if="form23.type=='yb'" label="易宝回调地址" prop="ybNotifyUrl">
-            <el-input  v-model="form23.ybNotifyUrl" label="易宝回调地址"></el-input>
-          </el-form-item>
-
-          <el-form-item  v-if="form23.type=='wx'" label="微信商户号" prop="wxMchId">
-            <el-input   v-model="form23.wxMchId"  label="请输入微信商户号"></el-input>
-          </el-form-item>
-          <el-form-item v-if="form23.type=='wx'" label="微信Key" prop="wxMchKey">
-            <el-input  v-model="form23.wxMchKey" label="请输入微信Key"></el-input>
-          </el-form-item>
-          <el-form-item v-if="form23.type=='wx'" label="微信商户V3密钥" prop="wxMchKey">
-            <el-input  v-model="form23.wxApiV3Key" label="请输入商户V3密钥"></el-input>
-          </el-form-item>
-          <el-form-item v-if="form23.type=='wx'" label="keyPath" prop="wxMchKey">
-            <el-input  v-model="form23.keyPath" label="请输入商户V3密钥"></el-input>
-          </el-form-item>
-          <el-form-item v-if="form23.type=='wx'" label="privateKeyPath" prop="wxMchKey">
-            <el-input  v-model="form23.privateKeyPath" label="请输入商户V3密钥"></el-input>
-          </el-form-item>
-          <el-form-item v-if="form23.type=='wx'" label="privateCertPath" prop="wxMchKey">
-            <el-input  v-model="form23.privateCertPath" label="请输入商户V3密钥"></el-input>
-          </el-form-item>
-          <el-form-item v-if="form23.type=='wx'" label="notifyUrlScrm" prop="wxMchKey">
-            <el-input  v-model="form23.notifyUrlScrm" label="请输入商户V3密钥"></el-input>
-          </el-form-item>
-          <el-form-item v-if="form23.type=='wx'" label="publicKeyId" prop="wxMchKey">
-            <el-input  v-model="form23.publicKeyId" label="请输入商户V3密钥"></el-input>
-          </el-form-item>
-          <el-form-item v-if="form23.type=='wx'" label="publicKeyPath" prop="wxMchKey">
-            <el-input  v-model="form23.publicKeyPath" label="请输入商户V3密钥"></el-input>
-          </el-form-item>
-
-
-          <el-form-item  v-if="form23.type=='hf'" label="汇付产品号" prop="hfProductId">
-            <el-input   v-model="form23.hfProductId"  label="汇付产品号"></el-input>
-          </el-form-item>
-          <el-form-item v-if="form23.type=='hf'" label="系统号" prop="hfSysId">
-            <el-input  v-model="form23.hfSysId" label="系统号Key"></el-input>
-          </el-form-item>
-          <el-form-item v-if="form23.type=='hf'" label="商户号" prop="huifuId">
-            <el-input  v-model="form23.huifuId" label="商户号"></el-input>
-          </el-form-item>
-          <el-form-item v-if="form23.type=='hf'" label="商户私钥" prop="hfRsaPrivateKey">
-            <el-input  v-model="form23.hfRsaPrivateKey" label="商户私钥"></el-input>
-          </el-form-item>
-          <el-form-item v-if="form23.type=='hf'" label="汇付公钥" prop="hfRsaPublicKey">
-            <el-input  v-model="form23.hfRsaPublicKey" label="汇付公钥"></el-input>
-          </el-form-item>
-          <el-form-item v-if="form23.type=='hf'" label="汇付支付回调地址" prop="hfPayNotifyUrl">
-            <el-input  v-model="form23.hfPayNotifyUrl" label="汇付支付回调地址"></el-input>
-          </el-form-item>
-          <el-form-item v-if="form23.type=='hf'" label="大额支付回调地址" prop="hfPayOnlineNotifyUrl">
-            <el-input  v-model="form23.hfPayOnlineNotifyUrl" label="汇付支付回调地址"></el-input>
-          </el-form-item>
-          <el-form-item v-if="form23.type=='hf'" label="汇付退款回调地址" prop="hfRefundNotifyUrl">
-            <el-input  v-model="form23.hfRefundNotifyUrl" label="汇付退款回调地址"></el-input>
-          </el-form-item>
-          <el-form-item v-if="form23.type=='hf'" label="汇付大额退款回调地址" prop="hfOnlineRefundNotifyUrl">
-            <el-input  v-model="form23.hfOnlineRefundNotifyUrl" label="汇付分账回调地址"></el-input>
-          </el-form-item>
-          <div   class="footer">
-            <el-button type="primary" @click="submitForm23">提  交</el-button>
-          </div>
-        </el-form>
-      </el-tab-pane>
+<!--      <el-tab-pane label="APP支付配置" name="store.pay">-->
+<!--        <el-form ref="form23" :model="form23"  label-width="160px">-->
+<!--          <el-form-item label="支付类型" prop="type">-->
+<!--            <el-radio-group v-model="form23.type">-->
+<!--              <el-radio label="yb">易宝</el-radio>-->
+<!--              <el-radio label="wx">微信</el-radio>-->
+<!--              <el-radio label="hf">汇付</el-radio>-->
+<!--            </el-radio-group>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item   label="appId" prop="appId">-->
+<!--            <el-input   v-model="form23.appId"  label="请输入appId"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item  v-if="form23.type=='yb'" label="易宝商户号" prop="ybAccount">-->
+<!--            <el-input   v-model="form23.ybAccount"  label="请输入易宝商户号"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item v-if="form23.type=='yb'" label="易宝Key" prop="ybKey">-->
+<!--            <el-input  v-model="form23.ybKey" label="请输入易宝Key"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item v-if="form23.type=='yb'" label="易宝回调地址" prop="ybNotifyUrl">-->
+<!--            <el-input  v-model="form23.ybNotifyUrl" label="易宝回调地址"></el-input>-->
+<!--          </el-form-item>-->
+
+<!--          <el-form-item  v-if="form23.type=='wx'" label="微信商户号" prop="wxMchId">-->
+<!--            <el-input   v-model="form23.wxMchId"  label="请输入微信商户号"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item v-if="form23.type=='wx'" label="微信Key" prop="wxMchKey">-->
+<!--            <el-input  v-model="form23.wxMchKey" label="请输入微信Key"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item v-if="form23.type=='wx'" label="微信商户V3密钥" prop="wxMchKey">-->
+<!--            <el-input  v-model="form23.wxApiV3Key" label="请输入商户V3密钥"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item v-if="form23.type=='wx'" label="keyPath" prop="wxMchKey">-->
+<!--            <el-input  v-model="form23.keyPath" label="请输入商户V3密钥"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item v-if="form23.type=='wx'" label="privateKeyPath" prop="wxMchKey">-->
+<!--            <el-input  v-model="form23.privateKeyPath" label="请输入商户V3密钥"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item v-if="form23.type=='wx'" label="privateCertPath" prop="wxMchKey">-->
+<!--            <el-input  v-model="form23.privateCertPath" label="请输入商户V3密钥"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item v-if="form23.type=='wx'" label="notifyUrlScrm" prop="wxMchKey">-->
+<!--            <el-input  v-model="form23.notifyUrlScrm" label="请输入商户V3密钥"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item v-if="form23.type=='wx'" label="publicKeyId" prop="wxMchKey">-->
+<!--            <el-input  v-model="form23.publicKeyId" label="请输入商户V3密钥"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item v-if="form23.type=='wx'" label="publicKeyPath" prop="wxMchKey">-->
+<!--            <el-input  v-model="form23.publicKeyPath" label="请输入商户V3密钥"></el-input>-->
+<!--          </el-form-item>-->
+
+
+<!--          <el-form-item  v-if="form23.type=='hf'" label="汇付产品号" prop="hfProductId">-->
+<!--            <el-input   v-model="form23.hfProductId"  label="汇付产品号"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item v-if="form23.type=='hf'" label="系统号" prop="hfSysId">-->
+<!--            <el-input  v-model="form23.hfSysId" label="系统号Key"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item v-if="form23.type=='hf'" label="商户号" prop="huifuId">-->
+<!--            <el-input  v-model="form23.huifuId" label="商户号"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item v-if="form23.type=='hf'" label="商户私钥" prop="hfRsaPrivateKey">-->
+<!--            <el-input  v-model="form23.hfRsaPrivateKey" label="商户私钥"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item v-if="form23.type=='hf'" label="汇付公钥" prop="hfRsaPublicKey">-->
+<!--            <el-input  v-model="form23.hfRsaPublicKey" label="汇付公钥"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item v-if="form23.type=='hf'" label="汇付支付回调地址" prop="hfPayNotifyUrl">-->
+<!--            <el-input  v-model="form23.hfPayNotifyUrl" label="汇付支付回调地址"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item v-if="form23.type=='hf'" label="大额支付回调地址" prop="hfPayOnlineNotifyUrl">-->
+<!--            <el-input  v-model="form23.hfPayOnlineNotifyUrl" label="汇付支付回调地址"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item v-if="form23.type=='hf'" label="汇付退款回调地址" prop="hfRefundNotifyUrl">-->
+<!--            <el-input  v-model="form23.hfRefundNotifyUrl" label="汇付退款回调地址"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <el-form-item v-if="form23.type=='hf'" label="汇付大额退款回调地址" prop="hfOnlineRefundNotifyUrl">-->
+<!--            <el-input  v-model="form23.hfOnlineRefundNotifyUrl" label="汇付分账回调地址"></el-input>-->
+<!--          </el-form-item>-->
+<!--          <div   class="footer">-->
+<!--            <el-button type="primary" @click="submitForm23">提  交</el-button>-->
+<!--          </div>-->
+<!--        </el-form>-->
+<!--      </el-tab-pane>-->
     <el-tab-pane label="布局配置" name="his.appShow" >
         <div >
           <el-table border :data="form10">
@@ -735,6 +759,7 @@
         <el-radio v-model="form13.erpType" label=3>瀚智OMS</el-radio>
         <el-radio v-model="form13.erpType" label=4>代服管家</el-radio>
         <el-radio v-model="form13.erpType" label=5>聚水潭</el-radio>
+        <el-radio v-model="form13.erpType" label=6>金博</el-radio>
       </el-form-item>
      <el-form-item   label="不推送erp的公司" v-if="form13.erpOpen == 1">
        <el-select filterable v-model="form13.noErpCompany" placeholder="请选公司" multiple clearable size="small"
@@ -910,6 +935,25 @@
          <el-input   v-model="form13.erpJstrehouseCode"  label="请输入erpJstrehouseCode"></el-input>
        </el-form-item>
 
+       <el-form-item   label="kingbosan" v-if="form13.erpOpen == 1 && form13.erpType == 6 " prop="kingbosan">
+         <el-input   v-model="form13.kingbosan"  label="请输入账套名称(kingbosan)"></el-input>
+       </el-form-item>
+       <el-form-item   label="kingbosSecret" v-if="form13.erpOpen == 1 && form13.erpType == 6 " prop="kingbosSecret">
+         <el-input   v-model="form13.kingbosSecret"  label="请输入密钥(kingbosSecret)"></el-input>
+       </el-form-item>
+       <el-form-item   label="kingbosUrl" v-if="form13.erpOpen == 1 && form13.erpType == 6 " prop="kingbosUrl">
+         <el-input   v-model="form13.kingbosUrl"  label="请输入金博地址(kingbosUrl)"></el-input>
+       </el-form-item>
+       <el-form-item   label="corgid" v-if="form13.erpOpen == 1 && form13.erpType == 6 " prop="corgid">
+         <el-input   v-model="form13.corgid"  label="请输入机构编码(corgid)"></el-input>
+       </el-form-item>
+       <el-form-item   label="cwarehouseCode" v-if="form13.erpOpen == 1 && form13.erpType == 6 " prop="cwarehouseCode">
+         <el-input   v-model="form13.cwarehouseCode"  label="请输入仓库编码(cwarehouseCode)"></el-input>
+       </el-form-item>
+       <el-form-item   label="cwarehouseName" v-if="form13.erpOpen == 1 && form13.erpType == 6 " prop="cwarehouseName">
+         <el-input   v-model="form13.cwarehouseName"  label="请输入仓库名称(cwarehouseName)"></el-input>
+       </el-form-item>
+
 
       <el-form-item   label="appid" prop="appid">
           <el-input   v-model="form13.appid"  label="请输入appid"></el-input>
@@ -1138,10 +1182,11 @@
              <el-radio-group v-model="form18.rewardType">
                <el-radio label="1">红包</el-radio>
                <el-radio label="2">积分</el-radio>
+               <el-radio label="3">红包+积分</el-radio>
              </el-radio-group>
            </el-form-item>
 
-           <el-form-item label="红包金额" v-if="form18.rewardType == 1">
+           <el-form-item label="红包金额" v-if="form18.rewardType == 1 || form18.rewardType == 3">
              <el-tooltip class="item" effect="dark" content="课程默认红包金额" placement="top-end">
                <el-input-number  v-model="form18.redPackageMoney" :min="0.01" ></el-input-number>
              </el-tooltip>
@@ -1171,7 +1216,7 @@
              <el-button @click="addDisabledTime" style="margin-top: 10px">添加时间段</el-button>
            </el-form-item>
 
-           <el-form-item label="红包模式" v-if="form18.rewardType==1">
+           <el-form-item label="红包模式" v-if="form18.rewardType==1 || form18.rewardType == 3">
              <el-radio-group v-model="form18.redPacketMode">
                <el-radio label="1">总公司</el-radio>
                <el-radio label="2">分公司</el-radio>
@@ -1247,6 +1292,12 @@
              </el-tooltip>
            </el-form-item>
 
+           <el-form-item label="炮灰发服务号红包落地地址">
+             <el-tooltip class="item" effect="dark" content="炮灰看课发红包-服务号发" placement="top-end">
+               <el-input style="width: 200px"  v-model="form18.userCourseH5Reward" label="服务号红包落地地址"></el-input>
+             </el-tooltip>
+           </el-form-item>
+
            <el-form-item label="是否绑定" prop="doctorRegister">
              <el-switch
                v-model="form18.isBound"
@@ -1277,16 +1328,17 @@
                  :disabled="!scope.row.editing">
                  <el-option label="小程序" value="1"></el-option>
                  <el-option label="服务号" value="2"></el-option>
+                 <el-option label="自定义" value="3"></el-option>
                </el-select>
              </template>
            </el-table-column>
            <el-table-column label="小程序原始ID" align="center" prop="username">
-             <template slot-scope="scope" v-if="scope.row.type == 1">
+             <template slot-scope="scope" v-if="scope.row.type == 1 || scope.row.type == 3 ">
                <el-input v-model="scope.row.username" placeholder="请输入原始ID" :disabled="!scope.row.editing" />
              </template>
            </el-table-column>
            <el-table-column label="小程序图标" align="center" prop="log">
-             <template slot-scope="scope" v-if="scope.row.type == 1">
+             <template slot-scope="scope" v-if="scope.row.type == 1 || scope.row.type == 3 ">
                <el-image v-if="!scope.row.editing && scope.row.log" :src="scope.row.log" :preview-src-list="[scope.row.log]" />
                <image-upload v-if="scope.row.editing" v-model="scope.row.log" :file-type='["png", "jpg", "jpeg"]' :limit="1"/>
              </template>
@@ -1338,6 +1390,12 @@
                  icon="el-icon-delete"
                  @click="deleteCourseMaConfig(scope.$index)"
                >删除</el-button>
+               <el-button
+                 size="mini"
+                 type="text"
+                 icon="el-icon-setting"
+                 @click="handleSwitchConfig(scope.row)"
+               >是否展示销售管理</el-button>
              </template>
            </el-table-column>
          </el-table>
@@ -1346,7 +1404,39 @@
            <el-button type="primary" @click="submitCourseMaConfig">提 交</el-button>
          </div>
        </el-tab-pane>
-       <el-tab-pane label="红包商户配置" name="redPacket.config" >
+
+      <!-- 开关配置对话框 -->
+      <el-dialog title="开关配置" :visible.sync="switchDialogVisible" width="500px" class="switch-dialog">
+        <el-form :model="switchForm" label-width="100px">
+          <el-form-item label="AppId">
+            <el-input v-model="switchForm.appId" :disabled="true"></el-input>
+          </el-form-item>
+          <el-form-item label="开关状态">
+            <el-switch
+              v-model="switchForm.switchStatus"
+              active-text="开启"
+              inactive-text="关闭"
+              active-value="001"
+              inactive-value="002">
+            </el-switch>
+          </el-form-item>
+          <el-form-item label="配置信息" v-if="switchForm.configInfo">
+            <el-input
+              type="textarea"
+              :rows="4"
+              v-model="switchForm.configInfo"
+              :disabled="true">
+            </el-input>
+          </el-form-item>
+        </el-form>
+        <span slot="footer" class="dialog-footer">
+                <el-button @click="switchDialogVisible = false">取 消</el-button>
+                <el-button type="primary" @click="submitSwitchConfig">确 定</el-button>
+            </span>
+      </el-dialog>
+
+
+      <el-tab-pane label="红包商户配置" name="redPacket.config" >
          <el-form ref="form19" :model="form19"  label-width="150px">
            <el-form-item   label="红包接口类型" prop="isNew">
              <el-radio-group v-model="form19.isNew">
@@ -1397,13 +1487,13 @@
          <el-form ref="form20" :model="form20" :rules="rules20" label-width="120px">
            <el-form-item label="评级天数(天)" prop="levelDay">
              <el-tooltip class="item" effect="dark" content="最小评级天数(天)" placement="top-end">
-               <el-input-number v-model="form20.levelDay" :min="7" :max="365"></el-input-number>
+               <el-input-number v-model="form20.levelDay" :min="4" :max="365"></el-input-number>
              </el-tooltip>
            </el-form-item>
 
            <el-form-item label="超过多少天的客户没看课评E级" prop="levelDay">
              <el-tooltip class="item" effect="dark" content="超过多少天的客户没看课评E级,且不生成sop执行记录了,不发了" placement="top-end">
-               <el-input-number v-model="form20.notStudyDays" :min="7" :max="365"></el-input-number>
+               <el-input-number v-model="form20.notStudyDays" :min="4" :max="365"></el-input-number>
              </el-tooltip>
            </el-form-item>
 
@@ -1493,7 +1583,7 @@
         </el-form>
 
       </el-tab-pane>
-       <el-tab-pane label="企业理念" name="store.concept">
+      <el-tab-pane label="企业理念" name="store.concept">
          <el-form ref="form21" :model="form21" :rules="rules21" label-width="160px">
            <el-form-item   label="企业理念图片" prop="images">
              <Material v-model="images" type="image" :num="10" :width="150" :height="150" />
@@ -1519,6 +1609,32 @@
         </div>
       </el-form>
     </el-tab-pane>
+    <el-tab-pane label="APP推广" name="app.config">
+         <el-form ref="form25" :model="form25" :rules="rules25" label-width="160px">
+           <el-form-item   label="APP推广图片" prop="images">
+             <Material v-model="appImages" type="image" :num="10" :width="150" :height="150" />
+           </el-form-item>
+           <el-form-item label="APP推广视频" prop="videoUrl">
+             <div>
+               <el-upload
+                 ref="upload"
+                 class="upload-demo"
+                 :action="uploadUrl"
+                 :on-success="appHandleSuccess"
+                 :before-upload="beforeUpload"
+                 :limit="1"
+                 :accept="videoAccept"
+               >
+                 <el-button size="small" type="primary">点击上传视频</el-button>
+               </el-upload>
+               <video :src="form25.videoUrl" controls style="max-width: 400px; max-height: 400px;"></video>
+             </div>
+           </el-form-item>
+           <div  class="footer">
+             <el-button type="primary" @click="submitForm25">提  交</el-button>
+        </div>
+      </el-form>
+    </el-tab-pane>
     </el-tabs>
 
 
@@ -1534,7 +1650,7 @@
 </template>
 
 <script>
-import {   getConfigByKey,updateConfigByKey, clearCache } from "@/api/system/config";
+import {   getConfigByKey,updateConfigByKey, clearCache,updateIsTownOn } from "@/api/system/config";
 import {listStore} from "@/api/his/storeProduct";
 import { js } from "js-beautify";
 import Material from '@/components/Material'
@@ -1558,10 +1674,16 @@ export default {
     return {
       citys:[],
       images:[],
+      appImages:[],
       uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
       videoAccept:"video/*",
       courseMaConfigLoading:false,
       courseMaConfigList:[],
+      switchDialogVisible: false,
+      switchForm: {
+        appId: '',
+        switchStatus: '001',
+      },
       deliveryGift:{
         open:false,
         title:"商品选择"
@@ -1613,8 +1735,8 @@ export default {
       form19:{
       },
       form20:{
-        levelDay: 7,
-        notStudyDays:7,
+        levelDay: 4,
+        notStudyDays:4,
         aLevelMin: 80,
         aLevelMax: 100,
         bLevelMin: 40,
@@ -1632,6 +1754,10 @@ export default {
       },
       form23:{
       },
+      form24:{
+      },
+      form25:{
+      },
       photoArr:[],
       couponList:[],
       inquirySubTypeOptions:[],
@@ -1685,7 +1811,8 @@ export default {
         cLevelMax: [{ required: true, message: '请输入C级最大值', trigger: 'blur' }],
         dLevelMax: [{ required: true, message: '请输入D级最大值', trigger: 'blur' }],
       },
-      rules21:{}
+      rules21:{},
+      rules25:{}
     };
   },
   created() {
@@ -1707,12 +1834,62 @@ export default {
     },
     images: function(val) {
      this.form21.images = val.join(',')
-   }
+    },
+    appImages: function(val) {
+     this.form25.images = val.join(',')
+    }
   },
   methods: {
+
+    // 处理开关配置
+    handleSwitchConfig(row) {
+      this.switchForm.appId = row.appid;
+      this.switchForm.switchStatus = "001"; // 默认关闭状态
+
+      // 调用接口获取开关状态
+      this.getSwitchConfig(row.appid);
+      this.switchDialogVisible = true;
+    },
+
+    // 获取开关配置
+    getSwitchConfig(appId) {
+      const params = {
+        appId: this.switchForm.appId
+      };
+      updateIsTownOn(params).then(response=>{
+        if (response.code === 200) {
+          if ( response.date){
+            this.switchForm.switchStatus = response.date;
+          }
+        } else {
+          this.$message.error('获取配置失败: ' + response.msg);
+        }
+      }).catch(error => {
+        this.$message.error('请求失败: ' + error.message);
+      });
+    },
+
+    // 提交开关配置
+    submitSwitchConfig() {
+      const params = {
+        appId: this.switchForm.appId,
+        bock: this.switchForm.switchStatus
+      };
+      updateIsTownOn(params).then(response=>{
+        if (response.code === 200) {
+          this.$message.success('配置更新成功');
+          this.switchDialogVisible = false;
+        } else {
+          this.$message.error('更新失败: ' + response.msg);
+        }
+      })
+    },
+
+
+
     handleCityChange(value) {
       // console.log(this.$refs.citySelect,this.$refs.citySelect[0])
-      var nodes=this.$refs.citySelect[0].getCheckedNodes();
+      var nodes=this.$refs.citySelect[value].getCheckedNodes();
       // console.log(nodes[0])
       // this.account[value].cityIds=value.toString();
       this.form13.dfAccounts[value].senderProvince=nodes[0].pathLabels[0];
@@ -1765,6 +1942,12 @@ export default {
       this.form21.videoUrl = response.url;
       this.$refs.upload.clearFiles();
     },
+    appHandleSuccess(response, file) {
+      // 上传成功后的回调函数
+      this.myloading.close();
+      this.form25.videoUrl = response.url;
+      this.$refs.upload.clearFiles();
+    },
     beforeUpload(file) {
       // 上传前的钩子函数,可以在这里对文件进行处理
       // 返回 false 则取消上传
@@ -1968,6 +2151,20 @@ export default {
             if(this.form21.images!=null){
               this.images=this.form21.images.split(",");
             }
+          } else if(key=="store.integral"){
+            this.configId=response.data.configId;
+            this.configKey=response.data.configKey;
+            console.log(response.data.configValue)
+            this.form24 =JSON.parse(response.data.configValue);
+            console.log(this.form24.sign)
+          }
+          else if(key=="app.config"){
+            this.configId=response.data.configId;
+            this.configKey=response.data.configKey;
+            this.form25 =JSON.parse(response.data.configValue);
+            if(this.form25.images!=null){
+              this.appImages=this.form25.images.split(",");
+            }
           }
         });
      },
@@ -2163,6 +2360,15 @@ export default {
       });
 
     },
+    submitForm25(){
+      var param={configId:this.configId,configKey:this.configKey,configValue:JSON.stringify(this.form25)}
+      console.log(param)
+      updateConfigByKey(param).then(response => {
+        if (response.code === 200) {
+          this.msgSuccess("修改成功");
+        }
+      });
+    },
     submitForm21(){
       var param={configId:this.configId,configKey:this.configKey,configValue:JSON.stringify(this.form21)}
       updateConfigByKey(param).then(response => {
@@ -2171,6 +2377,18 @@ export default {
         }
       });
     },
+    submitForm24(){
+      this.$refs["form24"].validate(valid => {
+        if (valid) {
+          var param={configId:this.configId,configKey:this.configKey,configValue:JSON.stringify(this.form24)}
+          updateConfigByKey(param).then(response => {
+            if (response.code === 200) {
+              this.msgSuccess("修改成功");
+            }
+          });
+        }
+      });
+    },
     submitform2(){
       // 将对象转换为JSON字符串并保留两位小数
       var json_data = JSON.stringify(this.form2, function(key, value) {

+ 4 - 4
src/views/system/config/config2.vue

@@ -1172,13 +1172,13 @@
          <el-form ref="form20" :model="form20" :rules="rules20" label-width="120px">
            <el-form-item label="评级天数(天)" prop="levelDay">
              <el-tooltip class="item" effect="dark" content="最小评级天数(天)" placement="top-end">
-               <el-input-number v-model="form20.levelDay" :min="7" :max="365"></el-input-number>
+               <el-input-number v-model="form20.levelDay" :min="4" :max="365"></el-input-number>
              </el-tooltip>
            </el-form-item>
 
            <el-form-item label="超过多少天的客户没看课评E级" prop="levelDay">
              <el-tooltip class="item" effect="dark" content="超过多少天的客户没看课评E级,且不生成sop执行记录了,不发了" placement="top-end">
-               <el-input-number v-model="form20.notStudyDays" :min="7" :max="365"></el-input-number>
+               <el-input-number v-model="form20.notStudyDays" :min="4" :max="365"></el-input-number>
              </el-tooltip>
            </el-form-item>
 
@@ -1366,8 +1366,8 @@ export default {
       form19:{
       },
       form20:{
-        levelDay: 7,
-        notStudyDays:7,
+        levelDay: 4,
+        notStudyDays:4,
         aLevelMin: 80,
         aLevelMax: 100,
         bLevelMin: 40,

+ 8 - 2
src/views/system/role/index.vue

@@ -189,7 +189,7 @@
             >{{dict.dictLabel}}</el-radio>
           </el-radio-group>
         </el-form-item>
-        <el-form-item label="是否可以查看手机全号" >
+        <el-form-item label="是否可以查看手机全号" v-if="isAdmin == 1">
           <span slot="label">
             <el-tooltip content="是否可以查看手机全号" placement="top">
               <i class="el-icon-question"></i>
@@ -361,7 +361,7 @@ export default {
         roleSort: [
           { required: true, message: "角色顺序不能为空", trigger: "blur" }
         ]
-      }
+      },
     };
   },
   created() {
@@ -370,6 +370,12 @@ export default {
       this.statusOptions = response.data;
     });
   },
+  computed: {
+    isAdmin() {
+      console.log(this.$store.state.user.isAdmin)
+      return this.$store.state.user.isAdmin
+    }
+  },
   methods: {
     /** 查询角色列表 */
     getList() {

+ 619 - 0
src/views/todo/todoItems/index.vue

@@ -0,0 +1,619 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px" >
+      <el-form-item label="标题" prop="title">
+        <el-input
+          v-model="queryParams.title"
+          placeholder="请输入待办事项标题"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="公司名称" prop="companyName">
+        <el-input
+          v-model="queryParams.companyName"
+          placeholder="请输入公司名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['todo:todoItems: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="['todo:todoItems: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="['todo:todoItems:remove']"
+        >删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table
+      v-loading="loading"
+      :data="todoItemsList"
+      @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="title" />
+      <el-table-column label="分配者" align="center" prop="creatorName" />
+      <el-table-column label="执行人" align="center" prop="assigneeName" />
+      <el-table-column label="描述" align="center" prop="description" show-overflow-tooltip />
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <el-tag :type="getStatusType(scope.row.status)" size="small">
+            {{ getStatusLabel(scope.row.status) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="优先级" align="center" prop="priority">
+        <template slot-scope="scope">
+          <el-tag :type="getPriorityType(scope.row.priority)" size="small">
+            {{ getPriorityLabel(scope.row.priority) }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="截止时间" align="center" prop="dueDate" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.dueDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="220">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['todo:todoItems:edit']"
+          >修改</el-button>
+<!--          <el-button-->
+<!--            size="mini"-->
+<!--            type="text"-->
+<!--            icon="el-icon-check"-->
+<!--            @click="handleUpdateStatus(scope.row)"-->
+<!--            v-hasPermi="['todo:todoItems:edit']"-->
+<!--          >更新状态</el-button>-->
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-user"
+            @click="handleAssignExecutor(scope.row)"
+            v-hasPermi="['todo:todoItems:edit']"
+            class="assign-executor-btn"
+          >分配执行者</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['todo:todoItems:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <div class="pagination-wrapper">
+      <pagination
+        v-show="total>0"
+        :total="total"
+        :page.sync="queryParams.pageNum"
+        :limit.sync="queryParams.pageSize"
+        @pagination="getList"
+      />
+    </div>
+
+    <!-- 添加或修改待办事项对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="标题" prop="title">
+          <el-input v-model="form.title" placeholder="请输入待办事项标题" />
+        </el-form-item>
+        <el-form-item label="描述" prop="description">
+          <el-input v-model="form.description" type="textarea" placeholder="请输入描述" />
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-select v-model="form.status" placeholder="请选择状态" default-first-option>
+            <el-option
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="dict.dictValue"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="优先级" prop="priority">
+          <el-select v-model="form.priority" placeholder="请选择优先级">
+            <el-option
+              v-for="dict in priorityOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="dict.dictValue"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="截止时间" prop="dueDate">
+          <el-date-picker clearable
+                          v-model="form.dueDate"
+                          type="date"
+                          value-format="yyyy-MM-dd"
+                          placeholder="请选择截止时间">
+          </el-date-picker>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 更新状态对话框 -->
+    <el-dialog title="更新状态" :visible.sync="statusOpen" width="300px" append-to-body>
+      <el-form ref="statusForm" :model="statusForm" label-width="80px">
+        <el-form-item label="状态" prop="status">
+          <el-select v-model="statusForm.status" placeholder="请选择状态">
+            <el-option
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="dict.dictLabel"
+              :value="dict.dictValue"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitStatusForm">确 定</el-button>
+        <el-button @click="cancelStatus">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 分配执行者对话框 -->
+    <el-dialog title="分配执行者" :visible.sync="assignOpen" width="700px" append-to-body>
+      <el-form ref="assignForm" :model="assignForm" :rules="assignRules" label-width="80px">
+        <el-form-item label="待办事项" prop="title">
+          <el-input v-model="assignForm.title" disabled />
+        </el-form-item>
+        <el-form-item label="执行者" prop="executorId">
+          <el-select v-model="assignForm.executorId" placeholder="请选择执行者" filterable class="executor-select">
+            <el-option
+              v-for="executor in executorList"
+              :key="executor.userId"
+              :label="executor.userName"
+              :value="executor.userId"
+            ></el-option>
+          </el-select>
+          <div class="el-form-item__tip">
+            <small>执行者列表会根据搜索条件中的公司名称进行过滤</small>
+          </div>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitAssignForm">确 定</el-button>
+        <el-button @click="cancelAssign">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listTodoItems, getTodoItems, delTodoItems, addTodoItems, updateTodoItems, updateTodoItemsStatus, assignExecutor, getExecutorList, getUserList } from "@/api/todo/todoItems";
+import {parseTime} from "../../../utils/common";
+
+export default {
+  name: "TodoItems",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 待办事项表格数据
+      todoItemsList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 是否显示状态更新弹出层
+      statusOpen: false,
+      // 是否显示分配执行者弹出层
+      assignOpen: false,
+      // 状态选项
+      statusOptions: [],
+      // 优先级选项
+      priorityOptions: [],
+      todoItemTypeOptions: [],
+      // 执行者列表
+      executorList: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        title: null,
+        companyName: null,
+        status: null
+      },
+      // 表单参数
+      form: {
+        status: 0
+      },
+      // 状态表单参数
+      statusForm: {},
+      // 分配执行者表单参数
+      assignForm: {
+        id: null,
+        title: '',
+        executorId: null,
+        remark: ''
+      },
+      // 表单校验
+      rules: {
+        title: [
+          { required: true, message: "标题不能为空", trigger: "blur" }
+        ],
+        status: [
+          { required: true, message: "状态不能为空", trigger: "change" }
+        ]
+      },
+      // 分配执行者表单校验
+      assignRules: {
+        executorId: [
+          { required: true, message: "请选择执行者", trigger: "change" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("todo_status").then(response => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("todo_priority").then(response => {
+      this.priorityOptions = response.data;
+    });
+    this.getDicts("todo_item_type").then(response => {
+      this.todoItemTypeOptions = response.data;
+    });
+    // 获取执行者列表
+    this.getExecutorList();
+  },
+  methods: {
+    parseTime,
+    /** 查询待办事项列表 */
+    getList() {
+      this.loading = true;
+      listTodoItems(this.queryParams).then(response => {
+        this.todoItemsList = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    /** 获取执行者列表 */
+    getExecutorList() {
+      const params = {
+        companyName: this.queryParams.companyName || '',
+        companyId: null,
+        pageNum: 1,
+        pageSize: 10 // 获取足够多的执行者供选择
+      };
+      getUserList(params).then(response => {
+        if (response.code === 200) {
+          this.executorList = response.data || [];
+        }
+      });
+    },
+    /** 获取状态标签 */
+    getStatusLabel(status) {
+      const statusOption = this.statusOptions.find(option => option.dictValue === String(status));
+      return statusOption ? statusOption.dictLabel : '未知';
+    },
+    /** 获取状态标签类型(颜色) */
+    getStatusType(status) {
+      const statusMap = {
+        '0': 'info',      // 待处理 - 蓝色
+        '1': 'warning',   // 进行中 - 橙色
+        '2': 'success',   // 已完成 - 绿色
+        '3': 'danger'     // 已取消 - 红色
+      };
+      return statusMap[String(status)] || 'info';
+    },
+    /** 获取优先级标签 */
+    getPriorityLabel(priority) {
+      const priorityOption = this.priorityOptions.find(option => option.dictValue === String(priority));
+      return priorityOption ? priorityOption.dictLabel : '未知';
+    },
+    /** 获取优先级标签类型(颜色) */
+    getPriorityType(priority) {
+      const priorityMap = {
+        '0': 'info',      // 低 - 蓝色
+        '1': 'success',   // 中 - 绿色
+        '2': 'warning',   // 高 - 橙色
+        '3': 'danger'     // 紧急 - 红色
+      };
+      return priorityMap[String(priority)] || 'info';
+    },
+
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 取消状态更新
+    cancelStatus() {
+      this.statusOpen = false;
+      this.statusForm = {};
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        title: null,
+        description: null,
+        status: null,
+        priority: null,
+        dueDate: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+      // 更新执行者列表
+      this.getExecutorList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+      // 重置后更新执行者列表
+      this.getExecutorList();
+    },
+    // 多选框选中数据
+    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
+      // 确保id是单个值,如果是数组则取第一个
+      const todoId = Array.isArray(id) ? id[0] : id;
+      getTodoItems(todoId).then(response => {
+        this.form = response.data;
+        // 确保数据类型匹配
+        if (this.form.status !== null && this.form.status !== undefined) {
+          this.form.status = String(this.form.status);
+        }
+        if (this.form.priority !== null && this.form.priority !== undefined) {
+          this.form.priority = String(this.form.priority);
+        }
+        this.open = true;
+        this.title = "修改待办事项";
+      });
+    },
+    /** 更新状态按钮操作 */
+    handleUpdateStatus(row) {
+      this.statusForm = {
+        id: row.id,
+        status: String(row.status)
+      };
+      this.statusOpen = true;
+    },
+    /** 分配执行者按钮操作 */
+    handleAssignExecutor(row) {
+      this.assignForm = {
+        id: row.id,
+        title: row.title,
+        executorId: row.executorId || null,
+        remark: ''
+      };
+      this.assignOpen = true;
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateTodoItems(this.form).then(response => {
+              this.$message.success("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addTodoItems(this.form).then(response => {
+              this.$message.success("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 提交状态更新 */
+    submitStatusForm() {
+      updateTodoItemsStatus(this.statusForm.id, this.statusForm.status).then(response => {
+        this.$message.success("状态更新成功");
+        this.statusOpen = false;
+        this.getList();
+      });
+    },
+    /** 提交分配执行者 */
+    submitAssignForm() {
+      this.$refs["assignForm"].validate(valid => {
+        if (valid) {
+          assignExecutor(this.assignForm).then(response => {
+            this.$message.success("执行者分配成功");
+            this.assignOpen = false;
+            this.getList();
+          });
+        }
+      });
+    },
+    /** 取消分配执行者 */
+    cancelAssign() {
+      this.assignOpen = false;
+      this.assignForm = {
+        id: null,
+        title: '',
+        executorId: null,
+        remark: ''
+      };
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除待办事项编号为"' + ids + '"的数据项?').then(function() {
+        return delTodoItems(ids);
+      }).then(() => {
+        this.getList();
+        this.$message.success("删除成功");
+      }).catch(() => {});
+    }
+  }
+}
+</script>
+
+<style scoped>
+.mb8 {
+  margin-bottom: 8px;
+}
+
+.fixed-width {
+  width: 100px;
+}
+
+
+
+
+
+.assign-executor-btn {
+  margin-left: 5px;
+}
+
+.executor-select {
+  width: 100%;
+}
+
+.el-form-item__tip {
+  margin-top: 5px;
+  color: #909399;
+  font-size: 12px;
+}
+
+
+
+
+/* 标签样式优化 */
+.el-tag {
+  border-radius: 12px;
+  font-weight: 500;
+  padding: 4px 12px;
+  border: none;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+/* 分页样式 */
+.pagination-wrapper {
+  margin-top: 20px;
+}
+
+.el-pagination {
+  text-align: center;
+  padding: 20px;
+  background: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+/* 对话框样式 */
+.el-dialog {
+  border-radius: 12px;
+  overflow: hidden;
+}
+
+.el-dialog__header {
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  color: white;
+  padding: 20px;
+}
+
+.el-dialog__title {
+  color: white;
+  font-weight: 600;
+}
+
+.el-dialog__body {
+  padding: 30px;
+}
+
+.el-dialog__footer {
+  padding: 20px;
+  border-top: 1px solid #ebeef5;
+  background: #f8f9fa;
+}
+
+
+</style>

+ 308 - 0
src/views/user/complaint/category/index.vue

@@ -0,0 +1,308 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="分类名称" prop="categoryName">
+        <el-input
+          v-model="queryParams.categoryName"
+          placeholder="请输入分类名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="分类状态" clearable>
+          <el-option
+            v-for="dict in categoryStatusOptions"
+            :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="['complaint:category: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="['complaint:category: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="['complaint:category:remove']"
+        >删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="categoryList" @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="categoryName" />
+      <el-table-column label="分类编码" align="center" prop="categoryCode" />
+      <el-table-column label="排序" align="center" prop="sortOrder" />
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <el-switch
+            v-model="scope.row.status"
+            :active-value="1"
+            :inactive-value="0"
+            @change="handleStatusChange(scope.row)"
+          ></el-switch>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" 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="['complaint:category:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['complaint:category:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改投诉分类对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="分类名称" prop="categoryName">
+          <el-input v-model="form.categoryName" placeholder="请输入分类名称" />
+        </el-form-item>
+        <el-form-item label="分类编码" prop="categoryCode">
+          <el-input v-model="form.categoryCode" placeholder="请输入分类编码" />
+        </el-form-item>
+        <el-form-item label="显示顺序" prop="sortOrder">
+          <el-input-number v-model="form.sortOrder" :min="0" />
+        </el-form-item>
+        <el-form-item label="状态">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in categoryStatusOptions"
+              :key="dict.dictValue"
+              :label="dict.dictValue"
+            >{{dict.dictLabel}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listCategory, getCategory, delCategory, addCategory, updateCategory, changeStatus } from "@/api/complaint/category";
+import {parseTime} from "../../../../utils/common";
+
+export default {
+  name: "Category",
+  data() {
+    return {
+      dicts: ['sys_normal_disable'],
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 投诉分类表格数据
+      categoryList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        categoryName: undefined,
+        categoryCode: undefined,
+        status: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        categoryName: [
+          { required: true, message: "分类名称不能为空", trigger: "blur" }
+        ],
+        categoryCode: [
+          { required: true, message: "分类编码不能为空", trigger: "blur" }
+        ],
+        orderNum: [
+          { required: true, message: "显示顺序不能为空", trigger: "blur" }
+        ]
+      },
+      categoryStatusOptions: []
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts('category_status').then(response => {
+      this.categoryStatusOptions = response.data;
+    })
+  },
+  methods: {
+    parseTime,
+    /** 查询投诉分类列表 */
+    getList() {
+      this.loading = true;
+      listCategory(this.queryParams).then(response => {
+        this.categoryList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: undefined,
+        categoryName: undefined,
+        categoryCode: undefined,
+        orderNum: 0,
+        status: "0",
+        remark: undefined
+      };
+      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[0];
+      getCategory(id).then(response => {
+        this.form = response.data;
+        console.log(this.form)
+        this.form.status = response.data.status+"";
+        this.open = true;
+        this.title = "修改投诉分类";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != undefined) {
+            updateCategory(this.form).then(response => {
+              this.$message.success("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addCategory(this.form).then(response => {
+              this.$message.success("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除投诉分类编号为"' + ids + '"的数据项?').then(function() {
+        return delCategory(ids);
+      }).then(() => {
+        this.getList();
+        this.$message.success("删除成功");
+      }).catch(() => {});
+    },
+    /** 修改状态 */
+    handleStatusChange(row) {
+      let text = row.status === "1" ? "启用" : "停用";
+      this.$confirm('确认要"' + text + '""' + row.categoryName + '"分类吗?').then(function() {
+        return changeStatus({
+          id: row.id,
+          status: row.status
+        });
+      }).then(() => {
+        this.$message.success(text + "成功");
+      }).catch(function() {
+        row.status = row.status === "0" ? "1" : "0";
+      });
+    }
+  }
+};
+</script>

+ 437 - 0
src/views/user/complaint/index.vue

@@ -0,0 +1,437 @@
+<template>
+  <div class="app-container">
+    <!-- 查询条件 -->
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="投诉单号" prop="complaintNo">
+        <el-input
+          v-model="queryParams.complaintNo"
+          placeholder="请输入投诉单号"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="投诉分类" prop="categoryId">
+        <el-select v-model="queryParams.categoryId" placeholder="请选择投诉分类" clearable>
+          <el-option
+            v-for="category in categoryList"
+            :key="category.id"
+            :label="category.categoryName"
+            :value="category.id"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="投诉状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择投诉状态" clearable>
+          <el-option label="待处理" value="0" />
+          <el-option label="已处理" value="1" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="投诉时间">
+        <el-date-picker
+          v-model="dateRange"
+          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="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['complaint:add']"
+        >新增投诉</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="['complaint:delete']"
+        >批量删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <!-- 投诉列表 -->
+    <el-table v-loading="loading" :data="complaintList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="投诉单号" align="center" prop="complaintNo" />
+      <el-table-column label="投诉人" align="center" prop="complainantName" />
+      <el-table-column label="投诉分类" align="center" prop="categoryName" />
+      <el-table-column label="投诉内容" align="center" prop="content" show-overflow-tooltip />
+      <el-table-column label="投诉状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.status === '0'" type="warning">待处理</el-tag>
+          <el-tag v-else-if="scope.row.status === '1'" type="success">已处理</el-tag>
+          <el-tag v-else type="info">未知</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="投诉时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-view"
+            @click="handleDetail(scope.row)"
+            v-hasPermi="['complaint:query']"
+          >详情</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['complaint:edit']"
+          >编辑</el-button>
+          <el-button
+            v-if="scope.row.status === '0'"
+            size="mini"
+            type="text"
+            icon="el-icon-check"
+            @click="handleProcess(scope.row)"
+            v-hasPermi="['complaint:edit']"
+          >处理</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['complaint:delete']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页 -->
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改投诉对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="投诉人" prop="complainantName">
+          <el-input v-model="form.complainantName" placeholder="请输入投诉人姓名" />
+        </el-form-item>
+        <el-form-item label="联系电话" prop="phone">
+          <el-input v-model="form.phone" placeholder="请输入联系电话" />
+        </el-form-item>
+
+        <el-form-item label="投诉分类" prop="type">
+          <el-select v-model="form.type" placeholder="请选择投诉分类" style="width: 100%">
+            <el-option
+              v-for="category in categoryList"
+              :key="category.id"
+              :label="category.categoryName"
+              :value="category.id"
+            />
+          </el-select>
+        </el-form-item>
+
+        <el-form-item label="投诉内容" prop="content">
+          <el-input v-model="form.content" type="textarea" placeholder="请输入投诉内容" :rows="4" />
+        </el-form-item>
+        <!-- 图片上传 -->
+        <el-form-item label="投诉凭证" prop="url">
+          <image-upload
+            v-model="form.url"
+            :limit="0"
+            :file-size="5"
+            @change="handleImageChange"
+          />
+          <el-button type="primary" @click="submitForm">提交</el-button>
+        </el-form-item>
+        <el-form-item label="投诉状态" prop="status" v-if="form.id">
+          <el-select v-model="form.status" placeholder="请选择投诉状态">
+            <el-option label="待处理" value="0" />
+            <el-option label="已处理" value="1" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="处理备注" prop="remark" v-if="form.id">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入处理备注" :rows="3" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 投诉详情对话框 -->
+    <el-dialog title="投诉详情" :visible.sync="detailOpen" width="600px" append-to-body>
+      <el-descriptions :column="2" border>
+        <el-descriptions-item label="投诉单号">{{ detailData.complaintNo }}</el-descriptions-item>
+        <el-descriptions-item label="投诉状态">
+          <el-tag v-if="detailData.status === '0'" type="warning">待处理</el-tag>
+          <el-tag v-else-if="detailData.status === '1'" type="success">已处理</el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="投诉人">{{ detailData.complainantName }}</el-descriptions-item>
+        <el-descriptions-item label="联系电话">{{ detailData.phone }}</el-descriptions-item>
+        <el-descriptions-item label="投诉分类">{{ detailData.categoryName }}</el-descriptions-item>
+        <el-descriptions-item label="投诉时间" :span="2">
+          {{ parseTime(detailData.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}
+        </el-descriptions-item>
+        <el-descriptions-item label="投诉内容" :span="2">{{ detailData.content }}</el-descriptions-item>
+        <el-descriptions-item label="处理备注" :span="2" v-if="detailData.remark">
+          {{ detailData.remark }}
+        </el-descriptions-item>
+      </el-descriptions>
+      <div slot="footer" class="dialog--footer">
+        <el-button @click="detailOpen = false">关 闭</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  getComplaintPage,
+  getComplaintById,
+  submitComplaint,
+  updateComplaint,
+  deleteComplaint,
+  handleComplaint,
+  getAllCategory
+} from "@/api/complaint/complaint";
+import {parseTime} from "../../../utils/common";
+import ImageUpload from "@/components/ImageUpload/index.vue";
+
+export default {
+  name: "Complaint",
+  components: {ImageUpload},
+  data() {
+    return {
+      categoryList: [],
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 投诉表格数据
+      complaintList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 是否显示详情弹出层
+      detailOpen: false,
+      // 详情数据
+      detailData: {},
+      // 日期范围
+      dateRange: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        complaintNo: null,
+        status: null,
+        startTime: null,
+        endTime: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        complainantName: [
+          { required: true, message: "投诉人姓名不能为空", trigger: "blur" }
+        ],
+        phone: [
+          { required: true, message: "联系电话不能为空", trigger: "blur" },
+          { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }
+        ],
+        type: [
+          { required: true, message: "投诉分类不能为空", trigger: "change" }
+        ],
+        content: [
+          { required: true, message: "投诉内容不能为空", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getCategoryList();
+    this.getList();
+  },
+  methods: {
+    handleImageChange(newImages) {
+      this.form.url = newImages;
+    },
+    /** 获取投诉分类列表 */
+    getCategoryList() {
+      getAllCategory().then(response => {
+        this.categoryList = response.data || [];
+      }).catch(() => {
+        this.$message.error('获取投诉分类失败');
+        this.categoryList = [];
+      });
+    },
+    parseTime,
+    /** 查询投诉列表 */
+    getList() {
+      this.loading = true;
+      if (this.dateRange != null && this.dateRange.length === 2) {
+        this.queryParams.startTime = this.dateRange[0];
+        this.queryParams.endTime = this.dateRange[1];
+      } else {
+        this.queryParams.startTime = null;
+        this.queryParams.endTime = null;
+      }
+      getComplaintPage(this.queryParams).then(response => {
+        this.complaintList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        complainantName: null,
+        phone: null,
+        content: null,
+        status: "0",
+        remark: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加投诉";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getComplaintById(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改投诉";
+      });
+    },
+    /** 查看详情 */
+    handleDetail(row) {
+      getComplaintById(row.id).then(response => {
+        this.detailData = response.data;
+        this.detailOpen = true;
+      });
+    },
+    /** 处理投诉 */
+    handleProcess(row) {
+      this.$confirm('是否确认将投诉单号为"' + row.complaintNo + '"的投诉标记为已处理?').then(() => {
+        handleComplaint(row.id).then(() => {
+          this.$message.success('处理成功');
+          this.getList();
+        }).catch(() => {
+          this.$message.error('处理失败');
+        });
+      });
+    },
+    /** 删除投诉 */
+    handleDelete(row) {
+      const ids = row ? [row.id] : this.ids;
+      this.$confirm('确认删除选中的投诉吗?').then(() => {
+        deleteComplaint(ids).then(() => {
+          this.$message.success('删除成功');
+          this.getList();
+        }).catch(() => {
+          this.$message.error('删除失败');
+        });
+      });
+    },
+    /** 提交表单 */
+    submitForm() {
+      this.$refs['form'].validate((valid) => {
+        if (valid) {
+          if (this.form.id) {
+            updateComplaint(this.form.id, this.form).then(() => {
+              this.$message.success('修改成功');
+              this.getList();
+              this.cancel();
+            }).catch(() => {
+              this.$message.error('修改失败');
+            });
+          } else {
+            submitComplaint(this.form).then(() => {
+              this.$message.success('添加成功');
+              this.getList();
+              this.cancel();
+            }).catch(() => {
+              this.$message.error('添加失败');
+            });
+          }
+        } else {
+          return false;
+        }
+      });
+    }
+  }
+};
+</script>
+
+<style scoped>
+.app-container {
+  padding: 20px;
+}
+.mb8 {
+  margin-bottom: 8px;
+}
+.fixed-width {
+  width: 120px;
+}
+</style>

+ 755 - 0
src/views/user/rechargeTemplate/index.vue

@@ -0,0 +1,755 @@
+<template>
+  <div class="app-container">
+    <!-- 查询条件 -->
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="模板名称" prop="templateName">
+        <el-input
+          v-model="queryParams.templateName"
+          placeholder="请输入模板名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
+          <el-option label="启用" value="1" />
+          <el-option label="禁用" value="0" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="标签" prop="tag">
+        <el-input
+          v-model="queryParams.tag"
+          placeholder="请输入标签"
+          clearable
+          @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="['recharge:template:add']"
+        >新增</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="['recharge:template:remove']"
+        >删除</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <!-- 表格数据 -->
+    <el-table v-loading="loading" :data="templateList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="模板ID" align="center" prop="id" width="80" />
+      <el-table-column label="模板名称" align="center" prop="templateName" :show-overflow-tooltip="true" />
+      <el-table-column label="储值金额" align="center" prop="rechargeAmount" width="100">
+        <template slot-scope="scope">
+          <span>¥{{ scope.row.rechargeAmount }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="赠送金额" align="center" prop="bonusAmount" width="100">
+        <template slot-scope="scope">
+          <span>¥{{ scope.row.bonusAmount || 0 }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="标签" align="center" prop="tag" width="100">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.tag" size="mini">{{ scope.row.tag }}</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="限购次数" align="center" prop="purchaseLimit" width="100" />
+      <el-table-column label="排序" align="center" prop="sortOrder" width="80" />
+      <el-table-column label="状态" align="center" prop="status" width="100">
+        <template slot-scope="scope">
+          <el-switch
+            v-model="scope.row.status"
+            :active-value="1"
+            :inactive-value="0"
+            @change="handleStatusChange(scope.row)"
+          ></el-switch>
+        </template>
+      </el-table-column>
+      <el-table-column label="默认选中" align="center" prop="isDefault" width="100">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.isDefault === 1" type="success" size="mini">是</el-tag>
+          <el-tag v-else type="info" size="mini">否</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="绑定优惠券" align="center" width="100">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.couponCount" type="primary" size="mini">{{ scope.row.couponCount }}张</el-tag>
+          <el-tag v-else type="info" size="mini">无</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="有效期" align="center" width="180">
+        <template slot-scope="scope">
+          <span v-if="scope.row.startTime && scope.row.endTime">
+            {{ parseTime(scope.row.startTime, '{y}-{m}-{d}') }} 至 {{ parseTime(scope.row.endTime, '{y}-{m}-{d}') }}
+          </span>
+          <span v-else>永久有效</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-view"
+            @click="handleDetail(scope.row)"
+          >详情</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['recharge:template:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['recharge:template:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页 -->
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改充值模板对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="模板名称" prop="templateName">
+              <el-input v-model="form.templateName" placeholder="请输入模板名称" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="储值金额" prop="rechargeAmount">
+              <el-input-number v-model="form.rechargeAmount" :precision="2" :min="0" placeholder="请输入储值金额" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="赠送金额" prop="bonusAmount">
+              <el-input-number v-model="form.bonusAmount" :precision="2" :min="0" placeholder="请输入赠送金额" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="限购次数" prop="purchaseLimit">
+              <el-input-number v-model="form.purchaseLimit" :min="0" placeholder="请输入限购次数,0为不限制" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="排序序号" prop="sortOrder">
+              <el-input-number v-model="form.sortOrder" :min="0" placeholder="请输入排序序号" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="标签" prop="tag">
+              <el-input v-model="form.tag" placeholder="请输入标签" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="状态" prop="status">
+              <el-radio-group v-model="form.status">
+                <el-radio :label="1">启用</el-radio>
+                <el-radio :label="0">禁用</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="默认选中" prop="isDefault">
+              <el-radio-group v-model="form.isDefault">
+                <el-radio :label="1">是</el-radio>
+                <el-radio :label="0">否</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="有效期" prop="validTime">
+              <el-date-picker
+                v-model="validTime"
+                type="datetimerange"
+                range-separator="至"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                value-format="yyyy-MM-dd HH:mm:ss"
+                format="yyyy-MM-dd HH:mm:ss"
+              ></el-date-picker>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="图标" prop="iconUrl">
+              <el-upload
+                class="avatar-uploader"
+                :action="uploadFileUrl"
+                :headers="headers"
+                :show-file-list="false"
+                :on-success="handleIconSuccess"
+                :before-upload="beforeIconUpload"
+                :on-error="handleIconError"
+              >
+                <img v-if="form.iconUrl" :src="form.iconUrl" class="avatar" />
+                <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+              </el-upload>
+              <div class="el-upload__tip">
+                <div v-if="form.iconUrl" style="margin-top: 10px;">
+                  <el-button size="mini" type="danger" icon="el-icon-delete" @click="handleIconRemove">移除</el-button>
+                </div>
+                <div style="color: #999; font-size: 12px; margin-top: 5px;">
+                  只能上传jpg/png文件,且不超过2MB
+                </div>
+              </div>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="详情链接" prop="detailUrl">
+              <el-input v-model="form.detailUrl" placeholder="请输入详情链接" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="描述文案" prop="shortDesc">
+              <el-input v-model="form.shortDesc" type="textarea" placeholder="请输入描述文案" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="权益详情" prop="benefitDetails">
+              <el-input v-model="form.benefitDetails" type="textarea" placeholder="请输入权益详情" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="绑定优惠券" prop="couponIdList">
+              <el-select
+                v-model="form.couponIdList"
+                multiple
+                filterable
+                remote
+                reserve-keyword
+                placeholder="请输入优惠券名称搜索"
+                :remote-method="remoteCouponSearch"
+                :loading="couponLoading"
+                style="width: 100%"
+                @focus="handleCouponFocus"
+                @clear="handleCouponClear"
+                clearable
+              >
+                <el-option
+                  v-for="item in couponOptions"
+                  :key="item.couponId"
+                  :label="`${item.title}(¥${item.limitTime})`"
+                  :value="item.couponId"
+                >
+                  <span>{{ item.title }}</span>
+                  <span style="float: right; color: #8492a6; font-size: 13px">
+                    ¥{{ item.price }}
+                  </span>
+                </el-option>
+              </el-select>
+              <div class="el-form-item__tip" style="margin-top: 5px; color: #999; font-size: 12px;">
+                已选择 {{ form.couponIdList ? form.couponIdList.length : 0 }} 张优惠券
+              </div>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 详情对话框 -->
+    <el-dialog title="充值模板详情" :visible.sync="detailOpen" width="800px" append-to-body>
+      <el-descriptions :column="2" border>
+        <el-descriptions-item label="模板名称">{{ detailData.templateName }}</el-descriptions-item>
+        <el-descriptions-item label="储值金额">¥{{ detailData.rechargeAmount }}</el-descriptions-item>
+        ```vue
+        <el-descriptions-item label="赠送金额">¥{{ detailData.bonusAmount || 0 }}</el-descriptions-item>
+        <el-descriptions-item label="限购次数">{{ detailData.purchaseLimit || '不限制' }}</el-descriptions-item>
+        <el-descriptions-item label="排序序号">{{ detailData.sortOrder }}</el-descriptions-item>
+        <el-descriptions-item label="标签">{{ detailData.tag || '无' }}</el-descriptions-item>
+        <el-descriptions-item label="状态">
+          <el-tag :type="detailData.status === 1 ? 'success' : 'danger'">
+            {{ detailData.status === 1 ? '启用' : '禁用' }}
+          </el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="默认选中">
+          <el-tag :type="detailData.isDefault === 1 ? 'success' : 'info'">
+            {{ detailData.isDefault === 1 ? '是' : '否' }}
+          </el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="有效期" :span="2">
+          <span v-if="detailData.startTime && detailData.endTime">
+            {{ parseTime(detailData.startTime, '{y}-{m}-{d} {h}:{i}:{s}') }} 至 {{ parseTime(detailData.endTime, '{y}-{m}-{d} {h}:{i}:{s}') }}
+          </span>
+          <span v-else>永久有效</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="图标" :span="2">
+          <img v-if="detailData.iconUrl" :src="getImageUrl(detailData.iconUrl)" style="max-height: 100px;" />
+          <span v-else>无</span>
+        </el-descriptions-item>
+        <el-descriptions-item label="详情链接" :span="2">{{ detailData.detailUrl || '无' }}</el-descriptions-item>
+        <el-descriptions-item label="描述文案" :span="2">{{ detailData.shortDesc || '无' }}</el-descriptions-item>
+        <el-descriptions-item label="权益详情" :span="2">{{ detailData.benefitDetails || '无' }}</el-descriptions-item>
+        <el-descriptions-item label="绑定优惠券" :span="2">
+          <div v-if="detailData.coupons && detailData.coupons.length > 0">
+            <el-tag v-for="(coupon, index) in detailData.coupons" :key="index" type="success" style="margin-right: 5px; margin-bottom: 5px;">
+              {{ coupon.title }} (¥{{ coupon.price }})
+            </el-tag>
+          </div>
+          <span v-else>无</span>
+        </el-descriptions-item>
+      </el-descriptions>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="detailOpen = false">关 闭</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  listRechargeTemplate,
+  getRechargeTemplate,
+  delRechargeTemplate,
+  addRechargeTemplate,
+  updateRechargeTemplate,
+  updateRechargeTemplateStatus,
+  getCouponList
+} from "@/api/recharge/template";
+import { getToken } from "@/utils/auth";
+import { parseTime } from "@/utils/common";
+
+export default {
+  name: "RechargeTemplate",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 充值模板表格数据
+      templateList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 是否显示详情弹出层
+      detailOpen: false,
+      // 详情数据
+      detailData: {},
+      // 有效期时间范围
+      validTime: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        templateName: null,
+        status: null,
+        tag: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        templateName: [
+          { required: true, message: "模板名称不能为空", trigger: "blur" }
+        ],
+        rechargeAmount: [
+          { required: true, message: "储值金额不能为空", trigger: "blur" }
+        ],
+        status: [
+          { required: true, message: "状态不能为空", trigger: "change" }
+        ],
+        sortOrder: [
+          { required: true, message: "排序序号不能为空", trigger: "blur" }
+        ]
+      },
+      // 上传参数
+      uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 上传的图片服务器地址
+      headers: {
+        Authorization: "Bearer " + getToken()
+      },
+      // 优惠券相关
+      couponOptions: [],
+      couponLoading: false,
+      couponSearchTimer: null // 搜索防抖定时器
+    };
+  },
+  created() {
+    this.getList();
+  },
+  beforeDestroy() {
+    // 组件销毁时清理定时器
+    if (this.couponSearchTimer) {
+      clearTimeout(this.couponSearchTimer);
+    }
+  },
+  methods: {
+    parseTime,
+    handleIconRemove(){
+      this.form.iconUrl = null;
+    },
+    /** 查询充值模板列表 */
+    getList() {
+      this.loading = true;
+      listRechargeTemplate(this.queryParams).then(response => {
+        this.templateList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+
+    /** 搜索按钮操作 */
+    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.loadDefaultCoupons(); // 新增时加载默认选项
+      this.open = true;
+      this.title = "添加充值模板";
+    },
+
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids;
+      getRechargeTemplate(id).then(response => {
+        this.form = response.data;
+
+        // 设置有效期时间范围
+        if (this.form.startTime && this.form.endTime) {
+          this.validTime = [this.form.startTime, this.form.endTime];
+        }
+
+        // 如果已有绑定的优惠券,加载到选项中
+        if (this.form.couponIdList && this.form.couponIdList.length > 0) {
+          this.loadSelectedCoupons(this.form.couponIdList);
+        } else {
+          // 没有已选择的优惠券时,加载默认选项
+          this.loadDefaultCoupons();
+        }
+
+        this.open = true;
+        this.title = "修改充值模板";
+      });
+    },
+
+    /** 详情按钮操作 */
+    handleDetail(row) {
+      const id = row.id;
+      getRechargeTemplate(id).then(response => {
+        this.detailData = response.data;
+        this.detailOpen = true;
+      });
+    },
+
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          // 处理有效期时间
+          if (this.validTime && this.validTime.length === 2) {
+            this.form.startTime = this.validTime[0];
+            this.form.endTime = this.validTime[1];
+          } else {
+            this.form.startTime = null;
+            this.form.endTime = null;
+          }
+
+          if (this.form.id != null) {
+            updateRechargeTemplate(this.form).then(response => {
+              this.$message.success("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addRechargeTemplate(this.form).then(response => {
+              this.$message.success("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除充值模板编号为"' + ids + '"的数据项?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        return delRechargeTemplate(ids);
+      }).then(() => {
+        this.getList();
+        this.$message.success("删除成功");
+      }).catch(() => {});
+    },
+
+    /** 状态修改 */
+    handleStatusChange(row) {
+      let text = row.status === 1 ? "启用" : "停用";
+      this.$confirm('确认要"' + text + '""' + row.templateName + '"模板吗?').then(() => {
+        return updateRechargeTemplateStatus(row.id, row.status);
+      }).then(() => {
+        this.$message.success(text + "成功");
+      }).catch(() => {
+        row.status = row.status === 0 ? 1 : 0;
+      });
+    },
+
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+
+    // 表单重置
+    reset() {
+      // 清理搜索定时器
+      if (this.couponSearchTimer) {
+        clearTimeout(this.couponSearchTimer);
+        this.couponSearchTimer = null;
+      }
+
+      this.form = {
+        id: null,
+        templateName: null,
+        rechargeAmount: null,
+        bonusAmount: null,
+        benefitDetails: null,
+        status: 1,
+        sortOrder: 0,
+        startTime: null,
+        endTime: null,
+        userType: null,
+        purchaseLimit: null,
+        tag: null,
+        shortDesc: null,
+        detailUrl: null,
+        iconUrl: null,
+        isDefault: 0,
+        couponIdList: []
+      };
+      this.validTime = [];
+      this.resetForm("form");
+      this.couponOptions = [];
+    },
+
+    // 优惠券下拉框获得焦点时
+    handleCouponFocus() {
+      // 如果没有选项且没有已选择的优惠券,加载默认选项
+      if (this.couponOptions.length === 0 && (!this.form.couponIdList || this.form.couponIdList.length === 0)) {
+        this.loadDefaultCoupons();
+      }
+    },
+
+    // 清空优惠券选择
+    handleCouponClear() {
+      this.form.couponIdList = [];
+    },
+
+    // 加载默认优惠券列表
+    loadDefaultCoupons() {
+      this.couponLoading = true;
+      getCouponList({
+        pageSize: 20,
+        pageNum: 1,
+        status: 1 // 只查询有效的优惠券
+      }).then(response => {
+        this.couponOptions = response.data.list || [];
+        this.couponLoading = false;
+      }).catch(() => {
+        this.couponLoading = false;
+        this.couponOptions = [];
+      });
+    },
+
+    // 远程搜索优惠券(添加防抖)
+    remoteCouponSearch(query) {
+      // 清除之前的定时器
+      if (this.couponSearchTimer) {
+        clearTimeout(this.couponSearchTimer);
+      }
+
+      // 设置新的定时器,300ms后执行搜索
+      this.couponSearchTimer = setTimeout(() => {
+        if (query && query.trim() !== '') {
+          this.couponLoading = true;
+          getCouponList({
+            couponName: query.trim(),
+            pageSize: 50, // 增加搜索结果数量
+            pageNum: 1,
+            status: 1 // 只查询有效的优惠券
+          }).then(response => {
+            this.couponOptions = response.data.list || [];
+            this.couponLoading = false;
+          }).catch(() => {
+            this.couponLoading = false;
+            this.couponOptions = [];
+            this.$message.error('搜索优惠券失败');
+          });
+        } else {
+          // 如果搜索为空,加载默认选项
+          this.loadDefaultCoupons();
+        }
+      }, 300);
+    },
+
+    // 加载已选择的优惠券
+    loadSelectedCoupons(couponIds) {
+      if (couponIds && couponIds.length > 0) {
+        this.couponLoading = true;
+        getCouponList({
+          couponIds: couponIds.join(',')
+        }).then(response => {
+          // 合并已选择的优惠券到选项中,避免重复
+          const selectedCoupons = response.data.list || [];
+          const existingIds = this.couponOptions.map(item => item.couponId);
+
+          selectedCoupons.forEach(coupon => {
+            if (!existingIds.includes(coupon.couponId)) {
+              this.couponOptions.push(coupon);
+            }
+          });
+
+          this.couponLoading = false;
+        }).catch(() => {
+          this.couponLoading = false;
+        });
+      }
+    },
+
+    // 获取完整的图片URL
+    getImageUrl(url) {
+      if (!url) return '';
+      // 如果已经是完整URL,直接返回
+      if (url.startsWith('http://') || url.startsWith('https://')) {
+        return url;
+      }
+      // 如果是相对路径,拼接基础URL
+      return process.env.VUE_APP_BASE_API + url;
+    },
+
+    // 图标上传前校验
+    beforeIconUpload(file) {
+      const isJPG = file.type === 'image/jpeg';
+      const isPNG = file.type === 'image/png';
+      const isGIF = file.type === 'image/gif';
+      const isWebP = file.type === 'image/webp';
+      const isLt2M = file.size / 1024 /1024 < 2; // 限制大小为2MB
+      if (!isJPG && !isPNG && !isGIF && !isWebP) {
+        this.$message.error('上传头像图片只能是 JPG、PNG、GIF 或 WebP 格式!');
+      }
+      if (!isLt2M) {
+        this.$message.error('上传头像图片大小不能超过 2MB!');
+      }
+      return (isJPG || isPNG || isGIF || isWebP) && isLt2M;
+    },
+
+    // 图标上传成功后处理
+    handleIconUploadSuccess(response, file) {
+      if (response && response.url) {
+        this.form.iconUrl = response.url; // 赋值上传后的图片URL
+      } else {
+        this.$message.error('图标上传失败,请重试');
+      }
+    },
+
+    // 图标上传失败处理
+    handleIconUploadError() {
+      this.$message.error('图标上传失败,请重试');
+    },
+    handleIconSuccess(response, file) {
+      // 处理图标上传成功的逻辑
+      this.form.iconUrl = response.url; // 假设返回的数据结构有URL
+      this.$message.success('图标上传成功!');
+    },
+    handleIconError(err, file) {
+      // 处理图标上传失败的逻辑
+      this.$message.error('图标上传失败,请重试.');
+    },
+  }
+};
+</script>
+
+<style scoped>
+.dialog-footer {
+  text-align: right;
+}
+</style>
+

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff