Просмотр исходного кода

Merge remote-tracking branch 'origin/master'

yjwang 4 дней назад
Родитель
Сommit
f2eea468d1
33 измененных файлов с 2259 добавлено и 178 удалено
  1. 37 0
      .env.prod-jkj
  2. 1 0
      package.json
  3. 7 0
      src/api/course/qw/courseWatchLog.js
  4. 7 7
      src/api/course/userCourseComplaintRecord.js
  5. 18 0
      src/api/course/userCoursePeriod.js
  6. 9 1
      src/api/course/userTalent.js
  7. 10 0
      src/api/his/userOperationLog.js
  8. 9 1
      src/api/live/liveVideo.js
  9. BIN
      src/assets/logo/jkj.png
  10. 7 7
      src/components/ImageUpload/index.vue
  11. 4 4
      src/components/Material/index.vue
  12. 13 0
      src/router/index.js
  13. 2 1
      src/views/components/his/userAddDetails.vue
  14. 2 0
      src/views/components/his/userDetails.vue
  15. 12 1
      src/views/course/userCourse/index.vue
  16. 139 37
      src/views/course/userCourseComplaintRecord/index.vue
  17. 101 10
      src/views/course/userTalent/index.vue
  18. 11 9
      src/views/his/user/index.vue
  19. 460 0
      src/views/his/user/userBehavior.vue
  20. 173 0
      src/views/his/user/userCourseConversionRecord.vue
  21. 476 0
      src/views/his/user/userCoursePeriod.vue
  22. 222 0
      src/views/his/user/userCoursePeriodDetails.vue
  23. 57 0
      src/views/his/user/userCourseStatic.vue
  24. 71 0
      src/views/his/user/userDetails.vue
  25. 248 0
      src/views/his/user/userStaticAll.vue
  26. 10 1
      src/views/live/live/index.vue
  27. 76 68
      src/views/live/liveAnchor/index.vue
  28. 3 3
      src/views/live/liveData/index.vue
  29. 19 8
      src/views/live/liveGoods/index.vue
  30. 15 7
      src/views/live/liveOrder/index.vue
  31. 14 6
      src/views/live/liveOrderitems/index.vue
  32. 15 7
      src/views/live/liveVideo/index.vue
  33. 11 0
      src/views/system/config/config.vue

+ 37 - 0
.env.prod-jkj

@@ -0,0 +1,37 @@
+# 页面标题
+VUE_APP_TITLE =金康健互联网医院管理系统
+# 首页菜单标题
+VUE_APP_TITLE_INDEX =金康健互联网医院
+# 公司名称
+VUE_APP_COMPANY_NAME =西安金康健医药有限公司
+# ICP备案号
+VUE_APP_ICP_RECORD =陕ICP备2024035932号-15
+# ICP网站访问地址
+VUE_APP_ICP_URL =https://beian.miit.gov.cn
+# 网站LOG
+VUE_APP_LOG_URL =@/assets/logo/jkj.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 = jkj-hw079058881
+# 存储桶配置
+VUE_APP_COS_BUCKET = jkj-1323137866
+# 存储桶配置
+VUE_APP_COS_REGION = ap-chongqing
+# 线路一地址
+VUE_APP_VIDEO_LINE_1 = https://jkjtcpv.ylrzcloud.com
+# 线路二地址
+VUE_APP_VIDEO_LINE_2 = https://jkjobs.ylrztop.com
+
+# 开发环境配置
+ENV = 'production'
+
+# FS管理系统/开发环境
+VUE_APP_BASE_API = '/prod-api'
+
+# 路由懒加载
+VUE_CLI_BABEL_TRANSPILE_MODULES = true

+ 1 - 0
package.json

@@ -25,6 +25,7 @@
     "build:prod-whhm": "vue-cli-service build --mode prod-whhm",
     "build:prod-drk": "vue-cli-service build --mode prod-drk",
     "build:prod-qdtst": "vue-cli-service build --mode prod-qdtst",
+    "build:prod-jkj": "vue-cli-service build --mode prod-jkj",
     "build:stage": "vue-cli-service build --mode staging",
     "preview": "node build/index.js --preview",
     "lint": "eslint --ext .js,.vue src"

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

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

+ 7 - 7
src/api/course/userCourseComplaintRecord.js

@@ -9,13 +9,13 @@ export function listUserCourseComplaintRecord(query) {
   })
 }
 
-// // 查询看课投诉记录详细
-// export function getUserCourseComplaintRecord(recordId) {
-//   return request({
-//     url: '/course/userCourseComplaintRecord/' + recordId,
-//     method: 'get'
-//   })
-// }
+// 查询看课投诉记录详细
+export function getUserCourseComplaintRecord(recordId) {
+  return request({
+    url: '/course/userCourseComplaintRecord/' + recordId,
+    method: 'get'
+  })
+}
 //
 // // 新增看课投诉记录
 // export function addUserCourseComplaintRecord(data) {

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

@@ -181,3 +181,21 @@ export function delPeriodDay(periodId) {
     method: 'delete'
   })
 }
+
+
+export function periodCourseStatisticCount(data) {
+  return request({
+    url: '/course/period/periodCourseStatisticCount',
+    method: 'post',
+    data: data
+  })
+}
+
+// 查询该会员下该训练营下操作过的所有营期
+export function periodList(data) {
+  return request({
+    url: '/course/period/periodlist',
+    method: 'post',
+    data: data
+  })
+}

+ 9 - 1
src/api/course/userTalent.js

@@ -66,4 +66,12 @@ export function listBySearch(query) {
     method: 'get',
     params: query
   })
-}
+}
+
+//查询所属销售公司
+export function getCompanies(keyword) {
+  return request({
+    url: '/course/userTalent/listCompanyByKeyword/'+keyword,
+    method: 'get'
+  })
+}

+ 10 - 0
src/api/his/userOperationLog.js

@@ -0,0 +1,10 @@
+import request from '@/utils/request'
+
+// 查询用户操作日志对象列表
+export function listUserOperationLog(query) {
+  return request({
+    url: '/his/userOperationLog/list',
+    method: 'get',
+    params: query
+  })
+}

+ 9 - 1
src/api/live/liveVideo.js

@@ -17,6 +17,14 @@ export function getLiveVideo(videoId) {
   })
 }
 
+// 查询直播视频详细
+export function getLiveVideoByLiveId(liveId) {
+  return request({
+    url: '/live/liveVideo/liveVideoByLiveId/' + liveId,
+    method: 'get'
+  })
+}
+
 // 新增直播视频
 export function addLiveVideo(data) {
   return request({
@@ -50,4 +58,4 @@ export function exportLiveVideo(query) {
     method: 'get',
     params: query
   })
-}
+}

BIN
src/assets/logo/jkj.png


+ 7 - 7
src/components/ImageUpload/index.vue

@@ -165,8 +165,8 @@ export default {
           // 文件大于1MB时进行压缩
           this.compressImage(file).then((compressedFile) => {
             loadingInstance.close();
-            if (compressedFile.size / 1024 > 500) {
-              this.$message.error('图片压缩后仍大于500KB');
+            if (compressedFile.size / 1024 > 1000) {
+              this.$message.error('图片压缩后仍大于1000KB');
               reject();
             } else {
               // this.$message.success(`图片压缩成功,最终质量为: ${this.finalQuality.toFixed(2)}`);
@@ -195,7 +195,7 @@ export default {
       //     return false;
       //   }
       // }
-      
+
     },
     compressImage(file) {
       return new Promise((resolve, reject) => {
@@ -215,16 +215,16 @@ export default {
 
             let quality = 1; // 初始压缩质量
             let dataURL = canvas.toDataURL('image/jpeg', quality);
-            
+
             // 逐步压缩,直到图片大小小于500KB并且压缩质量不再降低
             while (dataURL.length / 1024 > 500 && quality > 0.1) {
               quality -= 0.01;
               dataURL = canvas.toDataURL('image/jpeg', quality);
             }
             this.finalQuality = quality; // 存储最终的压缩质量
-            
-            if (dataURL.length / 1024 > 500) {
-              reject(new Error('压缩后图片仍然大于500KB'));
+
+            if (dataURL.length / 1024 > 1000) {
+              reject(new Error('压缩后图片仍然大于1000KB'));
               return;
             }
 

+ 4 - 4
src/components/Material/index.vue

@@ -367,8 +367,8 @@ export default {
           // 文件大于1MB时进行压缩
           this.compressImage(file).then((compressedFile) => {
             loadingInstance.close();
-            if (compressedFile.size / 1024 > 500) {
-              this.$message.error('图片压缩后仍大于500KB');
+            if (compressedFile.size / 1024 > 1000) {
+              this.$message.error('图片压缩后仍大于1M');
               reject();
             } else {
               // this.$message.success(`图片压缩成功,最终质量为: ${this.finalQuality.toFixed(2)}`);
@@ -417,8 +417,8 @@ export default {
             }
             this.finalQuality = quality; // 存储最终的压缩质量
 
-            if (dataURL.length / 1024 > 500) {
-              reject(new Error('压缩后图片仍然大于500KB'));
+            if (dataURL.length / 1024 > 1000) {
+              reject(new Error('压缩后图片仍然大于1000KB'));
               return;
             }
 

+ 13 - 0
src/router/index.js

@@ -228,6 +228,19 @@ export const constantRoutes = [
       }
     ]
   },
+  {
+    path: '/live',
+    component: Layout,
+    hidden: true,
+    children: [
+      {
+        path: 'LiveConsole/:liveId', // 动态路由参数
+        component: () => import('@/views/live/liveConsole'), // 使用 import 动态加载
+        name: 'LiveConsole',
+        meta: { title: '直播中控台', activeMenu: '/live/liveConsole' }
+      }
+    ]
+  }
 ]
 
 export default new Router({

+ 2 - 1
src/views/components/his/userAddDetails.vue

@@ -115,6 +115,8 @@ export default {
       open: false,
       cityIds:null,
       address:null,
+      citys:[],
+
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -179,7 +181,6 @@ export default {
     });
   },
   methods: {
-     citys:[],
     /** 查询用户地址列表 */
     getList() {
       this.loading = true;

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

@@ -1,9 +1,11 @@
 <template>
 
 <div style="background-color: #f0f2f5; padding-bottom: 20px; min-height: 100%; " >
+<!--
   <div style="padding: 20px; background-color: #fff;">
     会员详情
   </div>
+-->
 
   <div class="contentx" v-if="item!=null" >
     <div class="desct">

+ 12 - 1
src/views/course/userCourse/index.vue

@@ -31,6 +31,16 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
+      <el-form-item label="关联的公司" prop="companyIds">
+        <el-select v-model="queryParams.companyIdsList" multiple placeholder="请选择公司" filterable clearable style="width: 90%;">
+          <el-option
+            v-for="dict in companyOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
       <el-form-item label="课堂类型" prop="isPrivate" style="display: none">
         <el-select v-model="queryParams.isPrivate" placeholder="请选择" clearable size="small">
           <el-option
@@ -350,7 +360,8 @@ export default {
         hotRanking: null,
         integral: null,
         price: null,
-        isPrivate: 1
+        isPrivate: 1,
+        companyIdsList:[],
       },
       // 表单参数
       form: {},

+ 139 - 37
src/views/course/userCourseComplaintRecord/index.vue

@@ -87,6 +87,13 @@
 <!--            @click="handleDelete(scope.row)"-->
 <!--            v-hasPermi="['course:userCourseComplaintRecord:remove']"-->
 <!--          >删除</el-button>-->
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-info"
+            @click="handleDetails(scope.row)"
+            v-hasPermi="['course:userCourseComplaintRecord:edit']"
+          >详情</el-button>
           <el-button
             size="mini"
             type="text"
@@ -106,32 +113,55 @@
       @pagination="getList"
     />
 
-    <!-- 添加或修改看课投诉记录对话框 -->
-<!--    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>-->
-<!--      <el-form ref="form" :model="form" :rules="rules" label-width="80px">-->
-<!--        <el-form-item label="用户昵称" prop="nickName">-->
-<!--          <el-input v-model="form.nickName" placeholder="请输入用户昵称" />-->
-<!--        </el-form-item>-->
-<!--        <el-form-item label="投诉类型" prop="complaintTypeName">-->
-<!--          <el-input v-model="form.complaintTypeName" placeholder="请输入投诉类型" />-->
+<!--     投诉记录详情对话框-->
+    <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="用户昵称" prop="nickName">
+          <el-input v-model="form.nickName" readonly />
+        </el-form-item>
+        <el-form-item label="投诉类型" prop="complaintTypeName">
+          <el-input v-model="form.complaintTypeName" readonly />
+        </el-form-item>
+        <el-form-item label="投诉内容" prop="complaintContent">
+          <el-input v-model="form.complaintContent" type="textarea" :rows="4" readonly />
+        </el-form-item>
+        <el-form-item label="投诉上传图片">
+          <div v-if="imageList.length > 0" class="image-preview-container">
+            <div v-for="(imageUrl, index) in imageList" :key="index" class="image-item">
+              <el-image
+                :src="imageUrl"
+                :preview-src-list="imageList"
+                fit="cover"
+                class="preview-image"
+                @click="previewImage(index)"
+              >
+                <div slot="error" class="image-slot">
+                  <i class="el-icon-picture-outline"></i>
+                </div>
+              </el-image>
+            </div>
+          </div>
+          <span v-else class="no-image-text">暂无图片</span>
+        </el-form-item>
+        <el-form-item label="所属课程" prop="courseName">
+          <el-input v-model="form.courseName" readonly />
+        </el-form-item>
+        <el-form-item label="所属小节" prop="title">
+          <el-input v-model="form.title" readonly />
+        </el-form-item>
+<!--        <el-form-item label="创建时间" prop="createTime">-->
+<!--          <el-input v-model="form.createTime" readonly />-->
 <!--        </el-form-item>-->
-<!--        <el-form-item label="所属课程" prop="courseName">-->
-<!--          <el-input v-model="form.courseName" placeholder="请输入所属课程" />-->
-<!--        </el-form-item>-->
-<!--        <el-form-item label="所属小节" prop="title">-->
-<!--          <el-input v-model="form.title" 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-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="cancel">关 闭</el-button>
+      </div>
+    </el-dialog>
   </div>
 </template>
 
 <script>
-import { listUserCourseComplaintRecord, delUserCourseComplaintRecord, exportUserCourseComplaintRecord } from "@/api/course/userCourseComplaintRecord";
+import { listUserCourseComplaintRecord, delUserCourseComplaintRecord, exportUserCourseComplaintRecord, getUserCourseComplaintRecord } from "@/api/course/userCourseComplaintRecord";
 import { addBlack } from "@/api/course/courseWatchComment";
 export default {
   name: "UserCourseComplaintRecord",
@@ -157,6 +187,8 @@ export default {
       title: "",
       // 是否显示弹出层
       open: false,
+      // 图片列表
+      imageList: [],
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -199,15 +231,17 @@ export default {
         recordId: null,
         nickName: null,
         complaintTypeName: null,
+        complaintContent: null,
+        complaintUrl: null,
         courseName: null,
         title: null,
-        createTime: null
-        // userId: null,
-        // complaintTypeId: null,
-        // complaintContent: null,
-        // courseId: null,
-        // videoId: null,
+        createTime: null,
+        userId: null,
+        complaintTypeId: null,
+        courseId: null,
+        videoId: null,
       };
+      this.imageList = [];
       this.resetForm("form");
     },
     /** 搜索按钮操作 */
@@ -232,16 +266,29 @@ export default {
     //   this.open = true;
     //   this.title = "添加看课投诉记录";
     // },
-    // /** 修改按钮操作 */
-    // handleUpdate(row) {
-    //   this.reset();
-    //   const recordId = row.recordId || this.ids
-    //   getUserCourseComplaintRecord(recordId).then(response => {
-    //     this.form = response.data;
-    //     this.open = true;
-    //     this.title = "修改看课投诉记录";
-    //   });
-    // },
+    /** 详情按钮操作 */
+    handleDetails(row) {
+      this.reset();
+      const recordId = row.recordId || this.ids
+      getUserCourseComplaintRecord(recordId).then(response => {
+        this.form = response.data;
+        // 处理多个图片URL,通过逗号分割
+        if (this.form.complaintUrl) {
+          this.imageList = this.form.complaintUrl.split(',').filter(url => url.trim() !== '');
+        } else {
+          this.imageList = [];
+        }
+        this.open = true;
+        this.title = "看课投诉记录详情";
+      }).catch(error => {
+        console.error('获取详情失败:', error);
+        this.msgError("获取详情失败,请稍后重试");
+      });
+    },
+    /** 预览图片 */
+    previewImage(index) {
+      // Element UI的图片组件会自动处理预览
+    },
     // /** 提交按钮 */
     // submitForm() {
     //   this.$refs["form"].validate(valid => {
@@ -315,3 +362,58 @@ export default {
   }
 };
 </script>
+
+<style scoped>
+.image-preview-container {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+}
+
+.image-item {
+  width: 100px;
+  height: 100px;
+  border: 1px solid #dcdfe6;
+  border-radius: 6px;
+  overflow: hidden;
+  cursor: pointer;
+}
+
+.preview-image {
+  width: 100%;
+  height: 100%;
+}
+
+.image-slot {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 100%;
+  height: 100%;
+  background: #f5f7fa;
+  color: #909399;
+  font-size: 20px;
+}
+
+.no-image-text {
+  color: #909399;
+  font-size: 14px;
+}
+
+/* 只读表单样式优化 */
+.el-input.is-disabled .el-input__inner,
+.el-input__inner[readonly] {
+  background-color: #f5f7fa;
+  border-color: #e4e7ed;
+  color: #606266;
+  cursor: not-allowed;
+}
+
+.el-textarea.is-disabled .el-textarea__inner,
+.el-textarea__inner[readonly] {
+  background-color: #f5f7fa;
+  border-color: #e4e7ed;
+  color: #606266;
+  cursor: not-allowed;
+}
+</style>

+ 101 - 10
src/views/course/userTalent/index.vue

@@ -19,6 +19,28 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
+      <el-form-item label="所属公司" prop="companyIds" >
+        <el-select
+          v-model="companyIds"
+          filterable
+          multiple
+          remote
+          reserve-keyword
+          placeholder="请输入关键字搜索"
+          :remote-method="fetchCompanies"
+          :loading="loadingCompanies"
+          size="small"
+          @change="formatCompanies"
+          style="width: 180px"
+        >
+          <el-option
+            v-for="company in companyOptions"
+            :key="company.companyId"
+            :label="company.companyName"
+            :value="company.companyId"
+          />
+        </el-select>
+      </el-form-item>
 
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
@@ -141,7 +163,7 @@
         </template>
       </el-table-column>
     </el-table>
-    
+
     <pagination
       v-show="total>0"
       :total="total"
@@ -151,15 +173,15 @@
     />
 
     <!-- 添加或修改达人对话框 -->
-    <el-dialog :title="title" :visible.sync="open" width="1000px" append-to-body>
+    <el-dialog :title="title" :visible.sync="open" width="1000px" append-to-body @close="handleClose">>
       <el-form ref="form" :model="form" :rules="rules" label-width="80px">
-        <el-row>
-          <el-col :span="8">
+        <el-row :gutter="20">
+          <el-col :span="12">
             <el-form-item label="昵称" prop="nickName">
               <el-input v-model="form.nickName" placeholder="请输入昵称" />
             </el-form-item>
           </el-col>
-          <el-col :span="8">
+          <el-col :span="12">
             <el-form-item label="性别" prop="sex">
               <el-select v-model="form.sex" placeholder="性别" clearable size="small">
                 <el-option
@@ -171,7 +193,9 @@
               </el-select>
             </el-form-item>
           </el-col>
-          <el-col :span="8">
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
             <el-form-item label="关联用户" prop="userId" >
               <el-select v-model="form.userId" remote filterable reserve-keyword placeholder="输入手机号搜索" @change="selectUser" :remote-method="userMethod" >
                 <el-option
@@ -186,6 +210,25 @@
               </el-select>
             </el-form-item>
           </el-col>
+          <el-col :span="12">
+            <el-form-item label="关联公司" prop="companyId" >
+              <el-select v-model="form.companyId"
+                         remote
+                         filterable
+                         reserve-keyword
+                         placeholder="输入公司名称搜索"
+                         :remote-method="fetchCompanies" >
+                <el-option
+                  v-for="item in companyOptions"
+                  :key="item.companyId"
+                  :label="item.companyId"
+                  :value="item.companyId">
+                  <span style="float: left">{{ item.companyId }}</span>
+                  <span style="margin-left: 30px ;">{{item.companyName}}</span>
+                </el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
         </el-row>
 
         <el-form-item label="头像" prop="avatar">
@@ -194,8 +237,8 @@
         <el-form-item label="标题" prop="title">
           <el-input v-model="form.title" type="textarea" placeholder="请输入内容" />
         </el-form-item>
-        
-        
+
+
         <el-row>
           <el-col :span="8">
             <el-form-item label="获赞数" prop="likes">
@@ -262,7 +305,16 @@
 </template>
 
 <script>
-import { listUserTalent, getUserTalent, delUserTalent, addUserTalent, updateUserTalent, exportUserTalent,auditUserTalent } from "@/api/course/userTalent";
+import {
+  listUserTalent,
+  getUserTalent,
+  delUserTalent,
+  addUserTalent,
+  updateUserTalent,
+  exportUserTalent,
+  auditUserTalent,
+  getCompanies
+} from '@/api/course/userTalent'
 import { listBySearch} from "@/api/his/user";
 import ImageUpload from '@/components/ImageUpload/index';
 import VideoUpload from '@/components/VideoUpload/index';
@@ -302,6 +354,8 @@ export default {
       },
       userList:[],
       tagsOptions:[],
+      companyOptions:[],
+      loadingCompanies: false, // 加载状态
       tags:[],
       sexOptions:[],
       // 遮罩层
@@ -339,8 +393,11 @@ export default {
         fans: null,
         likes: null,
         isDel: null,
-        isAudit:0
+        isAudit:0,
+        //销售公司
+        companyIdStr: null
       },
+      companyIds: [],
       // 表单参数
       form: {},
       // 表单校验
@@ -359,6 +416,9 @@ export default {
         ],
         title: [
           { required: true, message: "标题不能为空", trigger: "blur" }
+        ],
+        companyId: [
+          { required: true, message: "关联公司不能为空", trigger: "change" }
         ]
       }
     };
@@ -379,6 +439,27 @@ export default {
     handleVideoDuration(duration) {
       this.form.videoDuration = duration;
     },
+    async fetchCompanies(query) {
+      if (!query) {
+        this.companyOptions = [];
+        return;
+      }
+      this.loadingCompanies = true;
+      try {
+        getCompanies(query).then(response => {
+          this.companyOptions = response.data;
+        })
+      } catch (err) {
+        console.error('查询销售公司失败:', err);
+        this.companyOptions = [];
+      } finally {
+        this.loadingCompanies = false;
+      }
+    },
+    formatCompanies(){
+      if(this.companyIds)
+      this.queryParams.companyIdStr = this.companyIds.join(',');
+    },
     submitAuditForm(){
       this.$refs["auditForm"].validate(valid => {
         if(valid){
@@ -464,8 +545,14 @@ export default {
     /** 重置按钮操作 */
     resetQuery() {
       this.resetForm("queryForm");
+      this.resetCompany();
       this.handleQuery();
     },
+    resetCompany() {
+      this.companyOptions =  [];
+      this.companyIds = [];
+      this.queryParams.companyIdStr=null;
+    },
     // 多选框选中数据
     handleSelectionChange(selection) {
       this.ids = selection.map(item => item.talentId)
@@ -494,6 +581,10 @@ export default {
         this.title = "修改达人";
       });
     },
+    /**修改页面关闭方法*/
+    handleClose(){
+        this.resetCompany();
+    },
     /** 提交按钮 */
     submitForm() {
       this.$refs["form"].validate(valid => {

+ 11 - 9
src/views/his/user/index.vue

@@ -6,7 +6,7 @@
           v-model="queryCompanyId"
           placeholder="请选择所属公司"
           clearable
-          filterable 
+          filterable
           size="small"
           @change="handleQueryCompanyChange"
         >
@@ -19,12 +19,12 @@
         </el-select>
       </el-form-item>
       <el-form-item label="所属销售" prop="companyUserId">
-        
+
         <el-select
           v-model="queryCompanyUserId"
           placeholder="请选择所属销售"
           clearable
-          filterable 
+          filterable
           size="small"
         >
           <el-option
@@ -34,7 +34,7 @@
             :value="item.userId">
           </el-option>
         </el-select>
-      </el-form-item>    
+      </el-form-item>
       <el-form-item label="会员ID" prop="userId">
         <el-input
           v-model="queryParams.userId"
@@ -103,12 +103,12 @@
       <el-form-item label="注册时间" prop="createTime">
                 <el-date-picker v-model="createTime" size="small" style="width: 230px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" @change="change"></el-date-picker>
       </el-form-item>
-          
+
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
         <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
       </el-form-item>
-      
+
     </el-form>
 
     <el-row :gutter="10" class="mb8">
@@ -230,7 +230,8 @@
            :with-header="false"
             size="75%"
              :title="show.title" :visible.sync="show.open">
-         <userDetails  ref="userDetails" />
+<!--         <userDetails  ref="userDetails" />-->
+         <userDetailsByNew  ref="userDetailsByNew" />
        </el-drawer>
 
     <!-- 更换会员归属对话框 -->
@@ -269,10 +270,11 @@
 import { listUser, getUser, delUser, addUser, updateUser, exportUser } from "@/api/his/user";
 import { getCompanyUserList, changeCompanyUser, getCompanyList } from '@/api/company/companyUser';
 import userDetails from '../../components/his/userDetails.vue';
+import userDetailsByNew from './userDetails.vue';
 
 export default {
   name: "User",
-  components: {userDetails},
+  components: {userDetails,userDetailsByNew},
   data() {
     return {
       companyQueryOptions:[],
@@ -402,7 +404,7 @@ export default {
     handledetails(row){
             this.show.open=true;
             setTimeout(() => {
-                 this.$refs.userDetails.getDetails(row.userId);
+                 this.$refs.userDetailsByNew.getDetails(row.userId);
             }, 1);
      },
      handleQueryCompanyChange(companyId){

+ 460 - 0
src/views/his/user/userBehavior.vue

@@ -0,0 +1,460 @@
+<template>
+  <div class="behavior-track-container">
+    <!-- 筛选区域 -->
+    <div class="filter-section">
+      <div class="filter-item">
+        <label>操作类型:</label>
+        <el-select
+          v-model="queryParams.operationType"
+          class="type-select"
+          @change="handleTypeChange"
+          placeholder="请选择行为类型"
+          clearable
+        >
+          <el-option
+            v-for="item in typeList"
+            :key="item.dictValue"
+            :label="item.dictLabel"
+            :value="item.dictLabel"
+          ></el-option>
+        </el-select>
+      </div>
+    </div>
+    <div v-if="steps.length === 0" class="no-data">
+      <p>暂无数据</p>
+    </div>
+    <!-- 按日期分组展示(分页后的数据) -->
+    <div v-if="steps.length != 0" v-for="(records, date) in groupedPaginatedSteps" :key="date" class="date-group">
+      <!-- 日期标题(如果是今天,显示“今天”,否则显示具体日期) -->
+      <div class="date-title">
+        {{ isToday(date) ? '今天' : date }}
+      </div>
+      <div class="date-divider"></div>
+
+      <!-- 当前日期下的记录 -->
+      <el-steps
+        direction="vertical"
+        :space="120"
+        process-status="process"
+        finish-status="success"
+        class="custom-steps"
+      >
+        <el-step
+          v-for="(step, index) in records"
+          :key="index"
+          :icon="index === 0 ? 'el-icon-s-help' : 'el-icon-bangzhu'"
+        >
+          <template #title>
+            <div class="step-title">
+              {{ step.operationType }}
+              <span class="step-time">{{ step.createTime }}</span> <!-- 每个步骤的时间 -->
+            </div>
+          </template>
+          <template #description>
+            <!-- 答题 -->
+            <div v-if="step.operationType == '答题'" class="step-content">
+              <!-- 第一行 -->
+              <div class="step-row first-row">
+                <div v-if="step.paramVo" class="detail-item">
+                  <span class="detail-label"><i class="el-icon-notebook-2"></i> 课节名称:</span>
+                  <span class="detail-value">{{ step.paramVo.courseName }}</span>
+                </div>
+              </div>
+
+              <!-- 第二行 -->
+              <div v-if="step.details" class="step-row second-row">
+                <div class="detail-item">
+                  <span class="detail-label"><i class="el-icon-chat-dot-round"></i> 备注:</span>
+                  <span class="detail-value">{{ step.details }}</span>
+                </div>
+              </div>
+            </div>
+
+            <!-- 发放奖励 -->
+            <div v-else-if="step.operationType == '发送奖励'" class="step-content">
+              <!-- 第一行 -->
+              <div class="step-row first-row">
+                <div v-if="step.paramVo" class="detail-item">
+                  <span class="detail-label"><i class="el-icon-gift"></i> 课程名称:</span>
+                  <span class="detail-value">{{ step.paramVo.courseName }}</span>
+                </div>
+                <div v-if="step.paramVo" class="detail-item">
+                  <span class="detail-label"><i class="el-icon-coin"></i> 小节名称:</span>
+                  <span class="detail-value">{{ step.paramVo.title }}</span>
+                </div>
+                <div v-if="step.fsCourseRedPacketLog" class="detail-item">
+                  <span class="detail-label"><i class="el-icon-coin"></i> 发放金额:</span>
+                  <span class="detail-value">{{ step.fsCourseRedPacketLog.amount }} 元</span>
+                </div>
+              </div>
+
+              <!-- 第二行 -->
+              <div v-if="step.details" class="step-row second-row">
+                <div class="detail-item">
+                  <span class="detail-label"><i class="el-icon-chat-dot-round"></i> 备注:</span>
+                  <span class="detail-value">{{ step.details }}</span>
+                </div>
+              </div>
+            </div>
+
+            <!-- 其他类型 -->
+            <div v-else class="step-content">
+              <!-- 第一行 -->
+              <div class="step-row first-row">
+                <div v-if="step.paramVo" class="detail-item">
+                  <span class="detail-label"><i class="el-icon-office-building"></i> 训练营:</span>
+                  <span class="detail-value">{{ step.paramVo.trainingCampName }}</span>
+                </div>
+                <div v-if="step.paramVo" class="detail-item">
+                  <span class="detail-label"><i class="el-icon-collection-tag"></i> 营期名称:</span>
+                  <span class="detail-value">{{ step.paramVo.periodName }}</span>
+                </div>
+                <div v-if="step.paramVo" class="detail-item">
+                  <span class="detail-label"><i class="el-icon-notebook-2"></i> 课节名称:</span>
+                  <span class="detail-value">{{ step.paramVo.courseName }}</span>
+                </div>
+              </div>
+
+              <!-- 第二行 -->
+              <div v-if="step.details" class="step-row second-row">
+                <div class="detail-item">
+                  <span class="detail-label"><i class="el-icon-chat-dot-round"></i> 备注:</span>
+                  <span class="detail-value">{{ step.details }}</span>
+                </div>
+              </div>
+            </div>
+          </template>
+
+        </el-step>
+      </el-steps>
+    </div>
+
+    <!-- 分页 -->
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+
+
+</template>
+
+<script>
+import { listUserOperationLog} from "@/api/his/userOperationLog";
+
+export default {
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      typeList: [],
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        operationType:null,
+        userId:null,
+      },
+      total: 0,
+      steps: [
+      ]
+    };
+  },
+  created() {
+    this.getDicts("fs_user_operation_type").then(response => {
+      this.typeList = response.data;
+    });
+  },
+  computed: {
+    // 删除这个属性,直接在 getList 中使用后端的操作类型
+    groupedPaginatedSteps() {
+      const groups = {};
+      this.steps.forEach((step) => {
+        const date = step.createTime ?
+          (step.createTime instanceof Date ? step.createTime.toISOString().substr(0, 10) : new Date(step.createTime).toISOString().substr(0, 10))
+          : null;
+        if (!groups[date]) {
+          groups[date] = [];
+        }
+        groups[date].push(step);
+      });
+      return groups;
+    },
+
+  },
+  methods: {
+    getList() {
+      this.loading = true;
+      listUserOperationLog(this.queryParams).then(response => {
+        this.steps = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 判断是否为今天
+    isToday(date) {
+      const today = new Date();
+      const formattedDate = `${today.getFullYear()}-${(today.getMonth() + 1).toString().padStart(2, '0')}-${today.getDate().toString().padStart(2, '0')}`;
+      return date === formattedDate;
+    },
+    getDetails(orderId) {
+      this.queryParams.userId=orderId;
+      this.getList();
+
+    },
+    handleTypeChange() {
+      this.queryParams.pageNum = 1;  // 重置分页为第一页
+      this.getList();  // 重新获取数据
+    }
+  },
+};
+</script>
+
+<style scoped>
+.behavior-track-container {
+  width: 100%;
+  padding: 24px;
+  font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif;
+  background-color: #f9fbfd;
+  border-radius: 12px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
+}
+
+.filter-section {
+  margin-bottom: 24px;
+  background: #ffffff;
+  border-radius: 8px;
+  padding: 16px 20px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+  display: flex;
+  align-items: center;
+}
+
+.filter-item {
+  display: flex;
+  align-items: center;
+}
+
+.filter-item label {
+  font-weight: 600;
+  color: #333;
+  margin-right: 12px;
+  font-size: 14px;
+}
+
+.type-select {
+  width: 240px;
+}
+
+.custom-steps {
+  padding: 0 16px;
+}
+
+.step-title {
+  font-size: 16px;
+  font-weight: 600;
+  color: #333;
+}
+
+.step-detail p {
+  margin: 8px 0;
+  line-height: 1.6;
+  font-size: 14px;
+  color: #555;
+}
+
+/* 步骤条样式优化 - 移除图标边框 */
+.custom-steps >>> .el-step__head {
+  padding-right: 16px;
+}
+
+.custom-steps >>> .el-step__icon {
+  width: 24px;
+  height: 24px;
+  font-size: 18px;
+}
+
+.custom-steps >>> .el-step__icon.is-icon {
+  color: #52c41a;
+}
+
+.custom-steps >>> .el-step__line {
+  top: 36px;
+  left: 11px;
+  background-color: #e8e8e8;
+}
+
+/* 分页样式优化 */
+.pagination-wrapper {
+  margin-top: 32px;
+  text-align: center;
+  padding: 16px 0;
+}
+
+.custom-pagination >>> .el-pager li {
+  border-radius: 4px;
+  margin: 0 4px;
+}
+
+.custom-pagination >>> .el-pager li.active {
+  background-color: #52c41a;
+  color: #fff;
+}
+
+.custom-pagination >>> .el-pagination__jump {
+  margin-left: 12px;
+}
+
+.custom-pagination >>> .el-input__inner {
+  border-radius: 4px;
+}
+
+/* 新增和修改的样式 */
+.step-content {
+  margin-top: 8px;
+  padding: 16px;
+  background: #ffffff;
+  border-radius: 8px;
+  border: 1px solid #ebeef5;
+  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.06);
+  transition: all 0.3s ease;
+}
+
+.step-content:hover {
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
+  transform: translateY(-1px);
+}
+
+.detail-label {
+  display: inline-flex;
+  align-items: center;
+  width: 100px;
+  color: #606266;
+  font-weight: 500;
+  flex-shrink: 0;
+}
+
+.detail-label i {
+  margin-right: 6px;
+  font-size: 14px;
+  color: #909399;
+}
+
+.detail-value {
+  flex: 1;
+  color: #303133;
+  word-break: break-word;
+  padding-left: 4px;
+}
+
+.step-row {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: space-between;
+  margin-bottom: 8px;
+}
+
+.first-row .detail-item {
+  flex: 1 1 30%; /* 平均分布 */
+  display: flex;
+  align-items: center;
+  margin-right: 16px;
+}
+
+.second-row .detail-item {
+  display: flex;
+  align-items: center;
+}
+
+.time-item {
+  margin-left: auto; /* 时间靠右 */
+}
+
+.detail-label {
+  font-weight: 500;
+  color: #606266;
+  margin-right: 6px;
+}
+
+.detail-value {
+  color: #303133;
+  word-break: break-word;
+}
+
+@media (max-width: 768px) {
+  .first-row,
+  .second-row {
+    flex-direction: column;
+  }
+  .time-item {
+    margin-left: 0;
+  }
+}
+/* 完全重置步骤描述区域的样式 */
+.custom-steps >>> .el-step__description {
+  width: 100% !important;
+  max-width: 100% !important;
+  padding: 0 !important;
+  margin: 0 !important;
+}
+
+/* 确保步骤内容使用弹性布局 */
+.step-content {
+  display: flex;
+  flex-direction: column;
+  width: 100%;
+}
+
+/* 调整时间项 */
+.time-item {
+  align-self: flex-end; /* 替代 margin-left: auto */
+  margin-top: 8px; /* 如果需要与上方的间距 */
+}
+/* 日期标题样式 */
+.date-title {
+  font-size: 16px;
+  font-weight: bold;
+  color: #333;
+  margin-top: 16px;
+}
+
+.date-divider {
+  height: 1px;
+  background: #e8e8e8;
+  margin: 4px 0 12px;
+}
+
+/* 在步骤条标题旁边显示时间 */
+.step-title {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.step-time {
+  font-size: 12px;
+  color: #999;
+  margin-left: 10px;
+}
+
+/* 第二行的备注 */
+.second-row {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.second-row .detail-item {
+  display: flex;
+  align-items: center;
+}
+
+.no-data {
+  text-align: center;
+  color: #999;
+  font-size: 18px;
+  padding: 20px;
+}
+</style>

+ 173 - 0
src/views/his/user/userCourseConversionRecord.vue

@@ -0,0 +1,173 @@
+<template>
+
+  <div style="background-color: #f0f2f5; padding-bottom: 20px; min-height: 100%; " >
+    <div class="contentx" v-if="item!=null">
+      <div class="desct"> 优惠劵领取信息</div>
+      <el-tabs type="card" v-model="actName" @tab-click="handleClickX">
+        <el-tab-pane label="全部" name="10"></el-tab-pane>
+        <el-tab-pane v-for="(item,index) in couponStatusOptions" :label="item.dictLabel" :name="item.dictValue"></el-tab-pane>
+      </el-tabs>
+      <el-table v-loading="loading" :data="userCouponList">
+        <el-table-column label="优惠劵标题" align="center" prop="title" />
+        <el-table-column label="券号" align="center" prop="couponCode" />
+        <el-table-column label="会员昵称" align="center" prop="nickName" />
+        <el-table-column label="会员电话" align="center" prop="phone" />
+        <el-table-column label="关联订单ID" align="center" prop="businessId" />
+        <el-table-column label="订单类型" align="center" prop="businessType">
+          <template slot-scope="scope">
+            <dict-tag :options="businessTypeOptions" :value="scope.row.businessType"/>
+          </template>
+        </el-table-column>
+        <el-table-column label="状态" align="center" prop="status">
+          <template slot-scope="scope">
+            <dict-tag :options="couponStatusOptions" :value="scope.row.status"/>
+          </template>
+        </el-table-column>
+        <el-table-column label="领取时间" align="center" prop="createTime" width="180"/>
+        <el-table-column label="使用时间" align="center" prop="useTime" width="180"/>
+      </el-table>
+      <pagination
+        v-show="total>0"
+        :total="total"
+        :page.sync="queryParams.pageNum"
+        :limit.sync="queryParams.pageSize"
+        @pagination="getList"
+      />
+    </div>
+
+    <div class="contentx" v-if="item!=null" >
+      <div class="desct">
+        用户药品订单
+      </div>
+      <userStorerDetails  ref="userDetails" />
+    </div>
+  </div>
+</template>
+
+
+
+<script>
+import { getPatientByUserId} from "@/api/his/patient";
+import { getUser ,getUserAddr} from "@/api/his/user";
+import { getListUserCoupon } from "@/api/his/userCoupon";
+import userStorerDetails from "../../components/his/userStorerDetails.vue";
+import userPatietDetails from "../../components/his/userPatietDetails.vue";
+import userInquiryOrderDetails from "../../components/his/userInquiryOrderDetails.vue";
+import userAddDetails from "../../components/his/userAddDetails.vue";
+export default {
+  name: "storedet",
+  props:["data"],
+  components: { userStorerDetails ,userInquiryOrderDetails,userPatietDetails,userAddDetails},
+  data() {
+    return {
+      patientInfo: process.env.VUE_APP_PATIENT_INFO,
+      addr:[],
+      patient:[],
+      userOptions: [],
+      statusOptions: [],
+      sexOptions: [],
+      pOptions: [],
+      item:null,
+      total: 0,
+      loading: true,
+      // 会员优惠券表格数据
+      userCouponList: [],
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userId: null,
+        couponId: null,
+      },
+      actName:"10",
+      businessTypeOptions:[],
+      couponStatusOptions:[],
+    }
+  },
+  created() {
+    this.getDicts("sys_user_status").then(response => {
+      this.userOptions = response.data;
+    });
+    this.getDicts("sys_company_status").then(response => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("sys_patient_status").then(response => {
+      this.pOptions = response.data;
+    });
+    this.getDicts("sys_patient_sex").then(response => {
+      this.sexOptions = response.data;
+    });
+    this.getDicts("sys_coupon_business_type").then(response => {
+      this.businessTypeOptions = response.data;
+    });
+
+    this.getDicts("sys_coupon_status").then(response => {
+      this.couponStatusOptions = response.data;
+    });
+  },
+  methods: {
+    handleClickX(tab, event) {
+      if(tab.name=="10"){
+        this.queryParams.status=null;
+      }else{
+        this.queryParams.status=tab.name;
+      }
+      this.queryParams.pageNum = 1;
+      this.getList();
+
+    },
+    getList() {
+      this.loading = true;
+      getListUserCoupon(this.queryParams).then(response => {
+        this.userCouponList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+
+    getDetails(orderId) {
+      this.item=null;
+      getUser(orderId).then(response => {
+        this.item = response.data;
+        setTimeout(() => {
+          this.$refs.userDetails.getUserDetails(orderId);
+        }, 1);
+
+      });
+      this.patient=null;
+      getPatientByUserId(orderId).then(response => {
+        this.patient = response.data;
+      });
+      getUserAddr(orderId).then(response => {
+        this.addr = response.data;
+      });
+      this.queryParams.userId=orderId;
+      this.getList();
+
+    },
+  }
+}
+</script>
+<style>
+
+.contentx{
+  height: 100%;
+  background-color: #fff;
+  padding: 0px 20px 20px;
+
+
+  margin: 20px;
+}
+.el-descriptions-item__label.is-bordered-label{
+  font-weight: normal;
+}
+.el-descriptions-item__content {
+  max-width: 150px;
+  min-width: 100px;
+}
+.desct{
+  padding-top: 20px;
+  padding-bottom: 20px;
+  color: #524b4a;
+  font-weight: bold;
+}
+</style>

+ 476 - 0
src/views/his/user/userCoursePeriod.vue

@@ -0,0 +1,476 @@
+<template>
+  <div class="app-container">
+    <!-- 没有数据提示 -->
+    <div v-if="campList.length === 0 && !leftLoading" class="no-data">
+      <span>—— 没有数据 ——</span>
+    </div>
+
+    <el-container v-else>
+      <!-- 左侧区域 -->
+      <el-aside width="360px" class="left-aside">
+        <!-- 顶部区域 -->
+        <!-- 训练营列表 -->
+        <div class="camp-list" ref="campList" @scroll="handleScroll" v-loading="leftLoading">
+          <div
+            v-for="(item, index) in campList"
+            :key="index"
+            class="camp-item"
+            :class="{ 'active': activeCampIndex === index }"
+            @click="selectCamp(index)"
+          >
+            <div class="camp-content">
+              <div class="camp-title">
+                <i class="el-icon-s-flag camp-icon"></i>
+                {{ item.trainingCampName }}
+              </div>
+              <div class="camp-info">
+                <span>序号:{{ item.orderNumber }}</span>
+                <span>最新营期开课:{{ item.recentDate || '-' }}</span>
+              </div>
+            </div>
+          </div>
+          <!-- 底部加载更多提示 -->
+          <div v-if="loadingMore" class="loading-more">
+            <i class="el-icon-loading"></i>
+            <span>加载中...</span>
+          </div>
+
+          <!-- 所有数据加载完毕提示 -->
+          <div v-if="campList.length > 0 && !loadingMore" class="no-more-data">
+            <span>—— 已加载全部训练营 ——</span>
+          </div>
+        </div>
+      </el-aside>
+
+      <!-- 右侧区域 -->
+      <el-main><userCourseStatic  ref="userCourseStatic" /></el-main>
+    </el-container>
+
+  </div>
+</template>
+
+<script>
+import { listCamp} from "@/api/course/userCourseCamp";
+import userCourseStatic from './userCourseStatic.vue';
+export default {
+  name: "userCoursePeriod",
+  components: {
+    userCourseStatic
+  },
+  data() {
+    return {
+      // 加载更多状态
+      loadingMore: false,
+      // 激活的训练营索引
+      activeCampIndex: null,
+      // 训练营列表
+      campList: [],
+      // 遮罩层
+      loading: true,
+      updateDateOpen: false,
+      // 左侧遮罩层
+      leftLoading: true,
+      // 左侧查询参数
+      leftQueryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        hasNextPage: false,
+        scs: 'order_number(desc),training_camp_id(desc)',
+        trainingCampName: null,
+        userId:null,
+      },
+    };
+  },
+  created() {
+    // this.getLeftList();
+  },
+  methods: {
+    getDetails(orderId) {
+      this.userId=orderId;
+      this.leftQueryParams.userId=orderId;
+      this.getLeftList();
+    },
+    /** 查询左侧列表 */
+    getLeftList() {
+      this.leftLoading = true;
+      // 重置页码和加载更多状态
+      this.leftQueryParams.pageNum = 1;
+      this.loadingMore = false;
+
+      // 训练营数据
+      listCamp(this.leftQueryParams).then(response => {
+        if (response && response.code === 200) {
+          this.campList = response.data.list || [];
+          this.leftQueryParams.hasNextPage = response.data.hasNextPage;
+          this.activeCampIndex = this.campList.length > 0 ? 0 : null;
+          this.selectCamp(this.activeCampIndex);
+          // 如果当前显示的列表高度不足以触发滚动,但还有更多数据,自动加载下一页
+          this.$nextTick(() => {
+            const scrollEl = this.$refs.campList;
+            if (scrollEl && this.leftQueryParams.hasNextPage && scrollEl.scrollHeight <= scrollEl.clientHeight) {
+              this.loadMoreCamps();
+            }
+          });
+        } else {
+          this.$message.error(response.msg || '获取训练营列表失败');
+          this.campList = [];
+          this.leftQueryParams.hasNextPage = false;
+        }
+        this.leftLoading = false;
+      }).catch(error => {
+        console.error('获取训练营列表失败:', error);
+        this.$message.error('获取训练营列表失败');
+        this.campList = [];
+        this.leftQueryParams.hasNextPage = false;
+        this.leftLoading = false;
+      });
+    },
+    /** 选中训练营 */
+    selectCamp(index) {
+      if(index == null || index == undefined) return;
+      this.activeCampIndex = index;
+      // 加载对应的训练营营期数据
+      const selectedCamp = this.campList[index];
+      console.log(this.userId)
+      this.$refs.userCourseStatic.getDetails(selectedCamp,this.userId);
+      // this.queryParams.trainingCampId = selectedCamp.trainingCampId;
+      // this.getList();
+    },
+    /** 处理滚动事件,实现滚动到底部加载更多 */
+    handleScroll() {
+      // 如果正在节流中或者正在加载中,则不处理
+      if (this.scrollThrottle || this.loadingMore) return;
+
+      // 设置节流,200ms内不再处理滚动事件
+      this.scrollThrottle = true;
+      setTimeout(() => {
+        this.scrollThrottle = false;
+      }, 200);
+
+      const scrollEl = this.$refs.campList;
+      if (!scrollEl) return;
+
+      // 判断是否滚动到底部:滚动高度 + 可视高度 >= 总高度 - 30(添加30px的容差,提前触发加载)
+      const isBottom = scrollEl.scrollTop + scrollEl.clientHeight >= scrollEl.scrollHeight - 30;
+
+      // 如果滚动到底部,且有下一页数据,且当前不在加载中,则加载更多
+      if (isBottom && this.leftQueryParams.hasNextPage && !this.leftLoading && !this.loadingMore) {
+        this.loadMoreCamps();
+      }
+    },
+    /** 加载更多训练营数据 */
+    loadMoreCamps() {
+      // 已在加载中,防止重复加载
+      if (this.leftLoading || this.loadingMore) return;
+
+      // 设置加载状态
+      this.loadingMore = true;
+
+      // 页码加1
+      this.leftQueryParams.pageNum += 1;
+
+      // 加载下一页数据
+      listCamp(this.leftQueryParams).then(response => {
+        if (response && response.code === 200) {
+          // 将新数据追加到列表中
+          const newList = response.data.list || [];
+          if (newList.length > 0) {
+            this.campList = [...this.campList, ...newList];
+          }
+
+          // 更新是否有下一页的标志
+          this.leftQueryParams.hasNextPage = response.data.hasNextPage;
+
+          // 如果当前显示的列表高度不足以触发滚动,但还有更多数据,自动加载下一页
+          this.$nextTick(() => {
+            const scrollEl = this.$refs.campList;
+            if (scrollEl && this.leftQueryParams.hasNextPage && scrollEl.scrollHeight <= scrollEl.clientHeight) {
+              // 延迟一点再加载下一页,避免过快加载
+              setTimeout(() => {
+                this.loadMoreCamps();
+              }, 300);
+            }
+          });
+        } else {
+          this.$message.error(response.msg || '加载更多训练营失败');
+        }
+        this.loadingMore = false;
+      }).catch(error => {
+        console.error('加载更多训练营失败:', error);
+        this.$message.error('加载更多训练营失败');
+        this.loadingMore = false;
+      });
+    },
+
+  },
+};
+</script>
+
+<style scoped>
+.left-aside {
+  background-color: #fff;
+  border-right: 1px solid #EBEEF5;
+  padding: 0;
+  display: flex;
+  flex-direction: column;
+  height: 800px;
+}
+
+.left-header {
+  padding: 10px;
+  border-bottom: 1px solid #EBEEF5;
+}
+
+.left-header-top {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 10px;
+}
+
+.search-btn {
+  width: 50%;
+  height: 36px;
+  background-color: #409EFF;
+  color: white;
+  border: none;
+}
+
+.search-input-wrapper {
+  margin-bottom: 10px;
+}
+
+.sort-wrapper {
+  display: flex;
+  align-items: center;
+  margin-bottom: 10px;
+}
+
+.sort-label {
+  width: 70px;
+  font-size: 14px;
+  font-weight: 600;
+  color: #909399;
+}
+
+.sort-select {
+  margin-left: 10px;
+  width: 280px;
+}
+
+.color-wrapper {
+  display: flex;
+  align-items: center;
+  margin-bottom: 10px;
+}
+
+.color-label {
+  width: 70px;
+  color: #606266;
+}
+
+.color-hint {
+  margin-left: 10px;
+  color: #606266;
+  font-size: 12px;
+}
+
+.color-help {
+  margin-left: 5px;
+  color: #909399;
+  cursor: pointer;
+}
+
+.hint-text {
+  color: #606266;
+  font-size: 12px;
+  margin-top: 5px;
+}
+
+.camp-list {
+  flex: 1;
+  overflow-y: auto;
+  padding: 3px;
+}
+
+.camp-item {
+  margin-bottom: 5px;
+  padding: 15px;
+  background-color: #ffffff;
+  position: relative;
+  cursor: pointer;
+  display: flex;
+  justify-content: space-between;
+  border: 1px solid #eaedf2;
+}
+
+.camp-item:last-child {
+  margin-bottom: 0;
+}
+
+.camp-item:hover {
+  background-color: #f5f9ff;
+}
+
+.camp-item.active {
+  background-color: #eaf4ff;
+  border-left: 1px solid #75b8fc;
+}
+
+.camp-content {
+  flex: 1;
+  padding-right: 10px;
+}
+
+.camp-title {
+  font-weight: bold;
+  font-size: 16px;
+  margin-bottom: 8px;
+  color: #333;
+  display: flex;
+  align-items: center;
+}
+
+.camp-icon {
+  font-size: 16px;
+  margin-right: 6px;
+  color: #409EFF;
+}
+
+.camp-info {
+  display: flex;
+  justify-content: space-between;
+  margin-bottom: 8px;
+  font-size: 12px;
+  color: #c4c1c1;
+  line-height: 1.5;
+}
+
+.camp-stats {
+  display: flex;
+  justify-content: space-between;
+  font-size: 12px;
+  color: #666;
+  background-color: #f5f9ff;
+  padding: 6px 10px;
+  border-radius: 4px;
+  line-height: 1.5;
+}
+
+.stat-item {
+  display: flex;
+  align-items: center;
+}
+
+.stat-item i {
+  margin-right: 4px;
+  font-size: 14px;
+  color: #409EFF;
+}
+
+.camp-actions {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: flex-end;
+  gap: 8px;
+  border-left: 1px dashed #eaedf2;
+  padding-left: 12px;
+  min-width: 50px;
+}
+
+.action-btn {
+  padding: 2px 5px;
+  font-size: 12px;
+  border-radius: 4px;
+  transition: all 0.2s;
+}
+
+.action-btn:hover {
+  background-color: rgba(255, 255, 255, 0.8);
+}
+
+.delete-btn {
+  color: #f56c6c;
+}
+
+.delete-btn:hover {
+  background-color: rgba(245, 108, 108, 0.1);
+}
+
+.copy-btn {
+  color: #409EFF;
+}
+
+.copy-btn:hover {
+  background-color: rgba(64, 158, 255, 0.1);
+}
+
+.warning-icon {
+  color: #E6A23C;
+  font-size: 16px;
+  margin-left: 5px;
+}
+
+.el-main {
+  padding: 10px;
+}
+
+/* 添加训练营表单样式 */
+.drawer-footer {
+  /* position: absolute; */
+  bottom: 0;
+  left: 0;
+  right: 0;
+  padding: 20px;
+  background: #fff;
+  text-align: right;
+  border-top: 1px solid #e8e8e8;
+}
+
+.el-input-number {
+  width: 100%;
+}
+
+/* 加载更多样式 */
+.loading-more {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 12px 0;
+  color: #909399;
+  font-size: 14px;
+}
+
+.loading-more i {
+  margin-right: 5px;
+  font-size: 16px;
+}
+
+/* 无更多数据提示 */
+.no-more-data {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 12px 0;
+  color: #c0c4cc;
+  font-size: 13px;
+}
+
+.no-more-data span {
+  position: relative;
+  display: flex;
+  align-items: center;
+}
+/* 添加没有数据提示的样式 */
+.no-data {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 100vh;  /* 让提示居中,覆盖整个页面 */
+  font-size: 18px;
+  color: #c0c4cc;
+  background-color: #f5f5f5;
+}
+
+</style>

+ 222 - 0
src/views/his/user/userCoursePeriodDetails.vue

@@ -0,0 +1,222 @@
+<template>
+  <div class="statistics-container">
+    <!-- 营期课程选择 -->
+    <div class="fixed-header">
+      <el-form :inline="true" :model="queryParams" class="demo-form-inline">
+        <el-form-item label="营期课程">
+          <el-select
+            v-model="queryParams.periodId"
+            placeholder="请选择营期课程"
+            style="width: 400px"
+            clearable
+          >
+            <el-option
+              v-for="item in courseOptions"
+              :key="item.periodId"
+              :label="item.periodName"
+              :value="item.periodId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleQuery">查询</el-button>
+        </el-form-item>
+      </el-form>
+
+      <!-- 统计数据展示 -->
+      <el-row :gutter="20" class="statistics-row">
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">到课数</div>
+            <div class="statistics-value">{{ statistics.courseCompleteNum || 0 }}次</div>
+          </div>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">总学习时长</div>
+            <div class="statistics-value">{{ statistics.courseWatchNum || 0 }}分钟</div>
+          </div>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">正确答题数</div>
+            <div class="statistics-value">{{ statistics.correctAnswerNum || 0 }}次</div>
+          </div>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">获得红包数</div>
+            <div class="statistics-value">{{ statistics.redPacketCount || 0 }}次</div>
+          </div>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">红包总金额</div>
+            <div class="statistics-value">{{ statistics.redPacketAmount || 0 }}元</div>
+          </div>
+        </el-col>
+      </el-row>
+    </div>
+
+  </div>
+</template>
+
+<script>
+import {getDays, periodCourseStatisticCount,periodList} from "@/api/course/userCoursePeriod";
+
+export default {
+  name: "userCoursePeriodDetails",
+  props: {
+    periodId: {
+      type: [String, Number],
+      default: ''
+    },
+    active: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: false,
+      // 总条数
+      total: 0,
+      // 课程选项
+      courseOptions: [],
+      // 统计数据
+      statistics: {
+        courseCompleteNum: 0,
+        courseWatchNum: 0,
+        redPacketCount: 0,
+        correctAnswerNum: 0,
+        redPacketAmount: 0
+      },
+      // 列表数据
+      list: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        // videoId: '',
+        periodId: '',
+        trainingCampId:null,
+        userId:null,
+      },
+      // 是否已初始化
+      initialized: false
+    };
+  },
+  created() {
+  },
+  methods: {
+    getDetails(camp,userid) {
+      this.queryParams.trainingCampId = camp.trainingCampId;
+      this.camp = camp;
+      this.userId=userid;
+      this.queryParams.userId=userid;
+      this.user=null;
+      this.courseOptions = []
+      this.queryParams.periodId = null;
+      this.getCourseOptions();
+      this.calculateTotalStatistics();
+    },
+    /** 查询按钮操作 */
+    handleQuery() {
+      this.calculateTotalStatistics();
+    },
+    /** 获取课程选项 */
+    getCourseOptions() {
+
+      this.loading = true;
+      periodList(this.queryParams).then(r => {
+        if (r.code === 200) {
+          this.courseOptions = r.data;
+          this.loading = false;
+        } else {
+          this.$message.error(r.msg || '获取数据失败');
+        }
+        this.loading = false;
+      }).catch(() => {
+        this.loading = false;
+      });
+    },
+
+    /** 计算总统计数据 */
+    calculateTotalStatistics() {
+      console.log("this.queryParams:",this.queryParams)
+      periodCourseStatisticCount(this.queryParams).then(response => {
+        if (response.code === 200) {
+          // 设置列表数据
+          this.statistics.courseCompleteNum = response.data.courseCompleteNum || 0;
+          this.statistics.courseWatchNum = response.data.courseWatchNum || 0;
+          this.statistics.courseWatchTimes = response.data.courseWatchTimes || 0;
+          this.statistics.redPacketCount = response.data.redPacketCount || 0;
+          this.statistics.correctAnswerNum = response.data.correctAnswerNum || 0;
+          this.statistics.redPacketAmount = response.data.redPacketAmount || 0;
+
+        } else {
+          this.$message.error(response.msg || '获取数据失败');
+        }
+        this.loading = false;
+      }).catch(error => {
+        console.error('获取数据失败:', error);
+        this.$message.error('获取数据失败');
+        this.loading = false;
+      });
+
+    }
+  }
+};
+</script>
+
+<style scoped>
+.statistics-container {
+  height: 100%;
+  overflow: hidden;
+  position: relative;
+}
+
+.fixed-header {
+  position: sticky;
+  top: 0;
+  z-index: 10;
+  background-color: #fff;
+  padding: 10px 0;
+  border-bottom: 1px solid #EBEEF5;
+}
+/* 覆盖原有的pagination-container样式 */
+:deep(.pagination-container) {
+  height: auto !important;
+  margin-bottom: 0 !important;
+  margin-top: 0 !important;
+  padding: 0 !important;
+}
+
+.statistics-row {
+  margin: 20px 0;
+}
+
+.statistics-item {
+  background-color: #f5f7fa;
+  border-radius: 4px;
+  padding: 15px;
+  text-align: center;
+  height: 100px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+
+.statistics-title {
+  font-size: 14px;
+  color: #606266;
+  margin-bottom: 10px;
+}
+
+.statistics-value {
+  font-size: 20px;
+  font-weight: bold;
+  color: #303133;
+}
+</style>

+ 57 - 0
src/views/his/user/userCourseStatic.vue

@@ -0,0 +1,57 @@
+<template>
+  <el-tabs v-model="activeName" type="card" @tab-click="handleClick">
+    <el-tab-pane label="数据总览" name="first"><userStaticAll  ref="userStaticAll" /></el-tab-pane>
+    <el-tab-pane label="课节详情" name="second"><userCoursePeriodDetails  ref="userCoursePeriodDetails" /></el-tab-pane>
+    <el-tab-pane label="转化记录" name="third"><userCourseConversionRecord  ref="userCourseConversionRecord" /></el-tab-pane>
+
+  </el-tabs>
+</template>
+<script>
+import userStaticAll from './userStaticAll.vue';
+import userCoursePeriodDetails from './userCoursePeriodDetails.vue';
+import userCourseConversionRecord from './userCourseConversionRecord.vue';
+
+export default {
+  name: "userCourseStatic",
+  components: {
+    userStaticAll,userCoursePeriodDetails,userCourseConversionRecord
+  },
+  data() {
+
+    return {
+      camp:{},
+      userId:null,
+      activeName: 'first'
+    };
+  },
+  methods: {
+    handleClick(tab, event) {
+      if (tab.name === "first"){
+        setTimeout(() => {
+          this.$refs.userStaticAll.getDetails(this.camp,this.userId);
+        }, 1);
+      }else if (tab.name === "second"){
+        setTimeout(() => {
+          this.$refs.userCoursePeriodDetails.getDetails(this.camp,this.userId);
+        }, 1);
+      }else {
+        setTimeout(() => {
+          this.$refs.userCourseConversionRecord.getDetails(this.userId);
+        }, 1);
+      }
+
+    },
+
+    getDetails(camp,userid) {
+      this.camp = camp;
+      this.userId=userid;
+      this.activeName = 'first';
+      // 默认加载“数据总览”接口
+      this.$nextTick(() => {
+        this.$refs.userStaticAll.getDetails(this.camp, this.userId);
+      });
+
+    },
+  }
+};
+</script>

+ 71 - 0
src/views/his/user/userDetails.vue

@@ -0,0 +1,71 @@
+<template>
+  <div>
+    <div style="background-color: #f0f2f5; padding-bottom: 20px; min-height: 100%; " >
+      <div style="padding: 20px; background-color: #fff;">
+        会员详情
+      </div>
+    </div>
+    <template>
+      <el-tabs v-model="activeName"  :tab-position="tabPosition" style="height: 200px;margin: 40px">
+        <el-tab-pane label="基本信息" name="basic"><userDetails  ref="userDetails" /></el-tab-pane>
+        <el-tab-pane label="行为轨迹" name="behavior"><userBehavior  ref="userBehavior" /></el-tab-pane>
+        <el-tab-pane label="训练营"  name="course"><userCoursePeriod  ref="userCoursePeriod" /></el-tab-pane>
+      </el-tabs>
+    </template>
+  </div>
+
+</template>
+
+
+
+<script>
+import userDetails from '../../components/his/userDetails.vue';
+import userBehavior from './userBehavior.vue';
+import userCoursePeriod from './userCoursePeriod.vue';
+
+export default {
+  name: "userDetailsByNew",
+  props:["data"],
+  components: { userDetails,userBehavior,userCoursePeriod},
+  data() {
+    return {
+      activeName: 'basic',
+      // 左侧遮罩层
+      leftLoading: true,
+      // 左侧查询参数
+      leftQueryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        hasNextPage: false,
+        scs: 'order_number(desc),training_camp_id(desc)',
+        trainingCampName: null,
+        userId:null,
+      },
+      tabPosition: 'top',
+    }
+  },
+  created() {
+
+  },
+  methods: {
+    handleClick(tab, event) {
+      console.log(tab, event);
+    },
+    getDetails(userId) {
+      this. activeName='basic';
+      setTimeout(() => {
+        this.$refs.userDetails.getDetails(userId);
+      }, 1);
+      setTimeout(() => {
+        this.$refs.userBehavior.getDetails(userId);
+      }, 1);
+      setTimeout(() => {
+        this.$refs.userCoursePeriod.getDetails(userId);
+      }, 1);
+    },
+  }
+}
+</script>
+<style>
+
+</style>

+ 248 - 0
src/views/his/user/userStaticAll.vue

@@ -0,0 +1,248 @@
+<template>
+  <div class="statistics-container">
+    <!-- 营期课程选择 -->
+    <div class="fixed-header">
+      <!-- 统计数据展示 -->
+      <el-row :gutter="20" class="statistics-row">
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">到课数</div>
+            <div class="statistics-value">{{ statistics.courseCompleteNum || 0 }}次</div>
+          </div>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">总学习时长</div>
+            <div class="statistics-value">{{ statistics.courseWatchNum || 0 }}分钟</div>
+          </div>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">正确答题数</div>
+            <div class="statistics-value">{{ statistics.correctAnswerNum || 0 }}次</div>
+          </div>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">获得红包数</div>
+            <div class="statistics-value">{{ statistics.redPacketCount || 0 }}次</div>
+          </div>
+        </el-col>
+        <el-col :span="4">
+          <div class="statistics-item">
+            <div class="statistics-title">红包总金额</div>
+            <div class="statistics-value">{{ statistics.redPacketAmount || 0 }}元</div>
+          </div>
+        </el-col>
+      </el-row>
+    </div>
+
+    <!-- 列表统计展示 -->
+    <div class="table-wrapper">
+      <el-table v-loading="loading" :data="list">
+        <el-table-column type="index" label="序号" width="50" align="center" fixed/>
+        <el-table-column prop="courseName" label="课程名称" align="center" min-width="100" fixed/>
+        <el-table-column prop="videoName" label="课节名称" align="center" min-width="100" fixed/>
+        <el-table-column label="记录类型" align="center" prop="logType">
+          <template slot-scope="scope">
+            <el-tag prop="type" v-for="(item, index) in typeOptions" v-if="scope.row.logType==item.dictValue">{{item.dictLabel}}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="duration" label="播放时长" align="center" min-width="100"/>
+        <el-table-column prop="finishTime" label="完课时间" align="center" min-width="120"/>
+      </el-table>
+
+      <!-- 分页 -->
+      <div class="custom-pagination-container">
+        <pagination
+          v-show="total > 0"
+          :total="total"
+          :page.sync="queryParams.pageNum"
+          :limit.sync="queryParams.pageSize"
+          @pagination="getCountList"
+        />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import {periodCourseStatisticCount} from "@/api/course/userCoursePeriod";
+import { listBytrainingCampId } from "@/api/course/qw/courseWatchLog";
+
+
+export default {
+  name: "userStaticAll",
+  props: {
+    periodId: {
+      type: [String, Number],
+      default: ''
+    },
+    active: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      typeOptions: [],
+      // 遮罩层
+      loading: false,
+      // 总条数
+      total: 0,
+      // 统计数据
+      statistics: {
+        courseCompleteNum: 0,
+        courseWatchNum: 0,
+        redPacketCount: 0,
+        correctAnswerNum: 0,
+        redPacketAmount: 0
+      },
+      // 列表数据
+      list: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        // videoId: '',
+        periodId: '',
+        trainingCampId:null,
+        userId:null,
+      },
+    };
+  },
+  created() {
+    this.getDicts("sys_course_watch_log_type").then((response) => {
+      this.typeOptions = response.data;
+    });
+  },
+  methods: {
+    getDetails(camp,userid) {
+    this.queryParams.trainingCampId = camp.trainingCampId;
+      this.camp = camp;
+      this.userId=userid;
+      this.queryParams.userId=userid;
+      this.user=null;
+      if (this.queryParams.trainingCampId){
+        this.getCountList();
+        this.calculateTotalStatistics();
+      }
+
+    },
+    /** 获取列表数据 */
+    getCountList() {
+      this.loading = true;
+      if (!this.queryParams.trainingCampId || !this.queryParams.userId){
+        return
+      }
+      listBytrainingCampId(this.queryParams).then(response => {
+        if (response.code === 200) {
+          // 设置列表数据
+          this.list = response.rows;
+          this.total = response.total || 0;
+
+
+        } else {
+          this.$message.error(response.msg || '获取数据失败');
+        }
+        this.loading = false;
+      }).catch(error => {
+        console.error('获取数据失败:', error);
+        this.$message.error('获取数据失败');
+        this.loading = false;
+      });
+    },
+    /** 计算总统计数据 */
+    calculateTotalStatistics() {
+
+      console.log("this.queryParams:",this.queryParams)
+      periodCourseStatisticCount(this.queryParams).then(response => {
+        if (response.code === 200) {
+          // 设置列表数据
+          this.statistics.courseCompleteNum = response.data.courseCompleteNum || 0;
+          this.statistics.courseWatchNum = response.data.courseWatchNum || 0;
+          this.statistics.courseWatchTimes = response.data.courseWatchTimes || 0;
+          this.statistics.redPacketCount = response.data.redPacketCount || 0;
+          this.statistics.correctAnswerNum = response.data.correctAnswerNum || 0;
+          this.statistics.redPacketAmount = response.data.redPacketAmount || 0;
+
+        } else {
+          this.$message.error(response.msg || '获取数据失败');
+        }
+        this.loading = false;
+      }).catch(error => {
+        console.error('获取数据失败:', error);
+        this.$message.error('获取数据失败');
+        this.loading = false;
+      });
+
+    }
+  }
+};
+</script>
+
+<style scoped>
+.statistics-container {
+  height: 100%;
+  overflow: hidden;
+  position: relative;
+}
+
+.fixed-header {
+  position: sticky;
+  top: 0;
+  z-index: 10;
+  background-color: #fff;
+  padding: 10px 0;
+  border-bottom: 1px solid #EBEEF5;
+}
+
+.table-wrapper {
+  height: calc(100% - 220px);
+  overflow: visible;
+  position: relative;
+}
+
+.custom-pagination-container {
+  padding: 10px 0 12px 0;
+  text-align: right;
+  background-color: #fff;
+  position: relative;
+  z-index: 1;
+}
+
+/* 覆盖原有的pagination-container样式 */
+:deep(.pagination-container) {
+  height: auto !important;
+  margin-bottom: 0 !important;
+  margin-top: 0 !important;
+  padding: 0 !important;
+}
+
+.statistics-row {
+  margin: 20px 0;
+}
+
+.statistics-item {
+  background-color: #f5f7fa;
+  border-radius: 4px;
+  padding: 15px;
+  text-align: center;
+  height: 100px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+
+.statistics-title {
+  font-size: 14px;
+  color: #606266;
+  margin-bottom: 10px;
+}
+
+.statistics-value {
+  font-size: 20px;
+  font-weight: bold;
+  color: #303133;
+}
+</style>

+ 10 - 1
src/views/live/live/index.vue

@@ -103,6 +103,13 @@
             @click="handleDelete(scope.row)"
             v-hasPermi="['live:live:remove']"
           >删除</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-monitor"
+            @click="handleManage(scope.row)"
+            v-hasPermi="['live:live:remove']"
+          >管理</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -181,7 +188,6 @@
 <script>
 import { listLive, getLive, delLive, addLive, updateLive, exportLive } from "@/api/live/live";
 import Editor from '@/components/Editor/wang';
-import articleDetails from "@/views/components/his/doctorArticleDetails.vue";
 
 export default {
   name: "Live",
@@ -420,6 +426,9 @@ export default {
           this.msgSuccess("删除成功");
         }).catch(() => {});
     },
+    handleManage(row) {
+      this.$router.push('/live/liveConsole/' + row.liveId)
+    },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;

+ 76 - 68
src/views/live/liveAnchor/index.vue

@@ -1,69 +1,57 @@
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
-      <el-form-item label="昵称" prop="nickName">
-        <el-input
-          v-model="queryParams.nickName"
-          placeholder="请输入昵称"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="密码" prop="password">
-        <el-input
-          v-model="queryParams.password"
-          placeholder="请输入密码"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="手机号" prop="mobile">
-        <el-input
-          v-model="queryParams.mobile"
-          placeholder="请输入手机号"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="微信OPENID" prop="openId">
-        <el-input
-          v-model="queryParams.openId"
-          placeholder="请输入微信OPENID"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="身份证反面" prop="idCardBackUrl">
-        <el-input
-          v-model="queryParams.idCardBackUrl"
-          placeholder="请输入身份证反面"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="身份证正面" prop="idCardFrontUrl">
-        <el-input
-          v-model="queryParams.idCardFrontUrl"
-          placeholder="请输入身份证正面"
-          clearable
-          size="small"
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-      <el-form-item label="状态  1正常 0禁用" prop="status">
-        <el-select v-model="queryParams.status" placeholder="请选择状态  1正常 0禁用" clearable size="small">
-          <el-option label="请选择字典生成" value="" />
-        </el-select>
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
-      </el-form-item>
+      <el-row :gutter="10">
+        <el-col :span="6">
+          <el-form-item label="昵称" prop="nickName">
+            <el-input
+              v-model="queryParams.nickName"
+              placeholder="请输入昵称"
+              clearable
+              size="small"
+              @keyup.enter.native="handleQuery"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="6">
+          <el-form-item label="手机号" prop="mobile">
+            <el-input
+              v-model="queryParams.mobile"
+              placeholder="请输入手机号"
+              clearable
+              size="small"
+              @keyup.enter.native="handleQuery"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="6">
+          <el-form-item label="微信OPENID" prop="openId">
+            <el-input
+              v-model="queryParams.openId"
+              placeholder="请输入微信OPENID"
+              clearable
+              size="small"
+              @keyup.enter.native="handleQuery"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="6">
+          <el-form-item label="状态" prop="status">
+            <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
+              <el-option
+                v-for="dict in statusOptions"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="dict.dictValue"
+              ></el-option>
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+        <el-form-item>
+          <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+          <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+        </el-form-item>
     </el-form>
 
     <el-row :gutter="10" class="mb8">
@@ -122,7 +110,7 @@
       <el-table-column label="微信OPENID" align="center" prop="openId" />
       <el-table-column label="身份证反面" align="center" prop="idCardBackUrl" />
       <el-table-column label="身份证正面" align="center" prop="idCardFrontUrl" />
-      <el-table-column label="状态  1正常 0禁用" align="center" prop="status" />
+      <el-table-column label="状态" align="center" prop="status" :formatter="anchorStatusFormatter"/>
       <el-table-column label="备注" align="center" prop="remark" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
@@ -168,14 +156,17 @@
           <el-input v-model="form.openId" placeholder="请输入微信OPENID" />
         </el-form-item>
         <el-form-item label="身份证反面" prop="idCardBackUrl">
-          <el-input v-model="form.idCardBackUrl" placeholder="请输入身份证反面" />
+          <ImageUpload  v-model="form.idCardBackUrl" type="image" :limit=2 :width="150"
+                        :height="150"/>
         </el-form-item>
         <el-form-item label="身份证正面" prop="idCardFrontUrl">
-          <el-input v-model="form.idCardFrontUrl" placeholder="请输入身份证正面" />
+          <ImageUpload  v-model="form.idCardFrontUrl" type="image" :limit=1 :width="150"
+                       :height="150"/>
+<!--          示例图片-->
         </el-form-item>
-        <el-form-item label="状态  1正常 0禁用">
+        <el-form-item label="状态">
           <el-radio-group v-model="form.status">
-            <el-radio label="1">请选择字典生成</el-radio>
+            <el-radio :label="item.dictValue" v-for="item in statusOptions" >{{item.dictLabel}}</el-radio>
           </el-radio-group>
         </el-form-item>
         <el-form-item label="备注" prop="remark">
@@ -197,6 +188,8 @@ export default {
   name: "LiveAnchor",
   data() {
     return {
+      //字典
+      statusOptions: [],
       // 遮罩层
       loading: true,
       // 导出遮罩层
@@ -238,6 +231,9 @@ export default {
   },
   created() {
     this.getList();
+    this.getDicts("sys_live_anchor_status").then(response => {
+      this.statusOptions = response.data;
+    });
   },
   methods: {
     /** 查询主播列表 */
@@ -249,6 +245,9 @@ export default {
         this.loading = false;
       });
     },
+    anchorStatusFormatter(row, column) {
+      return this.selectDictLabel(this.statusOptions, row.status);
+    },
     // 取消按钮
     cancel() {
       this.open = false;
@@ -357,3 +356,12 @@ export default {
   }
 };
 </script>
+<style >
+.el-form-item__label {
+  width: 120px !important;
+}
+.el-input {
+  width: 80% !important;
+}
+
+</style>

+ 3 - 3
src/views/live/liveData/index.vue

@@ -148,7 +148,7 @@
         top10List: [
           {
             rank: 1,
-            name: "弘珍医药年末会员福利专场!",
+            name: "御君方年末会员福利专场!",
             cover:"https://cos.his.cdwjyyh.com/fs/20250304/710ea5b1896749b58438b76baf881d05.jpeg",
             pv: 88332,
             uv: 32674,
@@ -351,7 +351,7 @@
     methods: {
       changeDate(value) {
         if (this.selectedTimeRange === "week" && value) {
-          /*console.log("?? 监听到 selectedWeek 变化:", newVal);*/
+          /*console.log("🟢 监听到 selectedWeek 变化:", newVal);*/
           this.weekRange = this.getWeekRange(value);
         } else {
           this.weekRange = "";
@@ -359,7 +359,7 @@
         console.log("选择的时间:", value, "筛选方式:", this.selectedTimeRange);
       },
       getWeekRange(selectedWeek) {
-        console.log("?? selectedWeek 输入值:", selectedWeek); // 检查传入值
+        console.log("🔹 selectedWeek 输入值:", selectedWeek); // 检查传入值
         let date = new Date(selectedWeek);
 
         if (isNaN(date.getTime())) {

+ 19 - 8
src/views/live/liveGoods/index.vue

@@ -55,9 +55,10 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="状态 1上架 0下架" prop="status">
-        <el-select v-model="queryParams.status" placeholder="请选择状态 1上架 0下架" clearable size="small">
-          <el-option label="请选择字典生成" value="" />
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
+<!--          <el-option label="请选择字典生成" value="" />-->
+          <el-option v-for="(item,index) in goodsStatusOptions" :key="item.dictValue+index" :label="item.dictLabel" :value="item.dictValue" />
         </el-select>
       </el-form-item>
       <el-form-item label="库存表" prop="stock">
@@ -141,7 +142,7 @@
       <el-table-column label="组图" align="center" prop="images" />
       <el-table-column label="单价" align="center" prop="price" />
       <el-table-column label="原价" align="center" prop="opPrice" />
-      <el-table-column label="状态 1上架 0下架" align="center" prop="status" />
+      <el-table-column label="状态" align="center" prop="status" :formatter="goodsStatusFormatter"/>
       <el-table-column label="库存表" align="center" prop="stock" />
       <el-table-column label="排序号" align="center" prop="sort" />
       <el-table-column label="备注" align="center" prop="remark" />
@@ -186,10 +187,12 @@
           <el-input v-model="form.goodsDesc" placeholder="请输入描述" />
         </el-form-item>
         <el-form-item label="封图" prop="imgUrl">
-          <el-input v-model="form.imgUrl" placeholder="请输入封图" />
+          <ImageUpload  v-model="form.imgUrl" type="image" :limit=1 :width="150"
+                        :height="150"/>
         </el-form-item>
         <el-form-item label="组图" prop="images">
-          <el-input v-model="form.images" type="textarea" placeholder="请输入内容" />
+          <ImageUpload  v-model="form.images" type="image" :limit=10 :width="150"
+                        :height="150"/>
         </el-form-item>
         <el-form-item label="单价" prop="price">
           <el-input v-model="form.price" placeholder="请输入单价" />
@@ -197,9 +200,9 @@
         <el-form-item label="原价" prop="opPrice">
           <el-input v-model="form.opPrice" placeholder="请输入原价" />
         </el-form-item>
-        <el-form-item label="状态 1上架 0下架">
+        <el-form-item label="状态">
           <el-radio-group v-model="form.status">
-            <el-radio label="1">请选择字典生成</el-radio>
+            <el-radio :label="item.dictValue" v-for="item in goodsStatusOptions" >{{item.dictLabel}}</el-radio>
           </el-radio-group>
         </el-form-item>
         <el-form-item label="库存表" prop="stock">
@@ -227,6 +230,8 @@ export default {
   name: "LiveGoods",
   data() {
     return {
+      //字典
+      goodsStatusOptions: [],
       // 遮罩层
       loading: true,
       // 导出遮罩层
@@ -271,6 +276,9 @@ export default {
   },
   created() {
     this.getList();
+    this.getDicts("sys_live_goods_show").then(response => {
+      this.goodsStatusOptions = response.data;
+    });
   },
   methods: {
     /** 查询直播商品列表 */
@@ -282,6 +290,9 @@ export default {
         this.loading = false;
       });
     },
+    goodsStatusFormatter(row, column) {
+        return this.selectDictLabel(this.statusOptions, row.status);
+    },
     // 取消按钮
     cancel() {
       this.open = false;

+ 15 - 7
src/views/live/liveOrder/index.vue

@@ -107,9 +107,9 @@
           placeholder="选择完成时间">
         </el-date-picker>
       </el-form-item>
-      <el-form-item label="状态 1待支付 2已支付 3已发货 4已完成 -1已取消 -2已退款" prop="status">
-        <el-select v-model="queryParams.status" placeholder="请选择状态 1待支付 2已支付 3已发货 4已完成 -1已取消 -2已退款" clearable size="small">
-          <el-option label="请选择字典生成" value="" />
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
+          <el-option v-for="(item,index) in orderStatusOptions" :key="item.dictValue+index" :label="item.dictLabel" :value="item.dictValue" />
         </el-select>
       </el-form-item>
       <el-form-item>
@@ -167,7 +167,7 @@
 
     <el-table border v-loading="loading" :data="liveOrderList" @selection-change="handleSelectionChange">
       <el-table-column type="selection" width="55" align="center" />
-      <el-table-column label="状态 1待支付 2已支付 3已发货 4已完成 -1已取消 -2已退款" align="center" prop="orderId" />
+      <el-table-column label="订单ID" align="center" prop="orderId"/>
       <el-table-column label="订单号" align="center" prop="orderSn" />
       <el-table-column label="用户ID" align="center" prop="userId" />
       <el-table-column label="收货人" align="center" prop="userName" />
@@ -188,7 +188,7 @@
           <span>{{ parseTime(scope.row.finishTime, '{y}-{m}-{d}') }}</span>
         </template>
       </el-table-column>
-      <el-table-column label="状态 1待支付 2已支付 3已发货 4已完成 -1已取消 -2已退款" align="center" prop="status" />
+      <el-table-column label="状态" align="center" prop="status" :formatter="orderStatusFormatter"/>
       <el-table-column label="备注" align="center" prop="remark" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
@@ -267,9 +267,9 @@
             placeholder="选择完成时间">
           </el-date-picker>
         </el-form-item>
-        <el-form-item label="状态 1待支付 2已支付 3已发货 4已完成 -1已取消 -2已退款">
+        <el-form-item label="状态">
           <el-radio-group v-model="form.status">
-            <el-radio label="1">请选择字典生成</el-radio>
+            <el-radio :label="item.dictValue" v-for="item in orderStatusOptions" >{{item.dictLabel}}</el-radio>
           </el-radio-group>
         </el-form-item>
         <el-form-item label="备注" prop="remark">
@@ -291,6 +291,8 @@ export default {
   name: "LiveOrder",
   data() {
     return {
+      //字典
+      orderStatusOptions: [],
       // 遮罩层
       loading: true,
       // 导出遮罩层
@@ -338,6 +340,9 @@ export default {
   },
   created() {
     this.getList();
+    this.getDicts("sys_live_order_status").then(response => {
+      this.orderStatusOptions = response.data;
+    });
   },
   methods: {
     /** 查询订单列表 */
@@ -349,6 +354,9 @@ export default {
         this.loading = false;
       });
     },
+    orderStatusFormatter(row, column) {
+      return this.selectDictLabel(this.orderStatusOptions, row.status);
+    },
     // 取消按钮
     cancel() {
       this.open = false;

+ 14 - 6
src/views/live/liveOrderitems/index.vue

@@ -46,9 +46,9 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="状态 1正常 2已退款" prop="status">
-        <el-select v-model="queryParams.status" placeholder="请选择状态 1正常 2已退款" clearable size="small">
-          <el-option label="请选择字典生成" value="" />
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable size="small">
+          <el-option v-for="(item,index) in orderGoodsStatusOptions" :key="item.dictValue+index" :label="item.dictLabel" :value="item.dictValue" />
         </el-select>
       </el-form-item>
       <el-form-item>
@@ -113,7 +113,7 @@
       <el-table-column label="商品名" align="center" prop="goodsName" />
       <el-table-column label="单价" align="center" prop="price" />
       <el-table-column label="数量" align="center" prop="num" />
-      <el-table-column label="状态 1正常 2已退款" align="center" prop="status" />
+      <el-table-column label="状态" align="center" prop="status" :formatter="orderGoodsStatusFormatter"/>
       <el-table-column label="备注" align="center" prop="remark" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
@@ -164,9 +164,9 @@
         <el-form-item label="数量" prop="num">
           <el-input v-model="form.num" placeholder="请输入数量" />
         </el-form-item>
-        <el-form-item label="状态 1正常 2已退款">
+        <el-form-item label="状态">
           <el-radio-group v-model="form.status">
-            <el-radio label="1">请选择字典生成</el-radio>
+            <el-radio :label="item.dictValue" v-for="item in orderGoodsStatusOptions" >{{item.dictLabel}}</el-radio>
           </el-radio-group>
         </el-form-item>
         <el-form-item label="备注" prop="remark">
@@ -188,6 +188,8 @@ export default {
   name: "LiveOrderitems",
   data() {
     return {
+      //字典
+      orderGoodsStatusOptions: [],
       // 遮罩层
       loading: true,
       // 导出遮罩层
@@ -229,6 +231,9 @@ export default {
   },
   created() {
     this.getList();
+    this.getDicts("sys_live_order_goods_status").then(response => {
+      this.orderGoodsStatusOptions = response.data;
+    });
   },
   methods: {
     /** 查询订单商品列表 */
@@ -240,6 +245,9 @@ export default {
         this.loading = false;
       });
     },
+    orderGoodsStatusFormatter(row, column) {
+      return this.selectDictLabel(this.orderGoodsStatusOptions, row.status);
+    },
     // 取消按钮
     cancel() {
       this.open = false;

+ 15 - 7
src/views/live/liveVideo/index.vue

@@ -19,9 +19,9 @@
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
-      <el-form-item label="类型 1录播 2回放" prop="videoType">
-        <el-select v-model="queryParams.videoType" placeholder="请选择类型 1录播 2回放" clearable size="small">
-          <el-option label="请选择字典生成" value="" />
+      <el-form-item label="类型" prop="videoType">
+        <el-select v-model="queryParams.videoType" placeholder="请选择类型" clearable size="small">
+          <el-option v-for="(item,index) in videoTypeOptions" :key="item.dictValue+index" :label="item.dictLabel" :value="item.dictValue" />
         </el-select>
       </el-form-item>
       <el-form-item label="排序号" prop="sort">
@@ -91,7 +91,7 @@
       <el-table-column label="ID" align="center" prop="videoId" />
       <el-table-column label="直播ID" align="center" prop="liveId" />
       <el-table-column label="视频地址" align="center" prop="videoUrl" />
-      <el-table-column label="类型 1录播 2回放" align="center" prop="videoType" />
+      <el-table-column label="类型" align="center" prop="videoType" :formatter="videoTypeFormatter"/>
       <el-table-column label="排序号" align="center" prop="sort" />
       <el-table-column label="备注" align="center" prop="remark" />
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
@@ -131,9 +131,9 @@
         <el-form-item label="视频地址" prop="videoUrl">
           <el-input v-model="form.videoUrl" placeholder="请输入视频地址" />
         </el-form-item>
-        <el-form-item label="类型 1录播 2回放" prop="videoType">
-          <el-select v-model="form.videoType" placeholder="请选择类型 1录播 2回放">
-            <el-option label="请选择字典生成" value="" />
+        <el-form-item label="类型" prop="videoType">
+          <el-select v-model="form.videoType" placeholder="请选择类型">
+            <el-option v-for="(item,index) in videoTypeOptions" :key="item.dictValue+index" :label="item.dictLabel" :value="item.dictValue" />
           </el-select>
         </el-form-item>
         <el-form-item label="排序号" prop="sort">
@@ -158,6 +158,8 @@ export default {
   name: "LiveVideo",
   data() {
     return {
+      //字典
+      videoTypeOptions: [],
       // 遮罩层
       loading: true,
       // 导出遮罩层
@@ -196,6 +198,9 @@ export default {
   },
   created() {
     this.getList();
+    this.getDicts("sys_live_video_type").then(response => {
+      this.videoTypeOptions = response.data;
+    });
   },
   methods: {
     /** 查询直播视频列表 */
@@ -207,6 +212,9 @@ export default {
         this.loading = false;
       });
     },
+    videoTypeFormatter(row, column) {
+      return this.selectDictLabel(this.videoTypeOptions, row.status);
+    },
     // 取消按钮
     cancel() {
       this.open = false;

+ 11 - 0
src/views/system/config/config.vue

@@ -719,6 +719,7 @@
       <el-form-item   label="erp类型" v-if="form13.erpOpen == 1">
         <el-radio v-model="form13.erpType" label=1>管易</el-radio>
         <el-radio v-model="form13.erpType" label=2>旺店通</el-radio>
+        <el-radio v-model="form13.erpType" label=3>瀚智OMS</el-radio>
       </el-form-item>
       <el-form-item   label="erpAppKey" v-if="form13.erpOpen == 1 && form13.erpType == 1 " prop="erpAppKey">
           <el-input   v-model="form13.erpAppKey"  label="请输入erpAppKey"></el-input>
@@ -947,6 +948,16 @@
                <el-input-number  v-model="form18.answerIntegral" :min="1"    ></el-input-number>
              </el-tooltip>
            </el-form-item>
+           <el-form-item label="ipad发送延迟">
+             <el-tooltip class="item" effect="dark" content="ipad发送消息延迟时间(ms)" placement="top-end">
+               <el-input-number  v-model="form18.delayStart" :min="100"></el-input-number>
+             </el-tooltip>
+           </el-form-item>
+           <el-form-item label="ipad发送延迟">
+             <el-tooltip class="item" effect="dark" content="ipad发送消息延迟时间(ms)" placement="top-end">
+               <el-input-number  v-model="form18.delayEnd" :min="100"></el-input-number>
+             </el-tooltip>
+           </el-form-item>
            <el-form-item label="看课默认线路" prop="defaultLine">
              <el-radio-group v-model="form18.defaultLine">
                <el-radio label="0">线路一</el-radio>