Browse Source

销售后台 报表统计

wangxy 11 hours ago
parent
commit
0e74d4c21f

+ 26 - 31
src/views/statistics/userReport.vue

@@ -5,28 +5,28 @@
         <el-radio-button label="user">会员维度</el-radio-button>
         <el-radio-button label="dept">部门维度</el-radio-button>
       </el-radio-group>
-      <el-form-item label="公司名" prop="companyId">
-        <el-select filterable v-model="queryParams.companyId" placeholder="请选择公司名"
-                   clearable size="small">
-          <el-option
-            v-for="item in companys"
-            :key="item.companyId"
-            :label="item.companyName"
-            :value="item.companyId"
-          />
-        </el-select>
-      </el-form-item>
+<!--      <el-form-item label="公司名" prop="companyId">-->
+<!--        <el-select filterable v-model="queryParams.companyId" placeholder="请选择公司名"-->
+<!--                   clearable size="small">-->
+<!--          <el-option-->
+<!--            v-for="item in companys"-->
+<!--            :key="item.companyId"-->
+<!--            :label="item.companyName"-->
+<!--            :value="item.companyId"-->
+<!--          />-->
+<!--        </el-select>-->
+<!--      </el-form-item>-->
       <el-form-item label="所属部门" prop="deptId" v-if="queryParams.dimension === 'dept'">
-        <treeselect style="width:205.4px" v-model="queryParams.deptId" :options="deptTreeOptions" :show-count="true" placeholder="请选择所属部门" :aria-disabled="!queryParams.companyId" />
+        <treeselect style="width:205.4px" v-model="queryParams.deptId" :options="deptTreeOptions" :show-count="true" placeholder="请选择所属部门" />
       </el-form-item>
       <el-form-item label="项目" prop="project">
         <el-select filterable v-model="queryParams.project" placeholder="请选择项目"
                    clearable size="small">
           <el-option
             v-for="item in projectList"
-            :key="item.dictCode"
+            :key="item.dictValue"
             :label="item.dictLabel"
-            :value="item.dictCode"
+            :value="item.dictValue"
           />
         </el-select>
       </el-form-item>
@@ -74,14 +74,12 @@
       <el-table-column label="会员id" align="center" prop="userId" />
       <el-table-column label="用户昵称" align="center" prop="nickName" />
       <el-table-column label="用户状态" align="center" prop="status" />
-      <el-table-column label="用户积分" align="center" prop="Integral"/>
+      <el-table-column label="用户积分" align="center" prop="integral"/>
       <el-table-column label="所属销售" align="center" prop="companyUserName"/>
       <el-table-column label="所属销售部门" align="center" prop="deptName" v-if="showDeptNameColumn"/>
       <el-table-column label="所属销售公司" align="center" prop="companyName"/>
-      <el-table-column label="首次进线时间" align="center" prop="firstTime"/>
       <el-table-column label="最近看课时间" align="center" prop="lastWatchTime" />
       <el-table-column label="看课数" align="center" prop="watchCount" />
-      <el-table-column label="缺课数" align="center" prop="absentCount" />
       <el-table-column label="参与营期数量" align="center" prop="periodCount" />
       <el-table-column label="看课状态" align="center" prop="watchStatus" />
       <el-table-column label="已消耗积分" align="center" prop="consumedIntegral" />
@@ -91,7 +89,6 @@
     <div class="total-summary">
       <span class="total-title">总计:</span>
       <span class="total-item">看课数: {{ calculatedTotalData.watchCount }}</span>
-      <span class="total-item">缺课数: {{ calculatedTotalData.absentCount }}</span>
       <span class="total-item">参与营期数量: {{ calculatedTotalData.periodCount }}</span>
       <span class="total-item">已消耗积分: {{ calculatedTotalData.consumedIntegral }}</span>
       <span class="total-item">用户积分: {{ calculatedTotalData.Integral }}</span>
@@ -194,16 +191,16 @@ export default {
       this.form.images = val.join(',')
     },
     // 监听公司选择变化,动态加载对应部门
-    'queryParams.companyId': {
-      handler(newVal) {
-        this.queryParams.deptId = null; // 清空已选择的部门
-        if (newVal) {
-          this.getTreeselect(newVal); // 根据公司ID获取部门树
-        } else {
-          this.deptTreeOptions = []; // 如果没有选择公司,则清空部门选项
-        }
-      }
-    }
+    // 'queryParams.companyId': {
+    //   handler(newVal) {
+    //     this.queryParams.deptId = null; // 清空已选择的部门
+    //     if (newVal) {
+    //       this.getTreeselect(newVal); // 根据公司ID获取部门树
+    //     } else {
+    //       this.deptTreeOptions = []; // 如果没有选择公司,则清空部门选项
+    //     }
+    //   }
+    // }
   },
   data() {
     return {
@@ -232,7 +229,6 @@ export default {
       productJson: [],
       calculatedTotalData: {
         watchCount: 0,
-        absentCount: 0,
         periodCount: 0,
         consumedIntegral: 0,
         Integral: 0,
@@ -302,6 +298,7 @@ export default {
     };
   },
   created() {
+    this.getTreeselect(this.$store.state.user.user.companyId);
     getCampList().then(response => {
       this.camps = response.data.list
       if (this.camps != null && this.camps.length > 0) {
@@ -355,7 +352,6 @@ export default {
       // 重置总计数据
       this.calculatedTotalData = {
         watchCount: 0,
-        absentCount: 0,
         periodCount: 0,
         consumedIntegral: 0,
         Integral: 0,
@@ -365,7 +361,6 @@ export default {
       // 遍历当前页数据计算总和
       this.packageList.forEach(item => {
         this.calculatedTotalData.watchCount += Number(item.watchCount) || 0;
-        this.calculatedTotalData.absentCount += Number(item.absentCount) || 0;
         this.calculatedTotalData.periodCount += Number(item.periodCount) || 0;
         this.calculatedTotalData.consumedIntegral += Number(item.consumedIntegral) || 0;
         this.calculatedTotalData.Integral += Number(item.Integral) || 0;

+ 88 - 57
src/views/statistics/watchlogReport.vue

@@ -2,33 +2,33 @@
   <div class="app-container">
 
     <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px">
-      <el-radio-group v-model="queryParams.dimension" @change="handleDimensionChange">
-        <el-radio-button label="user">用户维度</el-radio-button>
-        <el-radio-button label="sales">销售维度</el-radio-button>
-        <el-radio-button label="company">公司维度</el-radio-button>
-      </el-radio-group>
-      <el-form-item label="公司名" prop="companyId">
-        <el-select filterable v-model="queryParams.companyId" placeholder="请选择公司名"
-                   clearable size="small">
-          <el-option
-            v-for="item in companys"
-            :key="item.companyId"
-            :label="item.companyName"
-            :value="item.companyId"
-          />
-        </el-select>
-      </el-form-item>
+<!--      <el-radio-group v-model="queryParams.dimension" @change="handleDimensionChange">-->
+<!--        <el-radio-button label="user">用户维度</el-radio-button>-->
+<!--        <el-radio-button label="sales">销售维度</el-radio-button>-->
+<!--        <el-radio-button label="company">公司维度</el-radio-button>-->
+<!--      </el-radio-group>-->
+<!--      <el-form-item label="公司名" prop="companyId">-->
+<!--        <el-select filterable v-model="queryParams.companyId" placeholder="请选择公司名"-->
+<!--                   clearable size="small">-->
+<!--          <el-option-->
+<!--            v-for="item in companys"-->
+<!--            :key="item.companyId"-->
+<!--            :label="item.companyName"-->
+<!--            :value="item.companyId"-->
+<!--          />-->
+<!--        </el-select>-->
+<!--      </el-form-item>-->
       <el-form-item label="所属部门" prop="deptId">
-        <treeselect style="width:205.4px" v-model="queryParams.deptId" :options="deptTreeOptions" :show-count="true" placeholder="请选择所属部门" :aria-disabled="!queryParams.companyId" />
+        <treeselect style="width:205.4px" v-model="queryParams.deptId" :options="deptTreeOptions" :show-count="true" placeholder="请选择所属部门" />
       </el-form-item>
       <el-form-item label="项目" prop="project">
         <el-select filterable v-model="queryParams.project" placeholder="请选择项目"
                    clearable size="small">
           <el-option
             v-for="item in projectList"
-            :key="item.dictCode"
+            :key="item.dictValue"
             :label="item.dictLabel"
-            :value="item.dictCode"
+            :value="item.dictValue"
           />
         </el-select>
       </el-form-item>
@@ -49,11 +49,16 @@
                     :normalizer="normalizer" />
       </el-form-item>
       <el-form-item>
-        <el-form-item label="下单时间" prop="createTime">
+        <el-form-item label="看课时间" prop="createTime">
           <el-date-picker v-model="createTime" size="small" style="width: 220px" value-format="yyyy-MM-dd"
                           type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
                           @change="xdChange"></el-date-picker>
         </el-form-item>
+        <el-form-item label="下单时间" prop="createTime">
+          <el-date-picker v-model="orderTime" size="small" style="width: 220px" value-format="yyyy-MM-dd"
+                          type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
+                          @change="ydChange"></el-date-picker>
+        </el-form-item>
       </el-form-item>
       <el-form-item label="会员ID" prop="userId">
         <el-input v-model="queryParams.userId" placeholder="请输入会员ID" clearable size="small" />
@@ -73,29 +78,32 @@
 
 
     <el-table v-loading="loading" border :data="packageList">
-      <!-- 动态列渲染 -->
-      <template v-for="column in dynamicColumns">
-        <el-table-column
-          :key="column.prop"
-          v-if="!column.condition || column.condition()"
-          :label="column.label"
-          :prop="column.prop"
-          :align="column.align || 'center'"
-          :width="column.width"
-          :sortable="column.sortable ? 'custom' : false"
-        />
-      </template>
+      <el-table-column label="会员id" align="center" prop="userId" />
+      <el-table-column label="会员昵称" align="center" prop="nickName" />
+      <el-table-column label="所属销售" align="center" prop="salesName" />
+      <el-table-column label="所属销售部门" align="center" prop="salesDept"/>
+      <el-table-column label="所属销售公司" align="center" prop="salesCompany"/>
+      <el-table-column label="训练营" align="center" prop="trainingCampName"/>
+      <el-table-column label="营期" align="center" prop="periodName"/>
+      <el-table-column label="小节名称" align="center" prop="videoTitle" />
+      <el-table-column label="看课状态" align="center" prop="watchStatus" />
+      <el-table-column label="播放时长" align="center" prop="duration" />
+      <el-table-column label="看课时间" align="center" prop="courseTime" />
+      <el-table-column label="完课时间" align="center" prop="finishTime" />
+      <el-table-column label="答题状态" align="center" prop="answerStatus" />
+      <el-table-column label="红包金额" align="center" prop="redPacketAmount" />
+      <el-table-column label="历史疗法订单数" align="center" prop="historyOrderCount" />
     </el-table>
-    <div class="total-summary">
-      <span class="total-title">总计:</span>
-      <span class="total-item">完课数: {{ calculatedTotalData.finishedCount }}</span>
-      <span class="total-item">未完课: {{ calculatedTotalData.unfinishedCount }}</span>
-      <span class="total-item">完课率: {{ calculatedTotalData.completionRate }}</span>
-      <span class="total-item">未看数: {{ calculatedTotalData.notWatchedCount }}</span>
-      <span class="total-item">未答题人数: {{ calculatedTotalData.notAnsweredCount }}</span>
-      <span class="total-item">红包金额: {{ calculatedTotalData.redPacketAmount }}</span>
-      <span class="total-item">历史疗法订单数: {{ calculatedTotalData.historyOrderCount }}</span>
-    </div>
+<!--    <div class="total-summary">-->
+<!--      <span class="total-title">总计:</span>-->
+<!--      <span class="total-item">完课数: {{ calculatedTotalData.finishedCount }}</span>-->
+<!--      <span class="total-item">未完课: {{ calculatedTotalData.unfinishedCount }}</span>-->
+<!--      <span class="total-item">完课率: {{ calculatedTotalData.completionRate }}</span>-->
+<!--      <span class="total-item">未看数: {{ calculatedTotalData.notWatchedCount }}</span>-->
+<!--      <span class="total-item">未答题人数: {{ calculatedTotalData.notAnsweredCount }}</span>-->
+<!--      <span class="total-item">红包金额: {{ calculatedTotalData.redPacketAmount }}</span>-->
+<!--      <span class="total-item">历史疗法订单数: {{ calculatedTotalData.historyOrderCount }}</span>-->
+<!--    </div>-->
     <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
                 @pagination="getList" />
 
@@ -192,16 +200,18 @@ export default {
       this.form.images = val.join(',')
     },
     // 监听公司选择变化,动态加载对应部门
-    'queryParams.companyId': {
-      handler(newVal) {
-        this.queryParams.deptId = null; // 清空已选择的部门
-        if (newVal) {
-          this.getTreeselect(newVal); // 根据公司ID获取部门树
-        } else {
-          this.deptTreeOptions = []; // 如果没有选择公司,则清空部门选项
-        }
-      }
-    }
+    // 'queryParams.companyId': {
+    //   handler(newVal) {
+    //     this.queryParams.deptId = null; // 清空已选择的部门
+    //     const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}');
+    //     const companyId = newVal || userInfo.companyId;
+    //     if (companyId) {
+    //       this.getTreeselect(companyId); // 根据公司ID获取部门树
+    //     } else {
+    //       this.deptTreeOptions = []; // 如果没有选择公司,则清空部门选项
+    //     }
+    //   }
+    // }
   },
   data() {
     return {
@@ -317,6 +327,7 @@ export default {
       // 总条数
       total: 0,
       createTime: null,
+      orderTime: null,
       // 套餐包表格数据
       packageList: [],
       // 弹出层标题
@@ -347,6 +358,8 @@ export default {
         periodId:null,
         sTime: null,
         eTime: null,
+        orderSTime: null,
+        orderETime: null,
         deptId: null,
         dimension: 'user'
       },
@@ -355,13 +368,15 @@ export default {
     };
   },
   computed: {
-    // 计算属性:根据当前维度返回动态列
-    dynamicColumns() {
-      const dimension = this.queryParams.dimension || 'user';
-      return this.columnConfig[dimension] || this.columnConfig.user;
-    }
+    // // 计算属性:根据当前维度返回动态列
+    // dynamicColumns() {
+    //   const dimension = this.queryParams.dimension || 'user';
+    //   return this.columnConfig[dimension] || this.columnConfig.user;
+    // }
   },
   created() {
+    console.log('公司id是否存在',this.$store.state.user.user)
+    this.getTreeselect(this.$store.state.user.user.companyId);
     this.$nextTick(() => {
       console.log('handleDimensionChange 方法是否存在:', typeof this.handleDimensionChange);
       console.log('所有方法:', Object.keys(this));
@@ -522,6 +537,7 @@ export default {
         productJson: null,
         status: 0,
         createTime: null,
+        orderTime: null,
         updateTime: null,
         isDel: null,
         payType: ["1"],
@@ -562,8 +578,13 @@ export default {
       this.handleQuery();
       // 清空所有时间相关变量
       this.createTime = null;
+      this.orderTime = null;
       this.startTime = null;
       this.endTime = null;
+      this.queryParams.sTime = null;
+      this.queryParams.orderSTime= null;
+      this.queryParams.eTime = null;
+      this.queryParams.orderETime= null;
     },
     xdChange() {
       if (this.createTime != null) {
@@ -573,7 +594,17 @@ export default {
         this.queryParams.sTime = null;
         this.queryParams.eTime = null;
       }
+    },
+    ydChange() {
+      if (this.orderTime != null) {
+        this.queryParams.orderSTime = this.orderTime[0];
+        this.queryParams.orderETime = this.orderTime[1];
+      } else {
+        this.queryParams.orderSTime = null;
+        this.queryParams.orderETime = null;
+      }
     }
+
   }
 };
 </script>

+ 697 - 0
src/views/statistics/watchlogReportCompany.vue

@@ -0,0 +1,697 @@
+<template>
+  <div class="app-container">
+
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px">
+<!--      <el-radio-group v-model="queryParams.dimension" @change="handleDimensionChange">-->
+<!--        <el-radio-button label="user">用户维度</el-radio-button>-->
+<!--        <el-radio-button label="sales">销售维度</el-radio-button>-->
+<!--        <el-radio-button label="company">公司维度</el-radio-button>-->
+<!--      </el-radio-group>-->
+<!--      <el-form-item label="公司名" prop="companyId">-->
+<!--        <el-select filterable v-model="queryParams.companyId" placeholder="请选择公司名"-->
+<!--                   clearable size="small">-->
+<!--          <el-option-->
+<!--            v-for="item in companys"-->
+<!--            :key="item.companyId"-->
+<!--            :label="item.companyName"-->
+<!--            :value="item.companyId"-->
+<!--          />-->
+<!--        </el-select>-->
+<!--      </el-form-item>-->
+      <el-form-item label="所属部门" prop="deptId">
+        <treeselect style="width:205.4px" v-model="queryParams.deptId" :options="deptTreeOptions" :show-count="true" placeholder="请选择所属部门" />
+      </el-form-item>
+      <el-form-item label="项目" prop="project">
+        <el-select filterable v-model="queryParams.project" placeholder="请选择项目"
+                   clearable size="small">
+          <el-option
+            v-for="item in projectList"
+            :key="item.dictValue"
+            :label="item.dictLabel"
+            :value="item.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="训练营" prop="trainingCampId">
+        <el-select filterable v-model="queryParams.trainingCampId" placeholder="请选择训练营"
+                   clearable size="small"  @change="handleCampChange">
+          <el-option
+            v-for="item in camps"
+            :key="item.dictValue"
+            :label="item.dictLabel"
+            :value="item.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <treeselect style="width: 220px" v-model="queryParams.periodId" :options="deptOptions"
+                    clearable :show-count="true" placeholder="请选择归属营期" value-consists-of="LEAF_PRIORITY"
+                    :normalizer="normalizer" />
+      </el-form-item>
+      <el-form-item>
+        <el-form-item label="看课时间" prop="createTime">
+          <el-date-picker v-model="createTime" size="small" style="width: 220px" value-format="yyyy-MM-dd"
+                          type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
+                          @change="xdChange"></el-date-picker>
+        </el-form-item>
+        <el-form-item label="下单时间" prop="orderTime">
+          <el-date-picker v-model="orderTime" size="small" style="width: 220px" value-format="yyyy-MM-dd"
+                          type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
+                          @change="ydChange"></el-date-picker>
+        </el-form-item>
+      </el-form-item>
+      <el-form-item label="会员ID" prop="userId">
+        <el-input v-model="queryParams.userId" placeholder="请输入会员ID" clearable size="small" />
+      </el-form-item>
+      <el-form-item label="会员手机号" prop="userPhone">
+        <el-input v-model="queryParams.userPhone" placeholder="请输入会员手机号" clearable size="small" />
+      </el-form-item>
+      <el-form-item label="会员昵称" prop="nickName">
+        <el-input v-model="queryParams.nickName" placeholder="请输入会员昵称" clearable size="small" />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+
+    <el-table v-loading="loading" border :data="packageList">
+      <el-table-column label="销售" align="center" prop="salesName" />
+      <el-table-column label="会员数" align="center" prop="userCount" />
+      <el-table-column label="当前会员上线数" align="center" prop="onlineUserCount" />
+      <el-table-column label="所属销售部门" align="center" prop="salesDept"/>
+      <el-table-column label="所属销售公司" align="center" prop="salesCompany"/>
+      <el-table-column label="训练营" align="center" prop="trainingCampName"/>
+      <el-table-column label="营期" align="center" prop="periodName"/>
+      <el-table-column label="课程小节" align="center" prop="videoTitle" />
+      <el-table-column label="完课数" align="center" prop="finishedCount" />
+      <el-table-column label="未完课" align="center" prop="unfinishedCount" />
+      <el-table-column label="完课率" align="center" prop="completionRate" />
+      <el-table-column label="看课时间" align="center" prop="courseTime" />
+      <el-table-column label="未看数" align="center" prop="notWatchedCount" />
+      <el-table-column label="未答题人数" align="center" prop="notAnsweredCount" />
+      <el-table-column label="红包金额" align="center" prop="redPacketAmount" />
+      <el-table-column label="历史疗法订单数" align="center" prop="historyOrderCount" />
+    </el-table>
+    <div class="total-summary">
+      <span class="total-title">总计:</span>
+      <span class="total-item">完课数: {{ calculatedTotalData.finishedCount }}</span>
+      <span class="total-item">未完课: {{ calculatedTotalData.unfinishedCount }}</span>
+      <span class="total-item">完课率: {{ calculatedTotalData.completionRate }}</span>
+      <span class="total-item">未看数: {{ calculatedTotalData.notWatchedCount }}</span>
+      <span class="total-item">未答题人数: {{ calculatedTotalData.notAnsweredCount }}</span>
+      <span class="total-item">红包金额: {{ calculatedTotalData.redPacketAmount }}</span>
+      <span class="total-item">历史疗法订单数: {{ calculatedTotalData.historyOrderCount }}</span>
+    </div>
+    <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
+                @pagination="getList" />
+
+    <!-- 添加或修改套餐包对话框 -->
+    <!-- <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="110px">
+        <el-form-item label="套餐包名称" prop="packageName">
+          <el-input v-model="form.packageName" placeholder="请输入套餐包名称" />
+        </el-form-item>
+        <el-form-item label="排序号" prop="sort">
+           <el-input-number v-model="form.sort"  :min="0" label="排序号"></el-input-number>
+        </el-form-item>
+        <el-form-item label="状态">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="parseInt(dict.dictValue)"
+            >{{dict.dictLabel}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="价格配置" prop="priceJson">
+
+
+                 <el-table :data="priceJson"    :cell-style="{ textAlign: 'center' }"		 :header-cell-style="{textAlign: 'center'}"   >
+                   <el-table-column label="子套餐标题" prop="title" width="150px">
+                     <template slot-scope="scope">
+                       <el-input v-model="scope.row.title" ></el-input>
+                     </template>
+                   </el-table-column>
+                   <el-table-column label="签约时长/日" prop="duration" width="150px">
+                     <template slot-scope="scope">
+                       <el-input-number v-model="scope.row.duration" controls-position="right" :min="0" size="small"></el-input-number>
+
+                     </template>
+                   </el-table-column>
+                   <el-table-column label="价格/元" prop="price" width="150px">
+                     <template slot-scope="scope">
+                        <el-input-number v-model="scope.row.price" controls-position="right"  :min="0" size="small"></el-input-number>
+
+                      </template>
+                   </el-table-column>
+                   <el-table-column label="状态"  prop="status">
+                     <template slot-scope="scope">
+                       <el-switch v-model="scope.row.status" active-color="#13ce66" inactive-color="#ff4949" ></el-switch>
+                     </template>
+                   </el-table-column>
+                   <el-table-column label="操作">
+                     <template slot-scope="scope">
+                        <el-button @click="deleteRow(scope.$index)"   size="mini" type="text" v-if="priceJson.length>1">删除</el-button>
+                         <el-button @click="addRow" size="mini" type="text" >新增</el-button>
+                     </template>
+                   </el-table-column>
+                 </el-table>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog> -->
+  </div>
+</template>
+
+<script>
+import {
+  listPackage,
+  getPackage,
+  delPackage,
+  addPackage,
+  updatePackage,
+  exportPackage,
+  userReport, watchLogReport
+} from "@/api/store/package";
+import { getAllFollowTempName } from "@/api/store/followTemp";
+import { allIcd } from "@/api/store/icd";
+import Editor from '@/components/Editor/wang.vue';
+import Material from '@/components/Material/index.vue';
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import { listStore,getCampList,getPeriodList} from "@/api/store/storeProduct";
+import { getAllCateList } from "@/api/store/packageCate";
+import { Loading } from 'element-ui';
+import {getCompanyList} from "@/api/company/company";
+import {selectDeptTree} from "@/api/company/companyDept";
+export default {
+  name: "WatchlogReport",
+  components: {Treeselect},
+  watch: {
+    imageArr: function (val) {
+      this.form.imgUrl = val.join(',')
+    },
+    photoArr: function (val) {
+      this.form.images = val.join(',')
+    },
+    // 监听公司选择变化,动态加载对应部门
+    // 'queryParams.companyId': {
+    //   handler(newVal) {
+    //     this.queryParams.deptId = null; // 清空已选择的部门
+    //     const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}');
+    //     const companyId = newVal || userInfo.companyId;
+    //     if (companyId) {
+    //       this.getTreeselect(companyId); // 根据公司ID获取部门树
+    //     } else {
+    //       this.deptTreeOptions = []; // 如果没有选择公司,则清空部门选项
+    //     }
+    //   }
+    // }
+  },
+  data() {
+    return {
+      normalizer: function(node) {
+        return {
+          id: node.id || node.dictValue,
+          label: node.label || node.dictLabel,
+          children: node.children
+        }
+      },
+      columnConfig: {
+        user: [
+          { prop: 'userId', label: '会员id', width: 120 },
+          { prop: 'nickName', label: '用户昵称', width: 120 },
+          { prop: 'salesName', label: '所属销售', width: 120 },
+          { prop: 'salesDept', label: '所属销售部门', width: 120, condition: () => this.showDeptNameColumn },
+          { prop: 'salesCompany', label: '所属销售公司', width: 120 },
+          { prop: 'trainingCampName', label: '训练营', width: 150 },
+          { prop: 'periodName', label: '营期', width: 150 },
+          { prop: 'videoTitle', label: '小节名称', width: 100 },
+          { prop: 'watchStatus', label: '看课状态', width: 100 },
+          { prop: 'duration', label: '播放时长', width: 120 },
+          { prop: 'courseTime', label: '看课时间', width: 100 },
+          { prop: 'finishTime', label: '完课时间', width: 100 },
+          { prop: 'answerStatus', label: '答题状态', width: 100 },
+          { prop: 'redPacketAmount', label: '红包金额', width: 120 },
+          { prop: 'historyOrderCount', label: '历史疗法订单数', width: 120 }
+        ],
+        sales: [
+          { prop: 'salesName', label: '销售', width: 120 },
+          { prop: 'userCount', label: '会员数', width: 120 },
+          { prop: 'onlineUserCount', label: '当前线上会员数', width: 120 },
+          { prop: 'salesDept', label: '所属销售部门', width: 100, sortable: true },
+          { prop: 'salesCompany', label: '所属销售公司', width: 120, sortable: true },
+          { prop: 'trainingCampName', label: '训练营', width: 100, sortable: true },
+          { prop: 'periodName', label: '营期', width: 100, sortable: true },
+          { prop: 'videoTitle', label: '课程小节', width: 100, sortable: true },
+          { prop: 'finishedCount', label: '完课数', width: 100, sortable: true },
+          { prop: 'unfinishedCount', label: '未完课', width: 120, sortable: true },
+          { prop: 'completionRate', label: '完课率', width: 100, sortable: true },
+          { prop: 'courseTime', label: '发课时间', width: 100, sortable: true },
+          { prop: 'notWatchedCount', label: '未看数', width: 100, sortable: true },
+          { prop: 'notAnsweredCount', label: '未答题人数', width: 100, sortable: true },
+          { prop: 'redPacketAmount', label: '红包金额', width: 120 },
+          { prop: 'historyOrderCount', label: '历史疗法订单数', width: 120 }
+        ],
+        company: [
+          { prop: 'salesDept', label: '销售部门', width: 120 },
+          { prop: 'salesCount', label: '销售数', width: 120 },
+          { prop: 'userCount', label: '会员数', width: 120 },
+          { prop: 'onlineUserCount', label: '当前会员上线数', width: 100, sortable: true },
+          { prop: 'salesCompany', label: '所属销售公司', width: 100, sortable: true },
+          { prop: 'trainingCampName', label: '训练营', width: 120, sortable: true },
+          { prop: 'periodName', label: '营期', width: 100, sortable: true },
+          { prop: 'videoTitle', label: '课程小节', width: 100, sortable: true },
+          { prop: 'finishedCount', label: '完课数', width: 100, sortable: true },
+          { prop: 'unfinishedCount', label: '未完课', width: 120, sortable: true },
+          { prop: 'completionRate', label: '完课率', width: 100, sortable: true },
+          { prop: 'courseTime', label: '发课时间', width: 100, sortable: true },
+          { prop: 'notWatchedCount', label: '未看数', width: 100, sortable: true },
+          { prop: 'notAnsweredCount', label: '未答题人数', width: 100, sortable: true },
+          { prop: 'redPacketAmount', label: '红包金额', width: 120 },
+          { prop: 'historyOrderCount', label: '历史疗法订单数', width: 120 }
+        ]
+      },
+      showDeptNameColumn: false,
+      projectList: [],
+      companys: [],
+      camps: [],
+      deptOptions : [],
+      deptTreeOptions: [],
+      uploadUrl: process.env.VUE_APP_BASE_API + "/common/uploadOSS",
+      photoArr: [],
+      productTypeOptions: [],
+      storeId: null,
+      storeOPtions: [],
+      totalMoney: 0.00,
+      drugOpen: false,
+      checkList: ['1'],
+      drugList: [],
+      productJson: [],
+      calculatedTotalData: {
+        finishedCount: 0,
+        unfinishedCount: 0,
+        completionRate: 0,
+        notWatchedCount: 0,
+        notAnsweredCount: 0,
+        redPacketAmount: 0,
+        historyOrderCount: 0
+      },
+      describeJson: { usageMethod: "", forPeople: "", tabootPeople: "", use: "" },
+      icdList: [],
+      show: {
+        open: false,
+      },
+      priceJson: [
+        { title: "套餐1", duration: "0", price: "0", status: true },
+      ],
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      startTime : null,
+      endTime : null,
+      // 总条数
+      total: 0,
+      createTime: null,
+      orderTime: null,
+      // 套餐包表格数据
+      packageList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 状态字典
+      tempOptions: [],
+      statusOptions: [],
+      payTypeOptions: [],
+      orOptions: [],
+      packageTypeOptions: [],
+      diseaseTypeOptions: [],
+      packageSubTypeOptions: [],
+      solarTermOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        packageName: null,
+        sort: null,
+        priceJson: null,
+        status: null,
+        isDel: null,
+        companyId:null,
+        project:null,
+        trainingCampId:null,
+        periodId:null,
+        sTime: null,
+        eTime: null,
+        orderSTime: null,
+        orderETime: null,
+        deptId: null,
+        dimension: 'sales'
+      },
+      // 表单参数
+      form: {},
+    };
+  },
+  computed: {
+    // // 计算属性:根据当前维度返回动态列
+    // dynamicColumns() {
+    //   const dimension = this.queryParams.dimension || 'user';
+    //   return this.columnConfig[dimension] || this.columnConfig.user;
+    // }
+  },
+  created() {
+    console.log('公司id是否存在',this.$store.state.user.user)
+    this.getTreeselect(this.$store.state.user.user.companyId);
+    this.$nextTick(() => {
+      console.log('handleDimensionChange 方法是否存在:', typeof this.handleDimensionChange);
+      console.log('所有方法:', Object.keys(this));
+    });
+    // 在调用 getList 前确保 dimension 参数存在
+    if (!this.queryParams.dimension) {
+      this.queryParams.dimension = 'sales';
+    }
+
+    getCampList().then(response => {
+      this.camps = response.data.list
+      if (this.camps != null && this.camps.length > 0) {
+        this.companyId = this.camps[0].dictValue;
+      }
+      this.camps.push({companyId: "-1", companyName: "无"})
+    });
+    getCompanyList().then(response => {
+      this.companys = response.data;
+      if (this.companys != null && this.companys.length > 0) {
+        this.companyId = this.companys[0].companyId;
+      }
+      this.companys.push({companyId: "-1", companyName: "无"})
+    });
+    this.getList();
+    this.getDicts("sys_company_status").then(response => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("sys_company_or").then(response => {
+      this.isDelOptions = response.data;
+      this.orOptions = response.data;
+    });
+    this.getDicts("sys_package_pay_type").then(response => {
+      this.payTypeOptions = response.data;
+    });
+    this.getDicts("sys_product_type").then(response => {
+      this.productTypeOptions = response.data;
+    });
+    this.getDicts("sys_package_type").then(response => {
+      this.packageTypeOptions = response.data;
+    });
+    this.getDicts("sys_package_sub_type").then(response => {
+      this.packageSubTypeOptions = response.data;
+    });
+    this.getDicts("sys_course_project").then(e => {
+      this.projectList = e.data;
+    })
+    // this.getDicts("sys_prescribe_disease_type").then(response => {
+    //   this.diseaseTypeOptions = response.data;
+    // });
+  },
+  methods: {
+    handleDimensionChange: function(val) {
+      console.log('维度切换到:', val);
+      // 重置分页
+      this.queryParams.pageNum = 1;
+      // 重新获取数据
+      this.getList();
+    },
+    calculateTotals() {
+      // 重置总计数据
+      this.calculatedTotalData = {
+        finishedCount: 0,
+        unfinishedCount: 0,
+        completionRate: 0,
+        notWatchedCount: 0,
+        notAnsweredCount: 0,
+        redPacketAmount: 0,
+        historyOrderCount: 0
+      };
+      // 遍历当前页数据计算总和
+      this.packageList.forEach(item => {
+        this.calculatedTotalData.finishedCount += Number(item.finishedCount) || 0;
+        this.calculatedTotalData.unfinishedCount += Number(item.unfinishedCount) || 0;
+        this.calculatedTotalData.completionRate += Number(item.completionRate) || 0;
+        this.calculatedTotalData.notWatchedCount += Number(item.notWatchedCount) || 0;
+        this.calculatedTotalData.notAnsweredCount += Number(item.notAnsweredCount) || 0;
+        this.calculatedTotalData.redPacketAmount += Number(item.redPacketAmount) || 0;
+        this.calculatedTotalData.historyOrderCount += Number(item.historyOrderCount) || 0;
+      });
+    },
+    getTreeselect(companyId) {
+      const query = { companyId: companyId };
+      selectDeptTree(query).then((response) => {
+        this.deptTreeOptions = response.data;
+      });
+    },
+    compute(){
+      this.totalMoney=0;
+      var that=this;
+      this.drugList.forEach (function (value) {
+        that.totalMoney += value.money;
+      });
+      that.totalMoney=that.totalMoney.toFixed(2);
+    },
+    // saveData(row) {
+    //   // 在这里可以进行数据保存操作,比如将数据提交到后端进行保存
+    //   console.log("保存数据", row);
+    // },
+    /** 查询套餐包列表 */
+    getList() {
+      this.loading = true;
+      // 添加调试日志,确认参数
+      console.log('请求参数:', this.queryParams);
+      watchLogReport(this.queryParams).then(response => {
+        this.packageList = response.rows;
+        this.total = response.total;
+        this.calculateTotals();
+        this.loading = false;
+        // 检查是否有数据且 deptName 字段有值,决定是否显示该列
+        if (this.packageList && this.packageList.length > 0) {
+          this.showDeptNameColumn = this.packageList.some(item => item.deptName);
+        } else {
+          this.showDeptNameColumn = false;
+        }
+      });
+    },
+    /** 训练营变更处理 */
+    handleCampChange(val) {
+      this.queryParams.trainingCampId = val;
+      this.queryParams.periodId = null; // 清空已选择的营期
+
+      if (val) {
+        // 获取对应的营期数据
+        this.getPeriodByCamp(val);
+      } else {
+        // 如果清空训练营,也清空营期选项
+        this.deptOptions = [];
+      }
+
+      // 触发查询
+      this.handleQuery();
+    },
+
+    /** 根据训练营获取营期数据 */
+    getPeriodByCamp(campId) {
+      const param = { campId: campId };
+      getPeriodList(param).then((response) => {
+        console.log('接口返回数据:', response);
+        console.log('营期列表数据:', response.data.list);
+        this.deptOptions = response.data.list || [];
+        console.log('deptOptions 已赋值:', this.deptOptions);
+      }).catch(error => {
+        console.error('获取营期数据失败:', error);
+        this.deptOptions = [];
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        packageId: null,
+        packageName: null,
+        sort: null,
+        productJson: null,
+        status: 0,
+        createTime: null,
+        orderTime: null,
+        sTime: null,
+        updateTime: null,
+        isDel: null,
+        payType: ["1"],
+        isShow: "1",
+        packageType: "1",
+        num: null,
+        price: null,
+        sales: null,
+        diseaseType: null,
+        tags: null,
+        packageSubType: "1",
+        describeJson: null,
+        productType: null,
+        totalPrice: null,
+        inquiryPrice: null,
+        productPrice: null,
+        cycle: null,
+        duration: null,
+        imgUrl: null,
+        images: null,
+        storeId: null,
+        recipeType: null,
+        counts: null,
+        followNum: null,
+        secondName: null,
+      };
+      this.photoArr = [];
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+      // 清空所有时间相关变量
+      this.createTime = null;
+      this.orderTime = null;
+      this.startTime = null;
+      this.endTime = null;
+      this.queryParams.sTime = null;
+      this.queryParams.eTime = null;
+      this.queryParams.orderSTime= null;
+      this.queryParams.orderETime= null;
+    },
+    xdChange() {
+      if (this.createTime != null) {
+        this.queryParams.sTime = this.createTime[0];
+        this.queryParams.eTime = this.createTime[1];
+      } else {
+        this.queryParams.sTime = null;
+        this.queryParams.eTime = null;
+      }
+    },
+    ydChange() {
+      if (this.orderTime != null) {
+        this.queryParams.orderSTime = this.orderTime[0];
+        this.queryParams.orderETime = this.orderTime[1];
+      } else {
+        this.queryParams.orderSTime = null;
+        this.queryParams.orderETime = null;
+      }
+    }
+  }
+};
+</script>
+
+<style>
+.icon-button {
+  border-radius: 0;
+}
+
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+
+.avatar-uploader .el-upload:hover {
+  border-color: #409EFF;
+}
+
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 150px;
+  height: 150px;
+  line-height: 150px !important;
+  text-align: center;
+}
+.total-summary {
+  margin-top: 15px;
+  padding: 15px 20px;
+  background: linear-gradient(135deg, #f5f7fa 0%, #e4e7f4 100%);
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+}
+
+.total-title {
+  font-weight: bold;
+  font-size: 16px;
+  color: #303133;
+  margin-right: 20px;
+  flex-shrink: 0;
+}
+
+.total-item {
+  margin-right: 25px;
+  padding: 5px 10px;
+  background: white;
+  border-radius: 3px;
+  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
+  display: inline-block;
+  margin-bottom: 5px;
+  font-size: 13px;
+  color: #606266;
+}
+
+.total-item::before {
+  content: "";
+  display: inline-block;
+  width: 3px;
+  height: 3px;
+  background: #409eff;
+  border-radius: 50%;
+  margin-right: 5px;
+  vertical-align: middle;
+}
+
+/* 响应式处理 */
+@media (max-width: 768px) {
+  .total-summary {
+    flex-direction: column;
+    align-items: flex-start;
+  }
+
+  .total-title {
+    margin-bottom: 10px;
+  }
+
+  .total-item {
+    margin-right: 10px;
+    margin-bottom: 8px;
+  }
+}
+</style>

+ 696 - 0
src/views/statistics/watchlogReportdept.vue

@@ -0,0 +1,696 @@
+<template>
+  <div class="app-container">
+
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="90px">
+<!--      <el-radio-group v-model="queryParams.dimension" @change="handleDimensionChange">-->
+<!--        <el-radio-button label="user">用户维度</el-radio-button>-->
+<!--        <el-radio-button label="sales">销售维度</el-radio-button>-->
+<!--        <el-radio-button label="company">公司维度</el-radio-button>-->
+<!--      </el-radio-group>-->
+<!--      <el-form-item label="公司名" prop="companyId">-->
+<!--        <el-select filterable v-model="queryParams.companyId" placeholder="请选择公司名"-->
+<!--                   clearable size="small">-->
+<!--          <el-option-->
+<!--            v-for="item in companys"-->
+<!--            :key="item.companyId"-->
+<!--            :label="item.companyName"-->
+<!--            :value="item.companyId"-->
+<!--          />-->
+<!--        </el-select>-->
+<!--      </el-form-item>-->
+      <el-form-item label="所属部门" prop="deptId">
+        <treeselect style="width:205.4px" v-model="queryParams.deptId" :options="deptTreeOptions" :show-count="true" placeholder="请选择所属部门" />
+      </el-form-item>
+      <el-form-item label="项目" prop="project">
+        <el-select filterable v-model="queryParams.project" placeholder="请选择项目"
+                   clearable size="small">
+          <el-option
+            v-for="item in projectList"
+            :key="item.dictValue"
+            :label="item.dictLabel"
+            :value="item.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="训练营" prop="trainingCampId">
+        <el-select filterable v-model="queryParams.trainingCampId" placeholder="请选择训练营"
+                   clearable size="small"  @change="handleCampChange">
+          <el-option
+            v-for="item in camps"
+            :key="item.dictValue"
+            :label="item.dictLabel"
+            :value="item.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <treeselect style="width: 220px" v-model="queryParams.periodId" :options="deptOptions"
+                    clearable :show-count="true" placeholder="请选择归属营期" value-consists-of="LEAF_PRIORITY"
+                    :normalizer="normalizer" />
+      </el-form-item>
+      <el-form-item>
+        <el-form-item label="看课时间" prop="createTime">
+          <el-date-picker v-model="createTime" size="small" style="width: 220px" value-format="yyyy-MM-dd"
+                          type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
+                          @change="xdChange"></el-date-picker>
+        </el-form-item>
+        <el-form-item label="下单时间" prop="orderTime">
+          <el-date-picker v-model="orderTime" size="small" style="width: 220px" value-format="yyyy-MM-dd"
+                          type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
+                          @change="ydChange"></el-date-picker>
+        </el-form-item>
+      </el-form-item>
+      <el-form-item label="会员ID" prop="userId">
+        <el-input v-model="queryParams.userId" placeholder="请输入会员ID" clearable size="small" />
+      </el-form-item>
+      <el-form-item label="会员手机号" prop="userPhone">
+        <el-input v-model="queryParams.userPhone" placeholder="请输入会员手机号" clearable size="small" />
+      </el-form-item>
+      <el-form-item label="会员昵称" prop="nickName">
+        <el-input v-model="queryParams.nickName" placeholder="请输入会员昵称" clearable size="small" />
+      </el-form-item>
+
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+
+    <el-table v-loading="loading" border :data="packageList">
+      <el-table-column label="所属销售部门" align="center" prop="salesDept"/>
+      <el-table-column label="销售数" align="center" prop="salesCount" />
+      <el-table-column label="会员数" align="center" prop="userCount" />
+      <el-table-column label="当前会员上线数" align="center" prop="onlineUserCount" />
+      <el-table-column label="所属销售公司" align="center" prop="salesCompany"/>
+      <el-table-column label="训练营" align="center" prop="trainingCampName"/>
+      <el-table-column label="营期" align="center" prop="periodName"/>
+      <el-table-column label="课程小节" align="center" prop="videoTitle" />
+      <el-table-column label="完课数" align="center" prop="finishedCount" />
+      <el-table-column label="未完课" align="center" prop="unfinishedCount" />
+      <el-table-column label="完课率" align="center" prop="completionRate" />
+      <el-table-column label="看课时间" align="center" prop="courseTime" />
+      <el-table-column label="未看数" align="center" prop="notWatchedCount" />
+      <el-table-column label="未答题人数" align="center" prop="notAnsweredCount" />
+      <el-table-column label="红包金额" align="center" prop="redPacketAmount" />
+      <el-table-column label="历史疗法订单数" align="center" prop="historyOrderCount" />
+    </el-table>
+    <div class="total-summary">
+      <span class="total-title">总计:</span>
+      <span class="total-item">完课数: {{ calculatedTotalData.finishedCount }}</span>
+      <span class="total-item">未完课: {{ calculatedTotalData.unfinishedCount }}</span>
+      <span class="total-item">完课率: {{ calculatedTotalData.completionRate }}</span>
+      <span class="total-item">未看数: {{ calculatedTotalData.notWatchedCount }}</span>
+      <span class="total-item">未答题人数: {{ calculatedTotalData.notAnsweredCount }}</span>
+      <span class="total-item">红包金额: {{ calculatedTotalData.redPacketAmount }}</span>
+      <span class="total-item">历史疗法订单数: {{ calculatedTotalData.historyOrderCount }}</span>
+    </div>
+    <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
+                @pagination="getList" />
+
+    <!-- 添加或修改套餐包对话框 -->
+    <!-- <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="110px">
+        <el-form-item label="套餐包名称" prop="packageName">
+          <el-input v-model="form.packageName" placeholder="请输入套餐包名称" />
+        </el-form-item>
+        <el-form-item label="排序号" prop="sort">
+           <el-input-number v-model="form.sort"  :min="0" label="排序号"></el-input-number>
+        </el-form-item>
+        <el-form-item label="状态">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="parseInt(dict.dictValue)"
+            >{{dict.dictLabel}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="价格配置" prop="priceJson">
+
+
+                 <el-table :data="priceJson"    :cell-style="{ textAlign: 'center' }"		 :header-cell-style="{textAlign: 'center'}"   >
+                   <el-table-column label="子套餐标题" prop="title" width="150px">
+                     <template slot-scope="scope">
+                       <el-input v-model="scope.row.title" ></el-input>
+                     </template>
+                   </el-table-column>
+                   <el-table-column label="签约时长/日" prop="duration" width="150px">
+                     <template slot-scope="scope">
+                       <el-input-number v-model="scope.row.duration" controls-position="right" :min="0" size="small"></el-input-number>
+
+                     </template>
+                   </el-table-column>
+                   <el-table-column label="价格/元" prop="price" width="150px">
+                     <template slot-scope="scope">
+                        <el-input-number v-model="scope.row.price" controls-position="right"  :min="0" size="small"></el-input-number>
+
+                      </template>
+                   </el-table-column>
+                   <el-table-column label="状态"  prop="status">
+                     <template slot-scope="scope">
+                       <el-switch v-model="scope.row.status" active-color="#13ce66" inactive-color="#ff4949" ></el-switch>
+                     </template>
+                   </el-table-column>
+                   <el-table-column label="操作">
+                     <template slot-scope="scope">
+                        <el-button @click="deleteRow(scope.$index)"   size="mini" type="text" v-if="priceJson.length>1">删除</el-button>
+                         <el-button @click="addRow" size="mini" type="text" >新增</el-button>
+                     </template>
+                   </el-table-column>
+                 </el-table>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog> -->
+  </div>
+</template>
+
+<script>
+import {
+  listPackage,
+  getPackage,
+  delPackage,
+  addPackage,
+  updatePackage,
+  exportPackage,
+  userReport, watchLogReport
+} from "@/api/store/package";
+import { getAllFollowTempName } from "@/api/store/followTemp";
+import { allIcd } from "@/api/store/icd";
+import Editor from '@/components/Editor/wang.vue';
+import Material from '@/components/Material/index.vue';
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import { listStore,getCampList,getPeriodList} from "@/api/store/storeProduct";
+import { getAllCateList } from "@/api/store/packageCate";
+import { Loading } from 'element-ui';
+import {getCompanyList} from "@/api/company/company";
+import {selectDeptTree} from "@/api/company/companyDept";
+export default {
+  name: "WatchlogReport",
+  components: {Treeselect},
+  watch: {
+    imageArr: function (val) {
+      this.form.imgUrl = val.join(',')
+    },
+    photoArr: function (val) {
+      this.form.images = val.join(',')
+    },
+    // 监听公司选择变化,动态加载对应部门
+    // 'queryParams.companyId': {
+    //   handler(newVal) {
+    //     this.queryParams.deptId = null; // 清空已选择的部门
+    //     const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}');
+    //     const companyId = newVal || userInfo.companyId;
+    //     if (companyId) {
+    //       this.getTreeselect(companyId); // 根据公司ID获取部门树
+    //     } else {
+    //       this.deptTreeOptions = []; // 如果没有选择公司,则清空部门选项
+    //     }
+    //   }
+    // }
+  },
+  data() {
+    return {
+      normalizer: function(node) {
+        return {
+          id: node.id || node.dictValue,
+          label: node.label || node.dictLabel,
+          children: node.children
+        }
+      },
+      columnConfig: {
+        user: [
+          { prop: 'userId', label: '会员id', width: 120 },
+          { prop: 'nickName', label: '用户昵称', width: 120 },
+          { prop: 'salesName', label: '所属销售', width: 120 },
+          { prop: 'salesDept', label: '所属销售部门', width: 120, condition: () => this.showDeptNameColumn },
+          { prop: 'salesCompany', label: '所属销售公司', width: 120 },
+          { prop: 'trainingCampName', label: '训练营', width: 150 },
+          { prop: 'periodName', label: '营期', width: 150 },
+          { prop: 'videoTitle', label: '小节名称', width: 100 },
+          { prop: 'watchStatus', label: '看课状态', width: 100 },
+          { prop: 'duration', label: '播放时长', width: 120 },
+          { prop: 'courseTime', label: '看课时间', width: 100 },
+          { prop: 'finishTime', label: '完课时间', width: 100 },
+          { prop: 'answerStatus', label: '答题状态', width: 100 },
+          { prop: 'redPacketAmount', label: '红包金额', width: 120 },
+          { prop: 'historyOrderCount', label: '历史疗法订单数', width: 120 }
+        ],
+        sales: [
+          { prop: 'salesName', label: '销售', width: 120 },
+          { prop: 'userCount', label: '会员数', width: 120 },
+          { prop: 'onlineUserCount', label: '当前线上会员数', width: 120 },
+          { prop: 'salesDept', label: '所属销售部门', width: 100, sortable: true },
+          { prop: 'salesCompany', label: '所属销售公司', width: 120, sortable: true },
+          { prop: 'trainingCampName', label: '训练营', width: 100, sortable: true },
+          { prop: 'periodName', label: '营期', width: 100, sortable: true },
+          { prop: 'videoTitle', label: '课程小节', width: 100, sortable: true },
+          { prop: 'finishedCount', label: '完课数', width: 100, sortable: true },
+          { prop: 'unfinishedCount', label: '未完课', width: 120, sortable: true },
+          { prop: 'completionRate', label: '完课率', width: 100, sortable: true },
+          { prop: 'courseTime', label: '发课时间', width: 100, sortable: true },
+          { prop: 'notWatchedCount', label: '未看数', width: 100, sortable: true },
+          { prop: 'notAnsweredCount', label: '未答题人数', width: 100, sortable: true },
+          { prop: 'redPacketAmount', label: '红包金额', width: 120 },
+          { prop: 'historyOrderCount', label: '历史疗法订单数', width: 120 }
+        ],
+        company: [
+          { prop: 'salesDept', label: '销售部门', width: 120 },
+          { prop: 'salesCount', label: '销售数', width: 120 },
+          { prop: 'userCount', label: '会员数', width: 120 },
+          { prop: 'onlineUserCount', label: '当前会员上线数', width: 100, sortable: true },
+          { prop: 'salesCompany', label: '所属销售公司', width: 100, sortable: true },
+          { prop: 'trainingCampName', label: '训练营', width: 120, sortable: true },
+          { prop: 'periodName', label: '营期', width: 100, sortable: true },
+          { prop: 'videoTitle', label: '课程小节', width: 100, sortable: true },
+          { prop: 'finishedCount', label: '完课数', width: 100, sortable: true },
+          { prop: 'unfinishedCount', label: '未完课', width: 120, sortable: true },
+          { prop: 'completionRate', label: '完课率', width: 100, sortable: true },
+          { prop: 'courseTime', label: '发课时间', width: 100, sortable: true },
+          { prop: 'notWatchedCount', label: '未看数', width: 100, sortable: true },
+          { prop: 'notAnsweredCount', label: '未答题人数', width: 100, sortable: true },
+          { prop: 'redPacketAmount', label: '红包金额', width: 120 },
+          { prop: 'historyOrderCount', label: '历史疗法订单数', width: 120 }
+        ]
+      },
+      showDeptNameColumn: false,
+      projectList: [],
+      companys: [],
+      camps: [],
+      deptOptions : [],
+      deptTreeOptions: [],
+      uploadUrl: process.env.VUE_APP_BASE_API + "/common/uploadOSS",
+      photoArr: [],
+      productTypeOptions: [],
+      storeId: null,
+      storeOPtions: [],
+      totalMoney: 0.00,
+      drugOpen: false,
+      checkList: ['1'],
+      drugList: [],
+      productJson: [],
+      calculatedTotalData: {
+        finishedCount: 0,
+        unfinishedCount: 0,
+        completionRate: 0,
+        notWatchedCount: 0,
+        notAnsweredCount: 0,
+        redPacketAmount: 0,
+        historyOrderCount: 0
+      },
+      describeJson: { usageMethod: "", forPeople: "", tabootPeople: "", use: "" },
+      icdList: [],
+      show: {
+        open: false,
+      },
+      priceJson: [
+        { title: "套餐1", duration: "0", price: "0", status: true },
+      ],
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      startTime : null,
+      endTime : null,
+      // 总条数
+      total: 0,
+      createTime: null,
+      orderTime: null,
+      // 套餐包表格数据
+      packageList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 状态字典
+      tempOptions: [],
+      statusOptions: [],
+      payTypeOptions: [],
+      orOptions: [],
+      packageTypeOptions: [],
+      diseaseTypeOptions: [],
+      packageSubTypeOptions: [],
+      solarTermOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        packageName: null,
+        sort: null,
+        priceJson: null,
+        status: null,
+        isDel: null,
+        companyId:null,
+        project:null,
+        trainingCampId:null,
+        periodId:null,
+        sTime: null,
+        eTime: null,
+        orderSTime: null,
+        orderETime: null,
+        deptId: null,
+        dimension: 'company'
+      },
+      // 表单参数
+      form: {},
+    };
+  },
+  computed: {
+    // // 计算属性:根据当前维度返回动态列
+    // dynamicColumns() {
+    //   const dimension = this.queryParams.dimension || 'user';
+    //   return this.columnConfig[dimension] || this.columnConfig.user;
+    // }
+  },
+  created() {
+    console.log('公司id是否存在',this.$store.state.user.user)
+    this.getTreeselect(this.$store.state.user.user.companyId);
+    this.$nextTick(() => {
+      console.log('handleDimensionChange 方法是否存在:', typeof this.handleDimensionChange);
+      console.log('所有方法:', Object.keys(this));
+    });
+    // 在调用 getList 前确保 dimension 参数存在
+    if (!this.queryParams.dimension) {
+      this.queryParams.dimension = 'company';
+    }
+
+    getCampList().then(response => {
+      this.camps = response.data.list
+      if (this.camps != null && this.camps.length > 0) {
+        this.companyId = this.camps[0].dictValue;
+      }
+      this.camps.push({companyId: "-1", companyName: "无"})
+    });
+    getCompanyList().then(response => {
+      this.companys = response.data;
+      if (this.companys != null && this.companys.length > 0) {
+        this.companyId = this.companys[0].companyId;
+      }
+      this.companys.push({companyId: "-1", companyName: "无"})
+    });
+    this.getList();
+    this.getDicts("sys_company_status").then(response => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("sys_company_or").then(response => {
+      this.isDelOptions = response.data;
+      this.orOptions = response.data;
+    });
+    this.getDicts("sys_package_pay_type").then(response => {
+      this.payTypeOptions = response.data;
+    });
+    this.getDicts("sys_product_type").then(response => {
+      this.productTypeOptions = response.data;
+    });
+    this.getDicts("sys_package_type").then(response => {
+      this.packageTypeOptions = response.data;
+    });
+    this.getDicts("sys_package_sub_type").then(response => {
+      this.packageSubTypeOptions = response.data;
+    });
+    this.getDicts("sys_course_project").then(e => {
+      this.projectList = e.data;
+    })
+    // this.getDicts("sys_prescribe_disease_type").then(response => {
+    //   this.diseaseTypeOptions = response.data;
+    // });
+  },
+  methods: {
+    handleDimensionChange: function(val) {
+      console.log('维度切换到:', val);
+      // 重置分页
+      this.queryParams.pageNum = 1;
+      // 重新获取数据
+      this.getList();
+    },
+    calculateTotals() {
+      // 重置总计数据
+      this.calculatedTotalData = {
+        finishedCount: 0,
+        unfinishedCount: 0,
+        completionRate: 0,
+        notWatchedCount: 0,
+        notAnsweredCount: 0,
+        redPacketAmount: 0,
+        historyOrderCount: 0
+      };
+      // 遍历当前页数据计算总和
+      this.packageList.forEach(item => {
+        this.calculatedTotalData.finishedCount += Number(item.finishedCount) || 0;
+        this.calculatedTotalData.unfinishedCount += Number(item.unfinishedCount) || 0;
+        this.calculatedTotalData.completionRate += Number(item.completionRate) || 0;
+        this.calculatedTotalData.notWatchedCount += Number(item.notWatchedCount) || 0;
+        this.calculatedTotalData.notAnsweredCount += Number(item.notAnsweredCount) || 0;
+        this.calculatedTotalData.redPacketAmount += Number(item.redPacketAmount) || 0;
+        this.calculatedTotalData.historyOrderCount += Number(item.historyOrderCount) || 0;
+      });
+    },
+    getTreeselect(companyId) {
+      const query = { companyId: companyId };
+      selectDeptTree(query).then((response) => {
+        this.deptTreeOptions = response.data;
+      });
+    },
+    compute(){
+      this.totalMoney=0;
+      var that=this;
+      this.drugList.forEach (function (value) {
+        that.totalMoney += value.money;
+      });
+      that.totalMoney=that.totalMoney.toFixed(2);
+    },
+    // saveData(row) {
+    //   // 在这里可以进行数据保存操作,比如将数据提交到后端进行保存
+    //   console.log("保存数据", row);
+    // },
+    /** 查询套餐包列表 */
+    getList() {
+      this.loading = true;
+      // 添加调试日志,确认参数
+      console.log('请求参数:', this.queryParams);
+      watchLogReport(this.queryParams).then(response => {
+        this.packageList = response.rows;
+        this.total = response.total;
+        this.calculateTotals();
+        this.loading = false;
+        // 检查是否有数据且 deptName 字段有值,决定是否显示该列
+        if (this.packageList && this.packageList.length > 0) {
+          this.showDeptNameColumn = this.packageList.some(item => item.deptName);
+        } else {
+          this.showDeptNameColumn = false;
+        }
+      });
+    },
+    /** 训练营变更处理 */
+    handleCampChange(val) {
+      this.queryParams.trainingCampId = val;
+      this.queryParams.periodId = null; // 清空已选择的营期
+
+      if (val) {
+        // 获取对应的营期数据
+        this.getPeriodByCamp(val);
+      } else {
+        // 如果清空训练营,也清空营期选项
+        this.deptOptions = [];
+      }
+
+      // 触发查询
+      this.handleQuery();
+    },
+
+    /** 根据训练营获取营期数据 */
+    getPeriodByCamp(campId) {
+      const param = { campId: campId };
+      getPeriodList(param).then((response) => {
+        console.log('接口返回数据:', response);
+        console.log('营期列表数据:', response.data.list);
+        this.deptOptions = response.data.list || [];
+        console.log('deptOptions 已赋值:', this.deptOptions);
+      }).catch(error => {
+        console.error('获取营期数据失败:', error);
+        this.deptOptions = [];
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        packageId: null,
+        packageName: null,
+        sort: null,
+        productJson: null,
+        status: 0,
+        createTime: null,
+        orderTime: null,
+        updateTime: null,
+        isDel: null,
+        payType: ["1"],
+        isShow: "1",
+        packageType: "1",
+        num: null,
+        price: null,
+        sales: null,
+        diseaseType: null,
+        tags: null,
+        packageSubType: "1",
+        describeJson: null,
+        productType: null,
+        totalPrice: null,
+        inquiryPrice: null,
+        productPrice: null,
+        cycle: null,
+        duration: null,
+        imgUrl: null,
+        images: null,
+        storeId: null,
+        recipeType: null,
+        counts: null,
+        followNum: null,
+        secondName: null,
+      };
+      this.photoArr = [];
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+      // 清空所有时间相关变量
+      this.createTime = null;
+      this.orderTime = null;
+      this.startTime = null;
+      this.endTime = null;
+      this.queryParams.sTime = null;
+      this.queryParams.eTime = null;
+      this.queryParams.orderSTime= null;
+      this.queryParams.orderETime= null;
+    },
+    xdChange() {
+      if (this.createTime != null) {
+        this.queryParams.sTime = this.createTime[0];
+        this.queryParams.eTime = this.createTime[1];
+      } else {
+        this.queryParams.sTime = null;
+        this.queryParams.eTime = null;
+      }
+    },
+    ydChange() {
+      if (this.orderTime != null) {
+        this.queryParams.orderSTime = this.orderTime[0];
+        this.queryParams.orderETime = this.orderTime[1];
+      } else {
+        this.queryParams.orderSTime = null;
+        this.queryParams.orderETime = null;
+      }
+    }
+  }
+};
+</script>
+
+<style>
+.icon-button {
+  border-radius: 0;
+}
+
+.avatar-uploader .el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+
+.avatar-uploader .el-upload:hover {
+  border-color: #409EFF;
+}
+
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 150px;
+  height: 150px;
+  line-height: 150px !important;
+  text-align: center;
+}
+.total-summary {
+  margin-top: 15px;
+  padding: 15px 20px;
+  background: linear-gradient(135deg, #f5f7fa 0%, #e4e7f4 100%);
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+}
+
+.total-title {
+  font-weight: bold;
+  font-size: 16px;
+  color: #303133;
+  margin-right: 20px;
+  flex-shrink: 0;
+}
+
+.total-item {
+  margin-right: 25px;
+  padding: 5px 10px;
+  background: white;
+  border-radius: 3px;
+  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
+  display: inline-block;
+  margin-bottom: 5px;
+  font-size: 13px;
+  color: #606266;
+}
+
+.total-item::before {
+  content: "";
+  display: inline-block;
+  width: 3px;
+  height: 3px;
+  background: #409eff;
+  border-radius: 50%;
+  margin-right: 5px;
+  vertical-align: middle;
+}
+
+/* 响应式处理 */
+@media (max-width: 768px) {
+  .total-summary {
+    flex-direction: column;
+    align-items: flex-start;
+  }
+
+  .total-title {
+    margin-bottom: 10px;
+  }
+
+  .total-item {
+    margin-right: 10px;
+    margin-bottom: 8px;
+  }
+}
+</style>