Browse Source

feat: :sparkles: 学校级数据看板-图表数据

chaooo 1 year ago
parent
commit
4e17012b38

+ 1 - 0
src/api/areaboard/types.ts

@@ -9,6 +9,7 @@ export interface AreaChartParams {
   grade_id: number;
   start_time: number;
   end_time: number;
+  device_id: number;
 }
 export interface AreaParams {
   province_id: number;

+ 2 - 0
src/api/dashboard/types.ts

@@ -16,6 +16,8 @@ interface Proportion {
   percentage: number[];
 }
 export interface DashboardData {
+  // 记录数
+  countRecord: number;
   // 初期专注力估值
   frontAverage: number;
   // 近期专注力估值

+ 34 - 4
src/components/Charts/LineChart.vue

@@ -33,6 +33,18 @@ const props = defineProps({
     type: Array,
     default: [] as Array<number>,
   },
+  dataSW: {
+    type: Array,
+    default: [] as Array<number>,
+  },
+  dataKL: {
+    type: Array,
+    default: [] as Array<number>,
+  },
+  dataZZL: {
+    type: Array,
+    default: [] as Array<number>,
+  },
 });
 const tipFormatter = (params: any) => {
   const num = <number[]>props.dataSets?.[1];
@@ -42,6 +54,19 @@ const tipFormatter = (params: any) => {
   label.push("均值:" + params.value);
   return label.join("<br>");
 };
+const getXAxisData = () => {
+  let l1 = props.dataSets?.[0].length | 0;
+  let l2 = props.dataSW?.[0].length | 0;
+  let l3 = props.dataKL?.[0].length | 0;
+  let l4 = props.dataZZL?.[0].length | 0;
+  let len = Math.max(l1, l2, l3, l4);
+  len = len > 15 ? len : 15;
+  let result = [];
+  for (let i = 0; i < len; i++) {
+    result.push(i);
+  }
+  return result;
+};
 /**
  * 配置项
  */
@@ -61,7 +86,7 @@ const options = {
   },
   xAxis: {
     type: "category",
-    data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
+    data: getXAxisData(),
     boundaryGap: true,
     axisLabel: {
       color: "#09132e",
@@ -103,6 +128,7 @@ const options = {
     top: 0,
     right: "5%",
     data: ["", "水舞", "恐龙", "专注力训练"],
+    selected: {"": true, 水舞: false, 恐龙: false, 专注力训练: false},
   },
   series: [
     {
@@ -134,7 +160,7 @@ const options = {
     },
     {
       name: "水舞",
-      data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 30],
+      data: props.dataSW?.[0] || [], // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 30],
       type: "line",
       color: "#6f95d4",
       symbolSize: 0,
@@ -146,7 +172,7 @@ const options = {
     },
     {
       name: "恐龙",
-      data: [1, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20],
+      data: props.dataKL?.[0] || [], // [1, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20],
       type: "line",
       color: "#7bdb64",
       symbolSize: 0,
@@ -158,7 +184,7 @@ const options = {
     },
     {
       name: "专注力训练",
-      data: [1, 17, 18, 19, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 9, 10, 50],
+      data: props.dataZZL?.[0] || [], // [1, 17, 18, 19, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 9, 10, 50],
       type: "line",
       color: "#db8364",
       symbolSize: 0,
@@ -191,5 +217,9 @@ onMounted(() => {
   window.addEventListener("resize", () => {
     chart.resize();
   });
+  console.log("全部", props.dataSets);
+  console.log("水舞", props.dataSW);
+  console.log("恐龙", props.dataKL);
+  console.log("专注力", props.dataZZL);
 });
 </script>

+ 75 - 30
src/views/admin/components/ComboCharts.vue

@@ -4,8 +4,9 @@ import LiquidChart from "@/components/Charts/LiquidChart.vue";
 import LineChart from "@/components/Charts/LineChart.vue";
 import PercentBarChart from "@/components/Charts/PercentBarChart.vue";
 import {DashboardData} from "@/api/dashboard/types";
-import {AreaChartParams, AreaLineData, AreaParams} from "@/api/areaboard/types";
+import {AreaChartParams, AreaLineData} from "@/api/areaboard/types";
 import {getAreaBoardLines, getAreaBoardPies} from "@/api/areaboard";
+import {Ref} from "vue";
 
 const props = defineProps({
   provinceId: {
@@ -39,7 +40,7 @@ const props = defineProps({
 const pieStatus = ref(false);
 const pieMessage = ref("加载中...");
 const pieChartData = ref<DashboardData>();
-async function getPieChartData(params: AreaParams) {
+async function getPieChartData(params: AreaChartParams) {
   pieStatus.value = false;
   getAreaBoardPies(params)
     .then(({data}) => {
@@ -58,22 +59,21 @@ async function getPieChartData(params: AreaParams) {
 const lineStatus = ref(false);
 const lineMessage = ref("加载中...");
 const lineChartData = ref<AreaLineData>();
-//const averageData = ref<number[][]>();
 const curveData = ref<number[][]>();
-async function getLineChartData(params: AreaParams) {
+const swCurveData = ref<number[][]>();
+const klCurveData = ref<number[][]>();
+const zzlCurveData = ref<number[][]>();
+async function getLineChartData(params: AreaChartParams) {
   lineStatus.value = false;
   getAreaBoardLines(params)
     .then(({data}) => {
       lineChartData.value = data;
-      // // 柱状图
-      // averageData.value = [];
-      // averageData.value?.push(lineChartData.value?.frontNum || []);
-      // averageData.value?.push(lineChartData.value?.afterNum || []);
       // 曲线图
       curveData.value = [];
       curveData.value?.push(lineChartData.value?.curve || []);
       curveData.value?.push(lineChartData.value?.num || []);
       lineStatus.value = true;
+      lineChartData.value = undefined;
     })
     .catch((error) => {
       lineStatus.value = false;
@@ -81,6 +81,15 @@ async function getLineChartData(params: AreaParams) {
       console.log(error.message);
     });
 }
+async function getLineChartDataSub(result: Ref<number[][] | undefined>, params: AreaChartParams) {
+  let tempData: AreaLineData;
+  getAreaBoardLines(params).then(({data}) => {
+    tempData = data;
+    result.value = [];
+    result.value?.push(tempData?.curve || []);
+    result.value?.push(tempData?.num || []);
+  });
+}
 /**
  * 筛选条件
  */
@@ -89,6 +98,7 @@ const dataParams: AreaChartParams = reactive({
   city_id: 0,
   school_id: 0,
   grade_id: 0,
+  device_id: 0,
   start_time: Math.ceil(Date.parse("2023/1/1 00:00") / 1000),
   end_time: Math.ceil(Date.now() / 1000),
 });
@@ -103,7 +113,14 @@ watchEffect(() => {
   // 饼图数据
   getPieChartData(dataParams);
   // 折线图数据
+  dataParams.device_id = 0;
   getLineChartData(dataParams);
+  dataParams.device_id = 1;
+  getLineChartDataSub(swCurveData, dataParams);
+  dataParams.device_id = 6;
+  getLineChartDataSub(klCurveData, dataParams);
+  dataParams.device_id = 7;
+  getLineChartDataSub(zzlCurveData, dataParams);
 });
 </script>
 
@@ -133,15 +150,18 @@ watchEffect(() => {
               </el-col>
               <el-col :span="12">
                 <div class="item">
-                  <LiquidChart
-                    id="liquidChart2"
-                    :key="pieChartData?.afterAverage"
-                    :data="pieChartData?.afterAverage || 0"
-                    height="200px"
-                    width="200px"
-                    color="#5563ac"
-                    bg-color="#cacce6"
-                    class="chart" />
+                  <template v-if="pieChartData?.countRecord && pieChartData.countRecord > 4">
+                    <LiquidChart
+                      id="liquidChart2"
+                      :key="pieChartData?.afterAverage"
+                      :data="pieChartData?.afterAverage || 0"
+                      height="200px"
+                      width="200px"
+                      color="#5563ac"
+                      bg-color="#cacce6"
+                      class="chart" />
+                  </template>
+                  <div v-else class="pieEmpty p1">训练数据不足</div>
                   <p>全体学员训练近期</p>
                   <p>专注力评估均值</p>
                 </div>
@@ -167,17 +187,20 @@ watchEffect(() => {
               </el-col>
               <el-col :span="12">
                 <div class="item">
-                  <CircleChart
-                    id="circleChart2"
-                    :key="pieChartData?.after"
-                    :data="pieChartData?.after || 0"
-                    height="200px"
-                    width="200px"
-                    color="#5563ac"
-                    bg-color="#e4e7f4"
-                    font-color="#5563ac"
-                    font-size="30px"
-                    :round-cap="Boolean(true)" />
+                  <template v-if="pieChartData?.countRecord && pieChartData.countRecord > 4">
+                    <CircleChart
+                      id="circleChart2"
+                      :key="pieChartData?.after"
+                      :data="pieChartData?.after || 0"
+                      height="200px"
+                      width="200px"
+                      color="#5563ac"
+                      bg-color="#e4e7f4"
+                      font-color="#5563ac"
+                      font-size="30px"
+                      :round-cap="Boolean(true)" />
+                  </template>
+                  <div v-else class="pieEmpty p2">训练数据不足</div>
                   <p>近期训练</p>
                   <p>专注力50以上训练占比</p>
                 </div>
@@ -197,8 +220,11 @@ watchEffect(() => {
           <template v-if="lineStatus">
             <line-chart
               id="lineChart1"
-              :key="curveData?.toString()"
-              :data-sets="curveData || [[], []]"
+              :key="dataParams?.toString()"
+              :dataSets="curveData || [[], []]"
+              :dataSW="swCurveData || [[], []]"
+              :dataKL="klCurveData || [[], []]"
+              :dataZZL="zzlCurveData || [[], []]"
               height="558px"
               width="100%" />
           </template>
@@ -335,5 +361,24 @@ watchEffect(() => {
   .empty {
     padding: 200px 0;
   }
+
+  .pieEmpty {
+    box-sizing: border-box;
+    width: 180px;
+    height: 180px;
+    margin: 10px auto;
+    color: red;
+    border-radius: 50%;
+
+    &.p1 {
+      line-height: 160px;
+      border: 5px solid #2f539b;
+    }
+
+    &.p2 {
+      line-height: 120px;
+      border: 20px solid #2f539b;
+    }
+  }
 }
 </style>

+ 5 - 0
src/views/admin/training/index.vue

@@ -116,6 +116,11 @@ onMounted(() => {
   padding: 20px 30px;
 }
 
+:deep(.el-table .el-table__header .el-table__cell .cell) {
+  overflow: visible;
+  white-space: nowrap;
+}
+
 .list-table {
   overflow: hidden;
   background: #fff;

+ 13 - 12
src/views/customer/student/download.vue

@@ -14,8 +14,6 @@ import {useUserStore} from "@/store/modules/user";
 import {getStudentBoard} from "@/api/student";
 import {StudentBoard} from "@/api/student/types";
 import html2canvas from "html2canvas";
-import {useRouter} from "vue-router";
-const router = useRouter();
 
 const userStore = useUserStore();
 defineOptions({
@@ -68,11 +66,18 @@ function starElement(index: number, compare: number) {
   //return `<div class="star s${star}"></div><div class="status">${tag}</div>`;
   return ["star s" + star, tag, value];
 }
+function goBack() {
+  window.history.back();
+}
 
 const dialogVisible = ref(false);
 onMounted(() => {
+  let schoolId: number = userStore.schoolId;
+  if (getUrlParam("school") && getUrlParam("school") * 1 > 0) {
+    schoolId = getUrlParam("school") * 1;
+  }
   // 图表数据
-  getChartData(userStore.schoolId);
+  getChartData(schoolId);
 });
 
 // 绑定需要生成图片的页面内容
@@ -100,7 +105,7 @@ const downloadHandle = (name: string) => {
       // 下载之后删除临时a标签
       saveElement.remove();
       // 返回上一页
-      router.push("/student/result?id=" + getUrlParam("id"));
+      goBack();
     })
     .catch((e) => {
       console.log(e);
@@ -112,16 +117,12 @@ const downloadHandle = (name: string) => {
   <div class="container">
     <el-dialog v-model="dialogVisible" title="已生成【训练效果分析】离线报告,您可以:">
       <el-button @click="dialogVisible = false">预览</el-button>
-      <el-button class="mr-3" color="#626aef" @click="downloadHandle(chartData?.name || '')">下载报告</el-button>
-      <router-link :to="'/student/result?id=' + getUrlParam('id')"
-        ><el-button color="#626aef" plain>返回上一页</el-button></router-link
-      >
+      <el-button color="#626aef" @click="downloadHandle(chartData?.name || '')">下载报告</el-button>
+      <el-button @click="goBack()" color="#626aef" plain>返回上一页</el-button>
     </el-dialog>
     <div class="download-btn">
-      <el-button class="mr-5" color="#626aef" @click="downloadHandle(chartData?.name || '')">下载报告</el-button>
-      <router-link :to="'/student/result?id=' + getUrlParam('id')"
-        ><el-button color="#626aef" plain>返回上一页</el-button></router-link
-      >
+      <el-button color="#626aef" @click="downloadHandle(chartData?.name || '')">下载报告</el-button>
+      <el-button @click="goBack()" color="#626aef" plain>返回上一页</el-button>
     </div>
     <div v-if="dataStatus" ref="exportPage" class="result-container">
       <div class="result-title">

+ 3 - 1
src/views/customer/student/result.vue

@@ -72,7 +72,9 @@ onMounted(() => {
 
 <template>
   <div v-if="dataStatus" class="result-container">
-    <router-link :to="'/download/student/result?id=' + getUrlParam('id')" class="download-btn">
+    <router-link
+      :to="'/download/student/result?id=' + getUrlParam('id') + '&school=' + getUrlParam('school')"
+      class="download-btn">
       <svg-icon icon-class="download" size="3rem" />
       <span>下载报告</span>
     </router-link>