Browse Source

添加页岩

lex 1 year ago
parent
commit
8637be0e09

+ 5 - 0
src/router/index.js

@@ -511,6 +511,8 @@ export const asyncRoutes = {
   indexErrDataRecord: () => import("@/views/indexErrDataRecord"),
   // 团练宝数据
   cloudDate: () => import("@/views/main/cloudDate/index.vue"),
+  // 云课堂观看统计
+  coursewareDate: () => import("@/views/main/coursewareDate/index.vue"),
   dictionaryManager: () => import("@/views/dictionaryManager"),
   // 会员排课列表
   memberClassList: () =>
@@ -642,6 +644,9 @@ export const asyncRoutes = {
   // 训练详情
   exerciseDurationDetail: () =>
     import("@/views/main/cloudDate/exerciseDurationDetail.vue"),
+  // 训练详情
+  coursewareDurationDetail: () =>
+    import("@/views/main/coursewareDate/exerciseDurationDetail.vue"),
   // 新课表列表
   newCourseList: () => import("@/views/newCourseList"),
   newOrderList: () => import("@/views/newCourseList/orderList"),

+ 13 - 0
src/store/modules/permission.js

@@ -311,6 +311,19 @@ function setDetailRoute(accessedRoutes) {
             belongTopMenu: "/main",
             activeMenu: "/workbench"
           }
+        },
+        {
+          name: "coursewareDurationDetail",
+          path: "/coursewareDurationDetail",
+          component: () =>
+            import("@/views/main/coursewareDate/exerciseDurationDetail.vue"),
+          hidden: true,
+          meta: {
+            noCache: "1",
+            title: "观看时长详情",
+            belongTopMenu: "/main",
+            activeMenu: "/workbench"
+          }
         }
         // /hasfreeCourse  排课时长消耗异常
       ]);

+ 428 - 0
src/views/main/coursewareDate/activeUserNum.vue

@@ -0,0 +1,428 @@
+<template>
+  <div>
+    <el-card>
+      <headers
+        title="活跃用户统计"
+        @changeOrgan="changeOrgan"
+        :special="true"
+      />
+      <div class="chioseBox">
+        <el-radio-group v-model="timers" @change="changeQuick">
+          <el-radio-button label="month">本月</el-radio-button>
+          <el-radio-button label="year">本年度</el-radio-button>
+          <el-radio-button label="lastYear">去年</el-radio-button>
+        </el-radio-group>
+        <el-date-picker
+          v-model="mdate"
+          type="daterange"
+          class="datePick"
+          style="width: 300px; padding: 0 10px"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          value-format="yyyy-MM-dd"
+          format="yyyy-MM-dd"
+          @change="changeValue"
+          :picker-options="bigin()"
+        >
+        </el-date-picker>
+        <p>单位:</p>
+
+        <el-radio-group v-model="timer">
+          <el-radio-button label="day">按天</el-radio-button>
+          <el-radio-button label="month">按月</el-radio-button>
+        </el-radio-group>
+      </div>
+      <ve-line
+        style="width: 100%"
+        height="350px"
+        :data="timer == 'day' ? chartData : chartDataForMoth"
+        :data-empty="dataEmpty"
+        :extend="chartExtend"
+        :legend="legend"
+      ></ve-line>
+    </el-card>
+  </div>
+</template>
+<script>
+import "v-charts/lib/style.css";
+import "echarts/lib/component/dataZoom";
+import headers from "./modals/headers.vue";
+import veLine from "v-charts/lib/line.common";
+import { getNowDateAndSunday, getNowDateAndMonday } from "@/utils/date";
+import { getIndex } from "../api";
+import { getTimes } from "@/utils";
+import { descs, chioseNum } from "../constant";
+export default {
+  components: {
+    headers,
+    veLine,
+  },
+  data() {
+    return {
+      timer: "day", // 按天 按月
+      timers: "", // 本月 本年 去年
+      mdate: [],
+      data: [],
+      organId: "",
+    };
+  },
+  mounted() {
+    this.init();
+  },
+  computed: {
+    legend() {
+      return {
+        left: "10px",
+      };
+    },
+    items() {
+      let obj = {};
+      let arr = [
+        "MEMBER_STUDENT_NUM",
+        "CLOUD_STUDY_LIVELY_STUDENT_NUM",
+        "CLOUD_STUDY_DAY_USE_STUDENT_NUM",
+        "CLOUD_STUDY_NEW_STUDENT_NUM",
+      ];
+      arr.forEach((str) => {
+        if (this.data[str]) {
+          obj[str] = this.data[str];
+        }
+      });
+      /**
+       *  {
+        HOMEWORK_CREATE_RATE:this.data["HOMEWORK_CREATE_RATE"] || {},
+        HOMEWORK_SUBMIT_RATE: this.data["HOMEWORK_SUBMIT_RATE"] || {},
+        HOMEWORK_COMMENT_RATE: this.data["HOMEWORK_COMMENT_RATE"] || {},
+      };
+       */
+      return obj;
+    },
+    chartExtend() {
+      return {
+        series: {
+          type: "line",
+          smooth: false,
+        },
+        yAxis: {
+          //纵轴标尺固定
+          minInterval: 1,
+          type: "value",
+          scale: true,
+          min: 0,
+          max: 100,
+          axisLabel: {
+            formatter: "{value}%",
+          },
+        },
+        tooltip: {
+          axisPointer: {
+            type: "shadow",
+            shadowStyle: {
+              color: "rgba(150,150,150,0.2)",
+            },
+          },
+
+          formatter: (item) => {
+            return [
+              item[0].axisValueLabel,
+              ...item.map(
+                (d) => `<br/>${d.marker}${d.seriesName}: ${d.value[1]} %`
+              ),
+            ].join("");
+          },
+        },
+      };
+    },
+    dataZoom() {
+      return [
+        {
+          grid: {
+            left: "0%",
+          },
+          type: "slider",
+          start: 40,
+          end: 100,
+        },
+      ];
+    },
+    chartData() {
+      const values = Object.values(this.items);
+      const months = {};
+      for (const item of values) {
+        for (const row of item.indexMonthData || []) {
+          const key = this.$helpers.dayjs(row.month).format("YYYY-MM-DD");
+          if (!months[key]) {
+            months[key] = {
+              日期: key,
+            };
+          }
+          months[key][item.title] = row.percent;
+        }
+      }
+      return {
+        columns: ["日期", ...values.map((item) => item.title)],
+        rows: Object.values(months),
+      };
+    },
+    chartDataForMoth() {
+      const values = Object.values(this.items);
+      //   console.log(values)
+      // values['VIP_GROUP_COURSE'].forEach(item=>{
+      //     console.log(item.month)
+      //   })
+      const months = {};
+
+      for (const item of values) {
+        for (const row of item.indexMonthData || []) {
+          const key = this.$helpers.dayjs(row.month).format("YYYY-MM");
+
+          if (!months[key]) {
+            months[key] = {
+              月份: key,
+            };
+            months[key][item.title] = row.percent;
+          } else {
+            if (
+              months[key][item.title] &&
+              item.dataType == "CLOUD_STUDY_NEW_STUDENT_NUM"
+            ) {
+              months[key][item.title] += parseFloat(row.percent);
+            } else {
+              months[key][item.title] = row.percent;
+            }
+          }
+        }
+      }
+      // console.log(Object.values(months));
+      return {
+        columns: ["月份", ...values.map((item) => item.title)],
+        rows: Object.values(months),
+      };
+    },
+    dataEmpty() {
+      return !this.chartData.rows.length;
+    },
+    chartExtend() {
+      return {
+        series: {
+          type: "line",
+          smooth: false,
+        },
+        yAxis: {
+          //纵轴标尺固定
+          minInterval: 1,
+          type: "value",
+          scale: true,
+          min: 0,
+          axisLabel: {
+            formatter: "{value}人",
+          },
+        },
+        tooltip: {
+          axisPointer: {
+            type: "shadow",
+            shadowStyle: {
+              color: "rgba(150,150,150,0.2)",
+            },
+          },
+          formatter: (item) => {
+            return [
+              item[0].axisValueLabel,
+              ...item.map(
+                (d) => `<br/>${d.marker}${d.seriesName}: ${d.value[1]}人`
+              ),
+            ].join("");
+          },
+        },
+      };
+    },
+  },
+  methods: {
+    init() {
+      let nowTiem = this.$helpers.dayjs(new Date()).format("YYYY-MM-DD");
+
+      let startTime = this.$helpers
+        .dayjs(nowTiem)
+        .subtract(8, "day")
+        .format("YYYY-MM-DD");
+
+      let endTime = this.$helpers
+        .dayjs(nowTiem)
+        .subtract(1, "day")
+        .format("YYYY-MM-DD");
+      this.mdate = [startTime, endTime];
+      this.FetchDetail();
+    },
+    changeValue(date) {
+      // 请求更改数据
+      this.mdate = date;
+      this.isDayOrMoth(date);
+      console.log("调用", date);
+      this.FetchDetail();
+    },
+    async FetchDetail() {
+      this.loading = true;
+      let data = [];
+      try {
+        // const { dates, ...rest } = this.search;
+        //   ...rest,
+        const res = await getIndex({
+          ...getTimes(this.mdate, ["startDate", "endDate"]),
+          organId: this.organId,
+          dataTypes:
+            "MEMBER_STUDENT_NUM,CLOUD_STUDY_LIVELY_STUDENT_NUM,CLOUD_STUDY_DAY_USE_STUDENT_NUM,CLOUD_STUDY_NEW_STUDENT_NUM",
+        });
+        for (const item of res.data) {
+          data[item.dataType] = {
+            ...item,
+            desc: descs[item.dataType],
+          };
+        }
+        this.data = data;
+        // for (const item of res.data) {
+        //   // 再循环一遍
+        //   for (const key in this.items) {
+
+        //     if (item.dataType == key) {
+        //       data[item.dataType] = {
+        //         ...item,
+        //         desc: descs[item.dataType],
+        //       };
+        //     }
+        //   }
+        // }
+      } catch (error) {
+        console.log(error);
+      }
+      this.loading = false;
+      this.data = data;
+      // this.$emit("resetDate", data);
+    },
+    changeQuick(val) {
+      let startDate;
+      let endDate;
+      if (val == "month") {
+        // 获取本月的第一天 获取本月的今天
+        let nowDate =  this.$helpers.dayjs(new Date()).get("date");
+
+        if (nowDate == 1) {
+          startDate =  this.$helpers.dayjs()
+            .add(-1, "month")
+            .startOf("month")
+            .format("YYYY-MM-DD");
+          endDate =  this.$helpers.dayjs(new Date()).subtract(1, "day").format("YYYY-MM-DD");
+        } else {
+          startDate =  this.$helpers.dayjs(new Date()).set("date", 1).format("YYYY-MM-DD");
+          endDate =  this.$helpers.dayjs(new Date()).subtract(1, "day").format("YYYY-MM-DD");
+        }
+        this.mdate = [startDate, endDate];
+        this.isDayOrMoth(this.mdate);
+        this.FetchDetail();
+        // this.submitDate(this.date);
+      } else if (val == "year") {
+        let nowDate = this.$helpers.dayjs(new Date()).get("date");
+        let nowMonth = this.$helpers.dayjs(new Date()).get("month") + 1;
+        if (nowDate == 1 && nowMonth == 1) {
+          startDate = this.$helpers
+            .dayjs(new Date())
+            .add(-1, "year")
+            .set("month", 0)
+            .set("date", 1)
+            .format("YYYY-MM-DD");
+          endDate = this.$helpers
+            .dayjs(new Date())
+            .subtract(1, "day")
+            .format("YYYY-MM-DD");
+        } else {
+          startDate = this.$helpers
+            .dayjs(new Date())
+            .set("month", 0)
+            .set("date", 1)
+            .format("YYYY-MM-DD");
+          this.endDate
+            ? (endDate = this.endDate)
+            : (endDate = this.$helpers
+                .dayjs(new Date())
+                .subtract(1, "day")
+                .format("YYYY-MM-DD"));
+        }
+        this.mdate = [startDate, endDate];
+        this.isDayOrMoth(this.mdate);
+        this.FetchDetail();
+        // this.submitDate(this.date);
+      } else if (val == "lastYear") {
+        startDate = this.$helpers
+          .dayjs(new Date())
+          .subtract(1, "year")
+          .set("month", 0)
+          .set("date", 1)
+          .format("YYYY-MM-DD");
+        endDate = this.$helpers
+          .dayjs()
+          .subtract(1, "year")
+          .endOf("year")
+          .format("YYYY-MM-DD");
+        this.mdate = [startDate, endDate];
+        this.isDayOrMoth(this.mdate);
+        this.FetchDetail();
+        // this.submitDate(this.date);
+      }
+    },
+    bigin() {
+      let self = this;
+      return {
+        firstDayOfWeek: 1,
+        disabledDate(time) {
+          if (self.endDate) {
+            let endTime = self.$helpers.dayjs(self.endDate).valueOf();
+            return time.getTime() > endTime;
+          } else {
+            return time.getTime() >= Date.now() - 24 * 60 * 60 * 1000;
+          }
+        },
+      };
+    },
+    isDayOrMoth(arr) {
+      if (!arr || arr.length < 1) {
+        this.timer = "day";
+      } else {
+        const count = this.$helpers
+          .dayjs(arr[0])
+          .diff(this.$helpers.dayjs(arr[1]), "day");
+        Math.abs(count) > chioseNum
+          ? (this.timer = "month")
+          : (this.timer = "day");
+      }
+    },
+    changeOrgan(val) {
+      this.organId = val;
+      this.FetchDetail();
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+::v-deep .el-card__body {
+  padding-top: 0 !important;
+}
+
+.chioseBox {
+  position: absolute;
+  right: 20px;
+  z-index: 1000;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  p {
+    font-size: 14px;
+    margin: 0 5px 0 10px;
+  }
+  .datePick {
+    margin-left: 10px;
+  }
+}
+.wrap {
+  position: relative;
+}
+</style>

+ 91 - 0
src/views/main/coursewareDate/allDate.vue

@@ -0,0 +1,91 @@
+<template>
+  <div>
+    <el-card>
+      <headers title="数据总览" :hidenOrgan="true" />
+      <div
+        class="wall"
+        style="height: 68px"
+        v-if="JSON.stringify(items) == '{}'"
+      >
+        暂无数据
+      </div>
+      <!--
+          -->
+      <statistic :col="6" class="statistic" :cols="0">
+        <statistic-item v-for="(item, key) in items" :key="key"  @click="active = key" :class="{ active: active === key }">
+          <span>
+            {{ item.title + "(人)" }}
+            <el-tooltip
+              v-if="item.desc"
+              :content="item.desc"
+              :open-delay="0.3"
+              placement="top"
+            >
+              <i
+                style="margin-left: 5px; cursor: pointer"
+                class="el-icon-warning-outline"
+              />
+            </el-tooltip>
+          </span>
+          <span> <count-to :endVal="item.percent || 0" /> </span>
+        </statistic-item>
+      </statistic>
+    </el-card>
+  </div>
+</template>
+<script>
+import headers from "./modals/headers.vue";
+import countTo from "vue-count-to";
+import { descs, titles } from "../constant";
+import { getCloudStudyStudentOverView } from "../api";
+export default {
+  props: ["data"],
+  components: {
+    headers,
+    countTo
+  },
+  data() {
+    return {
+      dataList:{},
+      active:''
+    };
+  },
+  async mounted() {
+    try {
+      const res = await getCloudStudyStudentOverView();
+      this.dataList = res.data;
+    } catch (e) {
+      console.log(e);
+    }
+    // 获取数据
+  },
+  computed: {
+    items() {
+      let obj = {};
+      //        "eVipStudentNum",
+      let arr = [
+        "totalStudentNum",
+        "waitActivateVipStudentNum",
+        "effectiveVipStudentNum",
+        "vipStudentNum",
+        "cloudStudyLivelyStudentNum",
+        // "newCloudStudyStudentNum",
+        // "cloudStudyTodayUseStudentNum",
+        "cloudStudyUseStudentNum",
+      ];
+      arr.forEach((str) => {
+        if (this.dataList[str]+'') {
+          obj[str] ={title:titles[str],percent:this.dataList[str],desc:descs[str]};
+        }
+      });
+      return obj;
+    },
+  },
+  methods: {},
+};
+</script>
+<style lang="scss" scoped>
+::v-deep .el-card__body {
+  padding-top: 0 !important;
+}
+</style>

+ 541 - 0
src/views/main/coursewareDate/exerciseDuration.vue

@@ -0,0 +1,541 @@
+<template>
+  <div class="m-container">
+    <!-- 搜索标题 -->
+    <saveform
+      :inline="true"
+      ref="searchForm"
+      class="searchForm"
+      saveKey="exerciseDuration"
+      :model.sync="searchForm"
+    >
+      <el-form-item prop="dates">
+        <!-- @change="changeWeek" -->
+        <el-date-picker
+          :clearable="false"
+          v-model="searchForm.dates"
+          value-format="yyyy-MM-dd"
+          :picker-options="{ firstDayOfWeek: 1 }"
+          type="daterange"
+          style="width: 405px"
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+        >
+        </el-date-picker>
+      </el-form-item>
+
+      <el-form-item>
+        <el-button @click="search" type="danger">搜索</el-button>
+        <el-button @click="onReSet" type="primary">重置</el-button>
+      </el-form-item>
+    </saveform>
+    <!-- 分组添加柱状图  -->
+    <ve-histogram
+      style="width: 100%"
+      height="350px"
+      :data="chartData"
+      :data-empty="dataEmpty"
+      :extend="chartExtend"
+      :legend="legend"
+      :data-zoom="dataZoom"
+    ></ve-histogram>
+
+    <el-button
+      type="primary"
+      @click="exportQuestion"
+      style="margin: 16px 0"
+      v-permission="'export/managerDownload/num'"
+      >导出</el-button
+    >
+    <div class="tableWrap">
+      <el-table
+        :data="tableList"
+        :header-cell-style="{ background: '#EDEEF0', color: '#444' }"
+        @sort-change="onSortChange"
+      >
+        <el-table-column width="120px" align="center" prop="id" label="排名">
+          <template slot-scope="scope">
+            <div>
+              {{ scope.$index + 1 }}
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          align="center"
+          prop="organName"
+          label="分部名称"
+        ></el-table-column>
+        <el-table-column
+          align="center"
+          prop="normalNum"
+          sortable="custom"
+          label="在读人数"
+        >
+          <template slot-scope="scope">
+            <div>{{ scope.row.normalNum }}人</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          align="center"
+          prop="normalNum"
+          sortable="custom"
+          label="无练习人数"
+        >
+          <template slot-scope="scope">
+            <div>{{ scope.row.normalNum }}人</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          align="center"
+          prop="train0"
+          sortable="custom"
+          label="0-10分钟"
+        >
+          <template slot-scope="scope">
+            <div>{{ scope.row.train0 }}人</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          align="center"
+          prop="train1"
+          sortable="custom"
+          label="10-60分钟"
+        >
+          <template slot-scope="scope">
+            <div>{{ scope.row.train1 }}人</div>
+          </template></el-table-column
+        >
+
+        <el-table-column
+          align="center"
+          prop="train2"
+          sortable="custom"
+          label="60-120分钟"
+        >
+          <template slot-scope="scope">
+            <div>{{ scope.row.train2 }}人</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          align="center"
+          prop="train3"
+          sortable="custom"
+          label="120-240分钟"
+        >
+          <template slot-scope="scope">
+            <div>{{ scope.row.train3 }}人</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          align="center"
+          prop="train4"
+          sortable="custom"
+          label=">240分钟"
+        >
+          <template slot-scope="scope">
+            <div>{{ scope.row.train4 }}人</div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          align="center"
+          prop="avgTrainTime"
+          sortable="custom"
+          label="平均时长"
+          width="100px"
+        >
+          <template slot-scope="scope">
+            <div>{{ scope.row.avgTrainTime || 0 }}分钟</div>
+          </template>
+        </el-table-column>
+
+        <el-table-column align="center" label="操作" fixed="right">
+          <template slot-scope="scope">
+            <el-button
+              v-permission="'/coursewareDurationDetail'"
+              @click="onDetail(scope.row)"
+              type="text"
+              >详情</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+  </div>
+</template>
+<script>
+import { Export } from "@/utils/downLoadFile";
+import saveform from "@/components/save-form";
+import dayjs from "dayjs";
+import histogram from "v-charts/lib/histogram.common";
+import { getNowDateAndMonday, getNowDateAndSunday } from "@/utils/utils";
+import { cloudTeacherNum } from "../api";
+let nowTime = dayjs()
+  .subtract(1, "day")
+  .format("YYYY-MM-DD");
+export const getTimes = (times, keys = []) => {
+  if (times && times.length) {
+    return {
+      [keys[0] || "start"]: dayjs(times[0]).format("YYYY-MM-DD"),
+      [keys[1] || "start"]: dayjs(times[1]).format("YYYY-MM-DD")
+    };
+  }
+  return {};
+};
+export default {
+  components: { saveform, "ve-histogram": histogram },
+  name: "helpCategory",
+  data() {
+    return {
+      searchForm: {
+        dates: [
+          dayjs()
+            .subtract(1, "day")
+            .format("YYYY-MM-DD"),
+          dayjs()
+            .subtract(1, "day")
+            .format("YYYY-MM-DD")
+        ]
+      },
+      tableList: []
+    };
+  },
+  async mounted() {
+    this.getList();
+  },
+  methods: {
+    onSortChange(val) {
+      console.log(val, "order");
+    },
+    exportQuestion() {
+      const { dates } = this.searchForm;
+      Export(
+        this,
+        {
+          url: "/api-web/export/managerDownload",
+          fileName: "云练习练习时长.xls",
+          method: "post",
+          params: {
+            exportEnum: "EXPORT_CLOUD_TEACHER_SUM",
+            queryInfo: {
+              ...getTimes(dates, ["startDate", "endDate"])
+            }
+          }
+        },
+        "您确定导出云练习练习时长?"
+      );
+    },
+    onDetail(row) {
+      this.$router.push({
+        path: "/coursewareDurationDetail",
+        query: {
+          organId: row.organId
+        }
+      });
+    },
+    search() {
+      this.$refs.searchForm.validate(valid => {
+        this.pageInfo = {
+          ...this.pageInfo,
+          page: 1
+        };
+        this.getList();
+      });
+    },
+    onReSet() {
+      this.pageInfo = {
+        ...this.pageInfo,
+        page: 1
+      };
+      this.$refs.searchForm.resetFields();
+      this.getList();
+    },
+    getDefaultTime() {
+      const dayjs = this.$helpers.dayjs;
+      let nowDate = dayjs(new Date()).format("YYYY-MM-DD");
+      let lastWeek = dayjs(nowDate)
+        .subtract(1, "week")
+        .format("YYYY-MM-DD");
+
+      console.log(lastWeek, nowDate, "121212");
+      this.searchForm.dates = [
+        getNowDateAndMonday(lastWeek),
+        getNowDateAndSunday(nowDate)
+      ];
+
+      console.log(this.searchForm.dates, "this.searchForm.dates");
+    },
+    changeWeek(val) {
+      if (val) {
+        // this.searchForm.dates = [
+        //   getNowDateAndMonday(val[0]),
+        //   getNowDateAndSunday(val[1])
+        // ];
+      } else {
+        this.getDefaultTime();
+      }
+    },
+    async getList() {
+      // cloudTeacherNum
+      try {
+        const { dates } = this.searchForm;
+        let params = {
+          ...getTimes(dates, ["startDate", "endDate"])
+        };
+        const res = await cloudTeacherNum({
+          page: 1,
+          rows: 10,
+          ...params
+        });
+        this.tableList = [];
+        this.tableList = res.data;
+      } catch {}
+    }
+  },
+  computed: {
+    items() {
+      let obj = {};
+      //        "eVipStudentNum",
+      let arr = [
+        "normalNum",
+        "train1",
+        "train2",
+        "train3",
+        "train4",
+        "buyRate",
+        "avgTrainTime"
+      ];
+      arr.forEach(str => {
+        if (this.dataList[str] + "") {
+          obj[str] = {
+            title: titles[str],
+            percent: this.dataList[str],
+            desc: descs[str]
+          };
+        }
+      });
+
+      return obj;
+    },
+    scaleItems() {
+      let obj = {};
+      //        "eVipStudentNum",
+      let arr = ["trainRate", "trainStandRate"];
+      arr.forEach(str => {
+        if (this.dataList[str] + "") {
+          obj[str] = {
+            title: titles[str],
+            percent: this.dataList[str],
+            desc: descs[str]
+          };
+        }
+      });
+
+      return obj;
+    },
+    legend() {
+      return {
+        left: "10px"
+      };
+    },
+    scaleCharData() {
+      const temp = {
+        trainRate: "练习率",
+        trainStandRate: "练习达标率"
+      };
+      const values = this.tableList;
+
+      const months = {};
+      for (const key in temp) {
+        for (const item of values) {
+          if (!months[item.organName]) {
+            months[item.organName] = {
+              分部: item.organName
+            };
+          }
+          months[item.organName][temp[key]] = item[key] || 0;
+        }
+      }
+      console.log(months, "months");
+      return {
+        columns: ["分部", "练习率", "练习达标率"],
+        rows: Object.values(months)
+      };
+    },
+    chartData() {
+      const temp = {
+        normalNum: "无练习人数",
+        train0: "0-10分钟",
+        train1: "10-60分钟",
+        train2: "60-120分钟",
+        train3: "120-240分钟",
+        train4: ">240分钟",
+        avgTrainTime: "平均时长"
+      };
+      const values = this.tableList;
+
+      const months = {};
+      for (const key in temp) {
+        for (const item of values) {
+          if (!months[item.organName]) {
+            months[item.organName] = {
+              分部: item.organName
+            };
+          }
+          months[item.organName][temp[key]] = item[key] || 0;
+        }
+      }
+      console.log(months, "months");
+      return {
+        columns: [
+          "分部",
+          "无练习人数",
+          "0-10分钟",
+          "10~60分钟",
+          "60-120分钟",
+          "120-240分钟",
+          ">240分钟",
+          "平均时长"
+        ],
+        rows: Object.values(months)
+      };
+    },
+    chartExtend() {
+      return {
+        yAxis: {
+          //纵轴标尺固定
+          minInterval: 1,
+          type: "value",
+          scale: true,
+          min: 0,
+          axisLabel: {
+            formatter: "{value}"
+          }
+        },
+        series: {
+          type: "bar",
+          smooth: false
+        },
+        tooltip: {
+          axisPointer: {
+            type: "shadow",
+            shadowStyle: {
+              color: "rgba(150,150,150,0.2)"
+            }
+          },
+          formatter: item => {
+            // let arr = [
+            //   { name: "会员人数", dot: "元" },
+            //   { name: "<60分钟", dot: "%" },
+            //   { name: "60-120分钟", dot: "元" },
+            //   { name: "120-240分钟", dot: "元" },
+            //   { name: ">240分钟", dot: "元" },
+            //   { name: "平均时长", dot: "元" }
+            // ];
+            // console.log(item, "-121212--------------");
+            return [
+              item[0].axisValueLabel,
+              ...item.map(d => {
+                return `<br/>${d.marker}${d.seriesName}: ${d.value}${
+                  d.seriesName == "平均时长" ? "分钟" : "人"
+                }`;
+              })
+            ].join("");
+          }
+        }
+      };
+    },
+    scalChartExtend() {
+      return {
+        yAxis: {
+          //纵轴标尺固定
+          minInterval: 1,
+          type: "value",
+          scale: true,
+          min: 0,
+          axisLabel: {
+            formatter: "{value}%"
+          }
+        },
+        series: {
+          type: "bar",
+          smooth: false
+        },
+        tooltip: {
+          axisPointer: {
+            type: "shadow",
+            shadowStyle: {
+              color: "rgba(150,150,150,0.2)"
+            }
+          },
+          formatter: item => {
+            return [
+              item[0].axisValueLabel,
+              ...item.map(d => {
+                return `<br/>${d.marker}${d.seriesName}: ${d.value}%`;
+              })
+            ].join("");
+          }
+        }
+      };
+    },
+    dataZoom() {
+      return [
+        {
+          show: true,
+          type: "slider",
+          start: 0,
+          end: 30,
+          filterMode: "empty",
+          zoomLock: true,
+          handleSize: 0
+        }
+      ];
+    },
+    dataEmpty() {
+      return !this.chartData.rows.length;
+    },
+    exporyun() {
+      return {
+        organId: this.organId
+      };
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+::v-deep .el-date-editor.el-input {
+  width: 100% !important;
+}
+::v-deep .el-select {
+  width: 100% !important;
+}
+::v-deep .el-table .cell {
+  display: -webkit-box;
+  overflow: hidden;
+  max-height: 45px;
+  text-overflow: ellipsis;
+  -webkit-line-clamp: 3;
+  -webkit-box-orient: vertical;
+}
+::v-deep .el-dialog__body {
+  padding: 10px 20px;
+}
+.newBand {
+  display: inline-block;
+}
+
+::v-deep .el-tabs__active-bar {
+  background-color: transparent !important;
+}
+::v-deep.el-tabs__nav-wrap {
+  &:after {
+    background-color: transparent !important;
+  }
+}
+/*去掉切换时el-tab-pane底部的蓝色下划线*/
+::v-deep .el-tabs__nav-wrap::after {
+  background-color: transparent !important;
+}
+
+/*去掉tabs底部的下划线*/
+</style>

+ 354 - 0
src/views/main/coursewareDate/exerciseDurationDetail.vue

@@ -0,0 +1,354 @@
+<template>
+  <div class="m-container">
+    <h2>
+      <el-page-header @back="onCancel" content="练习时长详情"></el-page-header>
+    </h2>
+
+    <div class="m-core">
+      <!-- 搜索标题 -->
+      <saveform
+        :inline="true"
+        ref="searchForm"
+        class="searchForm"
+        :model.sync="searchForm"
+      >
+        <el-form-item prop="organId">
+          <el-select
+            class="multiple"
+            v-model.trim="searchForm.organId"
+            filterable
+            clearable
+            placeholder="请选择分部"
+          >
+            <el-option
+              v-for="(item, index) in selects.branchs"
+              :key="index"
+              :label="item.name"
+              :value="item.id"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item prop="dates">
+          <el-date-picker
+            :clearable="false"
+            v-model="searchForm.dates"
+            value-format="yyyy-MM-dd"
+            :picker-options="{
+              firstDayOfWeek: 1,
+              disabledDate(time) {
+                return time.getTime() >= nowIndex;
+              }
+            }"
+            type="daterange"
+            style="width: 405px"
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+          >
+          </el-date-picker>
+        </el-form-item>
+
+        <el-form-item>
+          <el-button @click="search" type="danger">搜索</el-button>
+          <el-button @click="onReSet" type="primary">重置</el-button>
+        </el-form-item>
+      </saveform>
+      <!-- 分组添加柱状图  -->
+      <el-button
+        type="primary"
+        @click="exportQuestion"
+        style="margin: 0 0 16px"
+        v-permission="'export/managerDownload/numDetail'"
+        >导出</el-button
+      >
+      <div class="tableWrap">
+        <el-table
+          :data="tableList"
+          :header-cell-style="{ background: '#EDEEF0', color: '#444' }"
+        >
+          <!-- <el-table-column width="120px" align="center" prop="id" label="排名">
+            <template slot-scope="scope">
+              <div>
+                {{ scope.$index + 1 }}
+              </div>
+            </template>
+          </el-table-column> -->
+          <el-table-column
+            align="center"
+            prop="teacherName"
+            label="声部老师"
+          ></el-table-column>
+          <el-table-column align="center" prop="normalNum" label="会员人数">
+            <template slot-scope="scope">
+              <div>{{ scope.row.normalNum }}人</div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            align="center"
+            prop="trainStudentNum"
+            label="练习人数"
+          >
+            <template slot-scope="scope">
+              <div>{{ scope.row.trainStudentNum }}人</div>
+            </template></el-table-column
+          >
+          <el-table-column align="center" prop="trainRate" label="练习率">
+            <template slot-scope="scope">
+              <div>{{ scope.row.trainRate }}%</div>
+            </template>
+          </el-table-column>
+
+          <el-table-column align="center" label="≤10分钟">
+            <template slot-scope="scope">
+              <div>{{ scope.row.train0 }}人</div>
+            </template>
+          </el-table-column>
+
+          <el-table-column align="center" label="10~60分钟">
+            <template slot-scope="scope">
+              <div>{{ scope.row.train1 }}人</div>
+            </template></el-table-column
+          >
+
+          <el-table-column align="center" label="60~120分钟">
+            <template slot-scope="scope">
+              <div>{{ scope.row.train2 }}人</div>
+            </template>
+          </el-table-column>
+          <el-table-column align="center" prop="id" label="120~240分钟">
+            <template slot-scope="scope">
+              <div>{{ scope.row.train3 }}人</div>
+            </template>
+          </el-table-column>
+          <el-table-column align="center" prop="id" label="≥240分钟">
+            <template slot-scope="scope">
+              <div>{{ scope.row.train4 }}人</div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            align="center"
+            prop="avgTrainTime"
+            label="平均练习时长(会员)"
+            width="100px"
+          >
+            <template slot-scope="scope">
+              <div>{{ scope.row.avgTrainTime }}分钟</div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            align="center"
+            prop="trainAvgTrainTime"
+            label="平均练习时长(练习)"
+            width="100px"
+          >
+            <template slot-scope="scope">
+              <div>{{ scope.row.trainAvgTrainTime }}分钟</div>
+            </template>
+          </el-table-column>
+          <el-table-column align="center" prop="id" label="练习达标占比">
+            <template slot-scope="scope">
+              <div>{{ scope.row.trainStandRate }}%</div>
+            </template>
+          </el-table-column>
+        </el-table>
+        <pagination
+          sync
+          :total.sync="pageInfo.total"
+          :page.sync="pageInfo.page"
+          :limit.sync="pageInfo.limit"
+          :page-sizes="pageInfo.page_size"
+          @pagination="getList"
+        />
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import { Export } from "@/utils/downLoadFile";
+import pagination from "@/components/Pagination/index";
+import saveform from "@/components/save-form";
+import dayjs from "dayjs";
+import histogram from "v-charts/lib/histogram.common";
+import { getNowDateAndMonday, getNowDateAndSunday } from "@/utils/utils";
+import { cloudTeacherSumDetail } from "../api";
+let nowTime = new Date();
+nowTime =
+  nowTime.getFullYear() +
+  "-" +
+  (nowTime.getMonth() + 1) +
+  "-" +
+  nowTime.getDate();
+export const getTimes = (times, keys = []) => {
+  if (times && times.length) {
+    return {
+      [keys[0] || "start"]: dayjs(times[0]).format("YYYY-MM-DD"),
+      [keys[1] || "start"]: dayjs(times[1]).format("YYYY-MM-DD")
+    };
+  }
+  return {};
+};
+export default {
+  components: { saveform, "ve-histogram": histogram, pagination },
+  name: "helpCategory",
+  data() {
+    return {
+      nowIndex: dayjs(dayjs().format("YYYY-MM-DD")).valueOf(),
+      searchForm: {
+        dates: [
+          dayjs()
+            .subtract(1, "day")
+            .format("YYYY-MM-DD"),
+          dayjs()
+            .subtract(1, "day")
+            .format("YYYY-MM-DD")
+        ],
+        organId: ""
+      },
+      tableList: [],
+      activeName: "first",
+      specialList: [],
+      pageInfo: {
+        // 分页规则
+        limit: 10, // 限制显示条数
+        page: 1, // 当前页
+        total: 0, // 总条数
+        page_size: [10, 20, 40, 50] // 选择限制显示条数
+      }
+    };
+  },
+  async mounted() {
+    const query = this.$route.query;
+    this.searchForm.organId = query.organId ? Number(query.organId) : "";
+    await this.$store.dispatch("setBranchs");
+    const arr = [36, 39, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, 54, 56];
+    this.specialList = this.selects.branchs.filter(item => {
+      return arr.indexOf(item.id) == -1;
+    });
+    // this.searchForm.dates.push(getNowDateAndMonday(nowTime));
+    // this.searchForm.dates.push(getNowDateAndSunday(nowTime));
+    this.getList();
+  },
+  methods: {
+    exportQuestion() {
+      const { dates, organId } = this.searchForm;
+      Export(
+        this,
+        {
+          url: "/api-web/export/managerDownload",
+          fileName: "云练习练习时长.xls",
+          method: "post",
+          params: {
+            exportEnum: "EXPORT_CLOUD_TEACHER_SUM_DETAIL",
+            queryInfo: {
+              ...getTimes(dates, ["startDate", "endDate"]),
+              organId
+            }
+          }
+        },
+        "您确定导出云练习练习时长?"
+      );
+    },
+    search() {
+      this.$refs.searchForm.validate(valid => {
+        this.pageInfo = {
+          ...this.pageInfo,
+          page: 1
+        };
+        this.getList();
+      });
+    },
+    onCancel() {
+      this.$store.dispatch("delVisitedViews", this.$route);
+      this.$router.push({
+        path: "/cloudDate?tabrouter=exerciseDuration"
+      });
+    },
+    onReSet() {
+      this.pageInfo = {
+        ...this.pageInfo,
+        page: 1
+      };
+      this.$refs.searchForm.resetFields();
+      // this.searchForm.dates.push(getNowDateAndMonday(nowTime));
+      // this.searchForm.dates.push(getNowDateAndSunday(nowTime));
+      this.getList();
+    },
+    getDefaultTime() {
+      const dayjs = this.$helpers.dayjs;
+      let nowDate = dayjs(new Date()).format("YYYY-MM-DD");
+      let lastWeek = dayjs(nowDate)
+        .subtract(1, "week")
+        .format("YYYY-MM-DD");
+      this.searchForm.dates = [
+        getNowDateAndMonday(lastWeek),
+        getNowDateAndSunday(nowDate)
+      ];
+    },
+    changeWeek(val) {
+      if (val) {
+        // this.searchForm.dates = [
+        //   getNowDateAndMonday(val[0]),
+        //   getNowDateAndSunday(val[1])
+        // ];
+      } else {
+        this.getDefaultTime();
+      }
+    },
+    async getList() {
+      // cloudTeacherSumDetail
+      try {
+        const { dates, organId } = this.searchForm;
+        let params = {
+          ...getTimes(dates, ["startDate", "endDate"]),
+          organId
+        };
+        const res = await cloudTeacherSumDetail({
+          page: this.pageInfo.page,
+          rows: this.pageInfo.limit,
+          ...params
+        });
+        this.tableList = [];
+        this.tableList = res.data.rows || [];
+        this.pageInfo.total = res.data.total;
+      } catch {}
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+::v-deep .el-date-editor.el-input {
+  width: 100% !important;
+}
+::v-deep .el-select {
+  width: 100% !important;
+}
+::v-deep .el-table .cell {
+  display: -webkit-box;
+  overflow: hidden;
+  max-height: 45px;
+  text-overflow: ellipsis;
+  -webkit-line-clamp: 3;
+  -webkit-box-orient: vertical;
+}
+::v-deep .el-dialog__body {
+  padding: 10px 20px;
+}
+.newBand {
+  display: inline-block;
+}
+
+::v-deep .el-tabs__active-bar {
+  background-color: transparent !important;
+}
+::v-deep.el-tabs__nav-wrap {
+  &:after {
+    background-color: transparent !important;
+  }
+}
+/*去掉切换时el-tab-pane底部的蓝色下划线*/
+::v-deep .el-tabs__nav-wrap::after {
+  background-color: transparent !important;
+}
+
+/*去掉tabs底部的下划线*/
+</style>

+ 38 - 0
src/views/main/coursewareDate/index.vue

@@ -0,0 +1,38 @@
+<template>
+  <div class="m-container">
+    <h2>
+      <div class="squrt"></div>
+      观看时间统计
+    </h2>
+    <div class="m-core">
+      <exerciseDuration />
+    </div>
+  </div>
+</template>
+<script>
+import { permission } from "@/utils/directivePage";
+// exerciseDuration
+import allDate from "./allDate.vue";
+import organMemberList from "./organMemberList.vue";
+import exerciseDuration from "./exerciseDuration.vue";
+export default {
+  components: {
+    allDate,
+    organMemberList,
+    exerciseDuration
+  },
+  data() {
+    return {
+      activeKey: ""
+    };
+  },
+  methods: {
+    permission
+  }
+};
+</script>
+<style lang="scss" scoped>
+.marginBottom20 {
+  margin-bottom: 20px;
+}
+</style>

+ 67 - 0
src/views/main/coursewareDate/modals/headers.vue

@@ -0,0 +1,67 @@
+<template>
+  <div>
+    <div class="titleWrap">
+      <div class="box">
+        <span class="shape"></span>
+        <span>{{ title }}</span>
+      </div>
+      <div class="right">
+        <el-select
+          v-if="!hidenOrgan"
+
+          class="multiple"
+          v-model.trim="organId"
+          filterable
+          clearable
+          placeholder="请选择分部"
+          @change="changeOrgan"
+        >
+          <el-option
+            v-for="(item, index) in special?specialList:selects.branchs"
+            :key="index"
+            :label="item.name"
+            :value="item.id"
+          ></el-option>
+        </el-select>
+      </div>
+    </div>
+    <el-divider></el-divider>
+  </div>
+</template>
+<script>
+export default {
+  props: ["title", "hidenOrgan",'special'],
+  data() {
+    return {
+      organId: "",
+      specialList: [],
+    };
+  },
+  async mounted() {
+    await this.$store.dispatch("setBranchs");
+      const arr = [36,39,41,42,43,44,45,46,47,48,49,50,52,54,56]
+    this.specialList = this.selects.branchs.filter((item) => {
+      return arr.indexOf(item.id) == -1;
+    });
+  },
+  methods: {
+    changeOrgan(val) {
+      this.organId = val;
+      this.$emit("changeOrgan", val);
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.el-divider--horizontal {
+  margin-top: 0 !important;
+}
+.titleWrap {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  align-items: center;
+  height: 55px;
+}
+</style>

+ 443 - 0
src/views/main/coursewareDate/organDate.vue

@@ -0,0 +1,443 @@
+<template>
+  <div>
+    <el-card>
+      <headers title="分部数据" @changeOrgan="changeOrgan" :special="true" />
+      <div class="btnList">
+        <el-button
+          type="primary"
+          v-permission="'export/organStudentOverView'"
+          @click="organDateExport"
+          >导出</el-button
+        >
+        <el-button
+          type="text"
+          v-permission="'/organRankDetail'"
+          @click="gotoAll"
+          class="lookOrgan"
+          >全部分部 ></el-button
+        >
+      </div>
+
+      <div class="tableWrap">
+        <el-table
+          style="width: 100%"
+          :header-cell-style="{ background: '#EDEEF0', color: '#444' }"
+          :data="tableList"
+          @sort-change="sortChang"
+          :default-sort="{
+            prop: 'cloudStudyUseStudentDuty',
+            order: 'descending'
+          }"
+          sortable="custom"
+        >
+          <el-table-column
+            align="center"
+            prop="index"
+            label="排名"
+          ></el-table-column>
+          <el-table-column
+            align="center"
+            prop="organName"
+            label="分部"
+          ></el-table-column>
+          <el-table-column
+            align="center"
+            prop="totalStudentNum"
+            label="学员总数"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>学员总数</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">
+                    乐团在读学员+有剩余VIP课或网管课学员去重之和
+                  </div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            align="center"
+            prop="targetNum"
+            label="目标人数"
+            v-if="tenantId == 1"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>目标人数</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">
+                    进行中非会员乐团-已上乐团课小于等于4节学员-非本活动购买会员-弦乐声部学员
+                  </div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            align="center"
+            prop="cloudStudyLivelyStudentNum"
+            label="活跃人数"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>活跃人数</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">近15天内使用达到5天及以上的用户数</div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            align="center"
+            prop="cloudStudyUseStudentNum"
+            label="使用人数"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>使用人数</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">截止目前使用云练习的总人数</div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            align="center"
+            prop="newStudentNum"
+            label="新用户人数"
+          >
+            <template slot="header">
+              <div class="titleCell">
+                <span>新用户人数</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">乐团在读学员已上课程≤4节</div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            sortable="custom"
+            align="center"
+            prop="newStudentDuty"
+            label="新用户占比"
+          >
+            <template slot-scope="scope">
+              {{ scope.row.newStudentDuty }}%
+            </template>
+          </el-table-column>
+          <el-table-column
+            align="center"
+            prop="newCloudStudyStudentNum"
+            label="新增使用人数"
+            width="130px"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>新增使用人数</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">当日第一次使用云练习的人数</div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            align="center"
+            prop="cloudStudyUseStudentDuty"
+            label="使用比例"
+            sortable="custom"
+            width="140px"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>使用比例</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">使用人数 / 学员总数</div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+            <template slot-scope="scope">
+              <div>{{ scope.row.cloudStudyUseStudentDuty }}%</div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            align="center"
+            prop="vipStudentNum"
+            label="付费会员数"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>付费会员数</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">该分部生效中、待生效付费会员总数</div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            sortable="custom"
+            align="center"
+            prop="vipStudentDuty"
+            label="付费会员占比"
+            width="150px"
+            fixed="right"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>付费会员占比</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">付费会员数 / 学员总数</div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+            <template slot-scope="scope">
+              <div>{{ scope.row.vipStudentDuty }}%</div>
+            </template>
+          </el-table-column>
+          <!-- <el-table-column
+               sortable="custom"
+            align="center"
+            prop="eVipStudentNum"
+            label="试用会员"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>试用会员</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">
+                    有生效中或待生效的付费会员,不统计在内
+                  </div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column> -->
+
+          <el-table-column
+            align="center"
+            prop="studentId"
+            label="操作"
+            fixed="right"
+          >
+            <template slot-scope="scope">
+              <div>
+                <auth auths="/organDateDetail">
+                  <el-button type="text" @click="gotoDetail(scope.row)"
+                    >详情</el-button
+                  >
+                </auth>
+              </div>
+            </template>
+          </el-table-column>
+        </el-table>
+        <!-- <pagination
+          :autoScroll="false"
+          :total.sync="rules.total"
+          :page.sync="rules.page"
+          :limit.sync="rules.limit"
+          :page-sizes="rules.page_size"
+          @pagination="getList"
+        /> -->
+      </div>
+    </el-card>
+  </div>
+</template>
+<script>
+import headers from "./modals/headers.vue";
+import pagination from "@/components/Pagination/index";
+import { organStudentOverView } from "../api";
+import { Export } from "@/utils/downLoadFile";
+import qs from "qs";
+export default {
+  components: {
+    headers,
+    pagination
+  },
+  data() {
+    return {
+      tableList: [],
+      organId: "",
+      rules: {
+        // 分页规则
+        limit: 10, // 限制显示条数
+        page: 1, // 当前页
+        total: 0, // 总条数
+        page_size: [10, 20, 40, 50] // 选择限制显示条数
+      },
+      searchList: {
+        cloudStudyUseStudentDuty: "DESC"
+      },
+      tenantId: ""
+    };
+  },
+  mounted() {
+    this.tenantId = this.$helpers.tenantId;
+    this.getList();
+  },
+  methods: {
+    async getList() {
+      try {
+        // const arr = [36,39,41,42,43,44,45,46,47,48,49,50,52,54,55,56]
+        const res = await organStudentOverView({
+          page: 1,
+          rows: 10,
+          ...this.searchList,
+          organIds: this.organId
+        });
+        this.tableList = res.data.rows;
+        this.rules.total = res.data.total;
+        // console.log(this.tableList)
+      } catch (e) {
+        console.log(e);
+      }
+    },
+    sortChang(val) {
+      const dates = {
+        ascending: "ASC",
+        descending: "DESC"
+      };
+      this.searchList = {};
+      if (val.prop && val.order) {
+        this.searchList[val.prop] = dates[val.order];
+      }
+      this.rules.page = 1;
+      this.getList();
+    },
+    gotoDetail(row) {
+      // 跳转到分部数据详情 row.organId
+      this.$router.push({
+        name: "organDateDetail",
+        params: { organId: row.organId }
+      });
+    },
+    changeOrgan(val) {
+      this.organId = val;
+      this.rules.page = 1;
+      this.getList();
+    },
+    organDateExport() {
+      let params = { ...this.searchList, organIds: this.organId };
+      Export(
+        this,
+        {
+          url: "/api-web/export/organStudentOverView",
+          fileName: "分部云练习数据.xls",
+          method: "post",
+          params: qs.stringify(params)
+        },
+        "您确定导出分部云练习数据列表?"
+      );
+    },
+
+    gotoAll() {
+      this.$router.push({
+        name: "organRankDetail"
+      });
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+::v-deep .el-card__body {
+  padding-top: 0 !important;
+}
+.titleCell {
+  display: inline-block;
+}
+.tableWrap {
+  margin-top: 20px;
+}
+.btnList {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+}
+</style>

+ 358 - 0
src/views/main/coursewareDate/organDateDetail.vue

@@ -0,0 +1,358 @@
+<!--  -->
+<template>
+  <div class="m-container">
+    <el-page-header
+      @back="goback"
+      style="padding-bottom: 30px"
+      content="分部云练习数据详情"
+    >
+    </el-page-header>
+
+    <div class="m-core">
+      <save-form
+        :inline="true"
+        :model="searchForm"
+        @submit="search"
+        @reset="onReSet"
+        ref="saveForm"
+      >
+        <el-form-item prop="organId">
+          <el-select
+            class="multiple"
+            v-model.trim="searchForm.organId"
+            filterable
+            placeholder="请选择分部"
+            @change="search"
+          >
+            <el-option
+              v-for="(item, index) in specialList"
+              :key="index"
+              :label="item.name"
+              :value="item.id"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item>
+          <!-- <el-button native-type="submit" type="primary">搜索</el-button>
+          <el-button native-type="reset" type="danger">重置</el-button> -->
+          <el-button
+            type="primary"
+            @click="organDateExport"
+            v-permission="'export/organTeacherMemberStudentData'"
+            >导出</el-button
+          >
+        </el-form-item>
+      </save-form>
+      <a class="msg" v-if="noTeacherStudentNum > 0" @click="gotoStudentList"
+        >查看当前分部没有关联指导老师的学生</a
+      >
+      <div class="tableWrap">
+        <el-table
+          style="width: 100%"
+          :header-cell-style="{ background: '#EDEEF0', color: '#444' }"
+          :data="tableList"
+        >
+          <el-table-column
+            align="center"
+            prop="teacherName"
+            label="老师姓名"
+          ></el-table-column>
+          <el-table-column
+            align="center"
+            prop="totalStudentNum"
+            label="学员总数"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>学员总数</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">
+                    指导老师关联的乐团在读学员+有剩余VIP课或网管课学员去重之和
+                  </div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            align="center"
+            prop="cloudStudyUseStudentNum"
+            label="使用人数"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>使用人数</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">
+                    指导老师关联的截止目前使用云练习的总人数
+                  </div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            align="center"
+            prop="cloudStudyUseStudentDuty"
+            label="使用人数比"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>使用比例</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">使用人数 / 学员总数</div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+            <template slot-scope="scope">
+              <div>{{ scope.row.cloudStudyUseStudentDuty }}%</div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            align="center"
+            prop="vipStudentNum"
+            label="付费会员数"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>付费会员数</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">
+                    指导老师关联的生效中、待生效付费会员总数
+                  </div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column>
+          <!-- <el-table-column
+            align="center"
+            prop="eVipStudentNum"
+            label="试用会员"
+
+          ></el-table-column> -->
+          <el-table-column
+            align="center"
+            prop="vipStudentDuty"
+            label="付费会员占比"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>付费会员占比</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">付费会员数 / 学员总数</div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+            <template slot-scope="scope">
+              <div>{{ scope.row.vipStudentDuty }}%</div>
+            </template>
+          </el-table-column>
+          <el-table-column align="center" prop="studentId" label="操作">
+            <template slot-scope="scope">
+              <div>
+                <el-button type="text" @click="gotoDetail(scope.row)"
+                  >详情</el-button
+                >
+              </div>
+            </template>
+          </el-table-column>
+        </el-table>
+        <pagination
+          sync
+          :total.sync="rules.total"
+          :page.sync="rules.page"
+          :limit.sync="rules.limit"
+          :page-sizes="rules.page_size"
+          @pagination="getList"
+        />
+      </div>
+      <el-dialog
+        title="分部数据"
+        :visible.sync="studentVisible"
+        width="1100px"
+        v-if="studentVisible"
+      >
+        <organStudentDetail />
+        <!-- <span slot="footer" class="dialog-footer">
+          <el-button @click="studentVisible = false">取 消</el-button>
+          <el-button type="primary" @click="submitPlan">确 定</el-button>
+        </span> -->
+      </el-dialog>
+    </div>
+  </div>
+</template>
+
+<script>
+import axios from "axios";
+import { getToken } from "@/utils/auth";
+import pagination from "@/components/Pagination/index";
+import load from "@/utils/loading";
+import { Export } from "@/utils/downLoadFile";
+import { queryMemberStudentData } from "../api";
+import qs from "qs";
+export default {
+  name: "organDateDetail",
+  components: { pagination },
+  data() {
+    return {
+      searchForm: {
+        organId: null
+      },
+
+      tableList: [],
+      organList: [],
+      rules: {
+        // 分页规则
+        limit: 10, // 限制显示条数
+        page: 1, // 当前页
+        total: 0, // 总条数
+        page_size: [10, 20, 40, 50] // 选择限制显示条数
+      },
+      studentVisible: false,
+      noTeacherStudentNum: 0,
+      specialList: []
+    };
+  },
+  //生命周期 - 创建完成(可以访问当前this实例)
+  created() {},
+  //生命周期 - 挂载完成(可以访问DOM元素)
+  async mounted() {
+    // 获取分部
+    await this.$store.dispatch("setBranchs");
+    const arr = [
+      36,
+      39,
+      41,
+      42,
+      43,
+      44,
+      45,
+      46,
+      47,
+      48,
+      49,
+      50,
+      52,
+      54,
+      55,
+      56
+    ];
+    this.specialList = this.selects.branchs.filter(item => {
+      return arr.indexOf(item.id) == -1;
+    });
+    if (this.$route.params?.organId) {
+      this.searchForm.organId = this.$route.params.organId;
+    }
+
+    this.init();
+  },
+  methods: {
+    init() {
+      this.getList();
+    },
+    async getList() {
+      try {
+        const res = await queryMemberStudentData({
+          organId: this.searchForm.organId,
+          page: this.rules.page,
+          rows: this.rules.limit
+        });
+        this.tableList = res.data.rows;
+        this.rules.total = res.data.total;
+        this.noTeacherStudentNum = res.data.statInfo.noTeacherStudentNum;
+        this.$refs.saveForm.save();
+      } catch (e) {
+        console.log(e);
+      }
+    },
+    search() {
+      this.rules.page = 1;
+      this.getList();
+    },
+    onReSet() {},
+    gotoDetail(row) {
+      this.$router.push({
+        name: "studentList",
+        params: { teacherId: row.teacherId }
+      });
+      // this.studentVisible = true;
+    },
+    gotoStudentList() {
+      this.$router.push({
+        name: "studentList",
+        params: { hasTeacher: "0", organId: this.searchForm.organId }
+      });
+    },
+    goback() {
+      this.$store.dispatch("delVisitedViews", this.$route);
+      this.$router.push({ path: "/workbench?tabrouter=cloudDate" });
+    },
+    organDateExport() {
+      let params = { ...this.searchForm };
+      Export(
+        this,
+        {
+          url: "/api-web/export/organTeacherMemberStudentData",
+          fileName: "分部云练习数据详情.xls",
+          method: "post",
+          params: qs.stringify(params)
+        },
+        "您确定导出分部云练习数据详情列表?"
+      );
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+.msg {
+  color: red;
+  margin-bottom: 20px;
+  display: block;
+  text-decoration-line: underline;
+  font-size: 14px;
+}
+</style>

+ 539 - 0
src/views/main/coursewareDate/organMemberList.vue

@@ -0,0 +1,539 @@
+<template>
+  <div>
+    <el-card style="margin-bottom: 20px">
+      <!-- <headers title="数据总览" @changeOrgan="changeOrgan" :special="true" /> -->
+      <div
+        class="wall"
+        style="height: 68px"
+        v-if="JSON.stringify(items) == '{}'"
+      >
+        暂无数据
+      </div>
+      <!--
+          -->
+      <statistic :col="4" class="statistic" :cols="0">
+        <statistic-item
+          v-for="(item, key) in items"
+          :key="key"
+          @click="active = key"
+          :class="{ active: active === key }"
+        >
+          <span
+            v-if="
+              key == 'againBuyRate' ||
+                key == 'buyRate' ||
+                key == 'vipStudentRate'
+            "
+          >
+            {{ item.title + "(%)" }}
+            <el-tooltip
+              v-if="item.desc"
+              :content="item.desc"
+              :open-delay="0.3"
+              placement="top"
+            >
+              <i
+                style="margin-left: 5px; cursor: pointer"
+                class="el-icon-warning-outline"
+              />
+            </el-tooltip>
+          </span>
+          <span v-else>
+            {{ item.title + "(人)" }}
+            <el-tooltip
+              v-if="item.desc"
+              :content="item.desc"
+              :open-delay="0.3"
+              placement="top"
+            >
+              <i
+                style="margin-left: 5px; cursor: pointer"
+                class="el-icon-warning-outline"
+              />
+            </el-tooltip>
+          </span>
+
+          <span
+            v-if="
+              key == 'againBuyRate' ||
+                key == 'buyRate' ||
+                key == 'vipStudentRate'
+            "
+          >
+            <count-to :endVal="item.percent || 0" :decimals="2" />
+          </span>
+          <span v-else> <count-to :endVal="item.percent || 0" /> </span>
+        </statistic-item>
+        <!-- <statistic-item class="empty"></statistic-item>
+        <statistic-item class="empty"></statistic-item> -->
+      </statistic>
+
+      <ve-histogram
+        style="width: 100%"
+        height="350px"
+        :data="chartData"
+        :data-empty="dataEmpty"
+        :extend="chartExtend"
+        :legend="legend"
+        :data-zoom="dataZoom"
+      ></ve-histogram>
+    </el-card>
+
+    <el-card>
+      <!-- <headers title="分部数据" :hidenOrgan="true" /> -->
+      <el-button
+        type="primary"
+        @click="exportQuestion"
+        style="margin-top: 16px;"
+        v-permission="'export/now/cloudDate'"
+        >导出</el-button
+      >
+      <div class="tableWrap">
+        <el-table
+          style="width: 100%"
+          :header-cell-style="{ background: '#EDEEF0', color: '#444' }"
+          :data="tableList"
+          @sort-change="sortChang"
+          :default-sort="{
+            prop: 'cloudStudyUseStudentDuty',
+            order: 'descending'
+          }"
+          sortable="custom"
+        >
+          <el-table-column
+            align="center"
+            prop="organId"
+            label="分部编号"
+          ></el-table-column>
+          <el-table-column
+            align="center"
+            prop="organName"
+            label="分部名称"
+          ></el-table-column>
+          <el-table-column
+            align="center"
+            prop="totalStudentNum"
+            label="在读人数"
+          >
+            <!-- <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>学员总数</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">
+                    乐团在读学员+有剩余VIP课或网管课学员去重之和
+                  </div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template> -->
+          </el-table-column>
+          <!-- <el-table-column
+            align="center"
+            prop="effectiveStudentNum"
+            label="有效学员数"
+          >
+          </el-table-column> -->
+          <el-table-column
+            align="center"
+            prop="vipStudentNum"
+            label="生效待激活总人数"
+          >
+          </el-table-column>
+
+          <!-- <el-table-column
+            align="center"
+            prop="vipStudentRate"
+            label="会员占比"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>会员人数占比</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">
+                    会员总人数/有效学员数
+                  </div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style=" font-size: 18px;color: #f56c6c;top: 2px;position: relative;"
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+            <template slot-scope="scope">
+              <div>
+                {{ numeral(scope.row.vipStudentRate || 0).format("0.00") }}%
+              </div>
+            </template>
+          </el-table-column> -->
+
+          <el-table-column
+            align="center"
+            prop="effectiveVipStudentNum"
+            label="生效会员"
+          ></el-table-column>
+          <el-table-column
+            align="center"
+            prop="waitActivateVipStudentNum"
+            label="待激活会员"
+          ></el-table-column>
+
+          <el-table-column align="center" prop="buyRate" label="覆盖率">
+            <template slot-scope="scope">
+              {{ numeral(scope.row.buyRate || 0).format("0.00") }}%
+            </template>
+          </el-table-column>
+
+          <el-table-column align="center" prop="againBuyRate" label="复购率">
+            <template slot-scope="scope">
+              {{ numeral(scope.row.againBuyRate || 0).format("0.00") }}%
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            align="center"
+            prop="activeStudentNum"
+            label="活跃会员"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>近一月活跃人数</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">
+                    过去四周内有三周及以上每周训练时长超过60分钟为活跃学员
+                  </div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            align="center"
+            prop="cloudStudyTodayUseStudentNum"
+            label="今日使用人数"
+          ></el-table-column>
+        </el-table>
+        <!-- <pagination
+          :autoScroll="false"
+          :total.sync="rules.total"
+          :page.sync="rules.page"
+          :limit.sync="rules.limit"
+          :page-sizes="rules.page_size"
+          @pagination="getList"
+        /> -->
+      </div>
+    </el-card>
+  </div>
+</template>
+<script>
+// import ExportChiose from "@/components/Export-chiose";
+import pagination from "@/components/Pagination/index";
+import { getOrganMemberList } from "../api";
+import "echarts/lib/component/dataZoom";
+import histogram from "v-charts/lib/histogram.common";
+import { Export } from "@/utils/downLoadFile";
+import headers from "./modals/headers.vue";
+import countTo from "vue-count-to";
+import { descs, titles } from "../constant";
+import { getCloudStudyStudentOverView } from "../api";
+import numeral from "numeral";
+import qs from "qs";
+export default {
+  props: ["data"],
+  components: {
+    headers,
+    pagination,
+    "ve-histogram": histogram,
+    countTo
+  },
+  data() {
+    return {
+      tableList: [],
+      organId: "",
+      rules: {
+        // 分页规则
+        limit: 10, // 限制显示条数
+        page: 1, // 当前页
+        total: 0, // 总条数
+        page_size: [10, 20, 40, 50] // 选择限制显示条数
+      },
+      searchList: {
+        cloudStudyUseStudentDuty: "DESC"
+      },
+      tenantId: "",
+      dataList: {},
+      active: ""
+    };
+  },
+  mounted() {
+    this.tenantId = this.$helpers.tenantId;
+    this.getList();
+  },
+  methods: {
+    exportQuestion() {
+      Export(
+        this,
+        {
+          url: "/api-web/export/now",
+          fileName: "云练习数据汇总.xls",
+          method: "post",
+          params: { exportEnum: "CLOUD_STUDY_STUDENT_OVER_VIEW" }
+        },
+        "您确定导出云练习数据汇总?"
+      );
+    },
+    async getList() {
+      /**
+       * try {
+      const res = await getCloudStudyStudentOverView();
+      this.dataList = res.data;
+    } catch (e) {
+      console.log(e);
+    }
+       */
+      try {
+        const arr = [
+          36,
+          39,
+          41,
+          42,
+          43,
+          44,
+          45,
+          46,
+          47,
+          48,
+          49,
+          50,
+          52,
+          54,
+          56
+        ];
+        const res = await getCloudStudyStudentOverView({
+          page: 1,
+          rows: 10,
+          ...this.searchList,
+          organIds: this.organId
+        });
+        this.tableList = [];
+        //  res.data.forEach(ele => {
+        //    if(arr.indexOf (ele.organId) == -1){
+        //      this.tableList.push(ele)
+        //    }
+        //  });
+        this.tableList = res.data.list;
+        console.log(this.tableList, "tableList");
+        // this.rules.total = res.data.list?.total;
+        this.dataList = res.data?.overView || {};
+      } catch (e) {
+        console.log(e);
+      }
+    },
+    sortChang(val) {
+      const dates = {
+        ascending: "ASC",
+        descending: "DESC"
+      };
+      this.searchList = {};
+      if (val.prop && val.order) {
+        this.searchList[val.prop] = dates[val.order];
+      }
+      this.rules.page = 1;
+      this.getList();
+    },
+    gotoDetail(row) {
+      // 跳转到分部数据详情 row.organId
+      this.$router.push({
+        name: "organDateDetail",
+        params: { organId: row.organId }
+      });
+    },
+    changeOrgan(val) {
+      this.organId = val;
+      this.rules.page = 1;
+      this.getList();
+    },
+    // organDateExport() {
+    //   let params = { ...this.searchList, organIds: this.organId };
+    //   Export(
+    //     this,
+    //     {
+    //       url: "/api-web/export/organStudentOverView",
+    //       fileName: "分部云练习数据.xls",
+    //       method: "post",
+    //       params: qs.stringify(params)
+    //     },
+    //     "您确定导出分部云练习数据列表?"
+    //   );
+    // },
+
+    gotoAll() {
+      this.$router.push({
+        name: "organRankDetail"
+      });
+    },
+    numeral(val) {
+      return numeral(val);
+    }
+  },
+  computed: {
+    items() {
+      let obj = {};
+      //        "eVipStudentNum",
+      let arr = [
+        "totalStudentNum",
+        "vipStudentNum",
+        // "vipStudentRate",
+        "effectiveVipStudentNum",
+        "waitActivateVipStudentNum",
+        "buyRate",
+        "againBuyRate",
+        // "effectiveStudentNum",
+        "cloudStudyLivelyStudentNum",
+        // "newCloudStudyStudentNum",
+        // "cloudStudyUseStudentNum",
+        "cloudStudyTodayUseStudentNum"
+      ];
+      arr.forEach(str => {
+        if (this.dataList[str] + "") {
+          obj[str] = {
+            title: titles[str],
+            percent: this.dataList[str],
+            desc: descs[str]
+          };
+        }
+      });
+
+      return obj;
+    },
+    legend() {
+      return {
+        left: "10px"
+      };
+    },
+    chartData() {
+      const temp = {
+        totalStudentNum: "在读人数",
+        vipStudentNum: "会员人数",
+        effectiveVipStudentNum: "生效会员",
+        waitActivateVipStudentNum: "待激活",
+        activeStudentNum: "近一月活跃人数",
+        cloudStudyTodayUseStudentNum: "今日使用人数"
+      };
+      const values = Object.values(this.tableList);
+
+      const months = {};
+      for (const key in temp) {
+        for (const item of values) {
+          if (!months[item.organId]) {
+            months[item.organId] = {
+              分部: item.organName
+            };
+          }
+          months[item.organId][temp[key]] = item[key] || 0;
+        }
+      }
+      console.log(months, "months");
+      return {
+        columns: [
+          "分部",
+          "在读人数",
+          "会员人数",
+          "生效会员",
+          "待激活",
+          "近一月活跃人数",
+          "今日使用人数"
+        ],
+        rows: Object.values(months)
+      };
+    },
+    chartExtend() {
+      return {
+        yAxis: {
+          //纵轴标尺固定
+          minInterval: 1,
+          type: "value",
+          scale: true,
+          min: 0,
+          axisLabel: {
+            formatter: "{value}人"
+          }
+        },
+        series: {
+          type: "bar",
+          smooth: false
+        },
+        tooltip: {
+          axisPointer: {
+            type: "shadow",
+            shadowStyle: {
+              color: "rgba(150,150,150,0.2)"
+            }
+          },
+          formatter: item => {
+            return [
+              item[0].axisValueLabel,
+              ...item.map(d => {
+                return `<br/>${d.marker}${d.seriesName}: ${d.value}人`;
+              })
+            ].join("");
+          }
+        }
+      };
+    },
+    dataZoom() {
+      return [
+        {
+          show: true,
+          type: "slider",
+          start: 0,
+          end: 30,
+          filterMode: "empty",
+          zoomLock: true,
+          handleSize: 0
+        }
+      ];
+    },
+    dataEmpty() {
+      return !this.chartData.rows.length;
+    },
+    exporyun() {
+      return {
+        organId: this.organId
+      };
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+::v-deep .el-card__body {
+  padding-top: 0 !important;
+}
+.titleCell {
+  display: inline-block;
+}
+.tableWrap {
+  margin-top: 20px;
+}
+.btnList {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+}
+</style>

+ 493 - 0
src/views/main/coursewareDate/organRankDetail.vue

@@ -0,0 +1,493 @@
+<template>
+  <div class="m-container">
+    <el-page-header
+      @back="goback"
+      style="padding-bottom: 30px"
+      content="分部云练习数据"
+    >
+    </el-page-header>
+    <save-form
+      :inline="true"
+      :model="searchForm"
+      @submit="search"
+      ref="saveForm"
+    >
+      <el-form-item prop="organId">
+        <el-select
+          class="multiple"
+          v-model.trim="searchForm.organId"
+          clearable
+          filterable
+          placeholder="请选择分部"
+          @change="search"
+        >
+          <el-option
+            v-for="(item, index) in specialList"
+            :key="index"
+            :label="item.name"
+            :value="item.id"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+    </save-form>
+    <p style="margin-bottom: 20px; font-size: 14px">
+      共{{ tableList.length }}个分部
+    </p>
+    <div class="tableWrap">
+      <el-table
+        style="width: 100%"
+        :header-cell-style="{ background: '#EDEEF0', color: '#444' }"
+        :data="tableList"
+        @sort-change="sortChang"
+        :default-sort="{
+          prop: 'cloudStudyUseStudentDuty',
+          order: 'descending'
+        }"
+        sortable="custom"
+      >
+        <el-table-column
+          align="center"
+          prop="index"
+          label="排名"
+        ></el-table-column>
+        <el-table-column
+          align="center"
+          prop="organName"
+          label="分部"
+        ></el-table-column>
+        <el-table-column align="center" prop="totalStudentNum" label="学员总数">
+          <template slot="header" slot-scope="slot">
+            <div class="titleCell">
+              <span>学员总数</span>
+              <el-tooltip placement="top" popper-class="mTooltip">
+                <div slot="content">
+                  乐团在读学员+有剩余VIP课或网管课学员去重之和
+                </div>
+                <i
+                  class="el-icon-question micon el-tooltip"
+                  style="
+                    font-size: 18px;
+                    color: #f56c6c;
+                    top: 2px;
+                    position: relative;
+                  "
+                ></i>
+              </el-tooltip>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          align="center"
+          prop="targetNum"
+          label="目标人数"
+          v-if="tenantId == 1"
+        >
+          <template slot="header" slot-scope="slot">
+            <div class="titleCell">
+              <span>目标人数</span>
+              <el-tooltip placement="top" popper-class="mTooltip">
+                <div slot="content">
+                  进行中非会员乐团-已上乐团课小于等于4节学员-非本活动购买会员-弦乐声部学员
+                </div>
+                <i
+                  class="el-icon-question micon el-tooltip"
+                  style="
+                    font-size: 18px;
+                    color: #f56c6c;
+                    top: 2px;
+                    position: relative;
+                  "
+                ></i>
+              </el-tooltip>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          align="center"
+          prop="cloudStudyLivelyStudentNum"
+          label="活跃人数"
+        >
+          <template slot="header" slot-scope="slot">
+            <div class="titleCell">
+              <span>活跃人数</span>
+              <el-tooltip placement="top" popper-class="mTooltip">
+                <div slot="content">近15天内使用达到5天及以上的用户数</div>
+                <i
+                  class="el-icon-question micon el-tooltip"
+                  style="
+                    font-size: 18px;
+                    color: #f56c6c;
+                    top: 2px;
+                    position: relative;
+                  "
+                ></i>
+              </el-tooltip>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          align="center"
+          prop="cloudStudyUseStudentNum"
+          label="使用人数"
+        >
+          <template slot="header" slot-scope="slot">
+            <div class="titleCell">
+              <span>使用人数</span>
+              <el-tooltip placement="top" popper-class="mTooltip">
+                <div slot="content">截止目前使用云练习的总人数</div>
+                <i
+                  class="el-icon-question micon el-tooltip"
+                  style="
+                    font-size: 18px;
+                    color: #f56c6c;
+                    top: 2px;
+                    position: relative;
+                  "
+                ></i>
+              </el-tooltip>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column align="center" prop="newStudentNum" label="新用户人数">
+          <template slot="header">
+            <div class="titleCell">
+              <span>新用户人数</span>
+              <el-tooltip placement="top" popper-class="mTooltip">
+                <div slot="content">乐团在读学员已上课程≤4节</div>
+                <i
+                  class="el-icon-question micon el-tooltip"
+                  style="
+                    font-size: 18px;
+                    color: #f56c6c;
+                    top: 2px;
+                    position: relative;
+                  "
+                ></i>
+              </el-tooltip>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          sortable="custom"
+          align="center"
+          prop="newStudentDuty"
+          label="新用户占比"
+        >
+          <template slot-scope="scope">
+            {{ scope.row.newStudentDuty }}%
+          </template>
+        </el-table-column>
+        <el-table-column
+          align="center"
+          prop="newCloudStudyStudentNum"
+          label="新增使用人数"
+          width="130px"
+        >
+          <template slot="header" slot-scope="slot">
+            <div class="titleCell">
+              <span>新增使用人数</span>
+              <el-tooltip placement="top" popper-class="mTooltip">
+                <div slot="content">当日第一次使用云练习的人数</div>
+                <i
+                  class="el-icon-question micon el-tooltip"
+                  style="
+                    font-size: 18px;
+                    color: #f56c6c;
+                    top: 2px;
+                    position: relative;
+                  "
+                ></i>
+              </el-tooltip>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          align="center"
+          prop="cloudStudyUseStudentDuty"
+          label="使用比例"
+          sortable="custom"
+          width="140px"
+        >
+          <template slot="header" slot-scope="slot">
+            <div class="titleCell">
+              <span>使用比例</span>
+              <el-tooltip placement="top" popper-class="mTooltip">
+                <div slot="content">使用人数 / 学员总数</div>
+                <i
+                  class="el-icon-question micon el-tooltip"
+                  style="
+                    font-size: 18px;
+                    color: #f56c6c;
+                    top: 2px;
+                    position: relative;
+                  "
+                ></i>
+              </el-tooltip>
+            </div>
+          </template>
+          <template slot-scope="scope">
+            <div>{{ scope.row.cloudStudyUseStudentDuty }}%</div>
+          </template>
+        </el-table-column>
+        <el-table-column align="center" prop="vipStudentNum" label="付费会员数">
+          <template slot="header" slot-scope="slot">
+            <div class="titleCell">
+              <span>付费会员数</span>
+              <el-tooltip placement="top" popper-class="mTooltip">
+                <div slot="content">该分部生效中、待生效付费会员总数</div>
+                <i
+                  class="el-icon-question micon el-tooltip"
+                  style="
+                    font-size: 18px;
+                    color: #f56c6c;
+                    top: 2px;
+                    position: relative;
+                  "
+                ></i>
+              </el-tooltip>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column
+          sortable="custom"
+          align="center"
+          prop="vipStudentDuty"
+          label="付费会员占比"
+          width="150px"
+        >
+          <template slot="header" slot-scope="slot">
+            <div class="titleCell">
+              <span>付费会员占比</span>
+              <el-tooltip placement="top" popper-class="mTooltip">
+                <div slot="content">付费会员数 / 学员总数</div>
+                <i
+                  class="el-icon-question micon el-tooltip"
+                  style="
+                    font-size: 18px;
+                    color: #f56c6c;
+                    top: 2px;
+                    position: relative;
+                  "
+                ></i>
+              </el-tooltip>
+            </div>
+          </template>
+          <template slot-scope="scope">
+            <div>{{ scope.row.vipStudentDuty }}%</div>
+          </template>
+        </el-table-column>
+        <!-- <el-table-column
+               sortable="custom"
+            align="center"
+            prop="eVipStudentNum"
+            label="试用会员"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>试用会员</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">
+                    有生效中或待生效的付费会员,不统计在内
+                  </div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column> -->
+
+        <el-table-column align="center" prop="studentId" label="操作">
+          <template slot-scope="scope">
+            <div>
+              <auth auths="/organDateDetail">
+                <el-button type="text" @click="gotoDetail(scope.row)"
+                  >详情</el-button
+                >
+              </auth>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+      <!-- <pagination
+          :autoScroll="false"
+          :total.sync="rules.total"
+          :page.sync="rules.page"
+          :limit.sync="rules.limit"
+          :page-sizes="rules.page_size"
+          @pagination="getList"
+        /> -->
+    </div>
+  </div>
+</template>
+<script>
+import headers from "./modals/headers.vue";
+import pagination from "@/components/Pagination/index";
+import { Export } from "@/utils/downLoadFile";
+import dayjs from "dayjs";
+import qs from "qs";
+import { organStudentOverView } from "../api";
+export default {
+  components: {
+    headers,
+    pagination
+  },
+  data() {
+    return {
+      tableList: [],
+      searchList: {
+        cloudStudyUseStudentDuty: "DESC"
+      },
+      searchForm: {},
+      rules: {
+        // 分页规则
+        limit: 10, // 限制显示条数
+        page: 1, // 当前页
+        total: 0, // 总条数
+        page_size: [10, 20, 40, 50] // 选择限制显示条数
+      },
+      date: "",
+      specialList: [],
+      tenantId: ""
+    };
+  },
+  async mounted() {
+    this.date = dayjs(new Date())
+      .subtract(1, "day")
+      .format("YYYY-MM-DD");
+    await this.$store.dispatch("setBranchs");
+    const arr = [
+      36,
+      39,
+      41,
+      42,
+      43,
+      44,
+      45,
+      46,
+      47,
+      48,
+      49,
+      50,
+      52,
+      54,
+      55,
+      56
+    ];
+    this.specialList = this.selects.branchs.filter(item => {
+      return arr.indexOf(item.id) == -1;
+    });
+    if (this.$route.params?.organId) {
+      this.searchForm.organId = this.$route.params.organId;
+    }
+    this.getList();
+    this.tenantId = this.$helpers.tenantId;
+  },
+  methods: {
+    async getList() {
+      try {
+        const res = await organStudentOverView({
+          ...this.searchList,
+          rows: 999,
+          page: 1,
+          organIds: this.searchForm.organId
+        });
+        this.tableList = res.data.rows;
+        this.rules.total = res.data.total;
+      } catch (e) {
+        console.log(e);
+      }
+    },
+    search() {
+      this.getList();
+    },
+    bigin() {
+      let self = this;
+      return {
+        firstDayOfWeek: 1,
+        disabledDate(time) {
+          if (self.endDate) {
+            let endTime = self.$helpers.dayjs(self.endDate).valueOf();
+            return time.getTime() > endTime;
+          } else {
+            return time.getTime() >= Date.now() - 24 * 60 * 60 * 1000;
+          }
+        }
+      };
+    },
+    changeValue(val) {
+      this.date = val;
+      this.rules.page = 1;
+      this.getList();
+    },
+    sortChang(val) {
+      const dates = {
+        ascending: "ASC",
+        descending: "DESC"
+      };
+      this.searchList = {};
+      if (val.prop && val.order) {
+        this.searchList[val.prop] = dates[val.order];
+      }
+      this.rules.page = 1;
+      this.getList();
+    },
+    rankingExport() {
+      let params = { ...this.searchForm, date: this.date };
+      Export(
+        this,
+        {
+          url: "/api-web/export/cloudStudyStudentOverView",
+          fileName: "分部云练习数据排行.xls",
+          method: "post",
+          params: qs.stringify(params)
+        },
+        "您确定导出分部云练习数据排行?"
+      );
+    },
+    goback() {
+      this.$store.dispatch("delVisitedViews", this.$route);
+      this.$router.push({ path: "/workbench?tabrouter=cloudDate" });
+    },
+    gotoDetail(row) {
+      // 跳转到分部数据详情 row.organId
+      this.$router.push({
+        name: "organDateDetail",
+        params: { organId: row.organId }
+      });
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+::v-deep .el-card__body {
+  padding-top: 0 !important;
+}
+.titleCell {
+  display: inline-block;
+}
+.chioseBox {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: flex-start;
+  margin-bottom: 30px;
+  .lookOrgan {
+    margin-left: 10px;
+  }
+}
+.wrap {
+  position: relative;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 20px;
+}
+</style>

+ 471 - 0
src/views/main/coursewareDate/organRanking.vue

@@ -0,0 +1,471 @@
+<template>
+  <div>
+    <el-card>
+      <headers title="分部排行" :hidenOrgan="true" />
+      <div class="wrap">
+        <el-button
+          type="primary"
+          @click="rankingExport"
+          v-permission="'export/cloudStudyStudentOverView'"
+          >导出</el-button
+        >
+        <div class="chioseBox">
+          <el-date-picker
+            v-model="date"
+            type="date"
+            value-format="yyyy-MM-dd"
+            format="yyyy-MM-dd"
+            @change="changeValue"
+            :picker-options="bigin()"
+            :clearable="false"
+          >
+          </el-date-picker>
+          <!-- <el-button
+            type="text"
+            v-permission="'/organRankDetail'"
+            @click="gotoDetail"
+            class="lookOrgan"
+            >所有分部 ></el-button
+          > -->
+        </div>
+      </div>
+      <!--      :default-sort="{
+            prop: 'cloudStudyUseStudentDuty',
+            order: 'descending',
+          }" -->
+      <div class="tableWrap">
+        <el-table
+          ref="table"
+          style="width: 100%"
+          :header-cell-style="{ background: '#EDEEF0', color: '#444' }"
+          :data="tableList"
+          @sort-change="sortChang"
+        >
+          <el-table-column align="center" prop="index" label="排名">
+          </el-table-column>
+          <el-table-column
+            align="center"
+            prop="organName"
+            label="分部"
+          ></el-table-column>
+          <el-table-column
+            align="center"
+            prop="totalStudentNum"
+            label="学员总数"
+            width="100px"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>学员总数</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">
+                    乐团在读学员+有剩余VIP课或网管课学员去重之和
+                  </div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            align="center"
+            prop="cloudStudyLivelyStudentNum"
+            label="活跃人数"
+            width="100px"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>活跃人数</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">近15天内使用达到5天及以上的用户总数</div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column>
+
+          <!--  -->
+          <el-table-column
+            sortable="custom"
+            align="center"
+            prop="cloudStudyLivelyStudentDuty"
+            label="活跃人数占比"
+            width="150px"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>活跃人数占比</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">活跃人数 / 学员总数</div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+            <template slot-scope="scope">
+              <div>{{ scope.row.cloudStudyLivelyStudentDuty }}%</div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            align="center"
+            prop="cloudStudyUseStudentNum"
+            label="使用人数"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>当日使用人数</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">当日使用的总人数</div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            align="center"
+            prop="newCloudStudyStudentNum"
+            label="新增使用人数"
+            width="100px"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>当日新增使用人数</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">当日第一次使用云练习的人数</div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            sortable="custom"
+            width="150px"
+            align="center"
+            prop="cloudStudyUseStudentDuty"
+            label="当日使用人数比"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>使用人数占比</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">云练习当日使用人数 / 学员总数</div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+            <template slot-scope="scope">
+              <div>{{ scope.row.cloudStudyUseStudentDuty }}%</div>
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            sortable="custom"
+            width="140px"
+            align="center"
+            prop="vipStudentNum"
+            label="付费会员数"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>付费会员数</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">会员生效中或待生效总人数</div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column
+            sortable="custom"
+            width="150px"
+            align="center"
+            prop="vipStudentDuty"
+            label="付费会员比"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>付费会员占比</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">付费会员数 / 学员总数</div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+            <template slot-scope="scope">
+              <div>{{ scope.row.vipStudentDuty }}%</div>
+            </template>
+          </el-table-column>
+          <!-- <el-table-column
+               sortable="custom"
+            align="center"
+            prop="eVipStudentNum"
+            label="试用会员"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>试用会员数</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">当日试用会员总数</div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column> -->
+          <el-table-column
+            align="center"
+            prop="newMemberStudentNum"
+            label="新增付费会员"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>新增付费会员</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">当日新增付费会员数量</div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column>
+
+          <!-- <el-table-column
+              sortable="custom"
+            align="center"
+            prop="studentId"
+            label="活跃度"
+          >
+            <template slot="header" slot-scope="slot">
+              <div class="titleCell">
+                <span>活跃度</span>
+                <el-tooltip placement="top" popper-class="mTooltip">
+                  <div slot="content">
+                    当日使用过云练习的会员占比(生效中会员,含试用)
+                  </div>
+                  <i
+                    class="el-icon-question micon el-tooltip"
+                    style="
+                      font-size: 18px;
+                      color: #f56c6c;
+                      top: 2px;
+                      position: relative;
+                    "
+                  ></i>
+                </el-tooltip>
+              </div>
+            </template>
+          </el-table-column> -->
+        </el-table>
+        <pagination
+          :autoScroll="false"
+          sync
+          :total.sync="rules.total"
+          :page.sync="rules.page"
+          :limit.sync="rules.limit"
+          :page-sizes="rules.page_size"
+          @pagination="getList"
+        />
+      </div>
+    </el-card>
+  </div>
+</template>
+<script>
+import headers from "./modals/headers.vue";
+import pagination from "@/components/Pagination/index";
+import { Export } from "@/utils/downLoadFile";
+import dayjs from "dayjs";
+import qs from "qs";
+import { indexStudentOverView } from "../api";
+export default {
+  components: {
+    headers,
+    pagination
+  },
+  data() {
+    return {
+      tableList: [],
+      searchList: {},
+      rules: {
+        // 分页规则
+        limit: 10, // 限制显示条数
+        page: 1, // 当前页
+        total: 0, // 总条数
+        page_size: [10, 20, 40, 50] // 选择限制显示条数
+      },
+      date: ""
+    };
+  },
+  mounted() {
+    this.date = dayjs(new Date())
+      .subtract(1, "day")
+      .format("YYYY-MM-DD");
+    this.getList();
+  },
+  methods: {
+    async getList() {
+      try {
+        const res = await indexStudentOverView({
+          ...this.searchList,
+          date: this.date,
+          rows: this.rules.limit,
+          page: this.rules.page
+        });
+        this.tableList = res.data.rows;
+        this.rules.total = res.data.total;
+      } catch (e) {
+        console.log(e);
+      }
+    },
+    bigin() {
+      let self = this;
+      return {
+        firstDayOfWeek: 1,
+        disabledDate(time) {
+          if (self.endDate) {
+            let endTime = self.$helpers.dayjs(self.endDate).valueOf();
+            return time.getTime() > endTime;
+          } else {
+            return time.getTime() >= Date.now() - 24 * 60 * 60 * 1000;
+          }
+        }
+      };
+    },
+    changeValue(val) {
+      this.date = val;
+      this.rules.page = 1;
+      this.getList();
+    },
+    sortChang(val) {
+      const dates = {
+        ascending: "ASC",
+        descending: "DESC"
+      };
+      this.searchList = {};
+      if (val.prop && val.order) {
+        this.searchList[val.prop] = dates[val.order];
+      }
+      this.rules.page = 1;
+      this.getList();
+    },
+    rankingExport() {
+      let params = { ...this.searchForm, date: this.date };
+      Export(
+        this,
+        {
+          url: "/api-web/export/cloudStudyStudentOverView",
+          fileName: "分部云练习数据排行.xls",
+          method: "post",
+          params: qs.stringify(params)
+        },
+        "您确定导出分部云练习数据排行?"
+      );
+    },
+    gotoDetail() {
+      this.$router.push({
+        name: "organRankDetail"
+      });
+    }
+  }
+};
+</script>
+<style lang="scss" scoped>
+::v-deep .el-card__body {
+  padding-top: 0 !important;
+}
+.titleCell {
+  display: inline-block;
+}
+.chioseBox {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: flex-end;
+  .lookOrgan {
+    margin-left: 10px;
+  }
+}
+.wrap {
+  position: relative;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 20px;
+}
+</style>