ソースを参照

Merge remote-tracking branch 'origin/master'

yuhongqi 1 週間 前
コミット
c5e5ae2909

+ 17 - 1
src/api/course/courseTrafficLog.js

@@ -50,4 +50,20 @@ export function exportCourseTrafficLog(query) {
     method: 'get',
     params: query
   })
-}
+}
+
+export function statisticsSummaryList(query) {
+  return request({
+    url: '/course/courseTrafficLog/statisticsSummaryList',
+    method: 'get',
+    params: query
+  })
+}
+
+export function exportStatisticsSummary(query) {
+  return request({
+    url: '/course/courseTrafficLog/exportStatisticsSummary',
+    method: 'get',
+    params: query
+  })
+}

+ 9 - 0
src/api/his/user.js

@@ -142,3 +142,12 @@ export function delUserCompanyUser(id) {
     method: 'delete'
   })
 }
+
+// 解绑会员看课的会员和销售的关系
+export function batchUnbindUser(data) {
+  return request({
+    url: '/his/user/batchUnbind',
+    method: 'delete',
+    data: data
+  })
+}

+ 234 - 0
src/views/course/courseTrafficLog/statistics.vue

@@ -0,0 +1,234 @@
+<template>
+  <div class="app-container">
+    <!-- 查询条件 -->
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <!-- 公司选择 -->
+      <el-form-item label="统计维度">
+        <el-select v-model="queryParams.statisticsType" placeholder="请选择统计维度" filterable clearable size="small">
+          <el-option v-for="(option, index) in dimensionStatistics" :key="index" :value="option.value" :label="option.text"></el-option>
+        </el-select>
+      </el-form-item>
+
+      <!-- 项目选择 -->
+      <el-form-item label="选择公司">
+        <el-select v-model="queryParams.companyId" placeholder="请选择公司" filterable clearable size="small">
+          <el-option v-for="dict in companyList" :key="dict.dictValue" :label="dict.dictLabel" :value="dict.dictValue" />
+        </el-select>
+      </el-form-item>
+
+      <!-- 时间选择 -->
+      <el-form-item label="年月">
+        <el-date-picker
+          v-model="timeRange"
+          type="daterange"
+          placeholder="选择年月"
+          :value-format="'yyyy-MM-dd'"
+          :picker-options="pickerOptions"
+          @change="handleDateData"
+        ></el-date-picker>
+      </el-form-item>
+     
+    
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+      <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          :loading="exportLoading"
+          @click="handleExport"
+          v-hasPermi="['course:courseRedPacketLog:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+    
+
+    <!-- 表格 -->
+    <el-table border v-loading="loading" :data="courseTrafficLogList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="公司" align="center" prop="companyName" />
+      <el-table-column v-if="showDept" label="部门" align="center" prop="deptName" />
+      <el-table-column label="统计范围" align="center" prop="dateRange" />
+      <el-table-column label="使用流量" align="center"  prop="formattedTotalTraffic">
+      </el-table-column>
+      <el-table-column label="金额" align="center" prop="totalAmount">
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页 -->
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { listCourseTrafficLog, exportCourseTrafficLog,statisticsSummaryList,exportStatisticsSummary } from "@/api/course/courseTrafficLog";
+import { courseList } from "@/api/course/courseRedPacketLog";
+import { allList } from "@/api/company/company";
+
+export default {
+  data() {
+    return {
+      showDept:false,
+      dimensionStatistics:[
+        {text:"按公司",value:1},
+        {text:"按部门",value:2}
+      ],
+      timeRange: null, // 时间范围单独绑定
+      companyList: [],
+      projectOptions: [],
+      pickerOptions: {
+        shortcuts: [
+          {
+            text: '今日',
+            onClick(picker) {
+              const start = new Date();
+              const end = new Date();
+              picker.$emit('pick', [start, end]);
+            }
+          },
+          {
+            text: '昨日',
+            onClick(picker) {
+              const start = new Date();
+              start.setDate(start.getDate() - 1);
+              const end = new Date(start);
+              picker.$emit('pick', [start, end]);
+            }
+          },
+          {
+            text: '本周',
+            onClick(picker) {
+              const now = new Date();
+              const day = now.getDay() || 7;
+              const start = new Date(now);
+              start.setDate(now.getDate() - day + 1);
+              const end = new Date();
+              picker.$emit('pick', [start, end]);
+            }
+          },
+          {
+            text: '本月',
+            onClick(picker) {
+              const start = new Date(new Date().setDate(1));
+              const end = new Date();
+              picker.$emit('pick', [start, end]);
+            }
+          }
+        ]
+      },
+      courseLists: [],
+      loading: false,
+      exportLoading: false,
+      showSearch: true,
+      total: 0,
+      courseTrafficLogList: [],
+      queryParams: {
+        tabType: "", // 当前 tab 类型
+        startDate: null,
+        endDate: null,
+        pageNum: 1,
+        pageSize: 10,
+        statisticsType: null,//统计维度 1、按照公司 2、按照部门
+        companyId:null,
+        project: null,
+        courseId: null
+      }
+    };
+  },
+  created() {
+    courseList().then(res => this.courseLists = res.list);
+    this.getDicts("sys_course_project").then(res => this.projectOptions = res.data);
+    this.getAllCompany();
+    this.getList();
+  },
+  methods: {
+    handleTabClick(tab) {
+      this.queryParams.tabType = tab.name;
+      this.queryParams.pageNum = 1;
+
+      // 清理互斥参数
+      if (tab.name !== "project") this.queryParams.project = null;
+      if (tab.name !== "course") this.queryParams.courseId = null;
+      if (tab.name !== "company") this.queryParams.companyId = null;
+
+      this.getList();
+    },
+
+    handleDateData() {
+      if (this.timeRange) {
+        this.queryParams.startDate = this.timeRange[0];
+        this.queryParams.endDate = this.timeRange[1];
+      } else {
+        this.queryParams.startDate = null;
+        this.queryParams.endDate = null;
+      }
+    },
+    getAllCompany() {
+      allList().then(res => this.companyList = res.rows);
+    },
+    getList() {
+      this.loading = true;
+      if(this.queryParams.statisticsType == 2){
+         this.showDept = true;
+      }else{
+        this.showDept = false;
+      }
+      statisticsSummaryList(this.queryParams).then(res => {
+        this.courseTrafficLogList = res.rows;
+        this.total = res.total;
+      }).finally(() => {
+        this.loading = false;
+      });
+    },
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    resetQuery() {
+      this.timeRange = null;
+      this.queryParams = {
+        ...this.queryParams,
+        startDate: null,
+        endDate: null,
+        companyId: null,
+        project: null,
+        courseId: null,
+        pageNum: 1,
+      };
+      this.getList();
+    },
+    formatTrafficData(traffic) {
+      if (traffic < 1024) return `${traffic} B`;
+      if (traffic < 1024 ** 2) return `${(traffic / 1024).toFixed(2)} KB`;
+      if (traffic < 1024 ** 3) return `${(traffic / 1024 ** 2).toFixed(2)} MB`;
+      return `${(traffic / 1024 ** 3).toFixed(2)} GB`;
+    },
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.logId);
+    },
+    handleExport() {
+      this.$confirm("确认导出数据?", "提示").then(() => {
+        this.exportLoading = true;
+        return exportStatisticsSummary(this.queryParams);
+      }).then(res => {
+        this.download(res.msg);
+      }).finally(() => {
+        this.exportLoading = false;
+      });
+    }
+  }
+};
+</script>

+ 41 - 17
src/views/his/statistics/comprehensiveStatistics.vue

@@ -71,7 +71,7 @@
             <el-option
               v-for="user in userList"
               :key="user.userId"
-              :label="user.userName"
+              :label="user.nickName"
               :value="user.userId">
             </el-option>
           </el-select>
@@ -86,15 +86,22 @@
 
     <!-- 数据表格 -->
     <div class="table-section">
-      <el-table :data="paginatedTableData" border style="width: 100%" height="400">
+      <el-table :data="paginatedTableData" border style="width: 100%" height="600">
+        <!-- 添加时间列 -->
+        <el-table-column prop="statisticsTime" label="统计时间" width="180">
+          <template slot-scope="scope">
+            {{ formatDateTime(scope.row.statisticsTime) }}
+          </template>
+        </el-table-column>
         <el-table-column prop="companyName" label="公司名称" />
         <el-table-column prop="deptName" label="部门名称" />
-        <el-table-column prop="userName" label="人员姓名" />
-        <el-table-column prop="lineNum" label="进线数" />
-        <el-table-column prop="activeNum" label="激活数" />
-        <el-table-column prop="completeNum" label="完课数" />
+        <!-- 根据维度决定是否显示人员姓名 -->
+        <el-table-column prop="companyUserName" label="人员姓名" v-if="showUserNameColumn" />
+        <!-- 更新以下列为新的字段名 -->
+        <el-table-column prop="sendCount" label="发送数" />
         <el-table-column prop="answerNum" label="答题数" />
         <el-table-column prop="redPacketNum" label="红包领取数" />
+        <el-table-column prop="redPacketAmount" label="红包金额(元)" />
       </el-table>
 
       <el-pagination
@@ -104,10 +111,10 @@
         :page-sizes="[10, 20, 50, 100]"
         :page-size="pageSize"
         layout="total, sizes, prev, pager, next, jumper"
-        :total="tableData.length"
-        style="margin-top: 20px; text-align: right;">
+        :total="tableData.length"        style="margin-top: 20px; text-align: right;">
       </el-pagination>
     </div>
+
   </div>
 </template>
 
@@ -178,6 +185,12 @@ export default {
       return this.queryParams.dimension === 1 &&
         this.queryParams.companyId &&
         this.queryParams.deptId;
+    },
+
+    // 添加计算属性控制人员姓名列显示
+    showUserNameColumn() {
+      // 当维度为个人时显示人员姓名列,公司维度时不显示
+      return this.queryParams.dimension === 1 || this.queryParams.dimension === 3;
     }
   },
 
@@ -225,6 +238,26 @@ export default {
       });
     },
 
+    // 添加时间格式化方法
+    formatDateTime(dateString) {
+      if (!dateString) return '';
+      // 移除时区信息并格式化日期时间
+      const date = new Date(dateString.replace(/\.\d{3}\+\d{4}$/, ''));
+      const year = date.getFullYear();
+      const month = String(date.getMonth() + 1).padStart(2, '0');
+      const day = String(date.getDate()).padStart(2, '0');
+      return `${year}-${month}-${day}`;
+    },
+
+    formatDate(date) {
+      if (!date) return '';
+      const d = new Date(date);
+      const year = d.getFullYear();
+      const month = String(d.getMonth() + 1).padStart(2, '0');
+      const day = String(d.getDate()).padStart(2, '0');
+      return `${year}-${month}-${day}`;
+    },
+
     fetchStatisticsData() {
       // 构造请求参数对象
       const params = {
@@ -253,15 +286,6 @@ export default {
       });
     },
 
-    formatDate(date) {
-      if (!date) return '';
-      const d = new Date(date);
-      const year = d.getFullYear();
-      const month = String(d.getMonth() + 1).padStart(2, '0');
-      const day = String(d.getDate()).padStart(2, '0');
-      return `${year}-${month}-${day}`;
-    },
-
     handleCompanyChange(companyId) {
       this.queryParams.deptId = null;
       this.queryParams.userId = null;

+ 47 - 1
src/views/his/user/indexProject.vue

@@ -158,6 +158,15 @@
           v-hasPermi="['store:user:export']"
         >导出</el-button>
       </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="_blank"
+          icon="el-icon-brush"
+          size="mini"
+          @click="handleUnbind"
+          v-hasPermi="['his:user:unbind']"
+        >解绑会员</el-button>
+      </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
@@ -381,7 +390,7 @@
 </template>
 
 <script>
-import {listUserByProject, getUser, addUser, updateUser, exportUser, delUserCompanyUser,exportListProject} from "@/api/his/user";
+import {listUserByProject, getUser, addUser, updateUser, exportUser, delUserCompanyUser,exportListProject, batchUnbindUser} from "@/api/his/user";
 import { getCompanyUserList, changeCompanyUser, getCompanyList } from '@/api/company/companyUser';
 import userDetailsByNew from '@/views/his/user/userDetails.vue'
 export default {
@@ -710,6 +719,43 @@ export default {
         this.download(response.msg);
       }).catch(function() {});
     },
+
+    // 解绑会员
+    handleUnbind() {
+      // 检查是否有勾选列表行
+      if (this.selectedUser.length > 0) {
+        // 有勾选行,获取选中的userId列表
+        const userIds = this.selectedUser.map(item => item.userId);
+        this.$confirm('确定要解绑当前选中的' + this.selectedUser.length + '个会员吗?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          console.log('解绑选中会员,用户ID:', userIds);
+          return batchUnbindUser(userIds);
+        }).then(() => {
+          this.msgSuccess("解绑成功");
+          this.getList();
+        }).catch(function() {
+          this.$message.error('解绑失败');
+        });
+      } else {
+        // 没有勾选行,提示用户是否解绑当前筛选条件下的所有会员
+        this.$confirm('没有勾选列表项,将解绑当前筛选条件下的所有会员,请确认是否操作?', "警告", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning"
+        }).then(() => {
+          const userIds = this.userList.map(item => item.userId);
+          return batchUnbindUser(userIds);
+        }).then(() => {
+          this.msgSuccess("解绑成功");
+          this.getList();
+        }).catch(function() {
+          this.$message.error('解绑失败');
+        });
+      }
+    },
     handleShow(row){
       var that=this;
       that.show.open=true;