Commit 5e11badbf9ee3bb9d437aa6f168938127538d752

Authored by 梁保满
1 parent 8ef22809

使用分析

src/api/apis/apis.js
... ... @@ -1476,4 +1476,44 @@ export default {
1476 1476 data,
1477 1477 });
1478 1478 },
  1479 + //学校学段及年级
  1480 + sectionAndGradeList(data) {
  1481 + return service({
  1482 + url: setUpUrls.sectionAndGradeList,
  1483 + method: "POST",
  1484 + data,
  1485 + });
  1486 + },
  1487 + //学校设备使用分析
  1488 + usageStatistics(data) {
  1489 + return service({
  1490 + url: setUpUrls.usageStatistics,
  1491 + method: "POST",
  1492 + data,
  1493 + });
  1494 + },
  1495 + //集团设备使用分析
  1496 + tenantUsageStatistics(data) {
  1497 + return service({
  1498 + url: setUpUrls.tenantUsageStatistics,
  1499 + method: "POST",
  1500 + data,
  1501 + });
  1502 + },
  1503 + //集团学段及年级
  1504 + tenantSectionAndGradeList(data) {
  1505 + return service({
  1506 + url: setUpUrls.tenantSectionAndGradeList,
  1507 + method: "POST",
  1508 + data,
  1509 + });
  1510 + },
  1511 + //集团查询科目列表
  1512 + tenantSubjectList(data) {
  1513 + return service({
  1514 + url: setUpUrls.tenantSubjectList,
  1515 + method: "POST",
  1516 + data,
  1517 + });
  1518 + },
1479 1519 };
... ...
src/api/urls/apis.js
... ... @@ -382,4 +382,14 @@ export default {
382 382 updateSubject: "/api_html/school/manager/updateSubject",
383 383 //.net下载地址
384 384 runtimeEnvFileUrl: "/api_html/school/manager/runtimeEnvFileUrl",
  385 + //学校学段及年级
  386 + sectionAndGradeList: "/api_html/school/manager/sectionAndGradeList",
  387 + //学校设备使用分析
  388 + usageStatistics: "/api_html/school/manager/usageStatistics",
  389 + //集团设备使用分析
  390 + tenantUsageStatistics: "/api_html/tenant/usageStatistics",
  391 + //集团学段及年级
  392 + tenantSectionAndGradeList: "/api_html/tenant/sectionAndGradeList",
  393 + //集团查询科目列表
  394 + tenantSubjectList: "/api_html/tenant/subjectList",
385 395 }
... ...
src/components/charts/barChart.vue 0 → 100644
  1 +<template>
  2 + <div class="chart" :id="id"></div>
  3 +</template>
  4 +
  5 +<script>
  6 +export default {
  7 + name: "barChart",
  8 + props: {
  9 + id: String,
  10 + params: Array,
  11 + xAxis: Array,
  12 + },
  13 + watch: {
  14 + params: {
  15 + handler: function (val) {
  16 + this.initData();
  17 + },
  18 + deep: true,
  19 + },
  20 + },
  21 + data() {
  22 + return {
  23 + chart: null,
  24 + };
  25 + },
  26 + created() {},
  27 + mounted() {
  28 + // this.initData();
  29 + },
  30 + methods: {
  31 + setOption(xAxis,params) {
  32 + const that = this;
  33 + const options = {
  34 + color: this.colors || ["#4472c4", "#ed7d32", "#a5a5a5"],
  35 + backgroundColor: "#f8f8f8",
  36 + tooltip: {
  37 + trigger: "axis",
  38 + axisPointer: {
  39 + type: "shadow",
  40 + },
  41 + },
  42 + legend: {
  43 + show: true,
  44 + top: 20,
  45 + itemHeight: 2,
  46 + },
  47 + toolbox: {
  48 + show: true,
  49 + orient: "vertical",
  50 + right: "6",
  51 + top: "10",
  52 + feature: {
  53 + magicType: { show: true, type: ["line", "bar", "stack"] },
  54 + saveAsImage: { show: true },
  55 + },
  56 + },
  57 + xAxis: {
  58 + type: "category",
  59 + axisLine: { show: true, lineStyle: { color: "#e2e2e2" } },
  60 + axisLabel: { color: "#666" },
  61 + axisTick: { show: false },
  62 + boundaryGap: true,
  63 + data: xAxis,
  64 + },
  65 + yAxis: {
  66 + type: "value",
  67 + axisLine: { show: true, lineStyle: { color: "#e2e2e2" } },
  68 + splitLine: {
  69 + show: true,
  70 + lineStyle: { color: "#eee" },
  71 + },
  72 + axisLabel: {
  73 + color: "#666",
  74 + formatter: function (value, index) {
  75 + if (value != 0) {
  76 + return value;
  77 + } else {
  78 + return "";
  79 + }
  80 + },
  81 + },
  82 + },
  83 + grid: {
  84 + top: 60,
  85 + left: 20,
  86 + right: 40,
  87 + bottom: 30,
  88 + containLabel: true,
  89 + },
  90 + series: params.map((item) => {
  91 + return {
  92 + name: item.name,
  93 + type: "bar",
  94 + symbolSize: "8",
  95 + barWidth: 20,
  96 + itemStyle: {
  97 + borderRadius: [20, 20, 0, 0],
  98 + },
  99 + lineStyle: {
  100 + width: 3,
  101 + },
  102 + data: item.value,
  103 + };
  104 + }),
  105 + };
  106 + return options;
  107 + },
  108 + initData(xAxis,params) {
  109 + if (!xAxis.length) return;
  110 + if (!this.chart) {
  111 + const div = document.getElementById(this.id);
  112 + this.chart = this.$echarts.init(div);
  113 + }
  114 + const options = this.setOption(xAxis,params);
  115 + this.chart?.clear();
  116 + this.chart.setOption(options, true);
  117 + },
  118 + },
  119 +};
  120 +</script>
  121 +
  122 +<style lang="scss" scoped>
  123 +.chart {
  124 + height: 100%;
  125 +}
  126 +</style>
... ...
src/plugins/echarts.js
... ... @@ -3,6 +3,7 @@ import Vue from &#39;vue&#39;
3 3 import * as echarts from 'echarts/core';
4 4 // 引入柱状图图表,图表后缀都为 Chart
5 5 import {
  6 + BarChart,
6 7 LineChart,
7 8 PieChart,
8 9 ScatterChart,
... ... @@ -19,7 +20,8 @@ import {
19 20 GridComponent,
20 21 GraphicComponent,
21 22 SingleAxisComponent,
22   - LegendComponent
  23 + LegendComponent,
  24 + ToolboxComponent
23 25 } from 'echarts/components';
24 26  
25 27 // 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
... ... @@ -29,7 +31,7 @@ import {
29 31  
30 32 // 注册必须的组件
31 33 echarts.use(
32   - [LineChart,RadarChart, ScatterChart, PieChart, SingleAxisComponent, TitleComponent, TooltipComponent, GridComponent, CanvasRenderer, GraphicComponent, UniversalTransition, LabelLayout,LegendComponent]
  34 + [BarChart,LineChart,RadarChart, ScatterChart, PieChart, SingleAxisComponent, TitleComponent, TooltipComponent, GridComponent, CanvasRenderer, GraphicComponent, UniversalTransition, LabelLayout,LegendComponent,ToolboxComponent]
33 35 );
34 36  
35 37 Vue.prototype.$echarts = echarts
36 38 \ No newline at end of file
... ...
src/views/standard/analysis/index.vue
... ... @@ -6,219 +6,198 @@
6 6 </template>
7 7 </back-box>
8 8 <div class="page-content">
9   - <div class="answer-header">
10   - <div class="sel-box">
11   - <el-select
12   - class="sel"
13   - v-model="query.regionId"
14   - placeholder="选择区域"
15   - @change="_QueryData"
16   - v-if="role == 'ROLE_JITUAN'"
17   - >
18   - <el-option
19   - v-for="item in gradeList"
20   - :key="item.value"
21   - :label="item.label"
22   - :value="item.value"
23   - >
24   - </el-option>
25   - </el-select>
26   - <el-select
27   - v-else
28   - class="sel"
29   - v-model="query.gradeName"
30   - placeholder="选择年级"
31   - @change="_QueryData"
32   - >
33   - <el-option
34   - v-for="item in gradeList"
35   - :key="item.label"
36   - :label="item.label"
37   - :value="item.label"
38   - >
39   - </el-option>
40   - </el-select>
41   - <div class="d1">
42   - <el-date-picker
43   - v-model="query.startDay"
44   - type="date"
45   - @change="handleChangeTimeStart"
46   - placeholder="选择日期时间"
47   - value-format="yyyy-MM-dd"
48   - >
49   - </el-date-picker>
50   - ~
51   - <el-date-picker
52   - v-model="query.endDay"
53   - type="date"
54   - placeholder="选择日期时间"
55   - @change="handleChangeTimeEnd"
56   - value-format="yyyy-MM-dd"
57   - >
58   - </el-date-picker>
  9 + <ul class="params-box">
  10 + <li class="item">
  11 + <span class="s-txt">时间段:</span>
  12 + <div class="sel-box">
  13 + <div class="d1">
  14 + <el-date-picker
  15 + v-model="query.startDay"
  16 + type="date"
  17 + @change="handleChangeTimeStart"
  18 + placeholder="选择日期时间"
  19 + value-format="yyyy-MM-dd"
  20 + size="mini"
  21 + >
  22 + </el-date-picker>
  23 + ~
  24 + <el-date-picker
  25 + v-model="query.endDay"
  26 + type="date"
  27 + placeholder="选择日期时间"
  28 + @change="handleChangeTimeEnd"
  29 + value-format="yyyy-MM-dd"
  30 + size="mini"
  31 + >
  32 + </el-date-picker>
  33 + </div>
  34 + <p class="p1">
  35 + <span
  36 + @click="setDate(1)"
  37 + :class="[date == 1 ? 'active' : '', 's1']"
  38 + >今天</span
  39 + >
  40 + <span
  41 + @click="setDate(2)"
  42 + :class="[date == 2 ? 'active' : '', 's1']"
  43 + >本周</span
  44 + >
  45 + <span
  46 + @click="setDate(3)"
  47 + :class="[date == 3 ? 'active' : '', 's1']"
  48 + >本月</span
  49 + >
  50 + <span
  51 + @click="setDate(4)"
  52 + :class="[date == 4 ? 'active' : '', 's1']"
  53 + >本季度</span
  54 + >
  55 + </p>
59 56 </div>
60   - <p class="p1">
61   - <span @click="setDate(1)" :class="[date == 1 ? 'active' : '', 's1']"
62   - >今天</span
63   - >
64   - <span @click="setDate(2)" :class="[date == 2 ? 'active' : '', 's1']"
65   - >本周</span
66   - >
67   - <span @click="setDate(3)" :class="[date == 3 ? 'active' : '', 's1']"
68   - >本月</span
  57 + </li>
  58 + <li class="item" v-for="(item, index) in query.secGraClaSub">
  59 + <span class="s-txt">对比项{{ setBigNum(index) }}:</span>
  60 + <div class="sel-box">
  61 + <el-cascader
  62 + size="small"
  63 + class="sel sel2"
  64 + clearable
  65 + placeholder="选择范围"
  66 + v-model="query.secGraClaSub[index]"
  67 + :options="gradeList"
  68 + :props="props"
  69 + ></el-cascader>
  70 + </div>
  71 + <i class="el-icon-delete" @click="removeQuery(index)"></i>
  72 + </li>
  73 + <li class="item">
  74 + <span class="s-txt"></span>
  75 + <div class="disflex-b">
  76 + <el-button
  77 + class="btn"
  78 + icon="el-icon-plus"
  79 + size="small"
  80 + round
  81 + @click="query.secGraClaSub.push([])"
  82 + >添加对比项</el-button
69 83 >
70   - <span @click="setDate(4)" :class="[date == 4 ? 'active' : '', 's1']"
71   - >本季度</span
  84 + <el-button class="btn" round size="small" @click="getData"
  85 + >确定</el-button
72 86 >
73   - </p>
74   - <el-button type="primary" round @click="_QueryData">筛选</el-button>
75   - </div>
76   - </div>
77   - <div class="radio-box" v-if="role == 'ROLE_JITUAN'">
78   - <el-radio-group v-model="type" @change="changeType">
79   - <el-radio-button :label="1">学校使用对比</el-radio-button>
80   - <el-radio-button :label="2">学段使用对比</el-radio-button>
81   - </el-radio-group>
82   - </div>
83   - <div class="table-box" v-loading="loading">
84   - <el-empty
85   - :image-size="100"
86   - v-if="!tableData.length && !loading"
87   - description="没有更多数据"
88   - ></el-empty>
89   - <el-table
90   - v-else
91   - :data="tableData"
92   - :border="false"
93   - style="width: 100%"
94   - show-summary
95   - >
96   - <el-table-column align="center" fixed label="科目" prop="subjectName">
97   - </el-table-column>
98   - <el-table-column
99   - align="center"
100   - v-for="(item, index) in dataList"
101   - :key="index"
102   - :label="
103   - role == 'ROLE_JITUAN'
104   - ? item.schoolName || item.gradeName
105   - : item.gradeName || item.className
106   - "
107   - >
108   - <template v-if="role == 'ROLE_JITUAN'">
109   - <el-table-column
110   - :prop="'periodCount' + (type == 1 ? item.schoolId : item.grade)"
111   - label="课时数"
112   - align="center"
113   - >
114   - <template slot-scope="scoped">{{scoped.row['periodCount' + (type == 1 ? item.schoolId : item.grade)]||"--"}}</template>
115   - </el-table-column>
116   - <el-table-column
117   - :prop="'examCount' + (type == 1 ? item.schoolId : item.grade)"
118   - label="测练数"
119   - align="center"
120   - ><template slot-scope="scoped">{{scoped.row['examCount' + (type == 1 ? item.schoolId : item.grade)]||"--"}}</template></el-table-column>
121   - </template>
122   - <template v-else>
123   - <el-table-column
124   - :prop="'periodCount' + (item.grade || item.classId)"
125   - label="课时数"
126   - align="center"
127   - ><template slot-scope="scoped">{{scoped.row['periodCount' + (item.grade || item.classId)]||"--"}}</template></el-table-column>
128   - <el-table-column
129   - :prop="'examCount' + (item.grade || item.classId)"
130   - label="测练数"
131   - align="center"
132   - ><template slot-scope="scoped">{{scoped.row['examCount' + (item.grade || item.classId)]||"--"}}</template></el-table-column>
133   - </template>
134   - </el-table-column>
135   - </el-table>
136   - <p class="down" v-if="tableData.length">
137   - <el-button
138   - @click="downExc"
139   - type="primary"
140   - plain
141   - round
142   - icon="fa fa-cloud-download"
143   - >导出报表</el-button
144   - >
145   - </p>
  87 + </div>
  88 + </li>
  89 + </ul>
  90 + <div class="chart-box">
  91 + <barChart id="barChart" ref="barChart" />
146 92 </div>
147 93 </div>
148 94 </div>
149 95 </template>
150 96  
151 97 <script>
  98 +import barChart from "@/components/charts/barChart";
152 99 import { formatDate, downloadFile } from "@/utils";
153 100 export default {
  101 + components: {
  102 + barChart,
  103 + },
154 104 data() {
155 105 return {
156   - loading: false,
157   - exportLoading: false,
158 106 role: "",
  107 + loading: false,
159 108 date: "", //今天-本周-本月-本季度
160 109 type: 1, //集团管理员 表格切换
161 110 query: {
162 111 //搜索条件
163   - regionId: "",
164   - gradeName: "全部",
165 112 startDay: "",
166 113 endDay: "",
167 114 day: "",
  115 + secGraClaSub: [],
168 116 },
  117 + props: {
  118 + multiple: false,
  119 + checkStrictly: true,
  120 + },
  121 + params: [
  122 + {
  123 + index: 1,
  124 + sections: "小学",
  125 + grades: "二年级",
  126 + classIds: "2班",
  127 + subjectNames: "语文",
  128 + },
  129 + {
  130 + index: 2,
  131 + sections: "小学",
  132 + grades: "二年级",
  133 + },
  134 + ],
169 135 gradeList: [],
170   - tableData: [],
171   - dataList: [],
  136 + chartData: [
  137 + {
  138 + name: "课时数",
  139 + value: [],
  140 + },
  141 + {
  142 + name: "测练数",
  143 + value: [],
  144 + },
  145 + ],
  146 + xAxis: [],
172 147 };
173 148 },
174   - created() {
175   - this.role = this.$store.getters.info.showRole || this.$store.getters.info.permissions[0].role;
176   - this._QueryGradeList();
177   - this.setDate(1);
  149 + async created() {
  150 + let that = this;
  151 + this.role =
  152 + this.$store.getters.info.showRole ||
  153 + this.$store.getters.info.permissions[0].role;
  154 + if (this.role == "ROLE_JITUAN") {
  155 + (this.props.lazy = true),
  156 + (this.props.lazyLoad = function (node, resolve) {
  157 + const { level } = node;
  158 + if (level == 3) {
  159 + console.log(node);
  160 + that.$request
  161 + .tenantSubjectList({
  162 + schoolId: node.path[0],
  163 + grade: node.value,
  164 + })
  165 + .then((res) => {
  166 + let children = res.data?.subjectNames.map((item) => {
  167 + return {
  168 + label: item,
  169 + value: item,
  170 + leaf: true,
  171 + };
  172 + });
  173 + const nodes = [...children];
  174 + // 通过调用resolve将子节点数据返回,通知组件数据加载完成
  175 + resolve(nodes);
  176 + });
  177 + } else {
  178 + resolve(node);
  179 + }
  180 + });
  181 + await this._QuerySchool();
  182 + }
  183 + await this._QueryGradeList();
  184 + if (this.role == "ROLE_XUEXIAO") {
  185 + await this._QueryClassList();
  186 + }
  187 +
178 188 let startDay = this.query?.startDay;
179 189 if (!startDay) {
180   - this.query.startDay = new Date();
181   - this.query.endDay = new Date();
  190 + this.query.startDay = formatDate(new Date(), "yyyy-MM-dd");
  191 + this.query.endDay = formatDate(new Date(), "yyyy-MM-dd");
182 192 }
183 193 },
184 194 methods: {
185   - async downExc() {
186   - if (this.exportLoading == true) return;
187   - let query = {};
188   - for (let key in this.query) {
189   - if (this.query[key] != "") {
190   - if (key == "gradeName") {
191   - query[key] = this.query[key] == "全部" ? "" : this.query[key];
192   - } else {
193   - query[key] = this.query[key];
194   - }
195   - }
196   - }
197   - if (this.role == "ROLE_JITUAN") {
198   - delete query.gradeName;
199   - } else {
200   - delete query.regionId;
201   - }
202   - this.exportLoading = true;
  195 + setBigNum(num) {
  196 + let txt = "";
  197 + let bigNum = ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十"];
  198 + txt = bigNum[num];
203 199  
204   - const exportUsageAnalysis = this.role != "ROLE_JITUAN"?this.$request.exportUsageAnalysis:
205   - this.$request.exportSchoolContrast
206   - const data = await exportUsageAnalysis({ ...query });
207   - this.exportLoading = false;
208   - if (data) {
209   - let blob = new Blob([data], {
210   - type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
211   - });
212   - downloadFile("使用分析.xlsx", blob);
213   - } else {
214   - this.$message.error("下载失败");
215   - }
216   - },
217   - changeType(val) {
218   - if (val == 1) {
219   - this.query.regionId = "";
220   - }
221   - this._QueryData(val);
  200 + return txt;
222 201 },
223 202 setDate(index) {
224 203 const that = this;
... ... @@ -266,8 +245,13 @@ export default {
266 245 that.query.endDay = formatDate(new Date(), "yyyy-MM-dd");
267 246 break;
268 247 }
269   - this.page = 1;
270   - this._QueryData();
  248 + },
  249 + removeQuery(index) {
  250 + this.query.secGraClaSub.splice(index, 1);
  251 + this.chartData[0].value.splice(index, 1);
  252 + this.chartData[1].value.splice(index, 1);
  253 + this.xAxis.pop();
  254 + this.$refs.barChart.initData(this.xAxis, this.chartData);
271 255 },
272 256 handleChangeTimeStart(val) {
273 257 this.query.day = "";
... ... @@ -289,108 +273,70 @@ export default {
289 273 }
290 274 }
291 275 },
292   - async _QueryData() {
293   - this.loading = true;
294   - //多课时对比
295   - let query = {};
296   - for (let key in this.query) {
297   - if (this.query[key] != "") {
298   - if (key == "gradeName") {
299   - query[key] = this.query[key] == "全部" ? "" : this.query[key];
300   - } else {
301   - query[key] = this.query[key];
302   - }
  276 + getData() {
  277 + if (!this.query.secGraClaSub.length) {
  278 + this.$message.warning("请添加对比项,并选择对比条件!");
  279 + return;
  280 + }
  281 + let hasSpace = null;
  282 + this.query.secGraClaSub.map((item, index) => {
  283 + if (!item.length) {
  284 + hasSpace = index;
303 285 }
  286 + });
  287 + if (hasSpace !== null) {
  288 + this.$message.warning(
  289 + `对比项${this.setBigNum(hasSpace)}对比条件不能为空请检查!`
  290 + );
  291 + return;
304 292 }
305   - if (this.role == "ROLE_JITUAN") {
306   - delete query.gradeName;
  293 + this._QueryData();
  294 + },
  295 + setQuery() {
  296 + let query = { ...this.query };
  297 + delete query.secGraClaSub;
  298 + if (this.role != "ROLE_JITUAN") {
  299 + query.params = this.query.secGraClaSub.map((item) => {
  300 + let jsons = {};
  301 + jsons.section = item[0];
  302 + item.length > 1 ? (jsons.grade = item[1]) : "";
  303 + item.length > 2 ? (jsons.classId = item[2]) : "";
  304 + item.length == 4 ? (jsons.subjectName = item[3]) : "";
  305 + return jsons;
  306 + });
307 307 } else {
308   - delete query.regionId;
  308 + query.params = this.query.secGraClaSub.map((item) => {
  309 + let jsons = {};
  310 + jsons.schoolId = item[0];
  311 + item.length > 1 ? (jsons.section = item[1]) : "";
  312 + item.length > 2 ? (jsons.grade = item[2]) : "";
  313 + item.length == 4 ? (jsons.subjectName = item[3]) : "";
  314 + return jsons;
  315 + });
309 316 }
310   - this.tableData = [];
311   - const Contrast =
  317 + return query;
  318 + },
  319 + async _QueryData() {
  320 + this.loading = true;
  321 + let query = this.setQuery();
  322 + const usageStatistics =
312 323 this.role != "ROLE_JITUAN"
313   - ? this.$request.usageAnalysis
314   - : this.type == 1
315   - ? this.$request.schoolContrast
316   - : this.$request.gradeContrast;
317   - const { data, status, info } = await Contrast({
  324 + ? this.$request.usageStatistics
  325 + : this.$request.tenantUsageStatistics;
  326 + const { data, status, info } = await usageStatistics({
318 327 ...query,
319 328 });
320 329 this.loading = false;
321 330 if (status === 0) {
322   - let dataIdsList = [],
323   - dataList = [];
324   -
325   - data.map((item) => {
326   - item.dataList.map((items) => {
327   - if (this.role == "ROLE_JITUAN") {
328   - if (this.type == 1) {
329   - if (!dataIdsList.includes(items.schoolId)) {
330   - dataIdsList.push(items.schoolId);
331   - dataList.push(items);
332   - }
333   - } else if (this.type == 2) {
334   - if (!dataIdsList.includes(items.grade)) {
335   - dataIdsList.push(items.grade);
336   - dataList.push(items);
337   - }
338   - }
339   - } else {
340   - if (this.query.gradeName == "全部") {
341   - if (!dataIdsList.includes(items.grade)) {
342   - dataIdsList.push(items.grade);
343   - dataList.push(items);
344   - }
345   - } else {
346   - if (!dataIdsList.includes(items.classId)) {
347   - dataIdsList.push(items.classId);
348   - dataList.push(items);
349   - }
350   - }
351   - }
352   - });
353   - });
354   - console.log(dataList);
355   - this.tableData = data.map((item) => {
356   - let params = {};
357   - dataIdsList.map((ids, index) => {
358   - item.dataList.map((items) => {
359   - if (this.role == "ROLE_JITUAN") {
360   - if (this.type == 1) {
361   - if (items.schoolId == ids) {
362   - params["examCount" + items.schoolId] = items.examCount;
363   - params["periodCount" + items.schoolId] = items.periodCount;
364   - }
365   - } else if (this.type == 2) {
366   - if (items.grade == ids) {
367   - params["examCount" + items.grade] = items.examCount;
368   - params["periodCount" + items.grade] = items.periodCount;
369   - }
370   - }
371   - } else {
372   - if (this.query.gradeName == "全部") {
373   - if (items.grade == ids) {
374   - params["examCount" + items.grade] = items.examCount;
375   - params["periodCount" + items.grade] = items.periodCount;
376   - }
377   - } else if (this.query.gradeName) {
378   - if (items.classId == ids) {
379   - params["examCount" + items.classId] = items.examCount;
380   - params["periodCount" + items.classId] = items.periodCount;
381   - }
382   - }
383   - }
384   - });
385   - });
386   - return {
387   - subjectName: item.subjectName,
388   - ...params,
389   - };
390   - });
391   - this.dataList = dataList.sort((a, b) => {
392   - return a.grade - b.grade;
  331 + this.chartData[0].value = [];
  332 + this.chartData[1].value = [];
  333 + this.xAxis = [];
  334 + data?.list.map((item, index) => {
  335 + this.xAxis.push("对比项" + this.setBigNum(index));
  336 + this.chartData[0].value.push(item.periodCount);
  337 + this.chartData[1].value.push(item.examCount);
393 338 });
  339 + this.$refs.barChart.initData(this.xAxis, this.chartData);
394 340 } else {
395 341 this.$message.error(info);
396 342 }
... ... @@ -400,43 +346,101 @@ export default {
400 346 this.loading = true;
401 347 const gradeList =
402 348 this.role != "ROLE_JITUAN"
403   - ? this.$request.gradeList
404   - : this.$request.regionList;
  349 + ? this.$request.sectionAndGradeList
  350 + : this.$request.tenantSectionAndGradeList;
405 351 const { data, status, info } = await gradeList();
406 352 if (status === 0) {
407 353 if (!!data.list) {
408 354 if (this.role != "ROLE_JITUAN") {
409 355 this.gradeList =
410 356 data.list?.map((item) => {
411   - let gradeList = {
412   - value: item.grade,
413   - label: item.gradeName,
  357 + let gradeIds = [];
  358 + let children = item.gradeList.map((items) => {
  359 + gradeIds.push(items.grade);
  360 + return {
  361 + value: items.grade,
  362 + label: items.gradeName,
  363 + };
  364 + });
  365 + return {
  366 + value: item.section,
  367 + label: item.sectionName,
  368 + gradeIds: [...gradeIds],
  369 + children: [...children],
414 370 };
415   - return gradeList;
416 371 }) || [];
417   - this.gradeList.unshift({
418   - value: "",
419   - label: "全部",
420   - });
421 372 } else {
422   - this.gradeList =
423   - data.list?.map((item) => {
424   - let gradeList = {
425   - value: item.id,
426   - label: item.regionName,
  373 + let children = data.list?.map((item) => {
  374 + let children = item.gradeList.map((items) => {
  375 + return {
  376 + value: items.grade,
  377 + label: items.gradeName,
427 378 };
428   - return gradeList;
429   - }) || [];
430   - this.gradeList.unshift({
431   - value: "",
432   - label: "全部",
  379 + });
  380 + return {
  381 + value: item.section,
  382 + label: item.sectionName,
  383 + children: [...children],
  384 + };
433 385 });
  386 + this.gradeList = this.schoolList.map((item) => {
  387 + return {
  388 + value: item.id,
  389 + label: item.schoolName,
  390 + children: [...children],
  391 + };
  392 + });
  393 + }
  394 + }
  395 + } else {
  396 + this.$message.error(info);
  397 + }
  398 + },
  399 + // 查找班级
  400 + async _QueryClassList() {
  401 + const { data, status, info } = await this.$request.gradeList();
  402 + if (status === 0) {
  403 + if (!!data.list) {
  404 + if (this.role == "ROLE_XUEXIAO") {
  405 + data.list?.map((item) => {
  406 + let subList = item.subjectNames?.map((items) => {
  407 + return {
  408 + value: items,
  409 + label: items,
  410 + };
  411 + });
  412 + let children = item.classList.map((clazz) => {
  413 + return {
  414 + value: clazz.id,
  415 + label: clazz.className,
  416 + id: clazz.id,
  417 + children: [...subList],
  418 + };
  419 + });
  420 + this.gradeList.map((sec) => {
  421 + if (sec.gradeIds.includes(item.grade)) {
  422 + sec.children[sec.gradeIds.indexOf(item.grade)].children = [
  423 + ...children,
  424 + ];
  425 + }
  426 + });
  427 + }) || [];
434 428 }
435 429 }
436 430 } else {
437 431 this.$message.error(info);
438 432 }
439 433 },
  434 + async _QuerySchool() {
  435 + this.loading = true;
  436 + const { data, status, info } = await this.$request.schoolList();
  437 + this.loading = false;
  438 + if (status === 0) {
  439 + this.schoolList = [...data.list] || [];
  440 + } else {
  441 + this.$message.error(info);
  442 + }
  443 + },
440 444 },
441 445 };
442 446 </script>
... ... @@ -451,13 +455,89 @@ div::-webkit-scrollbar-thumb {
451 455 }
452 456 </style>
453 457 <style lang="scss" scoped>
454   -.table-box {
455   - padding: 0 20px;
  458 +.page-content {
  459 + padding: 20px 40px;
  460 +}
  461 +.disflex-b {
  462 + display: flex;
  463 + justify-content: space-between;
  464 + align-items: center;
  465 +}
  466 +.sel-box {
  467 + display: flex;
  468 + align-items: center;
  469 + flex-wrap: nowrap;
  470 + .sel {
  471 + width: 8%;
  472 + min-width: 160px;
  473 + margin-right: 20px;
  474 + }
  475 + :deep(.el-input__inner) {
  476 + border: 1px solid #e2e2e2;
  477 + border-radius: 20px;
  478 + height: 32px;
  479 + line-height: 30px;
  480 + }
  481 +
  482 + .el-input__icon {
  483 + line-height: 34px;
  484 + }
  485 + .el-date-editor.el-input,
  486 + .el-date-editor.el-input__inner {
  487 + width: 160px;
  488 + }
  489 +
  490 + .p1 {
  491 + flex: 1;
  492 +
  493 + .s1 {
  494 + margin-left: 36px;
  495 + cursor: pointer;
  496 + color: #7f7f7f;
  497 +
  498 + &:hover {
  499 + color: #409eff;
  500 + }
  501 +
  502 + &.active {
  503 + color: #667ffd;
  504 + }
  505 + }
  506 + }
  507 + .sel2 {
  508 + width: 240px;
  509 + }
456 510 }
457   -.radio-box {
458   - padding: 0 20px 12px;
  511 +.params-box {
  512 + .item {
  513 + display: flex;
  514 + align-items: center;
  515 + margin-bottom: 20px;
  516 + .s-txt {
  517 + width: 120px;
  518 + }
  519 + .btn {
  520 + font-size: 14px;
  521 + }
  522 + .disflex-b {
  523 + flex: 1;
  524 + padding-right: 100px;
  525 + }
  526 + &:hover {
  527 + .el-icon-delete {
  528 + display: block;
  529 + }
  530 + }
  531 + .el-icon-delete {
  532 + cursor: pointer;
  533 + display: none;
  534 + &:hover {
  535 + color: #667ffd;
  536 + }
  537 + }
  538 + }
459 539 }
460   -.down {
461   - padding-top: 20px;
  540 +.chart-box {
  541 + height: 600px;
462 542 }
463 543 </style>
464 544 \ No newline at end of file
... ...
src/views/standard/analysis/indexOld.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <back-box>
  4 + <template slot="title">
  5 + <span>使用分析</span>
  6 + </template>
  7 + </back-box>
  8 + <div class="page-content">
  9 + <div class="answer-header">
  10 + <div class="sel-box">
  11 + <el-select
  12 + class="sel"
  13 + v-model="query.regionId"
  14 + placeholder="选择区域"
  15 + @change="_QueryData"
  16 + v-if="role == 'ROLE_JITUAN'"
  17 + >
  18 + <el-option
  19 + v-for="item in gradeList"
  20 + :key="item.value"
  21 + :label="item.label"
  22 + :value="item.value"
  23 + >
  24 + </el-option>
  25 + </el-select>
  26 + <el-select
  27 + v-else
  28 + class="sel"
  29 + v-model="query.gradeName"
  30 + placeholder="选择年级"
  31 + @change="_QueryData"
  32 + >
  33 + <el-option
  34 + v-for="item in gradeList"
  35 + :key="item.label"
  36 + :label="item.label"
  37 + :value="item.label"
  38 + >
  39 + </el-option>
  40 + </el-select>
  41 + <div class="d1">
  42 + <el-date-picker
  43 + v-model="query.startDay"
  44 + type="date"
  45 + @change="handleChangeTimeStart"
  46 + placeholder="选择日期时间"
  47 + value-format="yyyy-MM-dd"
  48 + >
  49 + </el-date-picker>
  50 + ~
  51 + <el-date-picker
  52 + v-model="query.endDay"
  53 + type="date"
  54 + placeholder="选择日期时间"
  55 + @change="handleChangeTimeEnd"
  56 + value-format="yyyy-MM-dd"
  57 + >
  58 + </el-date-picker>
  59 + </div>
  60 + <p class="p1">
  61 + <span @click="setDate(1)" :class="[date == 1 ? 'active' : '', 's1']"
  62 + >今天</span
  63 + >
  64 + <span @click="setDate(2)" :class="[date == 2 ? 'active' : '', 's1']"
  65 + >本周</span
  66 + >
  67 + <span @click="setDate(3)" :class="[date == 3 ? 'active' : '', 's1']"
  68 + >本月</span
  69 + >
  70 + <span @click="setDate(4)" :class="[date == 4 ? 'active' : '', 's1']"
  71 + >本季度</span
  72 + >
  73 + </p>
  74 + <el-button type="primary" round @click="_QueryData">筛选</el-button>
  75 + </div>
  76 + </div>
  77 + <div class="radio-box" v-if="role == 'ROLE_JITUAN'">
  78 + <el-radio-group v-model="type" @change="changeType">
  79 + <el-radio-button :label="1">学校使用对比</el-radio-button>
  80 + <el-radio-button :label="2">学段使用对比</el-radio-button>
  81 + </el-radio-group>
  82 + </div>
  83 + <div class="table-box" v-loading="loading">
  84 + <el-empty
  85 + :image-size="100"
  86 + v-if="!tableData.length && !loading"
  87 + description="没有更多数据"
  88 + ></el-empty>
  89 + <el-table
  90 + v-else
  91 + :data="tableData"
  92 + :border="false"
  93 + style="width: 100%"
  94 + show-summary
  95 + >
  96 + <el-table-column align="center" fixed label="科目" prop="subjectName">
  97 + </el-table-column>
  98 + <el-table-column
  99 + align="center"
  100 + v-for="(item, index) in dataList"
  101 + :key="index"
  102 + :label="
  103 + role == 'ROLE_JITUAN'
  104 + ? item.schoolName || item.gradeName
  105 + : item.gradeName || item.className
  106 + "
  107 + >
  108 + <template v-if="role == 'ROLE_JITUAN'">
  109 + <el-table-column
  110 + :prop="'periodCount' + (type == 1 ? item.schoolId : item.grade)"
  111 + label="课时数"
  112 + align="center"
  113 + >
  114 + <template slot-scope="scoped">{{scoped.row['periodCount' + (type == 1 ? item.schoolId : item.grade)]||"--"}}</template>
  115 + </el-table-column>
  116 + <el-table-column
  117 + :prop="'examCount' + (type == 1 ? item.schoolId : item.grade)"
  118 + label="测练数"
  119 + align="center"
  120 + ><template slot-scope="scoped">{{scoped.row['examCount' + (type == 1 ? item.schoolId : item.grade)]||"--"}}</template></el-table-column>
  121 + </template>
  122 + <template v-else>
  123 + <el-table-column
  124 + :prop="'periodCount' + (item.grade || item.classId)"
  125 + label="课时数"
  126 + align="center"
  127 + ><template slot-scope="scoped">{{scoped.row['periodCount' + (item.grade || item.classId)]||"--"}}</template></el-table-column>
  128 + <el-table-column
  129 + :prop="'examCount' + (item.grade || item.classId)"
  130 + label="测练数"
  131 + align="center"
  132 + ><template slot-scope="scoped">{{scoped.row['examCount' + (item.grade || item.classId)]||"--"}}</template></el-table-column>
  133 + </template>
  134 + </el-table-column>
  135 + </el-table>
  136 + <p class="down" v-if="tableData.length">
  137 + <el-button
  138 + @click="downExc"
  139 + type="primary"
  140 + plain
  141 + round
  142 + icon="fa fa-cloud-download"
  143 + >导出报表</el-button
  144 + >
  145 + </p>
  146 + </div>
  147 + </div>
  148 + </div>
  149 +</template>
  150 +
  151 +<script>
  152 +import { formatDate, downloadFile } from "@/utils";
  153 +export default {
  154 + data() {
  155 + return {
  156 + loading: false,
  157 + exportLoading: false,
  158 + role: "",
  159 + date: "", //今天-本周-本月-本季度
  160 + type: 1, //集团管理员 表格切换
  161 + query: {
  162 + //搜索条件
  163 + regionId: "",
  164 + gradeName: "全部",
  165 + startDay: "",
  166 + endDay: "",
  167 + day: "",
  168 + },
  169 + gradeList: [],
  170 + tableData: [],
  171 + dataList: [],
  172 + };
  173 + },
  174 + created() {
  175 + this.role = this.$store.getters.info.showRole || this.$store.getters.info.permissions[0].role;
  176 + this._QueryGradeList();
  177 + this.setDate(1);
  178 + let startDay = this.query?.startDay;
  179 + if (!startDay) {
  180 + this.query.startDay = new Date();
  181 + this.query.endDay = new Date();
  182 + }
  183 + },
  184 + methods: {
  185 + async downExc() {
  186 + if (this.exportLoading == true) return;
  187 + let query = {};
  188 + for (let key in this.query) {
  189 + if (this.query[key] != "") {
  190 + if (key == "gradeName") {
  191 + query[key] = this.query[key] == "全部" ? "" : this.query[key];
  192 + } else {
  193 + query[key] = this.query[key];
  194 + }
  195 + }
  196 + }
  197 + if (this.role == "ROLE_JITUAN") {
  198 + delete query.gradeName;
  199 + } else {
  200 + delete query.regionId;
  201 + }
  202 + this.exportLoading = true;
  203 +
  204 + const exportUsageAnalysis = this.role != "ROLE_JITUAN"?this.$request.exportUsageAnalysis:
  205 + this.$request.exportSchoolContrast
  206 + const data = await exportUsageAnalysis({ ...query });
  207 + this.exportLoading = false;
  208 + if (data) {
  209 + let blob = new Blob([data], {
  210 + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
  211 + });
  212 + downloadFile("使用分析.xlsx", blob);
  213 + } else {
  214 + this.$message.error("下载失败");
  215 + }
  216 + },
  217 + changeType(val) {
  218 + if (val == 1) {
  219 + this.query.regionId = "";
  220 + }
  221 + this._QueryData(val);
  222 + },
  223 + setDate(index) {
  224 + const that = this;
  225 + this.date = index == this.date ? "" : index;
  226 + let aYear = new Date().getFullYear();
  227 + let aMonth = new Date().getMonth() + 1;
  228 + that.query.day = "";
  229 + that.query.startDay = "";
  230 + that.query.endDay = "";
  231 + switch (index) {
  232 + case 1:
  233 + that.query.day = formatDate(new Date(), "yyyy-MM-dd");
  234 + that.query.startDay = that.query.day;
  235 + that.query.endDay = that.query.day;
  236 + break;
  237 + case 2:
  238 + let day = new Date().getDay();
  239 + if (day == 0) {
  240 + //中国式星期天是一周的最后一天
  241 + day = 7;
  242 + }
  243 + day--;
  244 + let aTime = new Date().getTime() - 24 * 60 * 60 * 1000 * day;
  245 + that.query.startDay = formatDate(new Date(aTime), "yyyy-MM-dd");
  246 + that.query.endDay = formatDate(new Date(), "yyyy-MM-dd");
  247 + break;
  248 + case 3:
  249 + aMonth = aMonth < 10 ? "0" + aMonth : aMonth;
  250 + that.query.startDay = `${aYear}-${aMonth}-01`;
  251 + that.query.endDay = formatDate(new Date(), "yyyy-MM-dd");
  252 + break;
  253 + case 4:
  254 + if (aMonth > 0 && aMonth < 4) {
  255 + aMonth = "1";
  256 + } else if (aMonth > 3 && aMonth < 7) {
  257 + aMonth = "4";
  258 + } else if (aMonth > 6 && aMonth < 10) {
  259 + aMonth = "7";
  260 + } else {
  261 + aMonth = "10";
  262 + }
  263 +
  264 + aMonth = aMonth < 10 ? "0" + aMonth : aMonth;
  265 + that.query.startDay = `${aYear}-${aMonth}-01`;
  266 + that.query.endDay = formatDate(new Date(), "yyyy-MM-dd");
  267 + break;
  268 + }
  269 + this.page = 1;
  270 + this._QueryData();
  271 + },
  272 + handleChangeTimeStart(val) {
  273 + this.query.day = "";
  274 + this.date = "";
  275 + if (this.query.endDay) {
  276 + if (new Date(val).getTime() > new Date(this.query.endDay).getTime()) {
  277 + this.$message.error("任务结束时间不能任务开始时间前面,请重新设置");
  278 + this.query.startDay = "";
  279 + }
  280 + }
  281 + },
  282 + handleChangeTimeEnd(val) {
  283 + this.query.day = "";
  284 + this.date = "";
  285 + if (this.query.startDay) {
  286 + if (new Date(val).getTime() < new Date(this.query.startDay).getTime()) {
  287 + this.$message.error("任务结束时间不能任务开始时间前面,请重新设置");
  288 + this.query.endDay = "";
  289 + }
  290 + }
  291 + },
  292 + async _QueryData() {
  293 + this.loading = true;
  294 + //多课时对比
  295 + let query = {};
  296 + for (let key in this.query) {
  297 + if (this.query[key] != "") {
  298 + if (key == "gradeName") {
  299 + query[key] = this.query[key] == "全部" ? "" : this.query[key];
  300 + } else {
  301 + query[key] = this.query[key];
  302 + }
  303 + }
  304 + }
  305 + if (this.role == "ROLE_JITUAN") {
  306 + delete query.gradeName;
  307 + } else {
  308 + delete query.regionId;
  309 + }
  310 + this.tableData = [];
  311 + const Contrast =
  312 + this.role != "ROLE_JITUAN"
  313 + ? this.$request.usageAnalysis
  314 + : this.type == 1
  315 + ? this.$request.schoolContrast
  316 + : this.$request.gradeContrast;
  317 + const { data, status, info } = await Contrast({
  318 + ...query,
  319 + });
  320 + this.loading = false;
  321 + if (status === 0) {
  322 + let dataIdsList = [],
  323 + dataList = [];
  324 +
  325 + data.map((item) => {
  326 + item.dataList.map((items) => {
  327 + if (this.role == "ROLE_JITUAN") {
  328 + if (this.type == 1) {
  329 + if (!dataIdsList.includes(items.schoolId)) {
  330 + dataIdsList.push(items.schoolId);
  331 + dataList.push(items);
  332 + }
  333 + } else if (this.type == 2) {
  334 + if (!dataIdsList.includes(items.grade)) {
  335 + dataIdsList.push(items.grade);
  336 + dataList.push(items);
  337 + }
  338 + }
  339 + } else {
  340 + if (this.query.gradeName == "全部") {
  341 + if (!dataIdsList.includes(items.grade)) {
  342 + dataIdsList.push(items.grade);
  343 + dataList.push(items);
  344 + }
  345 + } else {
  346 + if (!dataIdsList.includes(items.classId)) {
  347 + dataIdsList.push(items.classId);
  348 + dataList.push(items);
  349 + }
  350 + }
  351 + }
  352 + });
  353 + });
  354 + console.log(dataList);
  355 + this.tableData = data.map((item) => {
  356 + let params = {};
  357 + dataIdsList.map((ids, index) => {
  358 + item.dataList.map((items) => {
  359 + if (this.role == "ROLE_JITUAN") {
  360 + if (this.type == 1) {
  361 + if (items.schoolId == ids) {
  362 + params["examCount" + items.schoolId] = items.examCount;
  363 + params["periodCount" + items.schoolId] = items.periodCount;
  364 + }
  365 + } else if (this.type == 2) {
  366 + if (items.grade == ids) {
  367 + params["examCount" + items.grade] = items.examCount;
  368 + params["periodCount" + items.grade] = items.periodCount;
  369 + }
  370 + }
  371 + } else {
  372 + if (this.query.gradeName == "全部") {
  373 + if (items.grade == ids) {
  374 + params["examCount" + items.grade] = items.examCount;
  375 + params["periodCount" + items.grade] = items.periodCount;
  376 + }
  377 + } else if (this.query.gradeName) {
  378 + if (items.classId == ids) {
  379 + params["examCount" + items.classId] = items.examCount;
  380 + params["periodCount" + items.classId] = items.periodCount;
  381 + }
  382 + }
  383 + }
  384 + });
  385 + });
  386 + return {
  387 + subjectName: item.subjectName,
  388 + ...params,
  389 + };
  390 + });
  391 + this.dataList = dataList.sort((a, b) => {
  392 + return a.grade - b.grade;
  393 + });
  394 + } else {
  395 + this.$message.error(info);
  396 + }
  397 + },
  398 + // 查找班级
  399 + async _QueryGradeList() {
  400 + this.loading = true;
  401 + const gradeList =
  402 + this.role != "ROLE_JITUAN"
  403 + ? this.$request.gradeList
  404 + : this.$request.regionList;
  405 + const { data, status, info } = await gradeList();
  406 + if (status === 0) {
  407 + if (!!data.list) {
  408 + if (this.role != "ROLE_JITUAN") {
  409 + this.gradeList =
  410 + data.list?.map((item) => {
  411 + let gradeList = {
  412 + value: item.grade,
  413 + label: item.gradeName,
  414 + };
  415 + return gradeList;
  416 + }) || [];
  417 + this.gradeList.unshift({
  418 + value: "",
  419 + label: "全部",
  420 + });
  421 + } else {
  422 + this.gradeList =
  423 + data.list?.map((item) => {
  424 + let gradeList = {
  425 + value: item.id,
  426 + label: item.regionName,
  427 + };
  428 + return gradeList;
  429 + }) || [];
  430 + this.gradeList.unshift({
  431 + value: "",
  432 + label: "全部",
  433 + });
  434 + }
  435 + }
  436 + } else {
  437 + this.$message.error(info);
  438 + }
  439 + },
  440 + },
  441 +};
  442 +</script>
  443 +<style>
  444 +div::-webkit-scrollbar {
  445 + width: 3px;
  446 + height: 10px;
  447 +}
  448 +div::-webkit-scrollbar-thumb {
  449 + border-radius: 10px;
  450 + background-color: #ccc;
  451 +}
  452 +</style>
  453 +<style lang="scss" scoped>
  454 +.table-box {
  455 + padding: 0 20px;
  456 +}
  457 +.radio-box {
  458 + padding: 0 20px 12px;
  459 +}
  460 +.down {
  461 + padding-top: 20px;
  462 +}
  463 +</style>
0 464 \ No newline at end of file
... ...
src/views/standard/card/index.vue
... ... @@ -146,6 +146,8 @@
146 146 }}
147 147 </template></el-table-column
148 148 >
  149 + <el-table-column align="center" label="操作次数" prop="operations"></el-table-column
  150 + >
149 151 <el-table-column align="center" label="描述">
150 152 <template slot-scope="scope">
151 153 {{
... ...