|
@@ -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>
|