xgb 1 день тому
батько
коміт
9149249c5e

+ 375 - 0
src/views/app/statistics/courseAppReport/index.vue

@@ -0,0 +1,375 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="85px">
+      <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="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>
+        <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"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+    <el-table height="500" v-loading="loading" border :data="packageOrderList">
+      <el-table-column label="销售公司" align="center" prop="companyName" width="120px"/>
+      <el-table-column label="新增注册人数" align="center" prop="appUserCount"/>
+<!--      <el-table-column label="APP活跃人数" align="center" prop="activeAppUserCount"/>-->
+      <el-table-column label="私域课待看课人次" align="center" prop="pendingCount"/>
+      <el-table-column label="私域课看课中人次" align="center" prop="watchingCount"/>
+      <el-table-column label="私域课看课中断人次" align="center" prop="stopCount"/>
+      <el-table-column label="私域课看课率" align="center" prop="watchRate"/>
+      <el-table-column label="私域课完课人次" align="center" prop="finishedCount"/>
+      <el-table-column label="答题人次" align="center" prop="answerUserCount"/>
+      <el-table-column label="红包领取人次" align="center" prop="packetUserCount"/>
+      <el-table-column label="红包金额" align="center" prop="packetAmount"/>
+    </el-table>
+    <div class="total-summary">
+      <span class="total-title">总计:</span>
+      <span class="total-item">新增注册人数:{{ calculatedTotalData.appUserCount }}</span>
+<!--      <span class="total-item">APP 活跃人数:{{ calculatedTotalData.activeAppUserCount }}</span>-->
+      <span class="total-item">私域课待看课人次:{{ calculatedTotalData.pendingCount }}</span>
+      <span class="total-item">私域课看课中人次:{{ calculatedTotalData.watchingCount }}</span>
+      <span class="total-item">私域课看课中断人次:{{ calculatedTotalData.stopCount }}</span>
+      <span class="total-item">私域课看课率:{{ calculatedTotalData.watchRate}}</span>
+      <span class="total-item">私域课完课人次:{{ calculatedTotalData.finishedCount }}</span>
+      <span class="total-item">答题人次:{{ calculatedTotalData.answerUserCount }}</span>
+      <span class="total-item">红包领取人次:{{ calculatedTotalData.packetUserCount}}</span>
+      <span class="total-item">红包金额:{{ calculatedTotalData.packetAmount }}</span>
+    </div>
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { getCompanyList } from "@/api/company/company";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import { getTask } from "@/api/common";
+import request from '@/utils/request'
+
+export default {
+  name: "AppCourseReport",
+  components: { Treeselect },
+  data() {
+    return {
+      normalizer: function(node) {
+        return {
+          id: node.id || node.dictValue,
+          label: node.label || node.dictLabel,
+          children: node.children
+        }
+      },
+      calculatedTotalData: {
+        appUserCount: 0,
+        // activeAppUserCount: 0,
+        pendingCount: 0,
+        watchingCount: 0,
+        stopCount: 0,
+        watchRate: '0%',
+        finishedCount: 0,
+        answerUserCount: 0,
+        packetUserCount: 0,
+        packetAmount: 0
+      },
+      companys: [],
+      deptOptions: [],
+      companyId: undefined,
+      show: {
+        open: false,
+      },
+      actName: "2",
+      loading: true,
+      startTime: null,
+      exportLoading: false,
+      ids: [],
+      createTime: null,
+      single: true,
+      multiple: true,
+      showSearch: true,
+      endTime: null,
+      total: 0,
+      packageOrderList: [],
+      title: "",
+      open: false,
+      isPayOptions: [],
+      statusOptions: [],
+      refundStatusOptions: [],
+      packageSubTypeOptions: [],
+      payTypeOptions: [],
+      deliveryPayStatusOptions: [],
+      deliveryStatusOptions: [],
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        companyId: null,
+        sTime: null,
+        eTime: null
+      },
+      form: {},
+      rules: {}
+    };
+  },
+  created() {
+    // 默认查询当天
+    const today = new Date();
+    const formatDate = (date) => {
+      const year = date.getFullYear();
+      const month = String(date.getMonth() + 1).padStart(2, '0');
+      const day = String(date.getDate()).padStart(2, '0');
+      return `${year}-${month}-${day}`;
+    };
+    const todayStr = formatDate(today);
+    this.createTime = [todayStr, todayStr];
+    this.queryParams.sTime = todayStr;
+    this.queryParams.eTime = todayStr;
+
+    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();
+    });
+  },
+  methods: {
+    getList() {
+      this.loading = true;
+      return request({
+        url: '/app/statistics/appCourseReport',
+        method: 'get',
+        params: this.queryParams
+      }).then(response => {
+        this.packageOrderList = response.rows || response.data;
+        this.total = response.total || 0;
+        this.calculateTotals();
+        this.loading = false;
+        setTimeout(() => {
+          this.$forceUpdate();
+        }, 100);
+      }).catch(() => {
+        this.loading = false;
+      });
+    },
+    calculateTotals() {
+      this.calculatedTotalData = {
+        appUserCount: 0,
+        // activeAppUserCount: 0,
+        pendingCount: 0,
+        watchingCount: 0,
+        stopCount: 0,
+        watchRate: 0,
+        finishedCount: 0,
+        answerUserCount: 0,
+        packetUserCount: 0,
+        packetAmount: 0
+      };
+
+      this.packageOrderList.forEach(item => {
+        this.calculatedTotalData.appUserCount += Number(item.appUserCount) || 0;
+        // this.calculatedTotalData.activeAppUserCount += Number(item.activeAppUserCount) || 0;
+        this.calculatedTotalData.pendingCount += Number(item.pendingCount) || 0;
+        this.calculatedTotalData.watchingCount += Number(item.watchingCount) || 0;
+        this.calculatedTotalData.stopCount += Number(item.stopCount) || 0;
+        this.calculatedTotalData.finishedCount += Number(item.finishedCount) || 0;
+        this.calculatedTotalData.answerUserCount += Number(item.answerUserCount) || 0;
+        this.calculatedTotalData.packetUserCount += Number(item.packetUserCount) || 0;
+        this.calculatedTotalData.packetAmount += Number(item.packetAmount) || 0;
+      });
+
+      if (this.calculatedTotalData.pendingCount > 0) {
+        this.calculatedTotalData.watchRate = ((this.calculatedTotalData.watchingCount / this.calculatedTotalData.pendingCount) * 100).toFixed(2) + '%';
+      } else {
+        this.calculatedTotalData.watchRate = '0.00%';
+      }
+
+      this.calculatedTotalData.packetAmount = this.calculatedTotalData.packetAmount.toFixed(2);
+    },
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    reset() {
+      this.form = {
+        orderId: null,
+        orderSn: null,
+        userId: null,
+        doctorId: null,
+        packageId: null,
+        packageName: null,
+        payMoney: null,
+        isPay: null,
+        days: null,
+        status: 0,
+        startTime: null,
+        finishTime: null,
+        createTime: null
+      };
+      this.resetForm("form");
+    },
+    handleQuery() {
+      this.getList();
+    },
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.createTime = null;
+      this.startTime = null;
+      this.endTime = null;
+
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        companyId: null,
+        sTime: null,
+        eTime: null
+      };
+
+      this.handleQuery();
+    },
+    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;
+      }
+    },
+    handleExport() {
+      const now = new Date();
+      const year = now.getFullYear();
+      const month = String(now.getMonth() + 1).padStart(2, '0');
+      const firstDay = `${year}-${month}-01`;
+      const lastDay = new Date(year, now.getMonth() + 1, 0);
+      const lastDayStr = `${year}-${month}-${String(lastDay.getDate()).padStart(2, '0')}`;
+
+      const { watchType, ...paramsWithoutWatchType } = this.queryParams;
+      const exportParams = {
+        ...paramsWithoutWatchType,
+        sTime: this.queryParams.sTime || firstDay,
+        eTime: this.queryParams.eTime || lastDayStr
+      };
+
+      this.$confirm('是否确认导出 APP 看课报表', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.exportLoading = true;
+        return request({
+          url: '/app/statistics/exportAppCourseReport',
+          method: 'get',
+          params: exportParams
+        });
+      }).then(response => {
+        this.download(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {
+        this.exportLoading = false;
+      });
+    },
+    endChange() {
+      if (this.endTime != null) {
+        this.queryParams.endStartTime = this.endTime[0];
+        this.queryParams.endEndTime = this.endTime[1];
+      } else {
+        this.queryParams.endStartTime = null;
+        this.queryParams.endEndTime = null;
+      }
+    }
+  }
+};
+</script>
+
+<style scoped>
+.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>

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

@@ -107,7 +107,7 @@
           </el-form-item>
         </el-col>
         <el-col :span="12">
-          <el-form-item  label="短视频/直播 获得积分" prop="integralFinishVideo">
+          <el-form-item  label="短视频/直播 最低获得积分" prop="integralFinishVideo">
             <el-tooltip class="item" effect="dark" content="每10秒获得最低多少积分" placement="top-end">
               <el-input-number  v-model="form11.integralFinishVideo"   ></el-input-number>
             </el-tooltip>