Browse Source

Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_his_scrm_adminUI

15376779826 3 weeks ago
parent
commit
df94e5bf4f
46 changed files with 9063 additions and 3406 deletions
  1. 40 0
      .env.prod-sczy
  2. 6 3
      .env.prod-sft
  3. 1 0
      package.json
  4. 9 0
      src/api/course/courseQuestionBank.js
  5. 8 0
      src/api/course/qw/courseWatchLog.js
  6. 9 0
      src/api/course/userCourseVideo.js
  7. 30 0
      src/api/his/integralOrder.js
  8. 1 1
      src/api/hisStore/city.js
  9. 9 0
      src/api/hisStore/storeOrder.js
  10. 7 0
      src/api/hisStore/storeProduct.js
  11. 17 0
      src/api/live/liveOrder.js
  12. 86 0
      src/api/qw/applyIpad.js
  13. 9 0
      src/api/qw/qwIpadServer.js
  14. 1 1
      src/api/statistics/statistics.js
  15. BIN
      src/assets/logo/sczy.png
  16. 493 0
      src/components/City/indexZm.vue
  17. 139 0
      src/components/Editor/wangZm.vue
  18. 6 1
      src/utils/obs.js
  19. 101 62
      src/views/components/course/userCourseCatalogDetails.vue
  20. 201 18
      src/views/components/his/integralOrderDetails.vue
  21. 2313 0
      src/views/components/index/statisticsDashboard.vue
  22. 72 0
      src/views/components/index/welcomePage.vue
  23. 107 3
      src/views/course/coursePlaySourceConfig/index.vue
  24. 50 3
      src/views/course/courseQuestionBank/index.vue
  25. 56 2
      src/views/course/courseWatchLog/qw/statistics.vue
  26. 46 10
      src/views/course/userCoursePeriod/index.vue
  27. 106 14
      src/views/course/userCoursePeriod/statistics.vue
  28. 2 2
      src/views/his/company/index.vue
  29. 532 5
      src/views/his/integralOrder/index.vue
  30. 138 138
      src/views/his/storeOrder/order1.vue
  31. 28 8
      src/views/his/user/indexProject.vue
  32. 38 2
      src/views/hisStore/menu/index.vue
  33. 23 6
      src/views/hisStore/shippingTemplates/index.vue
  34. 78 21
      src/views/hisStore/storeOrder/healthStoreList.vue
  35. 24 7
      src/views/hisStore/storeOrder/index.vue
  36. 26 10
      src/views/hisStore/storeProduct/index.vue
  37. 1799 0
      src/views/hisStore/storeProduct/indexZm.vue
  38. 1 2
      src/views/hisStore/storeProductPackage/index.vue
  39. 44 2277
      src/views/index.vue
  40. 2 2
      src/views/live/liveConfig/task.vue
  41. 49 11
      src/views/live/liveConsole/LiveConsole.vue
  42. 629 730
      src/views/live/liveData/index.vue
  43. 265 13
      src/views/live/liveOrder/index.vue
  44. 53 53
      src/views/live/liveOrder/liveOrderDetails.vue
  45. 1388 0
      src/views/qw/applyIpad/index.vue
  46. 21 1
      src/views/system/config/config.vue

+ 40 - 0
.env.prod-sczy

@@ -0,0 +1,40 @@
+# 页面标题
+VUE_APP_TITLE =致医总管理系统
+# 首页菜单标题
+VUE_APP_TITLE_INDEX =致医管理系统
+# 公司名称
+VUE_APP_COMPANY_NAME =重庆云联融智科技有限公司
+# ICP备案号
+VUE_APP_ICP_RECORD =渝ICP备2024031984号-1
+# ICP网站访问地址
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/sczy.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 = sczy-hw079058881
+# 存储桶配置
+VUE_APP_COS_BUCKET = sczy-1323137866
+# 存储桶配置
+VUE_APP_COS_REGION = ap-chongqing
+# 线路一地址
+VUE_APP_VIDEO_LINE_1 = https://sczycpv.ylrzcloud.com
+# 线路二地址
+VUE_APP_VIDEO_LINE_2 = https://sczyobs.ylrztop.com
+
+# 开发环境配置
+ENV = 'development'
+
+# FS管理系统/开发环境
+VUE_APP_BASE_API = '/prod-api'
+
+#默认 1、会员 2、企微
+VUE_APP_COURSE_DEFAULT = 2
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 6 - 3
.env.prod-sft

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

+ 1 - 0
package.json

@@ -46,6 +46,7 @@
     "build:prod-hst": "vue-cli-service build --mode prod-hst",
     "build:prod-czt": "vue-cli-service build --mode prod-czt",
     "build:prod-hat": "vue-cli-service build --mode prod-hat",
+    "build:prod-sczy": "vue-cli-service build --mode prod-sczy",
     "build:prod-ddgy": "vue-cli-service build --mode prod-ddgy",
     "build:prod-yxj": "vue-cli-service build --mode prod-yxj",
     "build:prod-bjzm": "vue-cli-service build --mode prod-bjzm",

+ 9 - 0
src/api/course/courseQuestionBank.js

@@ -52,6 +52,15 @@ export function exportCourseQuestionBank(query) {
   })
 }
 
+export function exportFail(data) {
+  return request({
+    url: '/course/courseQuestionBank/exportFail',
+    method: 'post',
+    data: data
+  })
+}
+
+
 // 下载模板
 export function importTemplate() {
   return request({

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

@@ -126,3 +126,11 @@ export function listBytrainingCampId(query) {
     params: query
   })
 }
+
+export function getSignProjectName() {
+  return request({
+    url: '/qw/course/courseWatchLog/getSignProjectName',
+    method: 'get'
+  })
+}
+

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

@@ -75,6 +75,15 @@ export function delUserCourseVideo(videoId) {
   })
 }
 
+// 同步课程模板
+export function syncTemplate(courseId) {
+  console.log(courseId)
+  return request({
+    url: '/course/userCourse/syncTemplate/' + courseId,
+    method: 'post'
+  })
+}
+
 // 导出课堂视频
 export function exportUserCourseVideo(query) {
   return request({

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

@@ -102,4 +102,34 @@ export function finishOrder(orderCode) {
     url: '/his/integralOrder/finishOrder/' + orderCode,
     method: 'get'
   })
+}
+//数据分捡
+export function batchSetErpOrder(params) {
+  return request({
+    url: '/his/integralOrder/batchSetErpOrder',
+    method: 'post',
+    data: params
+  })
+}
+//数据分捡
+export function batchCreateErpOrder(params) {
+  return request({
+    url: '/his/integralOrder/batchCreateErpOrder',
+    method: 'post',
+    data: params
+  })
+}
+//获取城市
+export function getCitys(){
+  return request({
+    url: '/his/city/getCitys',
+    method: 'get'
+  })
+}
+//获取模版
+export function getIntegralTemplate(){
+  return request({
+    url: '/his/integralOrder/importUpdateOrderTemplate',
+    method: 'get'
+  })
 }

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

@@ -10,7 +10,7 @@ export function listCity(query) {
 }
 export function getAllList(query) {
   return request({
-    url: '/store/city/getAllList',
+    url: '/his/city/getAllList',
     method: 'get',
     params: query
   })

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

@@ -377,3 +377,12 @@ export function getErpAccount() {
     method: 'get'
   })
 }
+
+// 导出发货单
+export function healthExportShippingOrder(query) {
+  return request({
+    url: '/store/store/storeOrder/healthExportShippingOrder',
+    method: 'get',
+    params: query
+  })
+}

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

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

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

@@ -293,3 +293,20 @@ export function updateErp(data) {
     data: data
   })
 }
+
+
+// 导出发货单
+export function healthExportShippingOrder(query) {
+  return request({
+    url: '/live/liveOrder/healthExportShippingOrder',
+    method: 'get',
+    params: query
+  })
+}
+
+export function importDeliveryNoteExpressTemplate() {
+  return request({
+    url: '/live/liveOrder/importDeliveryNoteExpressTemplate',
+    method: 'get'
+  })
+}

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

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

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

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

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

@@ -378,7 +378,7 @@ export function getSearchUserInfo(param){
  */
 export function getStatisticsDataN(data) {
   return request({
-    url: '/crm/ComprehensiveStatistics/statisticMainN',
+    url: '/statistic/manage/statisticMainN',
     method: 'post',
     data: data  // 使用 data 而不是 params
   })

BIN
src/assets/logo/sczy.png


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

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

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

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

+ 6 - 1
src/utils/obs.js

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

+ 101 - 62
src/views/components/course/userCourseCatalogDetails.vue

@@ -6,7 +6,7 @@
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
       <el-form-item label="小节名称" prop="title">
         <el-input v-model="queryParams.title" placeholder="请输入小节名称" clearable size="small"
-                  @keyup.enter.native="handleQuery" />
+                  @keyup.enter.native="handleQuery"/>
       </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
@@ -16,34 +16,45 @@
     <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:userCourseVideo:add']">新增目录</el-button>
+                   v-hasPermi="['course:userCourseVideo:add']">新增目录
+        </el-button>
       </el-col>
       <el-col :span="1.5">
         <el-button type="primary" plain :disabled="!ids || ids.length <= 0" size="mini" @click="openUpdates"
-                   v-hasPermi="['course:userCourseVideo:updateTime']">修改时间</el-button>
+                   v-hasPermi="['course:userCourseVideo:updateTime']">修改时间
+        </el-button>
       </el-col>
       <el-col :span="1.5">
         <el-button type="primary" plain size="mini" @click="openAdds"
-                   v-hasPermi="['course:userCourseVideo:batchAdd']">批量添加</el-button>
+                   v-hasPermi="['course:userCourseVideo:batchAdd']">批量添加
+        </el-button>
       </el-col>
       <el-col :span="1.5">
         <el-button type="primary" plain size="mini" @click="updateRedPageckeOpen"
-                   v-hasPermi="['course:userCourseVideo:updateRed']">修改红包</el-button>
+                   v-hasPermi="['course:userCourseVideo:updateRed']">修改红包
+        </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="['course:userCourseVideo:remove']">删除</el-button>
+                   v-hasPermi="['course:userCourseVideo:remove']">删除
+        </el-button>
       </el-col>
       <el-col :span="1.5">
         <el-button type="warning" plain icon="el-icon-edit" size="mini" @click="handleCourseSort"
-                   v-hasPermi="['course:userCourseVideo:sort']">修改课节排序</el-button>
+                   v-hasPermi="['course:userCourseVideo:sort']">修改课节排序
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="primary" plain icon="el-icon-delete" size="mini" @click="handleSync"
+                   v-hasPermi="['course:userCourseVideo:sync']">同步模板数据
+        </el-button>
       </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
     <el-table border v-loading="loading" :data="userCourseVideoList" @selection-change="handleSelectionChange">
-      <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="视频ID" align="center" prop="videoId" />
-      <el-table-column label="小节名称" align="center" show-overflow-tooltip prop="title" />
+      <el-table-column type="selection" width="55" align="center"/>
+      <el-table-column label="视频ID" align="center" prop="videoId"/>
+      <el-table-column label="小节名称" align="center" show-overflow-tooltip prop="title"/>
       <el-table-column label="视频文件名称" align="center" show-overflow-tooltip prop="fileName">
       </el-table-column>
       <el-table-column label="视频时长" align="center" prop="duration">
@@ -69,30 +80,33 @@
           <el-tag type="danger" v-if="!row.lastJoinTime">无</el-tag>
         </template>
       </el-table-column>
-      <el-table-column label="红包金额" align="center" prop="redPacketMoney" />
-      <el-table-column label="排序" align="center" prop="courseSort" />
-      <el-table-column label="上传时间" align="center" prop="createTime" />
+      <el-table-column label="红包金额" align="center" prop="redPacketMoney"/>
+      <el-table-column label="排序" align="center" prop="courseSort"/>
+      <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" icon="el-icon-edit" @click="handleUpdate(scope.row)"
-                     v-hasPermi="['course:userCourseVideo:edit']">修改</el-button>
+                     v-hasPermi="['course:userCourseVideo:edit']">修改
+          </el-button>
           <el-button size="mini" type="text" icon="el-icon-edit" @click="handleComment(scope.row)"
-                     v-hasPermi="['course:courseWatchComment:list']">查看评论</el-button>
+                     v-hasPermi="['course:courseWatchComment:list']">查看评论
+          </el-button>
           <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
-                     v-hasPermi="['course:userCourseVideo:remove']">删除</el-button>
+                     v-hasPermi="['course:userCourseVideo: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" />
+                @pagination="getList"/>
     <el-dialog :title="title" :visible.sync="open" width="1000px" append-to-body>
       <el-form ref="form" :model="form" :rules="rules" label-width="110px" v-loading="uploadLoading">
         <el-form-item label="视频标题" prop="title">
-          <el-input v-model="form.title" placeholder="请输入内容" />
+          <el-input v-model="form.title" placeholder="请输入内容"/>
         </el-form-item>
         <el-form-item label="视频描述" prop="description">
-          <el-input v-model="form.description" type="textarea" :rows="2" placeholder="请输入内容" />
+          <el-input v-model="form.description" type="textarea" :rows="2" placeholder="请输入内容"/>
         </el-form-item>
         <el-form-item label="课程排序" prop="courseSort">
           <el-input-number v-model="form.courseSort" :min="1"></el-input-number>
@@ -110,7 +124,8 @@
                       :line_2.sync="form.lineTwo" :line_3.sync="form.lineThree" :thumbnail.sync="form.thumbnail"
                       :uploadType.sync="form.uploadType" :isTranscode.sync="form.isTranscode"
                       :transcodeFileKey.sync="form.transcodeFileKey" @video-duration="handleVideoDuration"
-                      @change="handleVideoChange" @selectProjects="handleSelectProjects" ref="videoUpload" append-to-body />
+                      @change="handleVideoChange" @selectProjects="handleSelectProjects" ref="videoUpload"
+                      append-to-body/>
 
         <el-form-item label="课题选择" prop="questionBankId">
           <el-button size="small" type="primary" @click="chooseQuestionBank">选取课题</el-button>
@@ -127,14 +142,15 @@
             </el-table-column>
             <el-table-column label="类别" align="center" prop="type">
               <template slot-scope="scope">
-                <dict-tag :options="typeOptions" :value="scope.row.type" />
+                <dict-tag :options="typeOptions" :value="scope.row.type"/>
               </template>
             </el-table-column>
-            <el-table-column label="答案" align="center" prop="answer" />
+            <el-table-column label="答案" align="center" prop="answer"/>
             <el-table-column label="操作" align="center" width="100px" fixed="right">
               <template slot-scope="scope">
                 <el-button size="mini" type="text" icon="el-icon-delete"
-                           @click="handleQuestionBankDelete(scope.row)">删除</el-button>
+                           @click="handleQuestionBankDelete(scope.row)">删除
+                </el-button>
               </template>
             </el-table-column>
           </el-table>
@@ -155,14 +171,15 @@
         <el-form-item label="商品选择" v-if="form.isProduct === 1">
           <el-button size="small" type="primary" @click="chooseCourseProduct">选取商品</el-button>
           <el-table border width="100%" style="margin-top:5px;" :data="form.courseProducts">
-            <el-table-column label="商品名称" align="center" prop="productName" />
-            <el-table-column label="产品条码" align="center" prop="barCode" />
-            <el-table-column label="商品价格" align="center" prop="productPrice" />
-            <el-table-column label="库存" align="center" prop="stock" />
+            <el-table-column label="商品名称" align="center" prop="productName"/>
+            <el-table-column label="产品条码" align="center" prop="barCode"/>
+            <el-table-column label="商品价格" align="center" prop="productPrice"/>
+            <el-table-column label="库存" align="center" prop="stock"/>
             <el-table-column label="操作" align="center" width="100px" fixed="right">
               <template slot-scope="scope">
                 <el-button size="mini" type="text" icon="el-icon-delete"
-                           @click="handleCourseProductDelete(scope.row)">删除</el-button>
+                           @click="handleCourseProductDelete(scope.row)">删除
+                </el-button>
               </template>
             </el-table-column>
           </el-table>
@@ -188,7 +205,8 @@
     <el-dialog :title="title" :visible.sync="updateBatchData.open" width="1000px" append-to-body>
       <el-form ref="form" :model="updateBatchData.form" label-width="110px">
         <el-form-item label="看课时间" prop="timeRange">
-          <el-time-picker is-range v-model="updateBatchData.form.timeRange" range-separator="至" start-placeholder="开始时间"
+          <el-time-picker is-range v-model="updateBatchData.form.timeRange" range-separator="至"
+                          start-placeholder="开始时间"
                           value-format="HH:mm:ss" end-placeholder="结束时间" placeholder="选择时间范围">
           </el-time-picker>
         </el-form-item>
@@ -215,19 +233,20 @@
       <el-form :inline="true" :model="addBatchData.queryParams" class="library-search">
         <el-form-item label="素材名称">
           <el-input v-model="addBatchData.queryParams.resourceName" placeholder="请输入素材名称" clearable size="small"
-                    @keyup.enter.native="resourceList" />
+                    @keyup.enter.native="resourceList"/>
         </el-form-item>
         <el-form-item label="类型">
-          <el-select v-model="addBatchData.queryParams.typeId" @change="changeCateType" placeholder="请选择素材类型" clearable
+          <el-select v-model="addBatchData.queryParams.typeId" @change="changeCateType" placeholder="请选择素材类型"
+                     clearable
                      size="small">
             <el-option v-for="item in addBatchData.typeOptions" :key="item.dictValue" :label="item.dictLabel"
-                       :value="item.dictValue" />
+                       :value="item.dictValue"/>
           </el-select>
         </el-form-item>
         <el-form-item label="子类型">
           <el-select v-model="addBatchData.queryParams.typeSubId" placeholder="请选择素材子类型" clearable size="small">
             <el-option v-for="item in addBatchData.typeSubOptions" :key="item.dictValue" :label="item.dictLabel"
-                       :value="item.dictValue" />
+                       :value="item.dictValue"/>
           </el-select>
         </el-form-item>
         <el-form-item>
@@ -238,15 +257,15 @@
       <!-- 视频列表 -->
       <el-table v-loading="addBatchData.loading" :data="addBatchData.list"
                 @selection-change="handVideoleSelectionChange" height="400px">
-        <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="素材名称" align="center" prop="resourceName" />
-        <el-table-column label="文件名称" align="center" prop="fileName" />
-        <el-table-column label="排序" align="center" prop="sort" />
+        <el-table-column type="selection" width="55" align="center"/>
+        <el-table-column label="素材名称" align="center" prop="resourceName"/>
+        <el-table-column label="文件名称" align="center" prop="fileName"/>
+        <el-table-column label="排序" align="center" prop="sort"/>
         <el-table-column label="缩略图" align="center">
           <template slot-scope="scope">
             <el-popover placement="right" title="" trigger="hover">
-              <img alt="" slot="reference" :src="scope.row.thumbnail" style="width: 80px; height: 50px" />
-              <img alt="" :src="scope.row.thumbnail" style="max-width: 150px;" />
+              <img alt="" slot="reference" :src="scope.row.thumbnail" style="width: 80px; height: 50px"/>
+              <img alt="" :src="scope.row.thumbnail" style="max-width: 150px;"/>
             </el-popover>
           </template>
         </el-table-column>
@@ -260,7 +279,7 @@
       <!-- 分页 -->
       <pagination v-show="addBatchData.total > 0" :total="addBatchData.total"
                   :page.sync="addBatchData.queryParams.pageNum" :limit.sync="addBatchData.queryParams.pageSize"
-                  @pagination="resourceList" />
+                  @pagination="resourceList"/>
 
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="batchVideoSave">确 定</el-button>
@@ -268,7 +287,7 @@
     </el-dialog>
     <el-dialog title="章节红包" :visible.sync="redData.open" width="900px" append-to-body>
       <el-table border v-loading="redData.loading" :data="redData.list" height="600px">
-        <el-table-column label="小节名称" align="center" show-overflow-tooltip prop="title" />
+        <el-table-column label="小节名称" align="center" show-overflow-tooltip prop="title"/>
         <el-table-column label="视频文件名称" align="center" show-overflow-tooltip prop="fileName">
         </el-table-column>
         <el-table-column label="视频时长" align="center" prop="duration">
@@ -278,11 +297,11 @@
         </el-table-column>
         <el-table-column label="红包金额" align="center" prop="redPacketMoney">
           <template slot-scope="scope">
-            <el-input class="el-input" v-model="scope.row.redPacketMoney" />
+            <el-input class="el-input" v-model="scope.row.redPacketMoney"/>
           </template>
         </el-table-column>
-        <el-table-column label="排序" align="center" prop="courseSort" />
-        <el-table-column label="上传时间" align="center" prop="createTime" />
+        <el-table-column label="排序" align="center" prop="courseSort"/>
+        <el-table-column label="上传时间" align="center" prop="createTime"/>
       </el-table>
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="batchRedSave">确 定</el-button>
@@ -298,7 +317,8 @@
 
     <el-dialog title="修改课节排序" :visible.sync="openVideoSort" style="width: 1600px;" append-to-body>
       <draggable v-model="userCourseVideoSortList" @end="onDragEndDay" style="padding: 10px">
-        <el-button style="margin: 8px 4px;" v-for="(item, index) in userCourseVideoSortList" :class="item.newCourseSort != item.courseSort ? 'red':''">第{{
+        <el-button style="margin: 8px 4px;" v-for="(item, index) in userCourseVideoSortList"
+                   :class="item.newCourseSort != item.courseSort ? 'red':''">第{{
             item.newCourseSort
           }}序(原排序第{{ item.courseSort }})
         </el-button>
@@ -314,27 +334,31 @@
 <script>
 import {
   addUserCourseVideo,
+  batchSaveVideo,
+  batchUpdateRed,
   delUserCourseVideo,
   getSort,
   getUserCourseVideo,
   getVideoListByCourseId,
+  getVideoListByCourseIdAll,
+  sortCourseVideo,
   updates,
-  batchSaveVideo,
-  batchUpdateRed,
-  updateUserCourseVideo, getVideoListByCourseIdAll, sortCourseVideo
+  updateUserCourseVideo,
+  syncTemplate
 } from '@/api/course/userCourseVideo'
+// import {syncTemplate} from '@/api/course/userCourse'
 import QuestionBank from "@/views/course/courseQuestionBank/QuestionBank.vue";
 import CourseProduct from "@/views/course/fsCourseProduct/CourseProduct.vue";
 import VideoUpload from "@/components/VideoUpload/index.vue";
-import { listVideoResource } from '@/api/course/videoResource';
-import { getByIds } from '@/api/course/courseQuestionBank'
+import {listVideoResource} from '@/api/course/videoResource';
+import {getByIds} from '@/api/course/courseQuestionBank'
 import CourseWatchComment from "./courseWatchComment.vue";
-import { getCateListByPid, getCatePidList } from '@/api/course/userCourseCategory'
+import {getCateListByPid, getCatePidList} from '@/api/course/userCourseCategory'
 import draggable from 'vuedraggable'
 
 export default {
   name: "userCourseCatalog",
-  components: { VideoUpload, QuestionBank, CourseWatchComment, CourseProduct, draggable },
+  components: {VideoUpload, QuestionBank, CourseWatchComment, CourseProduct, draggable},
   data() {
     return {
       duration: null,
@@ -357,8 +381,8 @@ export default {
       isPrivate: null,
       videoUrl: "",
       uploadTypeOptions: [
-        { dictLabel: "线路一", dictValue: 2 },
-        { dictLabel: "线路二", dictValue: 3 },
+        {dictLabel: "线路一", dictValue: 2},
+        {dictLabel: "线路二", dictValue: 3},
       ],
       uploadLoading: false,
       courseId: null,
@@ -390,8 +414,7 @@ export default {
         list: [],
         open: false,
         loading: true,
-        form: {
-        }
+        form: {}
       },
       queryParams: {
         pageNum: 1,
@@ -440,10 +463,10 @@ export default {
       // 表单校验
       rules: {
         title: [
-          { required: true, message: "小节名称不能为空", trigger: "change" }
+          {required: true, message: "小节名称不能为空", trigger: "change"}
         ],
         courseSort: [
-          { required: true, message: "排序不能为空", trigger: "change" }
+          {required: true, message: "排序不能为空", trigger: "change"}
         ],
 
       },
@@ -581,7 +604,7 @@ export default {
         return
       }
 
-      const params = { ids: projectIds }
+      const params = {ids: projectIds}
       getByIds(params).then(response => {
         if (response.code === 200) {
           response.data.forEach(item => {
@@ -804,7 +827,7 @@ export default {
             this.form.packageJson = JSON.stringify(this.packageList);
           }
           if (this.form.courseProducts != null) {
-            this.form.productId = this.form.courseProducts[0].id
+            this.form.productId = this.form.courseProducts.map(item => item.id).join(',');
           }
           if (this.form.videoId != null) {
             updateUserCourseVideo(this.form).then(response => {
@@ -851,7 +874,23 @@ export default {
       }).then(() => {
         this.getList();
         this.msgSuccess("删除成功");
-      }).catch(() => { });
+      }).catch(() => {
+      });
+    },
+    /** 同步模板数据*/
+    handleSync() {
+      const courseId = this.courseId;
+      this.$confirm('是否同步课程数据至模板', "确认", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function () {
+        return syncTemplate(courseId);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("同步成功");
+      }).catch(() => {
+      });
     },
 
     handleCourseSort() {
@@ -879,7 +918,7 @@ export default {
 
     saveSorts() {
       let list = this.userCourseVideoSortList.filter(e => e.courseSort != e.newCourseSort).map(e => {
-        return { courseSort: e.newCourseSort, videoId: e.videoId }
+        return {courseSort: e.newCourseSort, videoId: e.videoId}
       })
       this.loading3 = true;
       sortCourseVideo(list).then(e => {

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

@@ -64,6 +64,12 @@
               }}</span></el-descriptions-item>
           <el-descriptions-item label="快递单号"><span v-if="item != null">{{ item.deliverySn
               }}</span></el-descriptions-item>
+          <!-- <el-descriptions-item label="物流状态"><span v-if="item != null">{{ item.deliveryType
+              }}</span></el-descriptions-item> -->
+          <el-descriptions-item label="物流状态" ><dict-tag :options="deliveryStatusOptions" :value="item.deliveryStatus"/></el-descriptions-item>
+
+          <el-descriptions-item label="物流跟踪状态" ><span v-if="item!=null"><dict-tag :options="deliveryTypeOptions" :value="item.deliveryType"/> </span></el-descriptions-item>
+
           <el-descriptions-item label="发货时间"><span v-if="item != null">{{ item.deliveryTime
               }}</span></el-descriptions-item>
           <el-descriptions-item label="提交时间"><span v-if="item != null">{{ item.createTime
@@ -100,7 +106,7 @@
 
       </el-table>
     </div>
-    <el-dialog width="50%" title="发货" :visible.sync="sendVisible" append-to-body @close="sendCancel">
+    <el-dialog width="35%" title="发货" :visible.sync="sendVisible" append-to-body @close="sendCancel">
       <el-form ref="form" :model="form" label-width="120px">
         <el-form-item label="快递名称" prop="deliveryName">
           <el-select v-model="selectedExpress" placeholder="请选择快递名称" value-key="name">
@@ -118,11 +124,10 @@
         </el-form-item>
 
         <!-- 代服账号选择表格 -->
-        <el-form-item label="代服账号选择" prop="selectedAccount" required>
+        <!-- <el-form-item label="代服账号选择" prop="selectedAccount" required>
           <div style="border: 1px solid #e6ebf5; border-radius: 4px; padding: 10px;">
             <el-table ref="accountTable" :data="tableData" highlight-current-row
               @current-change="handleAccountSelectionChange" style="width: 100%" size="small" max-height="400">
-              <!-- 固定高度,超出滚动 -->
 
               <el-table-column type="index" width="60" label="序号" align="center"></el-table-column>
               <el-table-column prop="loginAccount" label="登录账号" align="center" width="120"
@@ -147,7 +152,7 @@
 
             </el-table>
 
-            <!-- 分页 -->
+            
             <el-pagination small layout="prev, pager, next" :total="total" :page-size="queryParams.pageSize"
               :current-page="queryParams.pageNum" @current-change="handlePageChange"
               style="margin-top: 10px; text-align: center;">
@@ -157,13 +162,13 @@
               提示:点击表格行选择代服账号
             </div>
 
-            <!-- 显示选中信息 -->
+            
             <div v-if="selectedRow" style="margin-top: 10px; padding: 8px; background: #f5f7fa; border-radius: 4px;">
               <span style="color: #67C23A;">已选择:</span>
               <span>{{ selectedRow.loginAccount }} ({{ selectedRow.senderName }})</span>
             </div>
           </div>
-        </el-form-item>
+        </el-form-item> -->
 
       </el-form>
       <div slot="footer" class="dialog-footer">
@@ -198,11 +203,74 @@
         <el-form-item label="订单状态" prop="status">
           <el-select v-model="editForm.status" placeholder="请选择状态" clearable size="small" filterable>
             <el-option v-for="dict in statusOptions" :key="dict.dictValue" :label="dict.dictLabel"
-              :value="dict.dictValue" />
+              :value="dict.dictValue" :disabled="dict.dictValue==4||dict.dictValue==6||dict.dictValue==-1"/>
           </el-select>
         </el-form-item>
-        <el-form-item label="详情地址" prop="userAddress">
-          <el-input v-model="editForm.userAddress" placeholder="请输入" />
+        <el-form-item label="收货地址" required v-if="item.status == 1">
+          <div style="margin-bottom: 10px;">
+            <el-select 
+              v-model="selectedProvince" 
+              placeholder="请选择省" 
+              style="width: 32%; margin-right: 1%"
+              @change="onProvinceChange"
+              clearable
+            >
+              <el-option
+                v-for="item in provinceOptions"
+                :key="item.value"
+                :label="item.label"
+                :value="item"
+              />
+            </el-select>
+            
+            <el-select 
+              v-model="selectedCity" 
+              placeholder="请选择市" 
+              style="width: 32%; margin-right: 1%"
+              @change="onCityChange"
+              :disabled="!selectedProvince"
+              clearable
+            >
+              <el-option
+                v-for="item in cityOptions"
+                :key="item.value"
+                :label="item.label"
+                :value="item"
+              />
+            </el-select>
+            
+            <el-select 
+              v-model="selectedDistrict" 
+              placeholder="请选择区" 
+              style="width: 32%;"
+              @change="onDistrictChange"
+              :disabled="!selectedCity"
+              clearable
+            >
+              <el-option
+                v-for="item in districtOptions"
+                :key="item.value"
+                :label="item.label"
+                :value="item"
+              />
+            </el-select>
+          </div>
+          
+          <el-input 
+            v-model="detailAddress" 
+            placeholder="请输入详细地址(街道、门牌号等)" 
+            style="width: 100%"
+            clearable
+          />
+        </el-form-item>
+
+        <!-- 其他状态显示只读的地址信息 -->
+        <el-form-item label="收货地址" v-else>
+          <el-input 
+            v-model="editForm.userAddress" 
+            placeholder="请输入" 
+            disabled
+          />
         </el-form-item>
 
         <!-- 修改:快递信息改为下拉选择 -->
@@ -220,12 +288,11 @@
         </el-form-item>
 
         <!-- 代服账号选择表格 - 使用同一个数据源 -->
-        <el-form-item label="代服账号" prop="loginAccount">
+        <!-- <el-form-item label="代服账号" prop="loginAccount">
           <div style="border: 1px solid #e6ebf5; border-radius: 4px; padding: 10px;">
             <el-table ref="editAccountTable" :data="tableData" highlight-current-row
               @current-change="handleEditAccountSelectionChange" style="width: 100%" size="small" max-height="300">
 
-              <!-- 列定义与发货弹窗相同 -->
               <el-table-column type="index" width="60" label="序号" align="center"></el-table-column>
               <el-table-column prop="loginAccount" label="登录账号" align="center" width="120"
                 show-overflow-tooltip></el-table-column>
@@ -249,7 +316,6 @@
 
             </el-table>
 
-            <!-- 分页 - 使用同一个分页数据 -->
             <el-pagination small layout="prev, pager, next" :total="total" :page-size="queryParams.pageSize"
               :current-page="queryParams.pageNum" @current-change="handlePageChange"
               style="margin-top: 10px; text-align: center;">
@@ -259,14 +325,13 @@
               提示:点击表格行选择代服账号
             </div>
 
-            <!-- 显示选中信息 -->
             <div v-if="editSelectedRow"
               style="margin-top: 10px; padding: 8px; background: #f5f7fa; border-radius: 4px;">
               <span style="color: #67C23A;">已选择:</span>
               <span>{{ editSelectedRow.loginAccount }} ({{ editSelectedRow.senderName }})</span>
             </div>
           </div>
-        </el-form-item>
+        </el-form-item> -->
 
         <el-form-item label="备注" prop="remark">
           <el-input v-model="editForm.remark" placeholder="请输入备注" />
@@ -280,13 +345,14 @@
 </template>
 
 <script>
-import { getExpress,mandatoryRefunds,finishOrder, listIntegralOrder, sendgoods, getIntegralOrder, delIntegralOrder, addIntegralOrder, updateIntegralOrder, exportIntegralOrder, getOrderUserPhone } from "@/api/his/integralOrder";
+import { getExpress,mandatoryRefunds,getCitys,finishOrder, listIntegralOrder, sendgoods, getIntegralOrder, delIntegralOrder, addIntegralOrder, updateIntegralOrder, exportIntegralOrder, getOrderUserPhone } from "@/api/his/integralOrder";
 import { getExpressList } from "@/api/his/express";
 import { listAccount } from "@/api/his/dfAccount";
 export default {
   name: "integralOrder",
   data() {
     return {
+      deliveryStatusOptions:[],
       selectedExpress: null,
       expressOption: [],
       expressDialog: {
@@ -300,7 +366,7 @@ export default {
       editForm: {
         orderId: null,
         status: null,
-        userAddress: null,
+        userAddress: null, // 这个字段将存储拼接后的完整地址
         remark: "",
         loginAccount: null,
         // 新增快递相关字段
@@ -354,6 +420,15 @@ export default {
       total: 0, // 总条数,
       expressOptions: [], // 物流产品字典
       editSelectedExpress: null,
+      // 地址选择相关数据
+      provinceOptions: [], // 省列表
+      cityOptions: [], // 市列表
+      districtOptions: [], // 区列表
+      selectedProvince: null, // 选中的省
+      selectedCity: null, // 选中的市
+      selectedDistrict: null, // 选中的区
+      detailAddress: '', // 详细地址
+      deliveryTypeOptions:[],
     }
   },
   created() {
@@ -363,6 +438,12 @@ export default {
     this.getDicts("df_account_express").then(response => {
       this.expressOptions = response.data;
     });
+    this.getDicts("sys_store_order_delivery_status").then(response => {
+          this.deliveryStatusOptions = response.data;
+    });
+    this.getDicts("sys_delivery_type").then(response => {
+              this.deliveryTypeOptions = response.data;
+            });
   },
   watch: {
     selectedExpress(newVal) {
@@ -454,10 +535,15 @@ export default {
           }
         }
 
-        // 3. 等待代服账号数据加载完成
+        // 3. 初始化地址选择器(只在待发货状态时执行)
+        if (this.item.status == 1) {
+          await this.initAddressSelector();
+        }
+
+        // 4. 等待代服账号数据加载完成
         await this.getAccountList();
 
-        // 4. 在数据都加载完成后尝试选中对应的行
+        // 5. 在数据都加载完成后尝试选中对应的行
         if (this.item.loginAccount) {
           this.$nextTick(() => {
             this.selectCurrentAccount();
@@ -467,6 +553,88 @@ export default {
         console.error('加载数据失败:', error);
       }
     },
+    // 初始化地址选择器
+    async initAddressSelector() {
+      // 重置地址选择器
+      this.provinceOptions = [];
+      this.cityOptions = [];
+      this.districtOptions = [];
+      this.selectedProvince = null;
+      this.selectedCity = null;
+      this.selectedDistrict = null;
+      this.detailAddress = '';
+
+      // 只有在待发货状态时才初始化地址选择器
+      if (this.item.status == 1) {
+        // 获取省份数据
+        try {
+          const response = await getCitys(); // 假设getCitys是您导入的方法
+          this.provinceOptions = response.data || [];
+          
+          // 如果现有地址不为空,尝试解析并设置初始值
+          if (this.item.userAddress) {
+            this.parseExistingAddress(this.item.userAddress);
+          }
+        } catch (error) {
+          console.error('获取地址数据失败:', error);
+        }
+      }
+    },
+
+    // 解析现有地址
+    parseExistingAddress(address) {
+      if (!address || this.item.status != 1) return;
+      
+      // 假设地址格式为 "省 市 区 详细地址"
+      const parts = address.split(' ');
+      if (parts.length >= 4) {
+        const provinceName = parts[0];
+        const cityName = parts[1];
+        const districtName = parts[2];
+        this.detailAddress = parts.slice(3).join(' '); // 剩余部分作为详细地址
+        
+        // 设置省份
+        const province = this.provinceOptions.find(p => p.label === provinceName);
+        if (province) {
+          this.selectedProvince = province;
+          this.onProvinceChange(province);
+          
+          // 设置城市
+          const city = province.children?.find(c => c.label === cityName);
+          if (city) {
+            this.selectedCity = city;
+            this.onCityChange(city);
+            
+            // 设置区域
+            const district = city.children?.find(d => d.label === districtName);
+            if (district) {
+              this.selectedDistrict = district;
+            }
+          }
+        }
+      } else {
+        // 如果格式不匹配,将整个地址作为详细地址
+        this.detailAddress = address;
+      }
+    },
+    // 省份选择变化
+    onProvinceChange(province) {
+      this.selectedCity = null;
+      this.selectedDistrict = null;
+      this.cityOptions = province?.children || [];
+      this.districtOptions = [];
+    },
+
+    // 城市选择变化
+    onCityChange(city) {
+      this.selectedDistrict = null;
+      this.districtOptions = city?.children || [];
+    },
+
+    // 区域选择变化
+    onDistrictChange(district) {
+      // 可以在这里处理区域选择后的逻辑
+    },
     // 选中当前账号(修改订单弹窗使用)
     selectCurrentAccount() {
       if (!this.item.loginAccount || !this.tableData || this.tableData.length === 0) {
@@ -492,6 +660,21 @@ export default {
     },
     //修改订单状态
     submitEditForm() {
+      // 只有在待发货状态(status=1)时才更新地址
+      if (this.item.status == 1) {
+        // 拼接完整地址
+        const province = this.selectedProvince ? this.selectedProvince.label : '';
+        const city = this.selectedCity ? this.selectedCity.label : '';
+        const district = this.selectedDistrict ? this.selectedDistrict.label : '';
+        const detail = this.detailAddress || '';
+        
+        // 使用空格拼接四个字段
+        this.editForm.userAddress = `${province} ${city} ${district} ${detail}`.trim();
+      } else {
+        // 其他状态保持原地址不变
+        this.editForm.userAddress = this.item.userAddress;
+      }
+      
       this.$refs["editForm"].validate(valid => {
         if (valid) {
           updateIntegralOrder(this.editForm).then(response => {

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

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

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

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

+ 107 - 3
src/views/course/coursePlaySourceConfig/index.vue

@@ -39,6 +39,21 @@
           size="small"
           @keyup.enter.native="handleQuery"
         />
+      </el-form-item>
+            <el-form-item label="状态" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="请选择状态"
+          clearable
+          size="small"
+        >
+          <el-option
+            v-for="item in statusOptions"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          />
+        </el-select>
       </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
@@ -141,6 +156,15 @@
         <template slot-scope="scope">
           <el-tag prop="isMall" v-for="(item, index) in isMallOptions" v-if="scope.row.isMall==item.dictValue">{{item.dictLabel}}</el-tag>
         </template>
+      </el-table-column>
+            <el-table-column label="状态" align="center" prop="status" width="100px">
+        <template slot-scope="scope">
+          <el-tag
+            :type="scope.row.status === 0 ? 'success' : scope.row.status === 1 ? 'warning' : 'danger'"
+          >
+            {{ getStatusLabel(scope.row.status) }}
+          </el-tag>
+        </template>
       </el-table-column>
       <el-table-column label="创建时间" align="center" prop="createTime" />
       <el-table-column label="修改时间" align="center" prop="updateTime" />
@@ -204,6 +228,28 @@
               :value="item.dictValue"
             />
           </el-select>
+        </el-form-item>
+         <el-form-item label="可查看设置公司" prop="setCompanyIdList">
+          <el-select
+            v-model="form.setCompanyIdList"
+            filterable
+            multiple
+            remote
+            reserve-keyword
+            placeholder="请输入公司名称搜索"
+            :remote-method="searchCompanies"
+            :loading="companySearchLoading"
+            style="width: 220px"
+            clearable
+            size="small"
+          >
+            <el-option
+              v-for="item in companyOptions"
+              :key="item.dictValue"
+              :label="item.dictLabel"
+              :value="item.dictValue"
+            />
+          </el-select>
         </el-form-item>
         <el-form-item label="是否是互医/商城小程序" prop="isMall">
           <el-select
@@ -219,6 +265,22 @@
               :value="item.dictValue"
             />
           </el-select>
+        </el-form-item>
+                <el-form-item label="状态" prop="status">
+          <el-select
+            v-model="form.status"
+            placeholder="请选择状态"
+            style="width: 220px"
+            clearable
+            size="small"
+          >
+            <el-option
+              v-for="item in statusOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
         </el-form-item>
         <el-form-item label="图标" prop="img">
           <image-upload v-model="form.img" :file-type='["png", "jpg", "jpeg"]' :limit="1"/>
@@ -286,7 +348,8 @@ export default {
         pageNum: 1,
         pageSize: 10,
         name: null,
-        appid: null
+        appid: null,
+        status: null
       },
       showSearch: true,
       single: true,
@@ -296,6 +359,20 @@ export default {
       list: [],
       total: 0,
       typesOptions: [],
+            statusOptions: [
+        {
+          label: "正常",
+          value: 0
+        },
+        {
+          label: "半封禁",
+          value: 1
+        },
+        {
+          label: "封禁",
+          value: 2
+        }
+      ],
       isMallOptions:[
         {
           dictLabel: "是",
@@ -308,7 +385,9 @@ export default {
       ],
       title: null,
       open: false,
-      form: {},
+      form: {
+        setCompanyIdList: []
+      },
       rules: {
         name: [
           { required: true, message: "名称不能为空", trigger: "blur" }
@@ -460,6 +539,15 @@ export default {
           ...response.data,
           type: response.data.type.toString()
         }
+        if(!!this.form.setCompanyIds){
+           this.$set(
+            this.form, 
+            "setCompanyIdList", 
+            this.form.setCompanyIds.split(",").map(str => parseInt(str, 10))
+          );
+          // this.form.setCompanyIdList = this.form.setCompanyIds.split(",").map(str => parseInt(str, 10));
+        }
+        console.log( this.form);
         this.searchCompanies("");
         this.open = true
         this.title = "修改小程序配置"
@@ -486,6 +574,12 @@ export default {
     submitForm() {
       this.$refs["form"].validate(valid => {
         if (valid) {
+          if(!!this.form.setCompanyIdList && this.form.setCompanyIdList.length > 0){
+            this.form.setCompanyIds = this.form.setCompanyIdList.join(',')
+          }else{
+            this.form.setCompanyIds = "";
+          }
+          console.log(this.form);
           if (this.form.id != null) {
             update(this.form).then(response => {
               const {code, msg} = response
@@ -524,12 +618,22 @@ export default {
         secret: null,
         img: null,
         originalId: null,
+        setCompanyIdList: [],
         token: 'cbnd7lJvkripVOpyTFAna6NAWCxCrvC',
         aesKey: 'HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E',
         msgDataFormat: 'JSON',
-        type: '1'
+        type: '1',
+        status: 0
       }
       this.resetForm("form");
+          },
+    getStatusLabel(status) {
+      const statusMap = {
+        0: '正常',
+        1: '半封禁',
+        2: '封禁'
+      };
+      return statusMap[status] || '未知';
     }
   },
 }

+ 50 - 3
src/views/course/courseQuestionBank/index.vue

@@ -307,13 +307,31 @@
     <el-dialog title="导入结果" :close-on-press-escape="false" :close-on-click-modal="false" :visible.sync="importMsgOpen" width="500px" append-to-body>
       <div class="import-msg" v-html="importMsg">
       </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="importMsgOpen = false">关 闭</el-button>
+        <el-button
+          v-if="failList && failList.length > 0"
+          type="primary"
+          @click="handleExportFailList(failList)"
+          :loading="exportFailLoading"
+        >导出失败信息</el-button>
+      </div>
     </el-dialog>
 
   </div>
 </template>
 
 <script>
-import { listCourseQuestionBank, getCourseQuestionBank, delCourseQuestionBank, addCourseQuestionBank, updateCourseQuestionBank, exportCourseQuestionBank, importTemplate } from "@/api/course/courseQuestionBank";
+import {
+  listCourseQuestionBank,
+  getCourseQuestionBank,
+  delCourseQuestionBank,
+  addCourseQuestionBank,
+  updateCourseQuestionBank,
+  exportCourseQuestionBank,
+  importTemplate,
+  exportFail
+} from "@/api/course/courseQuestionBank";
 import { getToken } from "@/utils/auth";
 import {
   listUserCourseCategory,
@@ -334,7 +352,7 @@ export default {
   },
   data() {
     return {
-
+      exportFailLoading: false,
       //单选
       selectedAnswer:null,
       //多选
@@ -397,6 +415,7 @@ export default {
       },
       // 导入
       importMsgOpen:false,
+      failList:[],
       importMsg: '',
       upload: {
         // 是否显示弹出层(文件导入)
@@ -426,6 +445,33 @@ export default {
     getOptionLabel(index) {
       return this.alphabet[index];
     },
+// 导出失败信息
+    handleExportFailList(failList) {
+      if (!failList || failList.length === 0) {
+        this.msgWarning("没有失败信息可导出");
+        return;
+      }
+
+
+      this.exportFailLoading = true;
+      this.$confirm('是否确认导出失败信息?', "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "info"
+      }).then(() => {
+        // 调用导出失败信息的API
+        exportFail(failList).then(response => {
+          this.download(response.msg);
+          this.msgSuccess("失败信息导出成功");
+          this.exportFailLoading = false;
+        }).catch(() => {
+          this.msgError("失败信息导出失败");
+          this.exportFailLoading = false;
+        });
+      }).catch(() => {
+        this.exportFailLoading = false;
+      });
+    },
 
     // 分类树
     getCategoryTree() {
@@ -661,7 +707,8 @@ export default {
       this.upload.isUploading = false;
       this.$refs.upload.clearFiles();
       this.importMsgOpen=true;
-      this.importMsg = response.msg
+      this.importMsg = response.data.message
+      this.failList = response.data.failList
       this.getList();
     },
   }

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

@@ -50,7 +50,24 @@
       </el-form-item>
     </el-form>
 
-    <el-table border v-loading="loading" :data="courseWatchLogList" @selection-change="handleSelectionChange"  show-summary>
+    <el-table v-if="'济南联志健康' == this.signProjectName" border v-loading="loading" :data="courseWatchLogList" @selection-change="handleSelectionChange"  show-summary :summary-method="getSummaries">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="企微员工名称" align="center" prop="qwUserName" />
+      <el-table-column label="发课时间" align="center" prop="createTime"/>
+      <el-table-column label="课程名称" align="center" prop="courseName" />
+      <el-table-column label="小节名称" align="center" prop="videoName" />
+      <el-table-column label="待看课" align="center" prop="type3" />
+      <el-table-column label="看课中" align="center" prop="type1" />
+      <el-table-column label="已完课" align="center" prop="type2" />
+      <el-table-column label="看课中断" align="center" prop="type4" />
+      <el-table-column label="注册用户待看课数" align="center" prop="isUserWaitNumber" />
+      <el-table-column label="未注册用户待看课数" align="center" prop="noUserWaitNumber" />
+      <el-table-column label="上线率" align="center" prop="onLineRate" />
+      <el-table-column label="完课率" align="center" prop="finishedRate" />
+      <el-table-column label="消耗红包金额" align="center" prop="redAmount" />
+    </el-table>
+
+    <el-table v-else border v-loading="loading" :data="courseWatchLogList" @selection-change="handleSelectionChange"  show-summary>
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="企微员工名称" align="center" prop="qwUserName" />
       <el-table-column label="发课时间" align="center" prop="createTime"/>
@@ -79,13 +96,14 @@
 </template>
 
 <script>
-import { listCourseWatchLog, getCourseWatchLog, delCourseWatchLog, addCourseWatchLog, updateCourseWatchLog, exportCourseWatchLog,statisticsList } from "@/api/course/qw/courseWatchLog";
+import { listCourseWatchLog, getCourseWatchLog, delCourseWatchLog, addCourseWatchLog, updateCourseWatchLog, exportCourseWatchLog,statisticsList,getSignProjectName } from "@/api/course/qw/courseWatchLog";
 import { courseList,videoList } from '@/api/course/courseRedPacketLog'
 import {getCompanyList} from "@/api/company/company";
 export default {
   name: "CourseWatchLog",
   data() {
     return {
+      signProjectName:"",
       companys:[],
       activeName:"00",
       createTime:null,
@@ -140,6 +158,11 @@ export default {
     };
   },
   created() {
+    getSignProjectName().then(res=>{
+      this.signProjectName = res.signProjectName;
+      console.log(this.signProjectName);
+    }).catch(res=>{});
+
     getCompanyList().then(response => {
       this.companys = response.data;
       if(this.companys!=null&&this.companys.length>0){
@@ -156,6 +179,37 @@ export default {
     });
   },
   methods: {
+   getSummaries(param) {
+        const { columns, data } = param;
+        const sums = [];
+         // 关键改动:创建一个不包含最后一行的新数据数组
+        // 如果数据长度大于1,则截取掉最后一行;否则,使用空数组避免错误
+        const dataToSum = data.length > 1 ? data.slice(0, -1) : [];
+        columns.forEach((column, index) => {
+          
+          if (index === 0) {
+            sums[index] = '页总计';
+            return;
+          }
+          const values = dataToSum.map(item => Number(item[column.property]));
+          
+          if (!values.every(value => isNaN(value))) {
+            sums[index] = values.reduce((prev, curr) => {
+              const value = Number(curr);
+              if (!isNaN(value)) {
+                return prev + curr;
+              } else {
+                return prev;
+              }
+            }, 0);
+            sums[index] += ' ';
+          } else {
+            sums[index] = 'N/A';
+          }
+        });
+
+        return sums;
+      },
     courseChange(row){
       this.queryParams.videoId=null;
       if(row === ''){

+ 46 - 10
src/views/course/userCoursePeriod/index.vue

@@ -366,15 +366,33 @@
             />
           </el-select>
         </el-form-item>
-        <el-form-item label="小节" prop="videoIds">
-          <el-select filterable  v-model="course.form.videoIds" placeholder="请选择小节" :multiple-limit="getDiff(course.row.periodStartingTime, course.row.periodEndTime) - course.total" multiple clearable size="small" style="width: 100%" :value-key="'dictValue'">
-            <el-option
-              v-for="dict in videoList"
-              :key="dict.dictValue"
-              :label="dict.dictLabel"
-              :value="parseInt(dict.dictValue)"
-            />
-          </el-select>
+         <el-form-item label="小节" prop="videoIds">
+          <div style="display: flex; align-items: center;">
+            <el-select
+              filterable
+              v-model="course.form.videoIds"
+              placeholder="请选择小节"
+              :multiple-limit="getDiff(course.row.periodStartingTime, course.row.periodEndTime) - course.total"
+              multiple
+              clearable
+              size="small"
+              style="flex: 1; margin-right: 10px;"
+              :value-key="'dictValue'">
+              <el-option
+                v-for="dict in videoList"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="parseInt(dict.dictValue)"
+              />
+            </el-select>
+            <el-button
+              type="primary"
+              size="small"
+              @click="selectAllVideos"
+              :disabled="videoList.length === 0 || !course.form.courseId">
+              全选
+            </el-button>
+          </div>
         </el-form-item>
         <el-form-item label="看课时间" prop="timeRange">
           <el-time-picker
@@ -439,7 +457,21 @@
           </el-date-picker>
           <p style="color: red;margin: 0;font-size: 12px">超过领取红包时间,只允许看课,不允许领取红包</p>
         </el-form-item>
+         <!--  是否批量修改开关 0-关 1-开 默认关闭 -->
+      </el-form>
+      <el-form>
+        <el-form-item label="是否批量修改" prop="batchUpdateSwitch" label-width="110px">
+          <el-radio-group
+          v-model="updateCourse.form.batchUpdateSwitch"
+          >
+          <el-radio :label="0">关</el-radio>
+          <el-radio :label="1">开</el-radio>
+          </el-radio-group>
+          <br />
+          <span style="color: red;margin: 0;font-size: 12px">批量修改开关开启后,后续的课程会默认+1修改课程和红包时间</span>
+        </el-form-item>
       </el-form>
+
       <div slot="footer" class="dialog-footer">
         <el-button type="primary" @click="submitUpdateCourseForm">确 定</el-button>
         <el-button @click="closeUpdateCourse">取 消</el-button>
@@ -706,7 +738,8 @@ export default {
         ids: [],
         form: {
           timeRange: null,
-          joinTime: null
+          joinTime: null,
+          batchUpdateSwitch: 0
         },
       },
       // 表单校验
@@ -855,6 +888,9 @@ export default {
 
   },
   methods: {
+    selectAllVideos() {
+      this.course.form.videoIds = this.videoList.map(video => parseInt(video.dictValue));
+    },
     /** 删除按钮操作 */
     async handleDeleteCourse(row) {
       const periodDayIds = row.id || this.updateCourse.ids;

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

@@ -7,8 +7,13 @@
           <el-select
             v-model="queryParams.videoIdList"
             multiple
-            placeholder="请选择营期课程"
+            filterable
+            remote
+            :remote-method="handleCourseSearch"
+            :loading="courseLoading"
+            placeholder="请输入关键词搜索营期课程"
             style="width: 400px"
+            @visible-change="handleCourseDropdownVisible"
           >
             <el-option
               v-for="item in courseOptions"
@@ -16,6 +21,13 @@
               :label="item.videoName"
               :value="item.videoId"
             />
+            <!-- 分页加载更多选项 -->
+            <el-option v-if="hasMoreCourses" key="load-more" disabled class="load-more-option">
+              <div class="load-more" @click="loadMoreCourses">
+                <span>加载更多</span>
+                <i class="el-icon-loading" v-if="loadingMore"></i>
+              </div>
+            </el-option>
           </el-select>
         </el-form-item>
 
@@ -146,10 +158,20 @@ export default {
     return {
       // 遮罩层
       loading: false,
+      courseLoading: false,
+      loadingMore: false,
       // 总条数
       total: 0,
       // 课程选项
       courseOptions: [],
+      courseTotal: 0,
+      courseQueryParams: {
+        pageNum: 1,
+        pageSize: 10, // 默认每页10条
+        videoName: '',
+        periodId: ''
+      },
+      hasMoreCourses: false,
       companyOptions: [],
       // 统计数据
       statistics: {
@@ -168,7 +190,7 @@ export default {
         pageNum: 1,
         pageSize: 100,
         videoIdList: [],
-        // videoId: '',
+        companyId: '',
         periodId: ''
       },
       // 是否已初始化
@@ -179,6 +201,7 @@ export default {
     periodId: {
       handler(newVal) {
         this.queryParams.periodId = newVal;
+        this.courseQueryParams.periodId = newVal;
         if (this.active && !this.initialized) {
           this.initializeData();
         }
@@ -198,10 +221,10 @@ export default {
     /** 初始化数据 */
     initializeData() {
       this.getCourseOptions();
-      this.getCountList();
-      this.getCompanyOptions()
+      this.getCompanyOptions();
       this.initialized = true;
     },
+
     getCompanyOptions() {
       getPeriodCompanyList({
         periodId: this.periodId
@@ -209,29 +232,74 @@ export default {
         this.companyOptions = response.data || [];
       });
     },
+
     /** 获取课程选项 */
-    getCourseOptions() {
-      this.loading = true;
-      getDays(this.queryParams).then(r => {
+    getCourseOptions(isLoadMore = false) {
+      if (!isLoadMore) {
+        this.courseLoading = true;
+        this.courseQueryParams.pageNum = 1; // 重置页码
+      } else {
+        this.loadingMore = true;
+      }
+
+      getDays(this.courseQueryParams).then(r => {
         if (r.code === 200) {
-          this.courseOptions = r.rows;
-          this.loading = false;
+          if (isLoadMore) {
+            // 加载更多时,追加数据
+            this.courseOptions = [...this.courseOptions, ...r.rows];
+          } else {
+            // 首次加载或搜索时,替换数据
+            this.courseOptions = r.rows;
+          }
+
+          this.courseTotal = r.total || 0;
+
+          // 计算是否还有更多数据
+          const loadedCount = this.courseOptions.length;
+          this.hasMoreCourses = loadedCount < this.courseTotal;
+
+          this.courseLoading = false;
+          this.loadingMore = false;
         } else {
           this.$message.error(r.msg || '获取数据失败');
+          this.courseLoading = false;
+          this.loadingMore = false;
         }
-        this.loading = false;
       }).catch(() => {
-        this.loading = false;
+        this.courseLoading = false;
+        this.loadingMore = false;
       });
     },
+
+    /** 加载更多课程 */
+    loadMoreCourses() {
+      if (this.loadingMore) return;
+
+      this.courseQueryParams.pageNum += 1;
+      this.getCourseOptions(true);
+    },
+
+    /** 处理下拉框显示/隐藏 */
+    handleCourseDropdownVisible(visible) {
+      if (visible && this.courseOptions.length === 0) {
+        // 当下拉框显示且没有数据时,加载初始数据
+        this.getCourseOptions();
+      }
+    },
+
+    /** 营期课程搜索 */
+    handleCourseSearch(query) {
+      this.courseQueryParams.videoName = query;
+      this.courseQueryParams.pageNum = 1; // 搜索时重置页码
+      this.getCourseOptions();
+    },
+
     /** 查询按钮操作 */
     handleQuery() {
       this.queryParams.pageNum = 1;
       this.getCountList();
     },
-    /** 课程选择变化 */
-    handleCourseChange() {
-    },
+
     /** 获取列表数据 */
     getCountList() {
       this.loading = true;
@@ -255,6 +323,7 @@ export default {
         this.loading = false;
       });
     },
+
     /** 计算总统计数据 */
     calculateTotalStatistics() {
       // 初始化统计数据
@@ -360,4 +429,27 @@ export default {
   font-weight: bold;
   color: #303133;
 }
+
+/* 加载更多选项样式 */
+.load-more-option {
+  text-align: center;
+  padding: 8px 0;
+}
+
+.load-more {
+  color: #409EFF;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 5px;
+}
+
+.load-more:hover {
+  color: #66b1ff;
+}
+
+:deep(.el-select-dropdown__list) {
+  padding-bottom: 0 !important;
+}
 </style>

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

@@ -1004,7 +1004,7 @@ export default {
       this.redSubmit=false
       this.redRechargeForm.companyId = row.companyId
       this.redRechargeForm.companyName = row.companyName
-      this.redRechargeForm.balance = row.money
+      this.redRechargeForm.balance = row.redPackageMoney
       this.redRechargeForm.money = null
       this.redRecharge.open = true
     },
@@ -1019,7 +1019,7 @@ export default {
     handleRedDeduct(row) {
       this.redDeductForm.companyId = row.companyId
       this.redDeductForm.companyName = row.companyName
-      this.redDeductForm.balance = row.money
+      this.redDeductForm.balance = row.redPackageMoney
       this.redDeductForm.money = null
       this.redDeduct.open = true
     },

+ 532 - 5
src/views/his/integralOrder/index.vue

@@ -82,6 +82,17 @@
           />
         </el-select>
       </el-form-item>
+      <!-- 这里就是之前添加的ERP账号下拉框 -->
+      <el-form-item label="ERP" prop="loginAccount">
+        <el-select v-model="queryParams.loginAccount" placeholder="ERP账号" size="small" clearable>
+          <el-option
+            v-for="account in erpAccountList"
+            :key="account"
+            :label="account"
+            :value="account"
+          />
+        </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>
@@ -100,7 +111,28 @@
           v-hasPermi="['his:integralOrder:export']"
         >导出</el-button>
       </el-col>
+      
       <el-col :span="1.5">
+          <el-button
+            type="info"
+            plain
+            icon="el-icon-upload2"
+            size="mini"
+            @click="handleImportStatus"
+          >导入订单状态</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-tooltip content="默认erp推送手机号" placement="top">
+          <el-button
+            type="warning"
+            plain
+            icon="el-icon-phone"
+            size="mini"
+            @click="handleErpPhone"
+          >推送手机号码</el-button>
+        </el-tooltip>
+      </el-col>
+<el-col :span="1.5">
         <el-button
           type="info"
           plain
@@ -108,9 +140,29 @@
           size="mini"
           @click="handleImport"
           v-hasPermi="['his:integralOrder:exportDeliver']"
+          v-show="actName === '6'||actName === '1'"
         >导入发货</el-button>
       </el-col>
-
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-s-operation"
+          size="mini"
+          @click="handleDataSort"
+          v-show="actName === '6'"
+        >数据分拣</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleCreateErp"
+          v-show="actName === '6'"
+        >创建ERP</el-button>
+      </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
     <el-tabs type="card" v-model="actName" @tab-click="handleClickX">
@@ -119,12 +171,14 @@
     </el-tabs>
     <el-table v-loading="loading" border :data="integralOrderList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="ERP账号" align="center" prop="loginAccount" />
+      <el-table-column label="ERP电话" align="center" prop="erpPhone" />
       <el-table-column label="订单编号" align="center" prop="orderCode" />
       <el-table-column label="用户名称" align="center" prop="userName" />
       <el-table-column label="用户电话" align="center" prop="userPhone" />
       <el-table-column label="用户地址" align="center" prop="userAddress" show-overflow-tooltip />
       <el-table-column label="支付积分" align="center" prop="integral" />
-      <el-table-column label="支付金额" align="center" prop="cash" />
+      <el-table-column label="支付金额" align="center" prop="payMoney" />
       <el-table-column label="状态" align="center" prop="status">
         <template slot-scope="scope">
           <dict-tag :options="statusOptions" :value="scope.row.status"/>
@@ -259,16 +313,170 @@
          <el-button @click="upload.open = false">取 消</el-button>
        </div>
      </el-dialog>
+     <!-- 数据分拣弹窗 -->
+    <el-dialog :title="erpAccountDialog.title" :visible.sync="erpAccountDialog.open" width="600px" append-to-body>
+      <div v-loading="erpAccountDialog.loading">
+        <el-form :model="erpAccountForm" label-width="100px">
+          <el-form-item label="ERP账户" required>
+            <el-select 
+              v-model="erpAccountForm.selectedAccount" 
+              placeholder="请选择ERP账户" 
+              style="width: 100%"
+              filterable
+            >
+              <el-option
+                v-for="account in erpAccountList"
+                :key="account"
+                :label="account"
+                :value="account"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="推送手机号">
+            <el-select 
+              v-model="erpAccountForm.selectedPhones" 
+              multiple 
+              placeholder="请选择推送手机号,不填默认订单用户电话"
+              style="width: 100%"
+              filterable
+            >
+              <el-option
+                v-for="phone in phoneList"
+                :key="phone.phone"
+                :label="phone.phone"
+                :value="phone.phone"
+              />
+            </el-select>
+          </el-form-item>
+        </el-form>
+        
+        <!-- 订单统计信息 -->
+        <div class="order-summary" v-if="orderSummary">
+          <el-divider content-position="left">订单统计</el-divider>
+          <el-row :gutter="20">
+            <el-col :span="8">
+              <div class="summary-item">
+                <span class="label">选中订单数:</span>
+                <span class="value">{{ orderSummary.selectedCount }}</span>
+              </div>
+            </el-col>
+            <el-col :span="8">
+              <div class="summary-item">
+                <span class="label">总金额:</span>
+                <span class="value">¥{{ orderSummary.totalAmount }}</span>
+              </div>
+            </el-col>
+            <el-col :span="8">
+              <div class="summary-item">
+                <span class="label">查询条件订单:</span>
+                <span class="value">{{ orderSummary.queryCount }}</span>
+              </div>
+            </el-col>
+          </el-row>
+        </div>
+      </div>
+      
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="cancelErpAccountDialog">取 消</el-button>
+        <el-button 
+          type="primary" 
+          @click="confirmCreateErpOrder"
+          :disabled="!erpAccountForm.selectedAccount"
+          :loading="erpAccountDialog.submitting"
+        >确认</el-button>
+      </div>
+    </el-dialog>
+    <!-- 推送手机号码管理弹窗 -->
+    <el-dialog :title="erpPhone.title" :visible.sync="erpPhone.open" width="600px" append-to-body>
+      <div style="margin-bottom: 20px;">
+        <el-button type="primary" size="small" @click="handleAddPhone">新增手机号</el-button>
+      </div>
+      <el-table :data="phoneList" border style="width: 100%">
+        <el-table-column prop="phone" label="手机号" align="center">
+          <template slot-scope="scope">
+            <el-input 
+              v-if="scope.row.editing" 
+              v-model="scope.row.phone" 
+              placeholder="请输入手机号"
+              @blur="validatePhone(scope.row)"
+              @keyup.enter.native="handleSavePhone(scope.$index)"
+            />
+            <span v-else>{{ scope.row.phone }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center" width="300">
+          <template slot-scope="scope">
+            <el-button 
+              v-if="scope.row.editing" 
+              type="success" 
+              size="mini" 
+              @click="handleSavePhone(scope.$index)"
+            >保存</el-button>
+            <el-button 
+              v-if="scope.row.editing" 
+              type="info" 
+              size="mini" 
+              @click="handleCancelEdit(scope.$index)"
+            >取消</el-button>
+            <el-button 
+              v-if="!scope.row.editing" 
+              type="primary" 
+              size="mini" 
+              @click="handleEditPhone(scope.$index)"
+            >修改</el-button>
+            <el-button 
+              type="danger" 
+              size="mini" 
+              @click="handleDeletePhone(scope.$index)"
+            >删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="handleSavePhoneList">确 定</el-button>
+        <el-button @click="handleCancelPhoneDialog">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog :title="uploadStatus.title" :visible.sync="uploadStatus.open" width="400px" append-to-body>
+        <el-upload
+          ref="uploadStatus"
+          :limit="1"
+          accept=".xlsx, .xls"
+          :headers="uploadStatus.headers"
+          :action="uploadStatus.url + '?updateSupport=' + upload.updateSupport"
+          :disabled="uploadStatus.isUploading"
+          :on-progress="handleFileUploadProgressOrder"
+          :on-success="handleFileSuccessOrder"
+          :auto-upload="false"
+          drag
+        >
+          <i class="el-icon-upload"></i>
+          <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
+          <div class="el-upload__tip text-center" slot="tip">
+            <div class="el-upload__tip" slot="tip">
+            </div>
+            <span>仅允许导入xls、xlsx格式文件。</span>
+            <el-link type="primary" :underline="false" style="font-size:12px;vertical-align: baseline;" @click="importUpdateOrderTemplate">下载模板</el-link>
+          </div>
+        </el-upload>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitOrderStatusFileForm">确 定</el-button>
+        <el-button @click="uploadStatus.open = false">取 消</el-button>
+      </div>
+    </el-dialog>
   </div>
 </template>
 
 <script>
-import {importTemplate, listIntegralOrder,importExpressTemplate, getIntegralOrder, delIntegralOrder, addIntegralOrder, updateIntegralOrder, exportIntegralOrder,cancelOrder } from "@/api/his/integralOrder";
+import {importTemplate,batchSetErpOrder,batchCreateErpOrder,listIntegralOrder,getIntegralTemplate, getIntegralOrder, delIntegralOrder, addIntegralOrder, updateIntegralOrder, exportIntegralOrder,cancelOrder } from "@/api/his/integralOrder";
 import integralOrderDetails from '../../components/his/integralOrderDetails.vue';
 import { getToken } from "@/utils/auth";
 import {getCompanyList} from "@/api/company/company";
 import {getAllUserlist} from "@/api/company/companyUser";
 import {getQwUserInfo} from "@/api/qw/qwUser";
+import {getErpAccount } from "@/api/his/storeOrder";
+import {queryErpPhone, saveErpPhone} from "@/api/his/storeOrder";
 
 export default {
   name: "IntegralOrder",
@@ -331,6 +539,7 @@ export default {
         companyUserId:null,
         qwUserId:null,
         companyId:null,
+        loginAccount: null  // 添加ERP账号筛选字段
       },
        createTime:null,
       qwCompanyList:[],
@@ -346,7 +555,44 @@ export default {
         status: [
           { required: true, message: "1:待发货;2:待收货;3:已完成不能为空", trigger: "change" }
         ],
-      }
+      },
+      dataSortOpen: false, // 数据分拣弹窗显示控制
+      erpAccountDialog: {
+        open: false,
+        loading: false,
+        submitting: false,
+        title: "数据分拣"
+      },
+      erpAccountForm: {
+        selectedAccount: null,
+        selectedPhones: [] // 添加推送手机号字段
+      },
+      erpAccountList: [],
+      orderSummary: {
+        selectedCount: 0,
+        totalAmount: 0,
+        queryCount: 0
+      },
+      erpPhone: {
+      open: false,
+        title: "设置推送手机号"
+      },
+      phoneList: [], // 手机号列表
+      originalPhoneList: [], // 原始手机号列表,用于取消时恢复
+      uploadStatus: {
+        // 是否显示弹出层
+        open: false,
+        // 弹出层标题
+        title: "",
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 设置上传的请求头部
+        headers: { Authorization: "Bearer " + getToken() },
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + "/his/integralOrder/importOrderStatusData"
+      },
     };
   },
   created() {
@@ -360,8 +606,29 @@ export default {
     getCompanyList().then(response => {
       this.qwCompanyList = response.data;
     });
+    this.loadErpAccountData();
   },
   methods: {
+    handleImportStatus() {
+        this.uploadStatus.title = "导入";
+        this.uploadStatus.open = true;
+       },
+    handleFileUploadProgressOrder(event, file, fileList) {
+          this.uploadStatus.isUploading = true;
+        },
+    // 文件上传成功处理
+         handleFileSuccessOrder(response, file, fileList) {
+          this.uploadStatus.open = false;
+          this.uploadStatus.isUploading = false;
+          this.$refs.uploadStatus.clearFiles();
+          this.$alert(response.msg, "导入结果", { dangerouslyUseHTMLString: true });
+          this.getList();
+        },
+    importUpdateOrderTemplate(){
+        getIntegralTemplate().then(response => {
+          this.download(response.msg);
+        });
+      },
      //取消订单
      cancelOrder(orderCode){
       this.$confirm('确定取消此订单?', '提示', {
@@ -565,7 +832,267 @@ export default {
           this.qwUserList=response.data;
         })
       }
-    }
+    },
+    // 数据分拣按钮点击事件
+    handleDataSort() {
+      this.erpAccountDialog.open = true;
+      this.erpAccountDialog.title = "数据分拣";
+      this.getErpPhoneList(); // 加载手机号列表
+      this.updateOrderSummary();
+    },
+    
+    // 加载ERP账户数据
+    async loadErpAccountData() {
+      try {
+        const response = await getErpAccount();
+        this.erpAccountList = response.data;
+      } catch (error) {
+        console.error('加载ERP账户失败:', error);
+      }
+    },
+    
+    // 更新订单统计
+    updateOrderSummary() {
+      // 如果没有选择任何数据,则使用查询出来的所有数据
+      if (this.ids.length === 0) {
+        this.orderSummary.selectedCount = this.total;
+        this.orderSummary.queryCount = this.total;
+      } else {
+        // 如果选择了数据,则使用选中的数据
+        this.orderSummary.selectedCount = this.ids.length;
+        this.orderSummary.queryCount = this.total;
+      }
+      
+      // 计算总金额(这里需要根据实际数据结构调整)
+      this.calculateTotalAmount();
+    },
+    // 计算总金额
+    calculateTotalAmount() {
+      let totalAmount = 0;
+      
+      if (this.ids.length === 0) {
+        // 使用所有查询数据计算金额
+        this.integralOrderList.forEach(order => {
+          totalAmount += parseFloat(order.payMoney || 0);
+        });
+      } else {
+        // 使用选中的数据计算金额
+        const selectedOrders = this.integralOrderList.filter(order => 
+          this.ids.includes(order.orderId)
+        );
+        selectedOrders.forEach(order => {
+          totalAmount += parseFloat(order.payMoney || 0);
+        });
+      }
+      
+      this.orderSummary.totalAmount = totalAmount.toFixed(2);
+    },
+    
+    // 取消ERP账户对话框
+    cancelErpAccountDialog() {
+      this.erpAccountDialog.open = false;
+      this.erpAccountForm.selectedAccount = null;
+    },
+    
+    // 确认创建ERP订单
+    async confirmCreateErpOrder() {
+      // 收集选中的orderId
+      let selectedOrderIds = [];
+      
+      if (this.ids.length === 0) {
+        // 如果没有选择任何数据,使用查询出来的所有数据的orderId
+        selectedOrderIds = this.integralOrderList.map(order => order.orderId);
+      } else {
+        // 如果选择了数据,使用选中的orderId
+        selectedOrderIds = this.ids;
+      }
+      
+      // 收集ERP账户和手机号
+      const selectedErpAccount = this.erpAccountForm.selectedAccount;
+      const selectedPhones = this.erpAccountForm.selectedPhones;
+      
+      // 准备请求参数
+      const params = {
+        orderIds: selectedOrderIds,
+        loginAccount: selectedErpAccount,
+        erpPhones: selectedPhones // 添加手机号参数
+      };
+      try {
+        this.erpAccountDialog.submitting = true;
+        
+        // 根据弹窗标题判断是数据分拣还是创建ERP
+        if (this.erpAccountDialog.title === "数据分拣") {
+          // 调用数据分拣接口
+          const response = await batchSetErpOrder(params);
+          this.$message.success('数据分拣成功');
+        } else if (this.erpAccountDialog.title === "创建ERP") {
+          // 调用创建ERP接口
+          const response = await batchCreateErpOrder(params);
+          // console.log("参数:",params)
+          this.$message.success('创建ERP成功');
+        }
+        
+        // 关闭弹窗
+        this.cancelErpAccountDialog();
+        
+        // 刷新列表
+        this.getList();
+        
+      } catch (error) {
+        console.error('操作失败:', error);
+        this.$message.error('操作失败');
+      } finally {
+        this.erpAccountDialog.submitting = false;
+      }
+    },
+    handleCreateErp() {
+      this.erpAccountDialog.open = true;
+      this.erpAccountDialog.title = "创建ERP";
+      this.getErpPhoneList(); // 加载手机号列表
+      this.updateOrderSummary();
+    },
+    // 获取ERP手机号列表
+    getErpPhoneList() {
+      queryErpPhone().then(response => {
+        if (response.data && response.data != null && response.data.length > 0) {
+          const phones = response.data.filter(phone => phone.trim());
+          this.phoneList = phones.map(phone => ({
+            phone: phone.trim(),
+            editing: false,
+            originalPhone: phone.trim()
+          }));
+        } else {
+          this.phoneList = [];
+        }
+      });
+    },
+    // 取消ERP账户对话框
+    cancelErpAccountDialog() {
+      this.erpAccountDialog.open = false;
+      this.erpAccountForm.selectedAccount = null;
+      this.erpAccountForm.selectedPhones = []; // 清空手机号选择
+    },
+    // 推送手机号码管理
+    handleErpPhone() {
+      this.getErpPhoneList();
+      this.erpPhone.open = true;
+    },
+    // 新增手机号
+    handleAddPhone() {
+      this.phoneList.push({
+        phone: '',
+        editing: true,
+        originalPhone: '',
+        isNew: true
+      });
+    },
+
+    // 编辑手机号
+    handleEditPhone(index) {
+      this.$set(this.phoneList[index], 'editing', true);
+      this.$set(this.phoneList[index], 'originalPhone', this.phoneList[index].phone);
+    },
+
+    // 保存手机号
+    handleSavePhone(index) {
+      const phone = this.phoneList[index].phone.trim();
+      if (!phone) {
+        this.$message.error('手机号不能为空');
+        return;
+      }
+      if (!this.validatePhoneFormat(phone)) {
+        this.$message.error('请输入正确的手机号格式');
+        return;
+      }
+      // 检查是否重复
+      const duplicateIndex = this.phoneList.findIndex((item, idx) => 
+        idx !== index && item.phone === phone
+      );
+      if (duplicateIndex !== -1) {
+        this.$message.error('手机号已存在');
+        return;
+      }
+      this.$set(this.phoneList[index], 'editing', false);
+      this.$set(this.phoneList[index], 'isNew', false);
+    },
+
+    // 取消编辑
+    handleCancelEdit(index) {
+      if (this.phoneList[index].isNew) {
+        // 如果是新增的,直接删除
+        this.phoneList.splice(index, 1);
+      } else {
+        // 如果是编辑的,恢复原值
+        this.$set(this.phoneList[index], 'phone', this.phoneList[index].originalPhone);
+        this.$set(this.phoneList[index], 'editing', false);
+      }
+    },
+
+    // 删除手机号
+    handleDeletePhone(index) {
+      this.$confirm('确认删除该手机号?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.phoneList.splice(index, 1);
+        this.$message.success('删除成功');
+      });
+    },
+
+    // 验证手机号格式
+    validatePhoneFormat(phone) {
+      const phoneRegex = /^1[3-9]\d{9}$/;
+      return phoneRegex.test(phone);
+    },
+
+    // 验证手机号
+    validatePhone(row) {
+      if (row.phone && !this.validatePhoneFormat(row.phone)) {
+        this.$message.error('请输入正确的手机号格式');
+      }
+    },
+
+    // 保存手机号列表
+    handleSavePhoneList() {
+      // 检查是否有正在编辑的项
+      const editingItem = this.phoneList.find(item => item.editing);
+      if (editingItem) {
+        this.$message.error('请先保存正在编辑的手机号');
+        return;
+      }
+      
+      // 检查是否有空的手机号
+      const emptyPhone = this.phoneList.find(item => !item.phone.trim());
+      if (emptyPhone) {
+        this.$message.error('存在空的手机号,请删除或填写完整');
+        return;
+      }
+      
+      // 构造手机号列表
+      const phoneList = this.phoneList.map(item => item.phone);
+      
+      // 调用保存接口
+      saveErpPhone(phoneList).then(response => {
+        if (response.code === 200) {
+          this.$message.success('保存成功');
+          this.erpPhone.open = false;
+        } else {
+          this.$message.error(response.msg || '保存失败');
+        }
+      }).catch(() => {
+        this.$message.error('保存失败');
+      });
+    },
+
+    // 取消手机号对话框
+    handleCancelPhoneDialog() {
+      this.erpPhone.open = false;
+      this.getErpPhoneList(); // 重新加载原始数据
+    },
+    submitOrderStatusFileForm(){
+      this.$refs.uploadStatus.submit();
+    },
   }
 };
 </script>

+ 138 - 138
src/views/his/storeOrder/order1.vue

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

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

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

+ 38 - 2
src/views/hisStore/menu/index.vue

@@ -10,6 +10,17 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
+
+      <el-form-item label="小程序" prop="appId">
+        <el-select v-model="queryParams.appId" placeholder="请选择所属小程序" clearable size="small">
+          <el-option
+            v-for="dict in appMallOptions"
+            :key="dict.appid"
+            :label="dict.name + '(' + dict.appid + ')'"
+            :value="dict.appid"
+          />
+        </el-select>
+      </el-form-item>
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
         <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
@@ -55,6 +66,11 @@
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="ID" align="center" prop="menuId" />
       <el-table-column label="菜单名称" align="center" prop="menuName" />
+      <el-table-column label="小程序" align="center" prop="appId" >
+        <template slot-scope="scope">
+          <el-tag prop="appId" v-for="(item, index) in appMallOptions"    v-if="scope.row.appId==item.appid">{{item.name}}</el-tag>
+        </template>
+      </el-table-column>
       <el-table-column label="图标" align="center" width="120">
         <template slot-scope="scope">
           <el-popover
@@ -142,6 +158,16 @@
             />
           </el-select>
         </el-form-item>
+        <el-form-item label="小程序" prop="appId">
+          <el-select style="width: 200px" v-model="form.appId" placeholder="请选择所属小程序" clearable size="small" >
+            <el-option
+              v-for="dict in appMallOptions"
+              :key="dict.appid"
+              :label="dict.name + '(' + dict.appid + ')'"
+              :value="dict.appid"
+            />
+          </el-select>
+        </el-form-item>
         <el-form-item label="状态" prop="isShow">
               <el-radio-group v-model="form.isShow">
                 <el-radio v-for="dict in statusOptions" :key="dict.dictValue" :label="dict.dictValue">{{dict.dictLabel}}</el-radio>
@@ -158,6 +184,7 @@
 
 <script>
 import { listMenu, getMenu, delMenu, addMenu, updateMenu, exportMenu } from "@/api/hisStore/menu";
+import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
 import Material from '@/components/Material'
 export default {
   name: "Menu",
@@ -171,6 +198,7 @@ export default {
   },
   data() {
     return {
+      appMallOptions:[],
       activeName:"00",
       menuLinkTypeOptions:[],
       menuTypeOptions:[
@@ -179,7 +207,9 @@ export default {
         {"dictLabel": "养生有道",
           "dictValue": "2"},
         {"dictLabel": "个人中心",
-          "dictValue": "3"}
+          "dictValue": "3"},
+        {"dictLabel": "主菜单-热销榜",
+          "dictValue": "4"}
       ],
       statusOptions:[],
       imageArr:[],
@@ -231,11 +261,17 @@ export default {
     this.getDicts("common_status").then((response) => {
       this.statusOptions = response.data;
     });
-
+    this.getAppMallOptions();
     this.getList();
 
   },
   methods: {
+    // 获取小程序选项列表
+    getAppMallOptions() {
+      getAppMallOptions({pageNum:1,pageSize:100,isMall:1}).then(response => {
+        this.appMallOptions = response.rows;
+      })
+    },
     handleClick(tab,event){
       this.activeName=tab.name;
       if(tab.name=="00"){

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

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

+ 78 - 21
src/views/hisStore/storeOrder/healthStoreList.vue

@@ -304,6 +304,16 @@
         >批量导入物流单号
         </el-button>
       </el-col>
+      <el-col :span="1.5">
+        <el-button
+          v-hasPermi="['store:storeOrder:healthExportShippingOrder']"
+          icon="el-icon-tickets"
+          size="mini"
+          type="success"
+          @click="handleExportShippingOrder"
+        >导出发货单
+        </el-button>
+      </el-col>
       <el-col :span="1.5">
         <el-button
           type="danger"
@@ -453,6 +463,12 @@
             <el-tooltip content="按应收金额排序" placement="top"/>
           </template>
         </el-table-column>
+
+      <el-table-column label="成本价格" align="center" prop="cost" v-if="showFinanceTableField"/>
+      <el-table-column label="结算价格" align="center" prop="fprice"  v-if="showFinanceTableField"/>
+      <el-table-column label="额外运费" align="center" prop="payPostage" v-if="showFinanceTableField"/>
+      <el-table-column label="商品编码" align="center" prop="barCode"  v-if="showFinanceTableField"/>
+      <el-table-column label="商品分类" align="center" prop="cateName" v-if="showFinanceTableField"/>
       <el-table-column align="center" label="下单时间" prop="createTime"/>
       <!-- <el-table-column label="支付状态" align="center" prop="paid" /> -->
       <el-table-column align="center" label="支付时间" prop="payTime" width="180">
@@ -724,24 +740,24 @@
       width="35%"
     >
       <span slot="footer" class="dialog-footer">
-        <!-- 小程序Appid选择 -->
-<!--        <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">-->
-<!--          <el-form-item label="小程序:" prop="miniAppId">-->
-<!--        <el-select-->
-<!--          v-model="ruleForm.miniAppId"-->
-<!--          clearable-->
-<!--          placeholder="请选择发货小程序"-->
-<!--          style="width: 100%"-->
-<!--        >-->
-<!--          <el-option-->
-<!--            v-for="item in miniAppList"-->
-<!--            :key="item.appId"-->
-<!--            :label="item.appName"-->
-<!--            :value="item.appId"-->
-<!--          />-->
-<!--        </el-select>-->
-<!--      </el-form-item>-->
-<!--        </el-form>-->
+         小程序Appid选择
+        <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
+          <el-form-item label="小程序:" prop="miniAppId">
+        <el-select
+          v-model="ruleForm.miniAppId"
+          clearable
+          placeholder="请选择发货小程序"
+          style="width: 100%"
+        >
+          <el-option
+            v-for="item in miniAppList"
+            :key="item.appId"
+            :label="item.appName"
+            :value="item.appId"
+          />
+        </el-select>
+      </el-form-item>
+        </el-form>
 
         <el-upload ref="upload" :action="orderUpload.url" :auto-upload="false" :disabled="orderUpload.isUploading" :headers="orderUpload.headers"
                    :limit="1" :on-progress="handleFileUploadProgress"
@@ -947,7 +963,7 @@ import {
   delStoreOrder,
   addStoreOrder,
   updateStoreOrder,
-  exportHealthStoreOrder, exportHealthStoreOrderDetails, exportHealthStoreOrderItemsDetails,getErpAccount,
+  exportHealthStoreOrder, exportHealthStoreOrderDetails, exportHealthStoreOrderItemsDetails,getErpAccount,healthExportShippingOrder,
   queryErpPhone,
   saveErpPhone,editErpPhone,batchCreateErpOrder,batchSetErpOrder
 } from '@/api/hisStore/storeOrder'
@@ -966,6 +982,7 @@ import Treeselect from '@riophae/vue-treeselect'
 import '@riophae/vue-treeselect/dist/vue-treeselect.css'
 import { getConfigByKey } from '@/api/system/config'
 import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
+import {checkPermi} from "@/utils/permission";
 
 export default {
   components: { productOrder, productSelect, addUser, addUserAddress, Treeselect },
@@ -1228,6 +1245,7 @@ export default {
       ruleForm:{
         miniAppId: null,
       },
+      showFinanceTableField: false,
     }
   },
   created() {
@@ -1256,6 +1274,9 @@ export default {
     this.getDicts('store_delivery_pay_status').then((response) => {
       this.deliveryPayStatusOptions = response.data
     })
+    if (checkPermi(['his:storeAfterSales:finance'])) {
+      this.showFinanceTableField = true;
+    }
 
     this.getList()
     this.getErpAccountList();
@@ -2360,7 +2381,7 @@ export default {
     //打开发货单
     openDeliveryNote() {
       this.deliveryNoteOpen = true
-      // this.getAppList();
+      this.getAppList();
     },
     handleClose(done) {
       this.$confirm('确认关闭?')
@@ -2400,7 +2421,43 @@ export default {
         return;
       }
       this.$refs.upload.submit();
-    }
+    },
+    handleExportShippingOrder() {
+      if (this.queryParams.status == '00') {
+        this.queryParams.status = null
+      }
+      if (this.createTimeRange != null && this.createTimeRange.length == 2) {
+        this.queryParams.createTimeRange = this.createTimeRange[0] + '--' + this.createTimeRange[1]
+      } else {
+        this.queryParams.createTimeRange = null
+      }
+      if (this.payTimeRange != null && this.payTimeRange.length == 2) {
+        this.queryParams.payTimeRange = this.payTimeRange[0] + '--' + this.payTimeRange[1]
+      } else {
+        this.queryParams.payTimeRange = null
+      }
+      if (this.deliveryImportTimeRange != null && this.deliveryImportTimeRange.length == 2) {
+        this.queryParams.deliveryImportTimeRange = this.deliveryImportTimeRange[0] + '--' + this.deliveryImportTimeRange[1]
+      } else {
+        this.queryParams.deliveryImportTimeRange = null
+      }
+      if (this.deliverySendTimeRange != null && this.deliverySendTimeRange.length == 2) {
+        this.queryParams.deliverySendTimeRange = this.deliverySendTimeRange[0] + '--' + this.deliverySendTimeRange[1]
+      } else {
+        this.queryParams.deliverySendTimeRange = null
+      }
+      const queryParams = this.addDateRange(this.queryParams, this.dateRange)
+      this.$confirm('是否确认导出所有订单明细数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(function() {
+        return healthExportShippingOrder(queryParams)
+      }).then(response => {
+        this.download(response.msg)
+      }).catch(function() {
+      })
+    },
 
   }
 }

+ 24 - 7
src/views/hisStore/storeOrder/index.vue

@@ -92,6 +92,16 @@
         />
       </el-form-item>
 
+      <el-form-item label="产品名称" prop="productName">
+        <el-input
+          v-model="queryParams.productName"
+          placeholder="请输入产品名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
       <el-form-item label="手机号" prop="userPhone">
         <el-input
           v-model="queryParams.userPhone"
@@ -470,6 +480,12 @@
               <span v-if="scope.row.totalPrice!=null">{{scope.row.totalPrice.toFixed(2)}}</span>
           </template>
       </el-table-column>
+
+      <el-table-column label="成本价格" align="center" prop="cost" v-if="showFinanceTableField"/>
+      <el-table-column label="结算价格" align="center" prop="fprice"  v-if="showFinanceTableField"/>
+      <el-table-column label="额外运费" align="center" prop="payPostage" v-if="showFinanceTableField"/>
+      <el-table-column label="商品编码" align="center" prop="barCode"  v-if="showFinanceTableField"/>
+      <el-table-column label="商品分类" align="center" prop="cateName" v-if="showFinanceTableField"/>
        <!-- <el-table-column label="应付金额" align="center" prop="payPrice" >
           <template slot-scope="scope">
               <span v-if="scope.row.payPrice!=null">{{scope.row.payPrice.toFixed(2)}}</span>
@@ -511,7 +527,7 @@
               <el-tag prop="orderMedium" v-for="(item, index) in orderMediumOptions"    v-if="scope.row.orderMedium==item.dictValue">{{item.dictLabel}}</el-tag>
           </template>
       </el-table-column>
-      <el-table-column label="订单产品" align="center" width="200px">
+      <el-table-column label="产品名称" align="center" width="200px">
         <template slot-scope="scope">
           <div v-if="scope.row.items && scope.row.items.length > 0">
             <el-tag
@@ -668,7 +684,7 @@
                     </el-popover>
                   </template>
                 </el-table-column>
-                <el-table-column label="品名称" show-overflow-tooltip align="center" prop="productName" />
+                <el-table-column label="品名称" show-overflow-tooltip align="center" prop="productName" />
                 <el-table-column label="商品规格" align="center" prop="sku" />
                 <el-table-column label="库存" align="center" prop="stock" />
                 <el-table-column label="单价" align="center" prop="price" />
@@ -1013,6 +1029,7 @@ import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 import { getConfigByKey } from '@/api/system/config'
 import {list as getAppMallOptions} from '@/api/course/coursePlaySourceConfig';
+import {checkPermi} from "@/utils/permission";
 
 export default {
   components: { productOrder,productSelect,addUser,addUserAddress,Treeselect },
@@ -1230,7 +1247,7 @@ export default {
         isSysDel: null,
         deptId:null,
         isUpload:null,
-
+        productName:null,
       },
       // 表单参数
       form: {
@@ -1280,6 +1297,7 @@ export default {
       ruleForm:{
         miniAppId: null,
       },
+      showFinanceTableField: false,
     };
   },
   created() {
@@ -1320,6 +1338,9 @@ export default {
     getTcmScheduleList().then(response => {
       this.scheduleOptions = response.data;
     });
+    if (checkPermi(['his:storeAfterSales:finance'])) {
+      this.showFinanceTableField = true;
+    }
     this.getList();
     this.getItemsNum();
     this.getErpAccountList();
@@ -1444,10 +1465,6 @@ export default {
 
     },
 
-    // 删除订单号
-    removeOrderCode(index) {
-      this.queryParams.orderCodes.splice(index, 1)
-    },
     // 清空所有标签
     clearAllTags() {
       this.$confirm('确认清空所有订单号吗?', '提示', {

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

@@ -437,6 +437,16 @@
               <el-input v-model="form.unitName" placeholder="请输入单位名" />
             </el-form-item>
           </el-col>
+          <el-col :span="12">
+            <el-form-item label="品牌" prop="brand">
+              <el-input v-model="form.brand" placeholder="请输入品牌" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="食品生产许可证编码" prop="unitName">
+              <el-input v-model="form.foodProductionLicenseCode" placeholder="请输入食品生产许可证编码" />
+            </el-form-item>
+          </el-col>
 
         </el-row>
         <el-row :gutter="10">
@@ -859,6 +869,9 @@
             />
           </el-select>
         </el-form-item>
+        <el-form-item label="退货地址" prop="returnAddress">
+          <el-input v-model="form.returnAddress" type="textarea" :rows="1" placeholder="请输入退货地址" />
+        </el-form-item>
         <el-form-item label="国药准字" v-if="form.productType==2" prop="prescribeCode">
           <el-input v-model="form.prescribeCode" placeholder="请输入国药准字" />
         </el-form-item>
@@ -1088,15 +1101,15 @@ export default {
         productName: [
           { required: true, message: "商品名称不能为空", trigger: "blur" }
         ],
-        productInfo: [
-          { required: true, message: "商品简介不能为空", trigger: "blur" }
-        ],
-        unitName: [
-          { required: true, message: "单位名不能为空", trigger: "blur" }
-        ],
-        keyword: [
-          { required: true, message: "关键字不能为空", trigger: "blur" }
-        ],
+        // productInfo: [
+        //   { required: true, message: "商品简介不能为空", trigger: "blur" }
+        // ],
+        // unitName: [
+        //   { required: true, message: "单位名不能为空", trigger: "blur" }
+        // ],
+        // keyword: [
+        //   { required: true, message: "关键字不能为空", trigger: "blur" }
+        // ],
         cateId: [
           { required: true, message: "分类id不能为空", trigger: "blur" }
         ],
@@ -1233,7 +1246,7 @@ export default {
       param.productId = this.ids;
       param.goodsStatus = this.form1.isShow;
       param.goodsIsShow = this.form1.isDisplay;
-      param.companyIds = this.companyId+''
+      param.companyIds = this.form1.companyId.join(',');
       batchModify(param).then(res=>{
         if(res.code === 200){
           this.$message.success("批量修改成功");
@@ -1481,6 +1494,8 @@ export default {
         createTime: null,
         updateTime: null,
         isPostage: null,
+        foodProductionLicenseCode: null,
+        brand: null,
         isDel: null,
         giveIntegral: null,
         cost: null,
@@ -1498,6 +1513,7 @@ export default {
         prescribeName: null,
         isDisplay:"1",
         companyIds:[],
+        returnAddress: "", // 退货地址
         isDrug: "1", // 是否药品
         drugImage: null, // 药品展示图
         drugRegCertNo: null, // 药品注册证书编号

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

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

+ 1 - 2
src/views/hisStore/storeProductPackage/index.vue

@@ -215,7 +215,7 @@
             </el-select>
         </el-form-item>
         <el-form-item label="所属公司" prop="companyId">
-          <el-select style="width: 240px" v-model="form.companyId" placeholder="请选择企业" clearable size="small" @change="handleCompanyChange">
+          <el-select style="width: 240px" v-model="form.companyId"  placeholder="请选择企业" clearable size="small" @change="handleCompanyChange">
             <el-option
               v-for="item in companyOptions"
               :key="item.companyId"
@@ -403,7 +403,6 @@ export default {
       },
       // 表单参数
       form: {
-        companyId: null
       },
        // 表单参数
       form1: {},

+ 44 - 2277
src/views/index.vue

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

+ 2 - 2
src/views/live/liveConfig/task.vue

@@ -723,9 +723,9 @@ export default {
         if (this.form.taskType == 1) {
           this.form.content = content.goodsId;
         }else if (this.form.taskType == 2) {
-          this.form.content = content.desc;
+          this.form.content = content.redId;
         }else if (this.form.taskType == 4) {
-          this.form.content = content.desc;
+          this.form.content = content.lotteryId;
         }else if(this.form.taskType == 5){
           this.form.content = content.couponId;
         }else if(this.form.taskType == 6){

+ 49 - 11
src/views/live/liveConsole/LiveConsole.vue

@@ -113,7 +113,16 @@
         </div>
         <el-scrollbar class="custom-scrollbar" style="height: 500px; width: 100%;" ref="manageRightRef">
           <el-row v-for="m in msgList" :key="m.msgId">
-            <el-row v-if="m.userId !== userId" style="margin-top: 5px" type="flex" align="top" >
+            <el-row v-if="m.userId === userId && m.msgId == null" style="padding: 8px 0" type="flex" align="top" justify="end">
+              <div style="display: flex;justify-content: flex-end">
+                <div style="display: flex;justify-content: flex-end;flex-direction: column;max-width: 200px;align-items: flex-end">
+                  <div style="font-size: 12px; color: #999; margin-bottom: 3px;">{{ m.nickName }}</div>
+                  <div style="white-space: normal; word-wrap: break-word;width: 100%; background-color: #e6f7ff; padding: 8px; border-radius: 5px;font-size: 14px;">{{ m.msg }}</div>
+                </div>
+                <el-avatar :src="m.avatar" style="margin-left: 10px; margin-right: 10px;"/>
+              </div>
+            </el-row>
+            <el-row v-else style="margin-top: 5px" type="flex" align="top" >
               <el-col :span="3" style="margin-left: 10px"><el-avatar :src="m.avatar"/></el-col>
               <el-col :span="15">
                 <el-row style="margin-left: 10px">
@@ -128,19 +137,12 @@
                     <a style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click="blockUser(m)">拉黑</a>
                     <a v-if="m.singleVisible === 1" style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click="singleVisible(m)">解除用户自见</a>
                     <a v-else style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click="singleVisible(m)">用户自见</a>
+                    <a style="cursor: pointer;color: #ff0000;padding: 8px 8px 0 0;font-size: 12px;" @click="deleteMsg(m)">删除</a>
                   </el-col>
                 </el-row>
               </el-col>
             </el-row>
-            <el-row v-if="m.userId === userId" style="padding: 8px 0" type="flex" align="top" justify="end">
-              <div style="display: flex;justify-content: flex-end">
-                <div style="display: flex;justify-content: flex-end;flex-direction: column;max-width: 200px;align-items: flex-end">
-                  <div style="font-size: 12px; color: #999; margin-bottom: 3px;">{{ m.nickName }}</div>
-                  <div style="white-space: normal; word-wrap: break-word;width: 100%; background-color: #e6f7ff; padding: 8px; border-radius: 5px;font-size: 14px;">{{ m.msg }}</div>
-                </div>
-                <el-avatar :src="m.avatar" style="margin-left: 10px; margin-right: 10px;"/>
-              </div>
-            </el-row>
+
           </el-row>
           <!-- 底部留白 -->
           <div style="height: 20px;"></div>
@@ -248,7 +250,7 @@
 <script>
 import LivePlayer from './LivePlayer.vue';
 import {blockUser, changeUserStatus, getLiveUserTotals, dashBoardWatchUserList} from '@/api/live/liveWatchUser'
-import { listLiveSingleMsg } from '@/api/live/liveMsg'
+import { listLiveSingleMsg,delLiveMsg } from '@/api/live/liveMsg'
 import { getLive } from '@/api/live/live'
 import { consoleList } from '@/api/live/task'
 import ScreenScale from './ScreenScale.vue'; // 路径根据实际位置调整
@@ -444,6 +446,42 @@ export default {
       }
       this.socket.send(JSON.stringify(msg))
     },
+    deleteMsg(m){
+      // 1. 弹出确认对话框
+      this.$confirm('此操作将永久删除该消息, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        delLiveMsg(m.msgId).then(res => {
+          if (res.code === 200) {
+            const index = this.msgList.findIndex(item => item.msgId === m.msgId);
+            if (index !== -1) {
+              this.msgList.splice(index, 1);
+              console.log(`消息 ${m.msgId} 已在本地删除。`);
+            }
+            let msg = {
+              liveId: this.liveId,
+              userId: m.userId,
+              msg: m.msgId, // 关键:将消息ID发送给后台
+              cmd: 'deleteMsg',
+            };
+            this.socket.send(JSON.stringify(msg));
+            // 可以在这里给用户一个删除成功的提示
+            this.$message({
+              type: 'success',
+              message: '消息删除成功!'
+            });
+          }
+        })
+      }).catch(() => {
+        // 3. 用户点击“取消”或关闭对话框后的回调
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        });
+      });
+    },
     globalVisibleChange( val){
       // 消息自可见
       let msg = {

+ 629 - 730
src/views/live/liveData/index.vue

@@ -1,760 +1,659 @@
 <template>
-  <div class="app-container">
-    <div class="title">近期直播</div>
-    <div class="live-container">
-      <div class="live-card" v-for="live in displayLives" :key="live.id">
-        <!-- 直播状态 -->
-        <div class="status">已结束</div>
-
-        <!-- 直播信息 -->
-        <div class="content">
-          <img :src="live.image" alt="直播封面" class="cover-image" />
-          <div class="info">
-            <h3 class="live-title">{{ live.title }}</h3>
-            <p class="time">开播时间: {{ live.time }}</p>
-          </div>
-        </div>
-
-        <!-- 直播数据 -->
-        <div class="stats">
-          <div class="stat-item">
-            <p class="label">直播间浏览量</p>
-            <p class="value">{{ live.views }}</p>
+  <div class="el-container-md">
+    <!-- 数据统计指标展示区域 -->
+    <el-card class="statistics-card" shadow="never">
+      <el-row :gutter="20">
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">累计观看人数</div>
+            <div class="statistics-value">{{ statisticsData.totalViewers || 0 }}</div>
           </div>
-          <div class="stat-item">
-            <p class="label">直播间访客数</p>
-            <p class="value">{{ live.visitors }}</p>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">
+              累计完课人数
+              <el-popover placement="top" width="200" trigger="click">
+                <div>
+                  <el-input-number v-model="completeWatchTime" :min="0" :precision="0" placeholder="看课时长(分钟)" style="width: 100%;"></el-input-number>
+                  <el-button type="primary" size="mini" style="width: 100%; margin-top: 10px;" @click="updateCompleteWatchTime('total')">确定</el-button>
+                </div>
+                <el-button slot="reference" size="mini" type="text" icon="el-icon-setting" style="margin-left: 5px;">设置</el-button>
+              </el-popover>
+            </div>
+            <div class="statistics-value">{{ statisticsData.totalCompletedCourses || 0 }}</div>
           </div>
-        </div>
-      </div>
-    </div>
-    <!-- 直播趋势统计 -->
-    <div class="trend-section">
-      <div class="trend-header">
-        <h3>直播趋势</h3>
-        <div class="filter-container">
-        <!-- 时间范围选择(下拉框) -->
-          <span class="filter-label">时间筛选:</span>
-          <el-select v-model="selectedTimeRange" placeholder="选择时间范围" @change="changeTimeRange" style="width: 180px">
-            <el-option label="自然天" value="day"></el-option>
-            <el-option label="自然周" value="week"></el-option>
-            <el-option label="自然月" value="month"></el-option>
-          </el-select>
-
-          <!-- 日期选择器 -->
-          <!-- 选择日期 -->
-          <el-date-picker
-            v-model="selectedDate"
-            :type="datePickerType"
-            :format="selectedTimeRange === 'week' ? weekRange : dateFormat"
-            :value-format="valueFormat"
-            placeholder="选择日期"
-            style="width: 280px"
-            @change="changeDate"
-          ></el-date-picker>
-        </div>
-      </div>
-
-      <div class="trend-cards">
-        <div
-          class="trend-card"
-          v-for="item in trendData"
-          :key="item.id"
-          :class="{ 'active': selectedMetric.id === item.id }"
-          @click="changeMetric(item)"
-        >
-          <div class="trend-header">
-            <p class="trend-title">{{ item.title }}</p>
-            <el-tooltip class="item" effect="dark" :content="item.tip" placement="top">
-              <i class="el-icon-info"></i>
-            </el-tooltip>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">直播观看人数</div>
+            <div class="statistics-value">{{ statisticsData.liveViewers || 0 }}</div>
           </div>
-          <p class="trend-value">{{ item.value }}</p>
-          <p class="trend-change" :class="{ 'up': computedChange(item) > 0, 'down': computedChange(item) < 0 }">
-            {{ changeLabel }} {{ computedChange(item) }}%
-          </p>
-        </div>
-      </div>
-
-      <!-- 直播趋势折线图 -->
-      <div id="liveChart" class="chart"></div>
-    </div>
-    <div class="top10-section">
-      <h3>直播TOP10排行榜</h3>
-      <div class="ranking-container">
-          <!-- 红榜 -->
-          <div class="ranking-section red-rank">
-            <span class="rank-title">红榜</span>
-            <div class="rank-filters">
-              <button
-                v-for="item in redRankTypes"
-                :key="item.value"
-                :class="{ active: selectedRank === item.value }"
-                @click="selectRank(item.value)"
-              >
-                {{ item.label }}
-              </button>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">
+              直播完课人数
+              <el-popover placement="top" width="200" trigger="click">
+                <div>
+                  <el-input-number v-model="liveCompleteWatchTime" :min="0" :precision="0" placeholder="看课时长(分钟)" style="width: 100%;"></el-input-number>
+                  <el-button type="primary" size="mini" style="width: 100%; margin-top: 10px;" @click="updateCompleteWatchTime('live')">确定</el-button>
+                </div>
+                <el-button slot="reference" size="mini" type="text" icon="el-icon-setting" style="margin-left: 5px;">设置</el-button>
+              </el-popover>
             </div>
+            <div class="statistics-value">{{ statisticsData.liveCompletedCourses || 0 }}</div>
           </div>
-
-          <!-- 黑榜 -->
-          <div class="ranking-section black-rank">
-            <div class="rank-filters">
-              <button
-                v-for="item in blackRankTypes"
-                :key="item.value"
-                :class="{ active: selectedRank === item.value }"
-                @click="selectRank(item.value)"
-              >
-                {{ item.label }}
-              </button>
-            </div>
-            <span class="rank-title">黑榜</span>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">回放观看人数</div>
+            <div class="statistics-value">{{ statisticsData.playbackViewers || 0 }}</div>
           </div>
-      </div>
-      <el-table :data="top10List" border style="width: 100%">
-        <el-table-column prop="rank" label="排名" width="80"></el-table-column>
-        <el-table-column prop="name" label="直播名称">
-          <template #default="scope">
-            <div class="live-name">
-              <img :src="scope.row.cover" class="live-cover" alt="封面">
-              <span class="live-title">{{ scope.row.name }}</span>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">
+              回放完课人数
+              <el-popover placement="top" width="200" trigger="click">
+                <div>
+                  <el-input-number v-model="replayCompleteWatchTime" :min="0" :precision="0" placeholder="看课时长(分钟)" style="width: 100%;"></el-input-number>
+                  <el-button type="primary" size="mini" style="width: 100%; margin-top: 10px;" @click="updateCompleteWatchTime('replay')">确定</el-button>
+                </div>
+                <el-button slot="reference" size="mini" type="text" icon="el-icon-setting" style="margin-left: 5px;">设置</el-button>
+              </el-popover>
             </div>
-          </template>
-        </el-table-column>
-        <el-table-column prop="pv" label="直播间浏览量(PV)"></el-table-column>
-        <el-table-column prop="uv" label="直播间访客数(UV)"></el-table-column>
-        <el-table-column prop="watchPV" label="累计观看人次(PV)"></el-table-column>
-        <el-table-column prop="watchUV" label="累计观看人数(UV)"></el-table-column>
-        <el-table-column prop="avgTime" label="人均观看时长"></el-table-column>
-        <el-table-column prop="maxOnline" label="最高在线人数"></el-table-column>
-      </el-table>
+            <div class="statistics-value">{{ statisticsData.playbackCompletedCourses || 0 }}</div>
+          </div>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20" style="margin-top: 20px;">
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">直播峰值</div>
+            <div class="statistics-value">{{ statisticsData.livePeak || 0 }}</div>
+          </div>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">直播平均时长</div>
+            <div class="statistics-value">{{ formatDuration(statisticsData.liveAvgDuration) }}</div>
+          </div>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">回放平均时长</div>
+            <div class="statistics-value">{{ formatDuration(statisticsData.playbackAvgDuration) }}</div>
+          </div>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">GMV</div>
+            <div class="statistics-value">¥{{ statisticsData.gmv || 0 }}</div>
+          </div>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">付费人数</div>
+            <div class="statistics-value">{{ statisticsData.paidUsers || 0 }}</div>
+          </div>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">付费单数</div>
+            <div class="statistics-value">{{ statisticsData.paidOrders || 0 }}</div>
+          </div>
+        </el-col>
+      </el-row>
+      <el-row :gutter="20" style="margin-top: 20px;">
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">销量统计</div>
+            <div class="statistics-value">{{ statisticsData.salesCount || 0 }}</div>
+          </div>
+        </el-col>
+      </el-row>
+    </el-card>
+
+    <!-- 筛选条件区域 -->
+    <el-form :model="queryParams" class="live-data-css" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
+      <el-form-item label="直播名称" prop="liveName">
+        <el-input
+          v-model="queryParams.liveName"
+          placeholder="请输入直播名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="观看类型" prop="watchType">
+        <el-select v-model="queryParams.watchType" placeholder="请选择观看类型" clearable size="small">
+          <el-option label="直播" value="live"></el-option>
+          <el-option label="回放" value="replay"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="完课状态" prop="completeStatus">
+        <el-select v-model="queryParams.completeStatus" placeholder="请选择完课状态" clearable size="small">
+          <el-option label="已完课" value="1"></el-option>
+          <el-option label="未完课" value="0"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="付费状态" prop="payStatus">
+        <el-select v-model="queryParams.payStatus" placeholder="请选择付费状态" clearable size="small">
+          <el-option label="已付费" value="1"></el-option>
+          <el-option label="未付费" value="0"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="观看时长" prop="watchDuration">
+        <el-input-number
+          v-model="queryParams.watchDuration"
+          :min="0"
+          :precision="0"
+          placeholder="观看时长(分钟)"
+          size="small"
+        ></el-input-number>
+      </el-form-item>
+      <el-form-item label="时间范围" prop="dateRange">
+        <el-date-picker
+          v-model="dateRange"
+          type="datetimerange"
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          size="small"
+          value-format="yyyy-MM-dd HH:mm:ss"
+        ></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>
+
+    <!-- 操作工具栏 -->
+    <div class="selection-toolbar">
+      <el-checkbox :indeterminate="isIndeterminate" v-model="allChecked" @change="toggleSelectAll">
+        {{ multipleSelection.length > 0 ? `已选 ${multipleSelection.length} 条` : '选中本页' }}
+      </el-checkbox>
+      <!--      <el-button plain size="mini" @click="handleAutoTag">自动打标签</el-button>-->
+      <!--      <el-button plain size="mini" @click="handleAutoRemark">自动备注</el-button>-->
+      <el-button plain type="primary" size="mini" icon="el-icon-download" :loading="exportLoading" @click="handleExport">导出</el-button>
     </div>
+
+    <!-- 数据表格 -->
+    <el-table
+      ref="dataTable"
+      :data="dataList"
+      style="width: 100%"
+      v-loading="loading"
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55"></el-table-column>
+      <el-table-column type="index" label="序号" width="55" align="center"></el-table-column>
+      <el-table-column prop="liveName" label="直播间名称" min-width="160" show-overflow-tooltip></el-table-column>
+      <el-table-column prop="liveType" label="直播类型" width="100" align="center">
+        <template slot-scope="scope">
+          <el-tag type="danger" v-if="scope.row.liveType == 1">直播</el-tag>
+          <el-tag type="success" v-else-if="scope.row.liveType == 2">录播</el-tag>
+          <el-tag v-else-if="scope.row.liveType == 3">直播回放</el-tag>
+          <span v-else>-</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="status" label="状态" width="100" align="center">
+        <template slot-scope="scope">
+          <el-tag type="info" v-if="scope.row.status == 1">未开始</el-tag>
+          <el-tag type="warning" v-else-if="scope.row.status == 2">进行中</el-tag>
+          <el-tag type="success" v-else-if="scope.row.status == 3">已结束</el-tag>
+          <span v-else>-</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="startTime" label="开始时间" width="180" align="center"></el-table-column>
+      <el-table-column prop="finishTime" label="结束时间" width="180" align="center"></el-table-column>
+      <el-table-column prop="totalViewers" label="累计观看" width="110" align="center"></el-table-column>
+      <el-table-column prop="liveViewers" label="直播观看" width="110" align="center"></el-table-column>
+      <el-table-column prop="playbackViewers" label="回放观看" width="110" align="center"></el-table-column>
+      <el-table-column prop="liveAvgDuration" label="直播平均时长" width="140" align="center">
+        <template slot-scope="scope">{{ formatDuration(scope.row.liveAvgDuration) }}</template>
+      </el-table-column>
+      <el-table-column prop="playbackAvgDuration" label="回放平均时长" width="140" align="center">
+        <template slot-scope="scope">{{ formatDuration(scope.row.playbackAvgDuration) }}</template>
+      </el-table-column>
+      <el-table-column prop="totalCompletedCourses" label="累计完课" width="110" align="center"></el-table-column>
+      <el-table-column prop="liveCompletedCourses" label="直播完课" width="110" align="center"></el-table-column>
+      <el-table-column prop="playbackCompletedCourses" label="回放完课" width="110" align="center"></el-table-column>
+      <el-table-column prop="gmv" label="GMV" width="120" align="center">
+        <template slot-scope="scope">¥{{ scope.row.gmv || 0 }}</template>
+      </el-table-column>
+      <el-table-column prop="paidUsers" label="付费人数" width="100" align="center"></el-table-column>
+      <el-table-column prop="paidOrders" label="付费单数" width="100" align="center"></el-table-column>
+      <el-table-column prop="salesCount" label="销量统计" width="100" align="center"></el-table-column>
+      <el-table-column label="操作" width="120" fixed="right">
+        <template slot-scope="scope">
+          <el-button type="text" size="small" @click="handleViewDetail(scope.row)">查看详情</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页组件 -->
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+      style="margin-top: 20px;"
+    />
+
+    <!-- 自动打标签弹窗 -->
+    <el-dialog
+      title="自动打标签"
+      :visible.sync="tagDialogVisible"
+      width="600px"
+      :close-on-click-modal="false"
+    >
+      <el-form :model="tagForm" label-width="120px">
+        <el-form-item label="打标签规则">
+          <el-checkbox-group v-model="tagForm.rules">
+            <el-checkbox label="liveComplete">直播完课</el-checkbox>
+            <el-checkbox label="replayComplete">回放完课</el-checkbox>
+            <el-checkbox label="pay">付费行为</el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+        <el-form-item label="标签名称">
+          <el-input v-model="tagForm.tagName" placeholder="请输入标签名称"></el-input>
+        </el-form-item>
+        <el-form-item label="备注格式">
+          <el-radio-group v-model="tagForm.remarkFormat">
+            <el-radio label="time">时间—行为(如:2024-01-01—直播完课)</el-radio>
+            <el-radio label="simple">仅行为(如:直播完课)</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="tagDialogVisible = false">取 消</el-button>
+        <el-button type="primary" @click="confirmAutoTag">确 定</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 自动备注弹窗 -->
+    <el-dialog
+      title="自动备注"
+      :visible.sync="remarkDialogVisible"
+      width="600px"
+      :close-on-click-modal="false"
+    >
+      <el-form :model="remarkForm" label-width="120px">
+        <el-form-item label="备注规则">
+          <el-checkbox-group v-model="remarkForm.rules">
+            <el-checkbox label="liveComplete">直播完课</el-checkbox>
+            <el-checkbox label="replayComplete">回放完课</el-checkbox>
+            <el-checkbox label="pay">付费行为</el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+        <el-form-item label="备注格式">
+          <el-radio-group v-model="remarkForm.remarkFormat">
+            <el-radio label="time">时间—行为(如:2024-01-01—直播完课)</el-radio>
+            <el-radio label="simple">仅行为(如:直播完课)</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="备注位置">
+          <el-radio-group v-model="remarkForm.position">
+            <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>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="remarkDialogVisible = false">取 消</el-button>
+        <el-button type="primary" @click="confirmAutoRemark">确 定</el-button>
+      </div>
+    </el-dialog>
   </div>
 </template>
 
-
 <script>
-  import * as echarts from "echarts";
-  import { listLive, getLive, delLive, addLive, updateLive, exportLive } from "@/api/live/live";
-  import Editor from '@/components/Editor/wang';
-
-  export default {
-    name: "Live",
-    components: { Editor },
-    data() {
-      return {
-        top10List: [
-          {
-            rank: 1,
-            name: "御君方年末会员福利专场!",
-            cover:"https://cos.his.cdwjyyh.com/fs/20250304/710ea5b1896749b58438b76baf881d05.jpeg",
-            pv: 88332,
-            uv: 32674,
-            watchPV: 41866,
-            watchUV: 24714,
-            avgTime: "00:13:12",
-            maxOnline: 4317,
-          },
-          {
-            rank: 2,
-            name: "立秋养生大作战",
-            cover:"https://cos.his.cdwjyyh.com/fs/20250304/710ea5b1896749b58438b76baf881d05.jpeg",
-            pv: 55092,
-            uv: 15066,
-            watchPV: 33522,
-            watchUV: 12343,
-            avgTime: "01:18:30",
-            maxOnline: 3160,
-          },
-          {
-            rank: 3,
-            name: "寒露养生大挑战:防寒防燥防疾病",
-            cover:"https://cos.his.cdwjyyh.com/fs/20250304/710ea5b1896749b58438b76baf881d05.jpeg",
-            pv: 36044,
-            uv: 12205,
-            watchPV: 26056,
-            watchUV: 11086,
-            avgTime: "01:16:08",
-            maxOnline: 3232,
-          },
-        ],
-        selectedRank: 'highFlow',
-        redRankTypes: [
-          { label: '高流量', value: 'highFlow' },
-          { label: '高观看', value: 'highView' },
-          { label: '高时长', value: 'highTime' },
-        ],
-        blackRankTypes: [
-          { label: '低时长', value: 'lowTime' },
-          { label: '低观看', value: 'lowView' },
-          { label: '低流量', value: 'lowFlow' },
-        ],
-        selectedTimeRange: "day", // 默认选中“自然天”
-        datePickerType: "date", // 默认 date 类型
-        weekRange: "", // 存储选择周的时间范围
-        selectedDate: new Date().toISOString().split("T")[0], // 默认今天
-        lives: [
-          {
-            id: 1,
-            image: "https://cos.his.cdwjyyh.com/fs/20250117/d9e3b268e3834a2497e0bb1f900eac90.jpg",
-            title: "李悦的直播",
-            time: "2024-10-10 15:00:00",
-            views: 352821,
-            visitors: 14505,
-          },
-          {
-            id: 2,
-            image: "https://cos.his.cdwjyyh.com/fs/20250117/d9e3b268e3834a2497e0bb1f900eac90.jpg",
-            title: "小付的直播",
-            time: "2024-10-12 18:00:00",
-            views: 284210,
-            visitors: 10234,
-          },
-          {
-            id: 3,
-            image: "https://cos.his.cdwjyyh.com/fs/20250117/d9e3b268e3834a2497e0bb1f900eac90.jpg",
-            title: "生活妙招分享",
-            time: "2024-11-05 20:00:00",
-            views: 182401,
-            visitors: 8734,
-          },
-          {
-            id: 4,
-            image: "https://cos.his.cdwjyyh.com/fs/20250117/d9e3b268e3834a2497e0bb1f900eac90.jpg",
-            title: "家庭健康指南",
-            time: "2024-12-01 14:00:00",
-            views: 254321,
-            visitors: 12345,
-          },
-          {
-            id: 5,
-            image: "https://cos.his.cdwjyyh.com/fs/20250117/d9e3b268e3834a2497e0bb1f900eac90.jpg",
-            title: "额外的直播",
-            time: "2024-12-15 19:00:00",
-            views: 100000,
-            visitors: 5000,
-          }
-        ],
-        trendData: [
-          {
-            id: "views",
-            title: "直播间浏览量",
-            tip: "直播间总浏览量",
-            value: 352421,
-            dailyChange:1,
-            weeklyChange:2,
-            monthlyChange:3,
-            change: 5.2,
-            dates: ["02-02", "02-04", "02-06", "02-08", "02-10"],
-            data: [10, 20, 15, 25, 30],
-          },
-          {
-            id: "visitors",
-            title: "直播间访客数",
-            tip: "直播间访客数",
-            value: 14505,
-            dailyChange:1,
-            weeklyChange:2,
-            monthlyChange:3,
-            change: 5.2,
-            dates: ["02-02", "02-04", "02-06", "02-08", "02-10"],
-            data: [5, 8, 6, 10, 12],
-          },
-          {
-            id: "streams",
-            title: "创建直播数",
-            tip: "每日直播场次",
-            value: 20,
-            dailyChange:1,
-            weeklyChange:2,
-            monthlyChange:3,
-            change: 5.2,
-            dates: ["02-02", "02-04", "02-06", "02-08", "02-10"],
-            data: [1, 2, 1, 3, 2],
-          },
-          {
-            id: "pv",
-            title: "累计观看人次(PV)",
-            tip: "累计观看人次",
-            value: 5000,
-            dailyChange:1,
-            weeklyChange:2,
-            monthlyChange:3,
-            change: 5.2,
-            dates: ["02-02", "02-04", "02-06", "02-08", "02-10"],
-            data: [0, 0, 1, 0, 0],
-          },
-          {
-            id: "uv",
-            title: "累计观看人数(UV)",
-            tip: "累计观看人数",
-            value: 3000,
-            dailyChange:1,
-            weeklyChange:2,
-            monthlyChange:3,
-            change: 5.2,
-            dates: ["02-02", "02-04", "02-06", "02-08", "02-10"],
-            data: [0, 0, 0, 1, 0],
-          },
-        ],
-        selectedMetric: {}, // 选中的卡片数据
-        chart: null, // ECharts 实例
-      };
-    },
-    computed: {
-      changeLabel() {
-        switch (this.selectedTimeRange) {
-          case 'day': return '比前一天';
-          case 'week': return '比上周';
-          case 'month': return '比上月';
-          default: return '变化';
-        }
-      },
-      displayLives() {
-        return this.lives.slice(0, 4); // 最多只显示前 4 条数据
+import { listLiveData, exportLiveData, autoTagAndRemark, dashboardData } from "@/api/live/liveData";
+import { batchUpdateExternalContactNotes } from "@/api/qw/externalContact";
+import { addTag } from "@/api/qw/externalContact";
+
+export default {
+  name: "LiveData",
+  data() {
+    return {
+      liveId: '',
+      loading: true,
+      exportLoading: false,
+      showSearch: true,
+      dataList: [],
+      total: 0,
+      multipleSelection: [],
+      allChecked: false,
+      isIndeterminate: false,
+      dateRange: [],
+      // 统计数据
+      statisticsData: {
+        gmv: 0,
+        liveAvgDuration: 0,
+        liveCompletedCourses: 0,
+        livePeak: 0,
+        liveViewers: 0,
+        paidOrders: 0,
+        paidUsers: 0,
+        playbackAvgDuration: 0,
+        playbackCompletedCourses: 0,
+        playbackViewers: 0,
+        salesCount: 0,
+        totalCompletedCourses: 0,
+        totalViewers: 1
       },
-      /*datePickerType() {
-        return this.selectedTimeRange === "day"
-          ? "date"
-          : this.selectedTimeRange === "week"
-            ? "week"
-            : "month";
-      },*/
-      dateFormat() {
-        return this.selectedTimeRange === "day"
-          ? "yyyy-MM-dd"
-          : this.selectedTimeRange === "week"
-            ? "yyyy-MM-dd 至 yyyy-MM-dd"
-            : "yyyy-MM";
+      // 完课时长设置
+      completeWatchTime: 0,
+      liveCompleteWatchTime: 0,
+      replayCompleteWatchTime: 0,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        liveId: null,
+        liveName: null,
+        watchType: null,
+        completeStatus: null,
+        payStatus: null,
+        watchDuration: null,
+        startTime: null,
+        endTime: null
       },
-      valueFormat() {
-        return this.selectedTimeRange === "day"
-          ? "yyyy-MM-dd"
-          : this.selectedTimeRange === "week"
-            ? "yyyy-MM-dd"
-            : "yyyy-MM";
+      // 打标签弹窗
+      tagDialogVisible: false,
+      tagForm: {
+        rules: [],
+        tagName: '',
+        remarkFormat: 'time'
       },
+      // 备注弹窗
+      remarkDialogVisible: false,
+      remarkForm: {
+        rules: [],
+        remarkFormat: 'time',
+        position: 1
+      }
+    };
+  },
+  created() {
+    this.liveId = this.$route.query.liveId;
+    this.queryParams.liveId = this.liveId;
+
+    this.getList();
+  },
+  methods: {
+    /** 获取统计数据 */
+    getStatistics() {
+      if (!this.liveId) return;
+      dashboardData(this.liveId).then(response => {
+        if (response.code === 200) {
+          this.statisticsData = response.data || {};
+        }
+      });
+    },
+    /** 获取列表数据 */
+    getList() {
+      this.loading = true;
+      // 处理时间范围
+      if (this.dateRange && 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;
+      }
+      listLiveData(this.queryParams).then(response => {
+        if (response.code === 200) {
+          this.statisticsData = response.data || {};
+          this.dataList = response.list || [];
+          this.total = response.total || 0;
+        }
+        this.loading = false;
+      }).catch(() => {
+        this.loading = false;
+      });
     },
-    created() {
-      //this.getList();
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
     },
-    mounted() {
-      this.selectedMetric = this.trendData[0]; // 默认选中第一个
-      this.initChart(); // 初始化折线图
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRange = [];
+      this.$refs.queryForm.resetFields();
+      this.handleQuery();
     },
-    methods: {
-      changeDate(value) {
-        if (this.selectedTimeRange === "week" && value) {
-          /*console.log("🟢 监听到 selectedWeek 变化:", newVal);*/
-          this.weekRange = this.getWeekRange(value);
-        } else {
-          this.weekRange = "";
-        }
-        console.log("选择的时间:", value, "筛选方式:", this.selectedTimeRange);
-      },
-      getWeekRange(selectedWeek) {
-        console.log("🔹 selectedWeek 输入值:", selectedWeek); // 检查传入值
-        let date = new Date(selectedWeek);
-
-        if (isNaN(date.getTime())) {
-          console.error("Invalid Date:", selectedWeek);
-          return "日期错误";
+    /** 全选或取消全选 */
+    toggleSelectAll(val) {
+      if (val) {
+        this.toggleSelection(this.dataList);
+      } else {
+        this.toggleSelection();
+      }
+    },
+    toggleSelection(rows) {
+      if (rows) {
+        rows.forEach(row => {
+          this.$refs.dataTable.toggleRowSelection(row);
+        });
+      } else {
+        this.$refs.dataTable.clearSelection();
+      }
+    },
+    /** 多选框选中数据 */
+    handleSelectionChange(val) {
+      this.multipleSelection = val;
+      this.allChecked = val.length === this.dataList.length;
+      this.isIndeterminate = val.length > 0 && val.length < this.dataList.length;
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      if (this.dateRange && 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;
+      }
+      this.$confirm('是否确认导出所有直播数据?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportLiveData(this.queryParams);
+      }).then(response => {
+        if (response.code === 200) {
+          this.download(response.msg);
         }
-
-        let dayOfWeek = date.getDay(); // 0(星期天)- 6(星期六)
-
-        // 计算周一
-        let startDate = new Date(date); // 创建一个新的 Date 实例
-        startDate.setDate(date.getDate() - dayOfWeek + (dayOfWeek === 0 ? -6 : 1));
-
-        // 计算周日(确保 `endDate` 是新实例)
-        let endDate = new Date(startDate.getTime()); // 复制 `startDate`
-        endDate.setDate(startDate.getDate() + 6);
-
-        console.log("周一:", this.formatDate(startDate));
-        console.log("周日:", this.formatDate(endDate));
-
-        return `${this.formatDate(startDate)} 至 ${this.formatDate(endDate)}`;
-      },
-      formatDate(date) {
-        const year = date.getFullYear();
-        const month = String(date.getMonth() + 1).padStart(2, "0");
-        const day = String(date.getDate()).padStart(2, "0");
-        return `${year}-${month}-${day}`;
-      },
-      computedChange(item) {
-        switch (this.selectedTimeRange) {
-          case 'day': return item.dailyChange;
-          case 'week': return item.weeklyChange;
-          case 'month': return item.monthlyChange;
-          default: return 0;
+        this.exportLoading = false;
+      }).catch(() => {
+        this.exportLoading = false;
+      });
+    },
+    /** 自动打标签 */
+    // handleAutoTag() {
+    //   if (this.multipleSelection.length === 0) {
+    //     this.$message.warning('请选择要打标签的数据');
+    //     return;
+    //   }
+    //   this.tagDialogVisible = true;
+    // },
+    /** 确认自动打标签 */
+    confirmAutoTag() {
+      if (this.tagForm.rules.length === 0) {
+        this.$message.warning('请选择打标签规则');
+        return;
+      }
+      const userIds = this.multipleSelection.map(item => item.userId).filter(id => id);
+      if (userIds.length === 0) {
+        this.$message.warning('所选数据中没有有效的用户ID');
+        return;
+      }
+      const data = {
+        userIds: userIds,
+        rules: this.tagForm.rules,
+        tagName: this.tagForm.tagName,
+        remarkFormat: this.tagForm.remarkFormat,
+        liveId: this.liveId
+      };
+      autoTagAndRemark(data).then(response => {
+        if (response.code === 200) {
+          this.$message.success('打标签成功');
+          this.tagDialogVisible = false;
+          this.tagForm = {
+            rules: [],
+            tagName: '',
+            remarkFormat: 'time'
+          };
+          this.getList();
         }
-      },
-      selectRank(type) {
-        this.selectedRank = type; // 只允许一个按钮被选中
-        console.log(`选中的排行方式: ${type}`);
-      },
-      fetchRankingData() {
-        // 这里根据 `selectedRedRank` 和 `selectedBlackRank` 来请求不同的排行榜数据
-        console.log(`获取排行榜数据: 红榜-${this.selectedRedRank}, 黑榜-${this.selectedBlackRank}`);
-      },
-      // 切换时间范围
-      changeTimeRange() {
-        // 根据选中的时间范围修改 datePicker 类型
-        if (this.selectedTimeRange === "day") {
-          this.datePickerType = "date";
-        } else if (this.selectedTimeRange === "month") {
-          this.datePickerType = "month";
-        } else if (this.selectedTimeRange === "week") {
-          this.datePickerType = "week";
+      });
+    },
+    /** 自动备注 */
+    // handleAutoRemark() {
+    //   if (this.multipleSelection.length === 0) {
+    //     this.$message.warning('请选择要备注的数据');
+    //     return;
+    //   }
+    //   this.remarkDialogVisible = true;
+    // },
+    /** 确认自动备注 */
+    confirmAutoRemark() {
+      if (this.remarkForm.rules.length === 0) {
+        this.$message.warning('请选择备注规则');
+        return;
+      }
+      const userIds = this.multipleSelection.map(item => item.userId).filter(id => id);
+      if (userIds.length === 0) {
+        this.$message.warning('所选数据中没有有效的用户ID');
+        return;
+      }
+      // 生成备注内容
+      let notes = '';
+      const now = new Date();
+      const dateStr = now.getFullYear() + '-' +
+        String(now.getMonth() + 1).padStart(2, '0') + '-' +
+        String(now.getDate()).padStart(2, '0');
+
+      this.remarkForm.rules.forEach((rule, index) => {
+        let ruleText = '';
+        if (rule === 'liveComplete') {
+          ruleText = '直播完课';
+        } else if (rule === 'replayComplete') {
+          ruleText = '回放完课';
+        } else if (rule === 'pay') {
+          ruleText = '付费行为';
         }
-        this.selectedDate = null; // 重置已选日期
-      },
-      // 切换时间(但目前只是选日期,没有请求后端)
-      /*changeDate() {
-        console.log("选择日期:", this.selectedDate);
-        // 这里可以做后端请求:this.fetchTrendData();
-      },*/
-      // 获取直播趋势数据
-      async fetchTrendData() {
-        try {
-          const response = await axios.get("/api/trend-data", { params: { date: this.selectedDate } });
-          this.trendData = response.data;
 
-          // 默认选择第一个指标
-          if (this.trendData.length > 0) {
-            this.changeMetric(this.trendData[0]);
-          }
-        } catch (error) {
-          console.error("获取直播数据失败:", error);
+        if (this.remarkForm.remarkFormat === 'time') {
+          notes += (index > 0 ? ';' : '') + dateStr + '—' + ruleText;
+        } else {
+          notes += (index > 0 ? ';' : '') + ruleText;
         }
-      },
-      // 切换日期时更新数据
-      updateTrendData() {
-        console.log(`更新 ${this.selectedDate} 的直播数据`);
-        // 这里可以加接口请求,获取新的数据
-        this.updateChart();
-      },
-      // 切换指标
-      // changeMetric(metric) {
-      //   this.selectedMetric = metric;
-      //   this.updateChart();
-      // },
-      // updateTrendData() {
-      //   console.log("选择的时间:", this.selectedDate);
-      //   this.trendData = this.trendData.map(item => ({
-      //     ...item,
-      //     value: Math.floor(Math.random() * 50),
-      //     change: (Math.random() * 10 - 5).toFixed(2)
-      //   }));
-      //   this.updateChart();
-      // },
-      initChart() {
-        let chartDom = document.getElementById("liveChart");
-        if (!chartDom) return;
-        this.chart = echarts.init(chartDom);
-        this.updateChart();
-      },
-      // 更新折线图
-      updateChart() {
-        if (!this.chart) return;
-
-        let options = {
-          tooltip: { trigger: "axis", backgroundColor: "rgba(0, 0, 0, 0.7)", textStyle: { color: "#fff" } },
-          grid: { left: "5%", right: "5%", bottom: "10%", top: "10%", containLabel: true },
-          xAxis: { type: "category", data: this.selectedMetric.dates || [], axisLine: { lineStyle: { color: "#ddd" } } },
-          yAxis: { type: "value", splitLine: { lineStyle: { type: "dashed", color: "#ddd" } } },
-          series: [
-            {
-              name: this.selectedMetric.title,
-              data: this.selectedMetric.data || [],
-              type: "line",
-              smooth: true,
-              symbol: "circle",
-              symbolSize: 8,
-              itemStyle: { color: "#007BFF", borderColor: "#fff", borderWidth: 2 },
-              lineStyle: { width: 3, color: "#007BFF" },
-              areaStyle: {
-                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-                  { offset: 0, color: "rgba(0, 123, 255, 0.5)" },
-                  { offset: 1, color: "rgba(0, 123, 255, 0)" },
-                ]),
-              },
-              emphasis: {
-                focus: "series",
-                label: { show: true, formatter: "{c}", fontSize: 14, color: "#333", backgroundColor: "#fff", padding: [4, 6] },
-              },
-              animationDuration: 1200,
-              animationEasing: "quadraticOut",
-            },
-          ],
-        };
+      });
+
+      const data = {
+        userIds: userIds,
+        notes: notes,
+        type: this.remarkForm.position,
+        nameType: 3, // 不添加客户名称
+        filter: false
+      };
 
-        this.chart.setOption(options);
-      },
-      changeMetric(metric) {
-        this.selectedMetric = metric;
-        this.updateChart();
-      },
+      batchUpdateExternalContactNotes(data).then(response => {
+        if (response.code === 200) {
+          this.$message.success('备注成功');
+          this.remarkDialogVisible = false;
+          this.remarkForm = {
+            rules: [],
+            remarkFormat: 'time',
+            position: 1
+          };
+          this.getList();
+        }
+      });
+    },
+    /** 查看详情 */
+    handleViewDetail(row) {
+      // 可以跳转到详情页面或打开详情弹窗
+      this.$message.info('查看详情功能待实现');
+    },
+    /** 格式化时长 */
+    formatDuration(seconds) {
+      if (!seconds) return '00:00:00';
+      const hours = Math.floor(seconds / 3600);
+      const minutes = Math.floor((seconds % 3600) / 60);
+      const secs = seconds % 60;
+      return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
+    },
+    /** 更新完课时长设置 */
+    updateCompleteWatchTime(type) {
+      // 这里可以调用API保存设置
+      let watchTime = 0;
+      if (type === 'total') {
+        watchTime = this.completeWatchTime;
+      } else if (type === 'live') {
+        watchTime = this.liveCompleteWatchTime;
+      } else if (type === 'replay') {
+        watchTime = this.replayCompleteWatchTime;
+      }
+      // 更新查询参数并重新获取数据
+      this.queryParams.completeWatchTime = watchTime;
+      // this.getStatistics();
+      this.getList();
+      this.$message.success('设置成功');
     }
-  };
+  }
+};
 </script>
 
 <style scoped>
-  .app-container {
-    padding: 20px;
-  }
-
-  .title {
-    font-size: 18px;
-    font-weight: bold;
-    margin-bottom: 10px;
-  }
-  .live-container {
-    display: flex;
-    gap: 15px; /* 控制卡片之间的间距 */
-    overflow-x: auto; /* 允许横向滚动 */
-    padding-bottom: 10px;
-  }
-
-  /* 卡片样式 */
-  .live-card {
-    width: 380px;
-    height: 225px;
-    background: rgb(250,250,250);
-    border-radius: 10px;
-    padding: 15px;
-    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
-    display: flex;
-    flex-direction: column;
-    align-items: flex-start;
-  }
-
-  /* 直播状态 */
-  .status {
-    background: #d3d3d3;
-    color: #333;
-    font-size: 14px;
-    padding: 4px 8px;
-    border-radius: 5px;
-    display: inline-block;
-
-
-  }
-
-  /* 直播信息部分 */
-  .content {
-    background: rgb(250,250,250);
-    display: flex;
-    gap: 10px;
-    align-items: center;
-    width: 90%;
-    margin-top: 0px;
-  }
-
-  /* 直播封面图片 */
-  .cover-image {
-    width: 70px;
-    height: 70px;
-    border-radius: 10px;
-    object-fit: cover;
-  }
-
-  /* 直播文本信息 */
-  .info {
-    flex: 1;
-  }
-
-  .live-title {
-    font-size: 16px;
-    font-weight: bold;
-    white-space: nowrap;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    max-width: 250px; /* 防止标题过长 */
-  }
-
-  .time {
-    font-size: 14px;
-    color: #666;
-  }
-
-  /* 直播数据部分 */
-  .stats {
-    display: flex;
-    justify-content: space-between;
-    width: 100%;
-    flex-shrink: 0;
-    margin-top: -40px;
-  }
-
-  .stat-item {
-    text-align: center;
-    flex: 1;
-  }
-
-  .label {
-    font-size: 14px;
-    color: #888;
-  }
-
-  .value {
-    font-size: 18px;
-    font-weight: bold;
-    color: #333;
-  }
-  /* 直播趋势 */
-  .trend-section {
-    margin-top: 30px;
-  }
-  .trend-header {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-  }
-  .trend-cards {
-    display: flex;
-    gap: 15px;
-  }
-  .trend-card {
-    width: 280px;
-    hight: 100px;
-    border: 1px solid #ddd;
-    border-radius: 8px;
-    padding: 16px;
-    transition: all 0.3s;
-    position: relative;
-  }
-
-  .trend-card.active {
-    border-color: #007bff; /* 选中时边框变蓝 */
-    box-shadow: 0px 0px 10px rgba(0, 123, 255, 0.3);
-  }
-
-  .trend-card.active::after {
-    content: "✔";
-    position: absolute;
-    bottom: 8px;
-    right: 8px;
-    color: white;
-    background: #007bff;
-    border-radius: 50%;
-    width: 20px;
-    height: 20px;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    font-size: 14px;
-    font-weight: bold;
-  }
-  .trend-value {
-    font-size: 24px;
-    font-weight: bold;
-  }
-
-  /* 折线图 */
-  .chart {
-    width: 100%;
-    height: 300px;
-    margin-top: 20px;
-  }
-  .top10-section {
-    margin-top: 20px;
-    background: #fff;
-    padding: 16px;
-    border-radius: 8px;
-    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-  }
-  .live-name {
-    display: flex;
-    align-items: center;
-  }
-
-  .live-cover {
-    width: 80px;  /* 直播封面宽度 */
-    height: 45px; /* 直播封面高度 */
-    border-radius: 4px;
-    margin-right: 10px;
-    object-fit: cover;
-  }
-
-  .live-title {
-    font-size: 14px;
-    color: #333;
-    white-space: nowrap;
-    overflow: hidden;
-    text-overflow: ellipsis;
-  }
-  .ranking-tabs {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    padding: 10px 20px;
-  }
-
-  .ranking-container {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    margin: 10px 0;
-    border-radius: 8px;
-    overflow: hidden;
-  }
-
-  .ranking-section {
-    display: flex;
-    align-items: center;
-    width: 50%;
-    padding: 10px 15px;
-  }
-
-  .red-rank {
-    background: linear-gradient(90deg, #ff6b6b, #ff8e8e);
-    justify-content: flex-start;
-  }
-
-  .black-rank {
-    background: linear-gradient(90deg, #4a4a4a, #6b6b6b);
-    justify-content: flex-end;
-  }
-
-  .rank-title {
-    font-size: 18px;
-    font-weight: bold;
-    color: white;
-    margin: 0 15px;
-  }
-
-  .rank-filters {
-    display: flex;
-  }
-
-  button {
-    background: rgba(255, 255, 255, 0.2);
-    border: 1px solid rgba(255, 255, 255, 0.5);
-    color: white;
-    font-size: 14px;
-    padding: 5px 12px;
-    margin: 0 5px;
-    border-radius: 15px;
-    cursor: pointer;
-    transition: all 0.3s ease;
-  }
-
-  button.active {
-    background: white;
-    color: #ff4d4f;
-  }
-  .filter-container {
-    display: flex;
-    align-items: center;
-    gap: 8px; /* 控制两个组件的间距 */
-  }
-
-  .filter-label {
-    font-weight: bold;
-    white-space: nowrap; /* 防止换行 */
-  }
+.statistics-card {
+  margin-bottom: 20px;
+}
+
+.statistics-item {
+  text-align: center;
+  padding: 15px;
+  background: #f5f7fa;
+  border-radius: 4px;
+}
+
+.statistics-title {
+  font-size: 14px;
+  color: #606266;
+  margin-bottom: 10px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.statistics-value {
+  font-size: 24px;
+  font-weight: bold;
+  color: #303133;
+}
+
+.selection-toolbar {
+  display: flex;
+  align-items: center;
+  margin-bottom: 10px;
+  padding-left: 10px;
+}
+
+.selection-toolbar .el-checkbox {
+  margin-right: 10px;
+}
+
+.live-data-css {
+  padding-left: 10px;
+  padding-top: 30px;
+}
 </style>
-

+ 265 - 13
src/views/live/liveOrder/index.vue

@@ -25,6 +25,35 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
+      <el-form-item label="订单号" prop="orderCode">
+        <el-input
+          v-model="queryParams.orderCode"
+          placeholder="请输入订单号"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item label="收货人电话" prop="userPhone">
+        <el-input
+          v-model="queryParams.userPhone"
+          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="productSpec">
         <el-input
@@ -100,11 +129,11 @@
       <el-form-item label="下单时间" prop="orderTimeRange">
         <el-date-picker
           v-model="orderTimeRange"
-          type="daterange"
+          type="datetimerange"
           range-separator="至"
           start-placeholder="开始日期"
           end-placeholder="结束日期"
-          value-format="yyyy-MM-dd"
+          value-format="yyyy-MM-dd HH:mm:ss"
           size="small"
           @change="handleOrderTimeChange"
         />
@@ -126,7 +155,26 @@
           :loading="exportLoading"
           @click="handleExport"
           v-hasPermi="['live:liveOrder:export']"
-        >导出</el-button>
+        >导出订单</el-button>
+        <el-col :span="1.5">
+          <el-button
+            icon="el-icon-s-order"
+            size="mini"
+            type="warning"
+            @click="openDeliveryNote"
+          >批量导入物流单号
+          </el-button>
+        </el-col>
+        <el-col :span="1.5">
+          <el-button
+            v-hasPermi="['store:storeOrder:healthExportShippingOrder']"
+            icon="el-icon-tickets"
+            size="mini"
+            type="success"
+            @click="handleExportShippingOrder"
+          >导出发货单
+          </el-button>
+        </el-col>
       </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
@@ -138,13 +186,14 @@
 
     <el-table border v-loading="loading" :data="liveOrderList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="订单号" align="center" prop="orderCode" />
       <el-table-column label="销售ID" align="center" prop="companyUserId" >
         <template slot-scope="scope">
           <span v-if="scope.row.companyUserId > 0" >{{ scope.row.companyUserId }}</span>
           <span v-else>-</span>
         </template>
       </el-table-column>
-      <el-table-column label="绑定销售昵称" align="center" prop="companyUserName" />
+      <el-table-column label="绑定销售昵称" align="center" prop="companyUserNickName" />
       <el-table-column label="客户编码" align="center" prop="userId" />
       <el-table-column label="会员等级" align="center" prop="userLevel">
       </el-table-column>
@@ -157,7 +206,8 @@
       <el-table-column label="客户ID" align="center" prop="userId" />
       <el-table-column label="客户昵称" align="center" prop="nickName" />
       <el-table-column label="客户绑定手机号" align="center" prop="userBindPhone" />
-      <el-table-column label="收货手机号" align="center" prop="userPhone" />
+      <el-table-column label="收货人电话" align="center" prop="userPhone" />
+      <el-table-column label="收货人姓名" align="center" prop="userName" />
       <el-table-column label="累计成交笔数" align="center" prop="totalOrderCount" />
       <el-table-column label="累计成交总额" align="center" prop="totalOrderAmount" />
       <el-table-column label="最新绑定时间" align="center" prop="latestBindTime" width="180">
@@ -177,7 +227,12 @@
       <el-table-column label="商品规格" align="center" prop="productSpec" width="120" />
       <el-table-column label="商品数量" align="center" prop="totalNum" />
       <el-table-column label="销售价格" align="center" prop="totalPrice" />
-      <el-table-column label="成本价格" align="center" prop="costPrice" />
+      <el-table-column label="成本价格" align="center" prop="costPrice" v-if="showFinanceTableField"/>
+      <el-table-column label="结算价格" align="center" prop="fprice"  v-if="showFinanceTableField"/>
+      <el-table-column label="额外运费" align="center" prop="payDelivery" v-if="showFinanceTableField"/>
+      <el-table-column label="商品编码" align="center" prop="barCode"  v-if="showFinanceTableField"/>
+      <el-table-column label="商品分类" align="center" prop="cateName" v-if="showFinanceTableField"/>
+      <el-table-column label="成交价" align="center" prop="payMoney"/>
       <el-table-column label="收货地址" align="center" prop="userAddress" width="200" />
       <el-table-column label="对应供应商" align="center" prop="supplierName" width="120" />
       <el-table-column label="下单时间" align="center" prop="createTime" width="180">
@@ -217,23 +272,100 @@
       :title="show.title" :visible.sync="show.open">
       <liveOrderDetails ref="Details" />
     </el-drawer>
+
+    <el-dialog
+      :before-close="handleClose"
+      :visible.sync="deliveryNoteOpen"
+      center
+      title="批量发货"
+      width="35%"
+    >
+      <span slot="footer" class="dialog-footer">
+        <!-- 小程序Appid选择 -->
+        <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
+          <el-form-item label="小程序:" prop="miniAppId">
+        <el-select
+          v-model="ruleForm.miniAppId"
+          clearable
+          placeholder="请选择发货小程序"
+          style="width: 100%"
+        >
+          <el-option
+            v-for="item in miniAppList"
+            :key="item.appId"
+            :label="item.appName"
+            :value="item.appId"
+          />
+        </el-select>
+      </el-form-item>
+        </el-form>
+
+        <el-upload ref="upload" :action="uploadUrl" :auto-upload="false" :disabled="orderUpload.isUploading" :headers="orderUpload.headers"
+                   :limit="1" :on-progress="handleFileUploadProgress"
+                   :on-success="handleFileSuccess" accept=".xlsx, .xls" drag
+        >
+        <i class="el-icon-upload"></i>
+        <div class="el-upload__text">
+          将文件拖到此处,或
+          <em>点击上传</em>
+        </div>
+        <div slot="tip" class="el-upload__tip">
+          <el-link style="font-size:12px" type="info" @click="importDeliveryNoteTemplate">下载模板</el-link>
+        </div>
+        <div slot="tip" class="el-upload__tip" style="color:red">提示:仅允许导入“xls”或“xlsx”格式文件!</div>
+      </el-upload>
+        <el-divider></el-divider>
+        <el-button @click="cancelResetDeliveryNote">取 消</el-button>
+        <el-button type="primary" @click="submitDeliveryNote('ruleForm')">确 定</el-button>
+      </span>
+    </el-dialog>
   </div>
 </template>
 
 <script>
-import { listLiveOrderZm, exportLiveOrderZm } from "@/api/live/liveOrder";
+import { listLiveOrderZm, exportLiveOrderZm,healthExportShippingOrder,importDeliveryNoteExpressTemplate } from "@/api/live/liveOrder";
 import liveOrderDetails from './liveOrderDetails.vue';
 import {getCompanyList} from "@/api/company/company";
 import Treeselect from "@riophae/vue-treeselect";
 import {treeselect} from "@/api/company/companyDept";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import { getToken } from '@/utils/auth'
 import {parseTime} from "../../../utils/common";
+import { checkPermi } from "@/utils/permission";
 
 export default {
   name: "LiveOrder",
   components: {Treeselect, liveOrderDetails },
   data() {
     return {
+      upload: {
+        // 是否显示弹出层(用户导入)
+        open: false,
+        // 弹出层标题(用户导入)
+        title: '',
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 设置上传的请求头部
+        headers: { Authorization: 'Bearer ' + getToken() },
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + '/live/liveOrder/importExpress'
+      },
+      orderUpload: {
+        // 是否显示弹出层(用户导入)
+        open: false,
+        // 弹出层标题(用户导入)
+        title: '',
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 设置上传的请求头部
+        headers: { Authorization: 'Bearer ' + getToken() },
+      },
+      deliveryNoteOpen: false,
+      miniAppList: [],
       // 字典
       orderStatusOptions: [],
       memberLevelOptions: [],
@@ -282,12 +414,27 @@ export default {
         orderEndTime: null,
         status: null,
       },
+      ruleForm:{
+        miniAppId: null,
+      },
       orderOptions: [],
       actName: "10",
       show: {
         title: "订单详情",
         open: false,
       },
+      rules: {
+        userId: [
+          { required: true, message: '会员信息不能为空' }
+        ],
+        addressId: [
+          { required: true, message: '收货信息不能为空' }
+        ],
+        miniAppId: [
+          { required: true, message: '发货小程序不能为空' }
+        ],
+      },
+      showFinanceTableField: false,
     };
   },
   created() {
@@ -298,29 +445,88 @@ export default {
         this.getTreeselect();
       }
     });
+    if (checkPermi(['live:liveOrder:finance'])) {
+      this.showFinanceTableField = true;
+    }
     this.queryParams.liveId = this.$route.query.liveId
     this.getList();
     this.getDicts("sys_live_order_status").then(response => {
       this.orderStatusOptions = response.data;
+      this.orderOptions = this.orderStatusOptions;
     });
-    this.getDicts("sys_order_status").then(response => {
-      this.orderOptions = response.data;
-    });
+    // this.getDicts("sys_order_status").then(response => {
+
+    // });
     this.getDicts("sys_user_level").then(response => {
       this.memberLevelOptions = response.data;
     });
     this.getDicts("sys_customer_status").then(response => {
       this.customerStatusOptions = response.data;
     });
+
+  },
+  computed: {
+
+    uploadUrl() {
+      return process.env.VUE_APP_BASE_API +
+        '/live/liveOrder/importDeliveryNoteExpress?miniAppId=' +
+        this.ruleForm.miniAppId;
+    },
+    userId() {
+      return this.$store.state.user.user.userId
+    },
   },
   methods: {
-    parseTime,
+    // 提交发货单
+    submitDeliveryNote(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          const uploadFiles = this.$refs.upload.uploadFiles
+          if (uploadFiles.length === 0) {
+            this.$message.error('请选择要上传的文件')
+            return
+          }
+          this.$refs.upload.submit()
+        } else {
+          return false
+        }
+      })
+    },
+    //发货单模板下载
+    importDeliveryNoteTemplate() {
+      importDeliveryNoteExpressTemplate().then((response) => {
+        this.download(response.msg)
+      })
+    },
+    handleFileSuccess(response, file, fileList) {
+      this.upload.open = false
+      this.upload.isUploading = false
+      this.$refs.upload.clearFiles()
+      this.importMsgOpen = true
+      this.importMsg = response.msg
+      // this.$alert(response.msg, '导入结果', {
+      //     dangerouslyUseHTMLString: true
+      //   });
+      this.getList()
+    },
+    // 文件上传中处理
+    handleFileUploadProgress(event, file, fileList) {
+      this.upload.isUploading = true
+    },
+    handleClose(done) {
+      this.$confirm('确认关闭?')
+        .then(_ => {
+          done()
+        })
+        .catch(_ => {
+        })
+    },
 
     // 下单时间范围选择变化处理
     handleOrderTimeChange(value) {
       if (value && value.length === 2) {
-        this.queryParams.createTimeStart = value[0] + ' 00:00:00';
-        this.queryParams.createTimeEnd = value[1] + ' 23:59:59';
+        this.queryParams.createTimeStart = value[0];
+        this.queryParams.createTimeEnd = value[1];
       } else {
         this.queryParams.createTimeStart = null;
         this.queryParams.createTimeEnd = null;
@@ -419,6 +625,52 @@ export default {
       this.queryParams.deptId = val;
       this.getList();
     },
+    handleExportShippingOrder() {
+      if (this.queryParams.status == '00') {
+        this.queryParams.status = null
+      }
+      if (this.createTimeRange != null && this.createTimeRange.length == 2) {
+        this.queryParams.createTimeRange = this.createTimeRange[0] + '--' + this.createTimeRange[1]
+      } else {
+        this.queryParams.createTimeRange = null
+      }
+      if (this.payTimeRange != null && this.payTimeRange.length == 2) {
+        this.queryParams.payTimeRange = this.payTimeRange[0] + '--' + this.payTimeRange[1]
+      } else {
+        this.queryParams.payTimeRange = null
+      }
+      if (this.deliveryImportTimeRange != null && this.deliveryImportTimeRange.length == 2) {
+        this.queryParams.deliveryImportTimeRange = this.deliveryImportTimeRange[0] + '--' + this.deliveryImportTimeRange[1]
+      } else {
+        this.queryParams.deliveryImportTimeRange = null
+      }
+      if (this.deliverySendTimeRange != null && this.deliverySendTimeRange.length == 2) {
+        this.queryParams.deliverySendTimeRange = this.deliverySendTimeRange[0] + '--' + this.deliverySendTimeRange[1]
+      } else {
+        this.queryParams.deliverySendTimeRange = null
+      }
+      const queryParams = this.addDateRange(this.queryParams, this.dateRange)
+      this.$confirm('是否确认导出所有订单明细数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(function() {
+        return healthExportShippingOrder(queryParams)
+      }).then(response => {
+        this.download(response.msg)
+      }).catch(function() {
+      })
+    },
+    //打开发货单
+    openDeliveryNote() {
+      this.deliveryNoteOpen = true
+      this.getAppList();
+    },
+    //取消重置
+    cancelResetDeliveryNote(){
+      this.deliveryNoteOpen = false;
+      this.resetForm('ruleForm')
+    },
   }
 };
 </script>

+ 53 - 53
src/views/live/liveOrder/liveOrderDetails.vue

@@ -6,7 +6,7 @@
     <div class="contentx" v-if="item!=null">
       <div class="desct"></div>
       <div class="order-status" v-if="item!=null" >
-        <el-steps  :active="item.status==4?item.status:item.status" align-center finish-status="success">
+        <el-steps  :active="item.status+1" align-center>
           <el-step title="待支付"></el-step>
           <el-step title="待发货"></el-step>
           <el-step title="待收货"></el-step>
@@ -76,57 +76,57 @@
         </el-descriptions>
       </el-card>
     </div>
-    <div class="contentx" v-if="item!=null" style="padding-bottom: 70px;">
-      <div style="margin-top: 20px">
-        <div class="desct">
-          物流信息
-        </div>
-        &nbsp;
-        <el-link  type="primary" @click="editDelivery(null)">添加物流信息</el-link>
-      </div>
-      <el-table
-        border
-        :data="deliverList"
-        size="small"
-        style="width: 100%;margin-top: 20px" >
-        <el-table-column label="物流公司编码" width="150" align="center">
-          <template slot-scope="scope">
-            <p>{{scope.row.deliverSn}}</p>
-          </template>
-        </el-table-column>
-        <el-table-column label="物流公司名称" width="300" align="center">
-          <template slot-scope="scope">
-            <p>{{scope.row.deliverName}}</p>
-          </template>
-        </el-table-column>
-        <el-table-column label="物流单号" width="300" align="center">
-          <template slot-scope="scope">
-            <p>{{scope.row.deliverId}}</p>
-          </template>
-        </el-table-column>
-        <el-table-column label="物流状态" width="300" align="center">
-          <template slot-scope="scope">
-              <span>
-              <el-tag v-for="(item, index) in deliveryStatusOptions"    v-if="scope.row!=null&&scope.row.status==item.dictValue">
-              {{item.dictLabel}}
-              </el-tag>
-              </span>
-          </template>
-        </el-table-column>
-        <el-table-column label="发货时间" width="240" align="center">
-          <template slot-scope="scope">
-            {{scope.row.deliverySendTime}}
-          </template>
-        </el-table-column>
-        <el-table-column label="操作" width="240" align="center">
-          <template slot-scope="scope">
-            <el-link  type="primary" @click="showExpress(scope)">查看物流跟踪</el-link>
-            &nbsp;&nbsp;
-            <el-link  type="primary" @click="editDelivery(scope)">修改物流</el-link>
-          </template>
-        </el-table-column>
-      </el-table>
-    </div>
+<!--    <div class="contentx" v-if="item!=null" style="padding-bottom: 70px;">-->
+<!--      <div style="margin-top: 20px">-->
+<!--        <div class="desct">-->
+<!--          物流信息-->
+<!--        </div>-->
+<!--        &nbsp;-->
+<!--        <el-link  type="primary" @click="editDelivery(null)">添加物流信息</el-link>-->
+<!--      </div>-->
+<!--      <el-table-->
+<!--        border-->
+<!--        :data="deliverList"-->
+<!--        size="small"-->
+<!--        style="width: 100%;margin-top: 20px" >-->
+<!--        <el-table-column label="物流公司编码" width="150" align="center">-->
+<!--          <template slot-scope="scope">-->
+<!--            <p>{{scope.row.deliverSn}}</p>-->
+<!--          </template>-->
+<!--        </el-table-column>-->
+<!--        <el-table-column label="物流公司名称" width="300" align="center">-->
+<!--          <template slot-scope="scope">-->
+<!--            <p>{{scope.row.deliverName}}</p>-->
+<!--          </template>-->
+<!--        </el-table-column>-->
+<!--        <el-table-column label="物流单号" width="300" align="center">-->
+<!--          <template slot-scope="scope">-->
+<!--            <p>{{scope.row.deliverId}}</p>-->
+<!--          </template>-->
+<!--        </el-table-column>-->
+<!--        <el-table-column label="物流状态" width="300" align="center">-->
+<!--          <template slot-scope="scope">-->
+<!--              <span>-->
+<!--              <el-tag v-for="(item, index) in deliveryStatusOptions"    v-if="scope.row!=null&&scope.row.status==item.dictValue">-->
+<!--              {{item.dictLabel}}-->
+<!--              </el-tag>-->
+<!--              </span>-->
+<!--          </template>-->
+<!--        </el-table-column>-->
+<!--        <el-table-column label="发货时间" width="240" align="center">-->
+<!--          <template slot-scope="scope">-->
+<!--            {{scope.row.deliverySendTime}}-->
+<!--          </template>-->
+<!--        </el-table-column>-->
+<!--        <el-table-column label="操作" width="240" align="center">-->
+<!--          <template slot-scope="scope">-->
+<!--            <el-link  type="primary" @click="showExpress(scope)">查看物流跟踪</el-link>-->
+<!--            &nbsp;&nbsp;-->
+<!--            <el-link  type="primary" @click="editDelivery(scope)">修改物流</el-link>-->
+<!--          </template>-->
+<!--        </el-table-column>-->
+<!--      </el-table>-->
+<!--    </div>-->
     <div class="contentx" v-if="item!=null" style="padding-bottom: 70px;">
       <div class="desct">
         商品信息
@@ -537,7 +537,7 @@ export default {
     this.getDicts("sys_store_pay_type").then(response => {
       this.PayOptions = response.data;
     });
-    this.getDicts("sys_order_status").then(response => {
+    this.getDicts("sys_live_order_status").then(response => {
       this.orderOptions = response.data;
     });
     this.getDicts("sys_order_pay").then(response => {

+ 1388 - 0
src/views/qw/applyIpad/index.vue

@@ -0,0 +1,1388 @@
+<template>
+  <div class="app-container">
+    <!-- 数据统计卡片 -->
+    <div class="statistics-cards">
+      <el-row :gutter="20">
+        <el-col :span="6">
+          <el-card class="stat-card" shadow="hover">
+            <div class="stat-content">
+              <div class="stat-icon pending">
+                <i class="el-icon-time"></i>
+              </div>
+              <div class="stat-info">
+                <div class="stat-value">{{ statistics.pending }}</div>
+                <div class="stat-label">待审核</div>
+              </div>
+            </div>
+          </el-card>
+        </el-col>
+        <el-col :span="6">
+          <el-card class="stat-card" shadow="hover">
+            <div class="stat-content">
+              <div class="stat-icon approved">
+                <i class="el-icon-check"></i>
+              </div>
+              <div class="stat-info">
+                <div class="stat-value">{{ statistics.approved }}</div>
+                <div class="stat-label">已通过</div>
+              </div>
+            </div>
+          </el-card>
+        </el-col>
+        <el-col :span="6">
+          <el-card class="stat-card" shadow="hover">
+            <div class="stat-content">
+              <div class="stat-icon rejected">
+                <i class="el-icon-close"></i>
+              </div>
+              <div class="stat-info">
+                <div class="stat-value">{{ statistics.rejected }}</div>
+                <div class="stat-label">已拒绝</div>
+              </div>
+            </div>
+          </el-card>
+        </el-col>
+        <el-col :span="6">
+          <el-card class="stat-card" shadow="hover">
+            <div class="stat-content">
+              <div class="stat-icon total">
+                <i class="el-icon-data-line"></i>
+              </div>
+              <div class="stat-info">
+                <div class="stat-value">{{ statistics.total }}</div>
+                <div class="stat-label">总申请数</div>
+              </div>
+            </div>
+          </el-card>
+        </el-col>
+      </el-row>
+    </div>
+
+    <!-- 搜索表单 -->
+    <el-card class="search-card" shadow="hover">
+      <div class="search-header">
+        <div class="search-title">
+          <i class="el-icon-search"></i>
+          <span>筛选条件</span>
+        </div>
+        <el-button type="text" @click="toggleSearch">
+          {{ showSearch ? '收起' : '展开' }}
+          <i :class="showSearch ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"></i>
+        </el-button>
+      </div>
+
+      <el-collapse-transition>
+        <el-form v-show="showSearch" :model="queryParams" ref="queryForm" :inline="true" label-width="80px"
+          class="search-form">
+          <el-row :gutter="20">
+            <el-col :span="6">
+              <el-form-item label="公司名称" prop="companyName">
+                <el-input v-model="queryParams.companyName" placeholder="请输入公司名称" clearable
+                  prefix-icon="el-icon-office-building" class="search-input" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="提交单号" prop="applicationNumber">
+                <el-input v-model="queryParams.applicationNumber" placeholder="请输入提交单号" clearable
+                  prefix-icon="el-icon-document" class="search-input" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="申请数量" prop="applyQuantity">
+                <el-input v-model="queryParams.applyQuantity" placeholder="请输入申请数量" clearable
+                  prefix-icon="el-icon-s-data" class="search-input" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="审核状态" prop="auditStatus">
+                <el-select v-model="queryParams.auditStatus" placeholder="请选择审核状态" clearable class="search-select">
+                  <el-option label="待审核" value="0" />
+                  <el-option label="审核通过" value="1" />
+                  <el-option label="审核拒绝" value="2" />
+                  <el-option label="部分分配" value="3" />
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+
+          <el-row :gutter="20">
+            <el-col :span="6">
+              <el-form-item label="提交时间" prop="submitTime">
+                <el-date-picker clearable v-model="queryParams.submitTime" type="datetime"
+                  value-format="yyyy-MM-dd HH:mm:ss" placeholder="选择提交时间" class="search-date">
+                </el-date-picker>
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="审核时间" prop="reviewTime">
+                <el-date-picker clearable v-model="queryParams.reviewTime" type="datetime"
+                  value-format="yyyy-MM-dd HH:mm:ss" placeholder="选择审核时间" class="search-date">
+                </el-date-picker>
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item label="实际分配" prop="allocatedQuantity">
+                <el-input v-model="queryParams.allocatedQuantity" placeholder="请输入实际分配数量" clearable
+                  prefix-icon="el-icon-s-marketing" class="search-input" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="6">
+              <el-form-item>
+                <el-button type="primary" icon="el-icon-search" @click="handleQuery" class="search-btn">
+                  搜索
+                </el-button>
+                <el-button icon="el-icon-refresh" @click="resetQuery" class="reset-btn">
+                  重置
+                </el-button>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+      </el-collapse-transition>
+    </el-card>
+
+    <!-- 批量操作工具栏 -->
+    <div class="batch-toolbar" v-show="selectedRows.length > 0">
+      <el-card class="batch-card" shadow="hover">
+        <div class="batch-content">
+          <div class="batch-info">
+            <i class="el-icon-warning-outline"></i>
+            <span>已选择 {{ selectedRows.length }} 项</span>
+          </div>
+          <div class="batch-actions">
+            <el-button size="small" @click="batchApprove" v-if="canBatchApprove" type="success">
+              <i class="el-icon-check"></i> 批量通过
+            </el-button>
+            <el-button size="small" @click="batchReject" v-if="canBatchReject" type="danger">
+              <i class="el-icon-close"></i> 批量拒绝
+            </el-button>
+            <el-button size="small" @click="handleBatchSync" type="warning">
+              <i class="el-icon-refresh"></i> 批量同步
+            </el-button>
+            <el-button size="small" @click="clearSelection">
+              <i class="el-icon-close"></i> 清空选择
+            </el-button>
+          </div>
+        </div>
+      </el-card>
+    </div>
+
+    <!-- 操作按钮区域 -->
+    <el-card class="action-card" shadow="never">
+      <div class="action-bar">
+        <div class="action-group">
+          <el-button type="primary" icon="el-icon-plus" @click="handleAdd" class="action-btn"
+            >
+            申请iPad
+          </el-button>
+
+          <el-button type="success" icon="el-icon-edit" @click="handleUpdate" :disabled="single" class="action-btn"
+            >
+            修改
+          </el-button>
+
+          <el-dropdown @command="handleBatchCommand" class="action-dropdown">
+            <el-button type="warning" class="action-btn">
+              批量操作<i class="el-icon-arrow-down el-icon--right"></i>
+            </el-button>
+            <el-dropdown-menu slot="dropdown">
+              <el-dropdown-item command="sync">
+                批量同步
+              </el-dropdown-item>
+              <el-dropdown-item command="export">
+                导出数据
+              </el-dropdown-item>
+            </el-dropdown-menu>
+          </el-dropdown>
+        </div>
+
+        <div class="action-right">
+          <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+        </div>
+      </div>
+    </el-card>
+
+    <!-- 数据表格 -->
+    <el-card class="table-card" shadow="hover">
+      <el-table border v-loading="loading" :data="recordsList" @selection-change="handleSelectionChange"
+        class="modern-table" :header-cell-class-name="headerCellClass" :cell-class-name="cellClass"
+        @row-click="handleRowClick">
+
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="公司名称" align="center" prop="companyName" min-width="150">
+          <template slot-scope="scope">
+            <div class="company-name">
+              <i class="el-icon-office-building"></i>
+              {{ scope.row.companyName }}
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="申请数量" align="center" prop="applyQuantity" width="100">
+          <template slot-scope="scope">
+            <el-tag type="info" effect="plain">{{ scope.row.applyQuantity }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="实际分配数量" align="center" prop="allocatedQuantity" width="120">
+          <template slot-scope="scope">
+            <el-tag type="success" effect="plain">{{ scope.row.allocatedQuantity || 0 }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="提交时间" align="center" prop="submitTime" width="180">
+          <template slot-scope="scope">
+            <div class="time-info">
+              <i class="el-icon-time"></i>
+              <span>{{ parseTime(scope.row.submitTime) }}</span>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="审核时间" align="center" prop="reviewTime" width="180">
+          <template slot-scope="scope">
+            <div class="time-info" v-if="scope.row.reviewTime">
+              <i class="el-icon-check"></i>
+              <span>{{ parseTime(scope.row.reviewTime) }}</span>
+            </div>
+            <span v-else class="no-data">-</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="审核状态" align="center" prop="auditStatus" width="120">
+          <template slot-scope="scope">
+            <div class="status-wrapper">
+              <el-tag :class="getStatusClass(scope.row.auditStatus)"
+                :effect="scope.row.auditStatus === 1 ? 'dark' : 'light'">
+                <i :class="getStatusIcon(scope.row.auditStatus)"></i>
+                {{ getStatusText(scope.row.auditStatus) }}
+              </el-tag>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="拒绝原因" align="center" prop="rejectionReason" min-width="150">
+          <template slot-scope="scope">
+            <el-tooltip :content="scope.row.rejectionReason" placement="top" v-if="scope.row.rejectionReason">
+              <span class="rejection-reason">{{ scope.row.rejectionReason }}</span>
+            </el-tooltip>
+            <span v-else class="no-data">-</span>
+          </template>
+        </el-table-column>
+
+        <el-table-column label="操作" align="center" width="180" fixed="right">
+          <template slot-scope="scope">
+            <div class="action-buttons">
+              <el-tooltip content="同步数据" placement="top">
+                <el-button type="text" icon="el-icon-refresh" class="action-icon-btn sync-btn"
+                  @click="handleSingleSync(scope.row)" />
+              </el-tooltip>
+
+              <el-tooltip content="释放管理" placement="top"
+                v-if="scope.row.auditStatus == 1 || scope.row.auditStatus == 3">
+                <el-button type="text" icon="el-icon-unlock" class="action-icon-btn release-btn"
+                  @click="handleRelease(scope.row)" />
+              </el-tooltip>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 分页 -->
+      <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
+        @pagination="getList" class="pagination-wrapper" />
+    </el-card>
+
+    <!-- 申请iPad对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="600px" :close-on-click-modal="false"
+      custom-class="modern-dialog" append-to-body>
+      <div class="dialog-content">
+        <div class="form-header">
+          <i class="el-icon-mobile-phone"></i>
+          <span>请填写申请信息</span>
+        </div>
+
+        <el-form ref="form" :model="form" :rules="rules" label-width="100px" class="modern-form">
+          <el-form-item label="申请地区" prop="area">
+            <el-input v-model="form.area" placeholder="请输入申请地区,如:广州、上海、重庆、北京等"
+              prefix-icon="el-icon-location" class="area-input" />
+            <div class="form-tip">
+              <i class="el-icon-info"></i>
+              请填写申请iPad使用的地区
+            </div>
+          </el-form-item>
+          <el-form-item label="申请数量" prop="applyQuantity">
+            <el-input-number v-model="form.applyQuantity" :min="1" :max="100" controls-position="right"
+              class="number-input" placeholder="请输入申请数量" />
+            <div class="form-tip">
+              <i class="el-icon-info"></i>
+              建议根据实际需求申请合理数量
+            </div>
+          </el-form-item>
+        </el-form>
+      </div>
+
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="cancel" class="cancel-btn">取 消</el-button>
+        <el-button type="primary" @click="submitForm" :loading="submitting" class="confirm-btn">
+          {{ submitting ? '提交中...' : '确定申请' }}
+        </el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 释放信息抽屉 -->
+    <el-drawer title="服务器分配信息" :visible.sync="releaseOpen" direction="rtl" size="70%" :before-close="handleDrawerClose"
+      custom-class="modern-drawer">
+      <div class="drawer-content">
+        <el-table :data="serverInfoList" border v-loading="releaseLoading" class="server-table">
+          <el-table-column label="访问地址" align="center" prop="accessUrl" min-width="200">
+            <template slot-scope="scope">
+              <a :href="scope.row.accessUrl" target="_blank" class="access-url">
+                <i class="el-icon-link"></i>
+                {{ scope.row.accessUrl }}
+              </a>
+            </template>
+          </el-table-column>
+          <el-table-column label="已分配座位数" align="center" prop="allocatedSeats" width="120">
+            <template slot-scope="scope">
+              <el-tag type="primary">{{ scope.row.allocatedSeats }}</el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column label="分配时间" align="center" prop="allocatedTime" width="180">
+            <template slot-scope="scope">
+              <span>{{ parseTime(scope.row.allocatedTime) }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="分配状态" align="center" prop="allocationStatus" width="100">
+            <template slot-scope="scope">
+              <el-tag :type="scope.row.allocationStatus === 1 ? 'success' : 'info'">
+                {{ scope.row.allocationStatus === 1 ? '有效' : '已释放' }}
+              </el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column label="IP地址" align="center" prop="ipAddress" width="120" />
+          <el-table-column label="端口" align="center" prop="port" width="80" />
+          <el-table-column label="地区" align="center" prop="region" width="100" />
+          <el-table-column label="创建时间" align="center" prop="createdTime" width="180">
+            <template slot-scope="scope">
+              <span>{{ parseTime(scope.row.createdTime) }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作" align="center" width="120">
+            <template slot-scope="scope">
+              <el-button size="mini" type="primary" @click="handleReleaseSeats(scope.row)"
+                :disabled="scope.row.allocationStatus !== 1" class="release-seats-btn">
+                释放座位
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+    </el-drawer>
+
+    <!-- 释放座位数量输入弹窗 -->
+    <el-dialog title="释放座位" :visible.sync="releaseSeatsOpen" width="400px" custom-class="release-dialog" append-to-body>
+      <el-form :model="releaseForm" :rules="releaseRules" ref="releaseForm" label-width="100px">
+        <el-form-item label="释放数量" prop="releaseCount">
+          <el-input-number v-model="releaseForm.releaseCount" :min="1" :max="releaseForm.maxSeats" placeholder="请输入释放数量"
+            controls-position="right" style="width: 100%" />
+          <div class="form-tip">
+            <i class="el-icon-info"></i>
+            最大可释放数量:{{ releaseForm.maxSeats }}
+          </div>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="releaseSeatsOpen = false">取 消</el-button>
+        <el-button type="primary" @click="submitReleaseSeats()">确 定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listRecords, getServerInfo, getRecords, delRecords, release, updateRecords, exportRecords, apply, batchUpdate } from "@/api/qw/applyIpad";
+
+export default {
+  name: "Records",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 提交状态
+      submitting: false,
+      // 选中数组
+      ids: [],
+      // 选中的行数据
+      selectedRows: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 分配记录表格数据
+      recordsList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        companyId: null,
+        companyName: null,
+        applicationNumber: null,
+        applyQuantity: null,
+        allocatedQuantity: null,
+        submitTime: null,
+        reviewTime: null,
+        auditStatus: null,
+        rejectionReason: null,
+        createdTime: null,
+        updatedTime: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        area: [
+          { required: true, message: "申请地区不能为空", trigger: "blur" }
+        ],
+        applyQuantity: [
+          { required: true, message: "申请数量不能为空", trigger: "blur" },
+          { pattern: /^[1-9]\d*$/, message: "申请数量必须为正整数", trigger: "blur" }
+        ]
+      },
+      // 释放抽屉显示状态
+      releaseOpen: false,
+      // 释放信息加载状态
+      releaseLoading: false,
+      // 服务器信息列表
+      serverInfoList: [],
+      // 释放座位弹窗显示状态
+      releaseSeatsOpen: false,
+      // 释放座位表单
+      releaseForm: {
+        releaseCount: null,
+        maxSeats: 0,
+        currentServer: null
+      },
+      // 释放座位表单校验规则
+      releaseRules: {
+        releaseCount: [
+          { required: true, message: "释放数量不能为空", trigger: "blur" },
+          { type: 'number', min: 1, message: "释放数量必须大于0", trigger: "blur" },
+          {
+            validator: (rule, value, callback) => {
+              if (value > this.releaseForm.maxSeats) {
+                callback(new Error(`释放数量不能超过${this.releaseForm.maxSeats}`));
+              } else {
+                callback();
+              }
+            },
+            trigger: "blur"
+          }
+        ]
+      },
+      // 当前选中的申请记录ID
+      currentRecordId: null,
+      // 统计数据
+      statistics: {
+        pending: 0,
+        approved: 0,
+        rejected: 0,
+        total: 0
+      }
+    };
+  },
+  computed: {
+    // 是否可以批量审核通过
+    canBatchApprove() {
+      return this.selectedRows.some(row => row.auditStatus === 0);
+    },
+    // 是否可以批量审核拒绝
+    canBatchReject() {
+      return this.selectedRows.some(row => row.auditStatus === 0);
+    }
+  },
+  created() {
+    this.getList();
+    this.calculateStatistics();
+    // 添加键盘事件监听
+    document.addEventListener('keydown', this.handleKeydown);
+  },
+  beforeDestroy() {
+    document.removeEventListener('keydown', this.handleKeydown);
+  },
+  methods: {
+    /** 查询分配记录列表 */
+    getList() {
+      this.loading = true;
+      listRecords(this.queryParams).then(response => {
+        this.recordsList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+        this.calculateStatistics();
+      });
+    },
+
+    /** 计算统计数据 */
+    calculateStatistics() {
+      this.statistics = {
+        pending: this.recordsList.filter(item => item.auditStatus === 0).length,
+        approved: this.recordsList.filter(item => item.auditStatus === 1).length,
+        rejected: this.recordsList.filter(item => item.auditStatus === 2).length,
+        total: this.recordsList.length
+      };
+    },
+
+    /** 键盘事件处理 */
+    handleKeydown(e) {
+      // Ctrl + N: 新建申请
+      if (e.ctrlKey && e.key === 'n') {
+        e.preventDefault();
+        this.handleAdd();
+      }
+      // Ctrl + E: 导出数据
+      if (e.ctrlKey && e.key === 'e') {
+        e.preventDefault();
+        this.handleExport();
+      }
+      // F5: 刷新数据
+      if (e.key === 'F5') {
+        e.preventDefault();
+        this.getList();
+      }
+    },
+
+    /** 切换搜索显示 */
+    toggleSearch() {
+      this.showSearch = !this.showSearch;
+    },
+
+    /** 表格头部样式 */
+    headerCellClass({ row, column, rowIndex, columnIndex }) {
+      return 'modern-header';
+    },
+
+    /** 表格单元格样式 */
+    cellClass({ row, column, rowIndex, columnIndex }) {
+      return 'modern-cell';
+    },
+
+    /** 行点击事件 */
+    handleRowClick(row, column, event) {
+      // 可以添加行点击后的处理逻辑
+    },
+
+    /** 获取状态样式类 */
+    getStatusClass(status) {
+      const statusMap = {
+        0: 'status-pending',
+        1: 'status-approved',
+        2: 'status-rejected',
+        3: 'status-partial'
+      };
+      return statusMap[status] || '';
+    },
+
+    /** 获取状态图标 */
+    getStatusIcon(status) {
+      const iconMap = {
+        0: 'el-icon-time',
+        1: 'el-icon-check',
+        2: 'el-icon-close',
+        3: 'el-icon-warning'
+      };
+      return iconMap[status] || 'el-icon-question';
+    },
+
+    /** 获取状态文本 */
+    getStatusText(status) {
+      const textMap = {
+        0: '待审核',
+        1: '审核通过',
+        2: '审核拒绝',
+        3: '部分分配'
+      };
+      return textMap[status] || '-';
+    },
+
+    /** 批量命令处理 */
+    handleBatchCommand(command) {
+      if (command === 'sync') {
+        this.handleBatchSync();
+      } else if (command === 'export') {
+        this.handleExport();
+      }
+    },
+
+    /** 批量审核通过 */
+    batchApprove() {
+      const pendingRows = this.selectedRows.filter(row => row.auditStatus === 0);
+      if (pendingRows.length === 0) {
+        this.msgWarning('没有可审核通过的记录');
+        return;
+      }
+
+      this.$confirm(`确认审核通过选中的 ${pendingRows.length} 条记录?`, '批量审核', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        // 这里调用批量审核通过的API
+        this.msgSuccess('批量审核通过成功');
+        this.getList();
+      });
+    },
+
+    /** 批量审核拒绝 */
+    batchReject() {
+      const pendingRows = this.selectedRows.filter(row => row.auditStatus === 0);
+      if (pendingRows.length === 0) {
+        this.msgWarning('没有可审核拒绝的记录');
+        return;
+      }
+
+      this.$confirm(`确认审核拒绝选中的 ${pendingRows.length} 条记录?`, '批量审核', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        // 这里调用批量审核拒绝的API
+        this.msgSuccess('批量审核拒绝成功');
+        this.getList();
+      });
+    },
+
+    /** 清空选择 */
+    clearSelection() {
+      this.$refs.multipleTable && this.$refs.multipleTable.clearSelection();
+      this.selectedRows = [];
+      this.ids = [];
+    },
+
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        area: null,
+        applyQuantity: 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.selectedRows = selection;
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "申请iPad";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getRecords(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改分配记录";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          this.submitting = true;
+          // 调用apply接口,传递申请数量和地区作为参数对象
+          apply({
+            applyCount: this.form.applyQuantity,
+            area: this.form.area
+          }).then(response => {
+            this.msgSuccess("申请成功");
+            this.open = false;
+            this.getList();
+          }).catch(() => {
+            // this.msgError("申请失败");
+          }).finally(() => {
+            this.submitting = false;
+          });
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除分配记录编号为"' + ids + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function () {
+        return delRecords(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => { });
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm('是否确认导出所有分配记录数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return exportRecords(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => { });
+    },
+    /** 单个同步按钮操作 */
+    handleSingleSync(row) {
+      const id = row.id;
+      this.$confirm('是否确认同步编号为"' + id + '"的数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        return batchUpdate([id]);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("同步成功");
+      }).catch(() => { });
+    },
+    /** 批量同步按钮操作 */
+    handleBatchSync() {
+      const ids = this.ids;
+      this.$confirm('是否确认同步选中的' + ids.length + '条数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        return batchUpdate(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("批量同步成功");
+      }).catch(() => { });
+    },
+    /** 释放按钮操作 */
+    handleRelease(row) {
+      this.releaseLoading = true;
+      this.releaseOpen = true;
+      this.serverInfoList = [];
+      this.currentRecordId = row.id;
+
+      // 调用getServerInfo接口获取服务器信息
+      getServerInfo(row.id).then(response => {
+        this.serverInfoList = response.data || [];
+        this.releaseLoading = false;
+      }).catch(error => {
+        this.releaseLoading = false;
+        this.msgError("获取服务器信息失败");
+      });
+    },
+
+    /** 抽屉关闭处理 */
+    handleDrawerClose(done) {
+      this.releaseOpen = false;
+      done();
+    },
+
+    /** 释放座位按钮操作 */
+    handleReleaseSeats(server) {
+      this.releaseForm = {
+        releaseCount: null,
+        maxSeats: server.allocatedSeats || 0,
+        currentServer: server
+      };
+
+      this.releaseSeatsOpen = true;
+      this.$nextTick(() => {
+        this.$refs.releaseForm && this.$refs.releaseForm.clearValidate();
+      });
+    },
+
+    /** 提交释放座位 */
+    submitReleaseSeats() {
+      this.$refs.releaseForm.validate(valid => {
+        if (valid) {
+          // 根据后端ServerParam类结构组装参数
+          const params = {
+            ipadServerId: this.releaseForm.currentServer.ipadRecordId, // 服务器ID
+            recordId: this.currentRecordId,                 // 记录ID
+            releaseCount: this.releaseForm.releaseCount,    // 释放数量
+            ipAddress: this.releaseForm.currentServer.ipAddress, // iPad地址
+            port: this.releaseForm.currentServer.port       // 端口号
+          };
+
+          // 调用release接口
+          release(params).then(response => {
+            this.msgSuccess("释放成功");
+            this.releaseSeatsOpen = false;
+            // 重新加载服务器信息
+            this.handleRelease({ id: this.currentRecordId });
+          }).catch(error => {
+            this.msgError("释放失败");
+          });
+        }
+      });
+    },
+
+    /** 重置释放座位表单 */
+    resetReleaseForm() {
+      this.releaseForm = {
+        releaseCount: null,
+        maxSeats: 0,
+        currentServer: null
+      };
+      this.$refs.releaseForm && this.$refs.releaseForm.clearValidate();
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.app-container {
+  padding: 20px;
+  background: #f0f2f5;
+  min-height: calc(100vh - 84px);
+}
+
+// 统计卡片样式
+.statistics-cards {
+  margin-bottom: 20px;
+
+  .stat-card {
+    border-radius: 12px;
+    border: none;
+    transition: all 0.3s ease;
+
+    &:hover {
+      transform: translateY(-5px);
+      box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
+    }
+
+    .stat-content {
+      display: flex;
+      align-items: center;
+      padding: 10px;
+
+      .stat-icon {
+        width: 60px;
+        height: 60px;
+        border-radius: 12px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        margin-right: 15px;
+        font-size: 24px;
+        color: white;
+
+        &.pending {
+          background: #409eff;
+        }
+
+        &.approved {
+          background: #67c23a;
+        }
+
+        &.rejected {
+          background: #f56c6c;
+        }
+
+        &.total {
+          background: #909399;
+        }
+      }
+
+      .stat-info {
+        flex: 1;
+
+        .stat-value {
+          font-size: 28px;
+          font-weight: bold;
+          color: #2c3e50;
+          line-height: 1;
+        }
+
+        .stat-label {
+          font-size: 14px;
+          color: #7f8c8d;
+          margin-top: 5px;
+        }
+      }
+    }
+  }
+}
+
+// 搜索卡片样式
+.search-card {
+  border-radius: 12px;
+  margin-bottom: 20px;
+  border: none;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
+  transition: all 0.3s ease;
+
+  &:hover {
+    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
+  }
+
+  .search-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding-bottom: 15px;
+    border-bottom: 1px solid #ebeef5;
+    margin-bottom: 20px;
+
+    .search-title {
+      display: flex;
+      align-items: center;
+      font-size: 16px;
+      font-weight: 600;
+      color: #2c3e50;
+
+      i {
+        margin-right: 8px;
+        color: #409eff;
+      }
+    }
+  }
+
+  .search-form {
+
+    .search-input,
+    .search-select,
+    .search-date {
+      width: 100%;
+    }
+
+    .search-btn,
+    .reset-btn {
+      border-radius: 8px;
+      font-weight: 500;
+      transition: all 0.3s ease;
+    }
+
+    .search-btn:hover {
+      background-color: #66b1ff;
+    }
+
+    .reset-btn:hover {
+      color: #409eff;
+      border-color: #c6e2ff;
+      background-color: #ecf5ff;
+    }
+  }
+}
+
+// 批量操作工具栏
+.batch-toolbar {
+  margin-bottom: 20px;
+
+  .batch-card {
+    border-radius: 12px;
+    border: none;
+    background: #fdf6ec;
+
+    .batch-content {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+
+      .batch-info {
+        display: flex;
+        align-items: center;
+        color: #f39c12;
+        font-weight: 500;
+
+        i {
+          margin-right: 8px;
+          font-size: 18px;
+        }
+      }
+
+      .batch-actions {
+        display: flex;
+        gap: 10px;
+
+        .el-button {
+          border-radius: 6px;
+          font-weight: 500;
+        }
+      }
+    }
+  }
+}
+
+// 操作按钮区域
+.action-card {
+  border-radius: 12px;
+  margin-bottom: 20px;
+  border: none;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
+
+  .action-bar {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+
+    .action-group {
+      display: flex;
+      gap: 15px;
+
+      .action-btn {
+        border-radius: 4px;
+        font-weight: 500;
+        transition: all 0.3s ease;
+
+        &:hover {
+          opacity: 0.8;
+        }
+      }
+    }
+  }
+}
+
+// 表格卡片样式
+.table-card {
+  border-radius: 12px;
+  border: none;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
+  transition: all 0.3s ease;
+
+  &:hover {
+    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
+  }
+
+  .modern-table {
+    border-radius: 8px;
+    overflow: hidden;
+
+    ::v-deep .modern-header {
+      background: #f5f7fa;
+      color: #606266;
+      font-weight: 600;
+    }
+
+    ::v-deep .modern-cell {
+      .company-name {
+        display: flex;
+        align-items: center;
+
+        i {
+          margin-right: 5px;
+          color: #409eff;
+        }
+      }
+
+      .time-info {
+        display: flex;
+        align-items: center;
+        font-size: 12px;
+
+        i {
+          margin-right: 5px;
+          color: #909399;
+        }
+      }
+
+      .no-data {
+        color: #c0c4cc;
+      }
+
+      .rejection-reason {
+        max-width: 150px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+        display: inline-block;
+      }
+    }
+
+    ::v-deep .el-table__row {
+      transition: all 0.3s ease;
+
+      &:hover {
+        background-color: #f5f7fa;
+      }
+    }
+
+    .action-buttons {
+      display: flex;
+      justify-content: center;
+      gap: 10px;
+
+      .action-icon-btn {
+        width: 32px;
+        height: 32px;
+        border-radius: 6px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        transition: all 0.3s ease;
+
+        &:hover {
+          transform: scale(1.1);
+        }
+
+        &.sync-btn {
+          color: #409eff;
+
+          &:hover {
+            background: rgba(64, 158, 255, 0.1);
+          }
+        }
+
+        &.release-btn {
+          color: #e6a23c;
+
+          &:hover {
+            background: rgba(230, 162, 60, 0.1);
+          }
+        }
+      }
+    }
+  }
+
+  .pagination-wrapper {
+    margin-top: 20px;
+    text-align: right;
+  }
+}
+
+// 状态标签样式
+.status-wrapper {
+  .el-tag {
+    border-radius: 20px;
+    padding: 4px 12px;
+    font-weight: 500;
+    border: none;
+
+    i {
+      margin-right: 5px;
+    }
+
+    &.status-pending {
+      background-color: #e1f3d8;
+      color: #67c23a;
+      border-color: #e1f3d8;
+    }
+
+    &.status-approved {
+      background-color: #f0f9ff;
+      color: #409eff;
+      border-color: #f0f9ff;
+    }
+
+    &.status-rejected {
+      background-color: #fef0f0;
+      color: #f56c6c;
+      border-color: #fef0f0;
+    }
+
+    &.status-partial {
+      background-color: #fdf6ec;
+      color: #e6a23c;
+      border-color: #fdf6ec;
+    }
+  }
+}
+
+// 对话框样式
+::v-deep .modern-dialog {
+  border-radius: 12px;
+
+  .el-dialog__header {
+    background: #f5f7fa;
+    color: #606266;
+    border-radius: 12px 12px 0 0;
+    padding: 20px;
+
+    .el-dialog__title {
+      font-weight: 600;
+    }
+  }
+
+  .el-dialog__body {
+    padding: 30px 20px;
+  }
+
+  .dialog-content {
+    .form-header {
+      display: flex;
+      align-items: center;
+      margin-bottom: 20px;
+      padding-bottom: 15px;
+      border-bottom: 1px solid #ebeef5;
+
+      i {
+        margin-right: 10px;
+        color: #409eff;
+        font-size: 20px;
+      }
+
+      span {
+        font-size: 16px;
+        font-weight: 600;
+        color: #2c3e50;
+      }
+    }
+
+    .modern-form {
+      .area-input {
+        width: 100%;
+      }
+      
+      .number-input {
+        width: 100%;
+      }
+
+      .form-tip {
+        display: flex;
+        align-items: center;
+        color: #909399;
+        font-size: 12px;
+        margin-top: 5px;
+
+        i {
+          margin-right: 5px;
+        }
+      }
+    }
+  }
+
+  .dialog-footer {
+    text-align: right;
+    padding: 15px 20px;
+    border-top: 1px solid #ebeef5;
+
+    .cancel-btn,
+    .confirm-btn {
+      border-radius: 8px;
+      font-weight: 500;
+      transition: all 0.3s ease;
+    }
+
+    .confirm-btn:hover {
+      background-color: #66b1ff;
+    }
+  }
+}
+
+// 抽屉样式
+::v-deep .modern-drawer {
+  .el-drawer__header {
+    background: #f5f7fa;
+    color: #606266;
+    padding: 20px;
+    margin-bottom: 0;
+
+    span {
+      font-weight: 600;
+    }
+  }
+
+  .drawer-content {
+    padding: 20px;
+
+    .server-table {
+      border-radius: 8px;
+      overflow: hidden;
+
+      .access-url {
+        color: #409eff;
+        text-decoration: none;
+
+        &:hover {
+          text-decoration: underline;
+        }
+
+        i {
+          margin-right: 5px;
+        }
+      }
+
+      .release-seats-btn {
+        border-radius: 6px;
+        font-weight: 500;
+      }
+    }
+  }
+}
+
+// 释放对话框样式
+::v-deep .release-dialog {
+  border-radius: 12px;
+
+  .el-dialog__header {
+    background: #f5f7fa;
+    color: #606266;
+    border-radius: 12px 12px 0 0;
+
+    .el-dialog__title {
+      font-weight: 600;
+    }
+  }
+}
+
+// 响应式设计
+@media (max-width: 768px) {
+  .app-container {
+    padding: 10px;
+  }
+
+  .statistics-cards {
+    .el-col {
+      margin-bottom: 10px;
+    }
+  }
+
+  .search-form {
+    .el-col {
+      margin-bottom: 10px;
+    }
+  }
+
+  .action-bar {
+    flex-direction: column;
+    align-items: stretch;
+
+    .action-group {
+      margin-bottom: 10px;
+      justify-content: center;
+    }
+  }
+
+  .batch-content {
+    flex-direction: column;
+    align-items: flex-start;
+
+    .batch-actions {
+      margin-top: 10px;
+      flex-wrap: wrap;
+    }
+  }
+}
+</style>

+ 21 - 1
src/views/system/config/config.vue

@@ -730,6 +730,16 @@
       <el-tab-pane label="短信配置" name="his.sms">
 
         <el-form ref="form14" :model="form14" label-width="150px">
+          <el-form-item label="是否开启APP短信验证" label-width="160px">
+            <el-switch
+              v-model="form14.isSmsVerification"
+              active-color="#13ce66"
+              inactive-color="#ff4949"
+              active-value="1"
+              inactive-value="0"
+            >
+            </el-switch>
+          </el-form-item>
           <el-form-item label="短信服务商" prop="type">
             <el-radio-group v-model="form14.type">
               <el-radio label="rf">重庆润芳</el-radio>
@@ -1248,6 +1258,13 @@
               <el-radio label="0">关</el-radio>
             </el-radio-group>
           </el-form-item>
+          <!-- 看视频休息暂停配置开关 默认打开要暂停 0-关闭 1-打开 -->
+          <el-form-item label="看课休息暂停开关(默认打开)">
+            <el-radio-group v-model="form18.isOpenRestReminder">
+              <el-radio label="1" >开</el-radio>
+              <el-radio label="0">关</el-radio>
+            </el-radio-group>
+          </el-form-item>
 
 
           <el-form-item label="禁止发送时间段">
@@ -2325,7 +2342,7 @@ export default {
       form16: {},
       form17: {},
       form18: {
-        viewCommentNum: 200
+        viewCommentNum: 200,
       },
       form19: {},
       form20: {
@@ -2920,6 +2937,9 @@ export default {
       })
     },
     submitForm14() {
+      if (!this.form14.isSmsVerification) {
+        this.form14.isSmsVerification = 0;
+      }
       var param = { configId: this.configId, configValue: JSON.stringify(this.form14) }
       updateConfigByKey(param).then(response => {
         if (response.code === 200) {