Parcourir la source

feat: :sparkles: 新增学校级看板-页面结构调整

chaooo il y a 1 an
Parent
commit
d99f33af03

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

@@ -2,13 +2,21 @@ export interface Area {
   area_id: number;
   area_name: string;
 }
-export interface AddressId {
+export interface AreaChartParams {
   province_id: number;
   city_id: number;
+  school_id: number;
+  grade_id: number;
+  start_time: number;
+  end_time: number;
 }
 export interface AreaParams {
   province_id: number;
   city_id: number;
+  start_time: number;
+  end_time: number;
+}
+export interface SchoolParams {
   school_id: number;
   grade_id: number;
   start_time: number;

+ 2 - 2
src/components/Charts/LineChart.vue

@@ -37,8 +37,8 @@ const props = defineProps({
 const tipFormatter = (params: any) => {
   const num = <number[]>props.dataSets?.[1];
   const label = [];
-  label.push(params.marker + "第" + params.name + "");
-  label.push("数:" + (num[params.dataIndex] || ""));
+  label.push(params.marker + "第" + params.name + "");
+  label.push("训练次数:" + (num[params.dataIndex] || ""));
   label.push("均值:" + params.value);
   return label.join("<br>");
 };

+ 35 - 21
src/store/modules/permission.ts

@@ -12,18 +12,18 @@ const adminRoutes: RouteRecordRaw[] = JSON.parse(
   JSON.stringify([
     {
       path: "/",
-      redirect: "/areaboard",
+      redirect: "/areaBoard",
       meta: {hidden: true, breadcrumb: false, name: "Home"},
     },
     {
-      path: "/areaboard",
+      path: "/areaBoard",
       component: "AdminIndex",
-      redirect: "/areaboard/index",
-      meta: {title: "区域级数据看板", name: "Dashboard"},
+      redirect: "/areaBoard/index",
+      meta: {title: "区域级数据看板", name: "AreaBoard"},
       children: [
         {
           path: "index",
-          component: "areaboard/index",
+          component: "admin/area/index",
           meta: {
             title: "区域级数据看板",
             name: "DashboardArea",
@@ -34,6 +34,25 @@ const adminRoutes: RouteRecordRaw[] = JSON.parse(
         },
       ],
     },
+    {
+      path: "/schoolBoard",
+      component: "AdminIndex",
+      redirect: "/schoolBoard/index",
+      meta: {title: "学校级数据看板", name: "SchoolBoard"},
+      children: [
+        {
+          path: "index",
+          component: "admin/school/index",
+          meta: {
+            title: "学校级数据看板",
+            name: "DashboardSchool",
+            icon: "board",
+            keepAlive: true,
+            breadcrumb: false,
+          },
+        },
+      ],
+    },
   ])
 );
 // 角色【学校负责人】拥有的权限路由
@@ -52,7 +71,7 @@ const schoolRoutes: RouteRecordRaw[] = JSON.parse(
       children: [
         {
           path: "index",
-          component: "dashboard/index",
+          component: "customer/dashboard/index",
           meta: {
             title: "数据看板",
             name: "DashboardIndex",
@@ -63,7 +82,7 @@ const schoolRoutes: RouteRecordRaw[] = JSON.parse(
         },
         {
           path: "example",
-          component: "dashboard/example",
+          component: "customer/dashboard/example",
           meta: {
             title: "优秀教学效果示例",
             name: "DashboardExample",
@@ -80,7 +99,7 @@ const schoolRoutes: RouteRecordRaw[] = JSON.parse(
       children: [
         {
           path: "index",
-          component: "grade/index",
+          component: "customer/grade/index",
           meta: {
             title: "班级管理",
             name: "ClassIndex",
@@ -99,7 +118,7 @@ const schoolRoutes: RouteRecordRaw[] = JSON.parse(
       children: [
         {
           path: "index",
-          component: "teacher/index",
+          component: "customer/teacher/index",
           meta: {
             title: "教师管理",
             name: "TeacherIndex",
@@ -118,7 +137,7 @@ const schoolRoutes: RouteRecordRaw[] = JSON.parse(
       children: [
         {
           path: "index",
-          component: "student/index",
+          component: "customer/student/index",
           meta: {
             title: "学生管理",
             name: "StudentIndex",
@@ -129,19 +148,14 @@ const schoolRoutes: RouteRecordRaw[] = JSON.parse(
         },
         {
           path: "result",
-          component: "student/result",
+          component: "customer/student/result",
           meta: {title: "训练效果分析", name: "StudentResult", hidden: true},
         },
-        // {
-        // 	path: "download",
-        // 	component: "student/download",
-        // 	meta: { title: "下载报告", name: "StudentDownload", hidden: true },
-        // },
       ],
     },
     {
       path: "/download/student/result",
-      component: "student/download",
+      component: "customer/student/download",
       meta: {title: "下载报告预览", name: "StudentDownload", hidden: true},
     },
     {
@@ -152,7 +166,7 @@ const schoolRoutes: RouteRecordRaw[] = JSON.parse(
       children: [
         {
           path: "index",
-          component: "equipment/index",
+          component: "customer/equipment/index",
           meta: {
             title: "设备管理",
             name: "EquipmentIndex",
@@ -171,7 +185,7 @@ const schoolRoutes: RouteRecordRaw[] = JSON.parse(
       children: [
         {
           path: "index",
-          component: "training/index",
+          component: "customer/training/index",
           meta: {
             title: "训练记录",
             name: "TrainingIndex",
@@ -182,7 +196,7 @@ const schoolRoutes: RouteRecordRaw[] = JSON.parse(
         },
         {
           path: "result",
-          component: "training/result",
+          component: "customer/training/result",
           meta: {title: "报告详情", name: "TrainingResult", hidden: true},
         },
       ],
@@ -195,7 +209,7 @@ const schoolRoutes: RouteRecordRaw[] = JSON.parse(
       children: [
         {
           path: "index",
-          component: "evaluation/index",
+          component: "customer/evaluation/index",
           meta: {
             title: "测评数据看板",
             name: "EvaluateIndex",

+ 3 - 3
src/views/areaboard/components/AreaDataCard.vue → src/views/admin/area/components/AreaDataCard.vue

@@ -83,7 +83,7 @@ watchEffect(() => {
   }
 
   &.c1 {
-    background: #fef6e9 url("../../../assets/areaboard/students.png") 90% 50% no-repeat;
+    background: #fef6e9 url("../../../../assets/areaboard/students.png") 90% 50% no-repeat;
 
     span.n {
       color: #e08e0a;
@@ -91,7 +91,7 @@ watchEffect(() => {
   }
 
   &.c2 {
-    background: #feeeee url("../../../assets/areaboard/games.png") 90% 50% no-repeat;
+    background: #feeeee url("../../../../assets/areaboard/games.png") 90% 50% no-repeat;
 
     span.n {
       color: #ca7676;
@@ -99,7 +99,7 @@ watchEffect(() => {
   }
 
   &.c3 {
-    background: #d0f6f1 url("../../../assets/areaboard/schools.png") 90% 50% no-repeat;
+    background: #d0f6f1 url("../../../../assets/areaboard/schools.png") 90% 50% no-repeat;
 
     span.n {
       color: #45a498;

+ 197 - 0
src/views/admin/area/index.vue

@@ -0,0 +1,197 @@
+<script setup lang="ts">
+import {Area, AreaCard, AreaChartParams, AreaParams} from "@/api/areaboard/types";
+import AreaDataCard from "@/views/admin/area/components/AreaDataCard.vue";
+import {getAreaAddress, getAreaCard} from "@/api/areaboard";
+import ComboCharts from "@/views/admin/components/ComboCharts.vue";
+
+defineOptions({
+  name: "DashboardArea",
+  inheritAttrs: false,
+});
+/**
+ * 筛选条件
+ */
+const dataParams: AreaParams = reactive({
+  province_id: 0,
+  city_id: 0,
+  start_time: Math.ceil(Date.parse("2023/1/1 00:00") / 1000),
+  end_time: Math.ceil(Date.now() / 1000),
+});
+const datePicker = ref<number[]>([Date.parse("2023/1/1 00:00"), Date.now()]);
+const provinceData = ref<Area[]>();
+const cityData = ref<Area[]>();
+async function getAddressData(id: number) {
+  getAreaAddress(id)
+    .then(({data}) => {
+      dataParams.city_id = 0;
+      if (id == 0) {
+        provinceData.value = data;
+        provinceData.value?.unshift({area_id: 0, area_name: "全部省"});
+        cityData.value = [{area_id: 0, area_name: "全部市"}];
+      } else {
+        cityData.value = data;
+        cityData.value?.unshift({area_id: 0, area_name: "全部市"});
+      }
+    })
+    .catch((error) => {
+      console.log(error.message);
+      dataParams.city_id = 0;
+      if (id == 0) {
+        provinceData.value = [{area_id: 0, area_name: "全部省"}];
+      } else {
+        cityData.value = [{area_id: 0, area_name: "全部市"}];
+      }
+    });
+}
+// 改变时间
+function changeDate() {
+  dataParams.start_time = Math.ceil(datePicker.value[0] / 1000);
+  dataParams.end_time = Math.ceil(datePicker.value[1] / 1000);
+}
+// 获取图表数据条件
+const chartParams: AreaChartParams = reactive({});
+/**
+ * 数据卡片
+ */
+const cardStatus = ref(false);
+const cards = ref<AreaCard>();
+async function getDataCard(params: AreaParams) {
+  getAreaCard(params)
+    .then(({data}) => {
+      cards.value = data;
+      cardStatus.value = true;
+    })
+    .catch((error) => {
+      console.log(error.message);
+    });
+}
+/**
+ * 获取页面数据
+ */
+function getPageData() {
+  // 数据卡片
+  getDataCard(dataParams);
+  chartParams.province_id = dataParams.province_id;
+  chartParams.city_id = dataParams.city_id;
+  chartParams.start_time = dataParams.start_time;
+  chartParams.end_time = dataParams.end_time;
+}
+onMounted(() => {
+  // 获取省份
+  getAddressData(0);
+  cityData.value = [{area_id: 0, area_name: "全部市"}];
+  // 获取页面数据
+  getPageData();
+});
+</script>
+
+<template>
+  <div class="area-container">
+    <div class="area-top">
+      <div class="search-box">
+        <el-select
+          v-model="dataParams.province_id"
+          placeholder="全部省"
+          size="large"
+          @change="getAddressData(dataParams.province_id)">
+          <el-option v-for="item in provinceData" :key="item.area_id" :label="item.area_name" :value="item.area_id" />
+        </el-select>
+        <el-select v-model="dataParams.city_id" placeholder="全部市" size="large">
+          <el-option v-for="item in cityData" :key="item.area_id" :label="item.area_name" :value="item.area_id" />
+        </el-select>
+        <div>
+          <el-date-picker
+            v-model="datePicker"
+            type="daterange"
+            size="large"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            format="YYYY-MM-DD"
+            value-format="x"
+            @change="changeDate()" />
+        </div>
+        <el-button color="#4284f2" size="large" @click="getPageData()">查找</el-button>
+      </div>
+      <div class="card-box">
+        <!-- 数据卡片 -->
+        <template v-if="cardStatus">
+          <AreaDataCard
+            :key="cards?.toString()"
+            :schools="cards?.school || 0"
+            :games="cards?.game || 0"
+            :students="cards?.student || 0" />
+        </template>
+      </div>
+    </div>
+    <!-- Echarts 图表 -->
+    <ComboCharts
+      :key="chartParams?.toString()"
+      :provinceId="chartParams.province_id"
+      :cityId="chartParams.city_id"
+      :startTime="chartParams.start_time"
+      :endTime="chartParams.end_time" />
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.area-top {
+  background: #fff;
+}
+
+.card-box {
+  padding: 0 30px 20px;
+}
+
+.search-box {
+  display: flex;
+  padding: 20px 55px;
+  line-height: 40px;
+
+  .el-select {
+    width: 140px;
+    margin-right: 10px;
+  }
+
+  .el-button {
+    padding: 0 26px;
+    margin: 0 20px;
+    font-size: 16px;
+    border-radius: 10px;
+  }
+}
+
+:deep(.el-select),
+:deep(.el-date-editor) {
+  --el-select-input-focus-border-color: none !important;
+
+  width: 300px;
+  margin: 0;
+  overflow: hidden;
+  border: 1px solid #ddd;
+  border-radius: 10px;
+}
+
+:deep(.search-box.s2 .el-select) {
+  border: none;
+}
+
+:deep(.el-date-editor) {
+  --el-select-input-focus-border-color: none !important;
+}
+
+:deep(.el-input__wrapper) {
+  box-shadow: none !important;
+}
+
+:deep(.el-input__wrapper.is-focus) {
+  box-shadow: none !important;
+}
+
+:deep(.el-select:hover:not(.el-select--disabled) .el-input__wrapper) {
+  box-shadow: none !important;
+}
+
+.mobile .el-col {
+  margin-bottom: 10px;
+}
+</style>

+ 374 - 0
src/views/admin/components/ComboCharts.vue

@@ -0,0 +1,374 @@
+<script setup lang="ts">
+import CircleChart from "@/components/Charts/CircleChart.vue";
+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 {getAreaBoardLines, getAreaBoardPies} from "@/api/areaboard";
+
+const props = defineProps({
+  provinceId: {
+    type: Number,
+    default: 0,
+  },
+  cityId: {
+    type: Number,
+    default: 0,
+  },
+  schoolId: {
+    type: Number,
+    default: 0,
+  },
+  gradeId: {
+    type: Number,
+    default: 0,
+  },
+  startTime: {
+    type: Number,
+    default: Math.ceil(Date.parse("2023/1/1 00:00") / 1000),
+  },
+  endTime: {
+    type: Number,
+    default: Math.ceil(Date.now() / 1000),
+  },
+});
+/**
+ * 饼图数据
+ */
+const pieStatus = ref(false);
+const pieMessage = ref("加载中...");
+const pieChartData = ref<DashboardData>();
+async function getPieChartData(params: AreaParams) {
+  pieStatus.value = false;
+  getAreaBoardPies(params)
+    .then(({data}) => {
+      pieChartData.value = data;
+      pieStatus.value = true;
+    })
+    .catch((error) => {
+      pieStatus.value = false;
+      pieMessage.value = error.message;
+      console.log(error.message);
+    });
+}
+/**
+ * 折线图数据
+ */
+const lineStatus = ref(false);
+const lineMessage = ref("加载中...");
+const lineChartData = ref<AreaLineData>();
+//const averageData = ref<number[][]>();
+const curveData = ref<number[][]>();
+async function getLineChartData(params: AreaParams) {
+  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;
+    })
+    .catch((error) => {
+      lineStatus.value = false;
+      lineMessage.value = error.message;
+      console.log(error.message);
+    });
+}
+/**
+ * 筛选条件
+ */
+const dataParams: AreaChartParams = reactive({
+  province_id: 0,
+  city_id: 0,
+  school_id: 0,
+  grade_id: 0,
+  start_time: Math.ceil(Date.parse("2023/1/1 00:00") / 1000),
+  end_time: Math.ceil(Date.now() / 1000),
+});
+// 监听数据变化
+watchEffect(() => {
+  dataParams.province_id = <number>props.provinceId;
+  dataParams.city_id = <number>props.cityId;
+  dataParams.school_id = <number>props.schoolId;
+  dataParams.grade_id = <number>props.gradeId;
+  dataParams.start_time = <number>props.startTime;
+  dataParams.end_time = <number>props.endTime;
+  // 饼图数据
+  getPieChartData(dataParams);
+  // 折线图数据
+  getLineChartData(dataParams);
+});
+</script>
+
+<template>
+  <!-- Echarts 图表 -->
+  <div class="charts-container">
+    <el-row :gutter="20">
+      <el-col :xs="24" :span="8">
+        <div class="charts-item">
+          <p class="title">学员专注力平均值整体对比分析</p>
+          <template v-if="pieStatus">
+            <el-row justify="space-between">
+              <el-col :span="12">
+                <div class="item">
+                  <LiquidChart
+                    id="liquidChart1"
+                    :key="pieChartData?.frontAverage"
+                    :data="pieChartData?.frontAverage || 0"
+                    height="200px"
+                    width="200px"
+                    color="#3a7fc2"
+                    bg-color="#accded"
+                    class="chart" />
+                  <p>全体学员初期</p>
+                  <p>专注力评估均值</p>
+                </div>
+              </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" />
+                  <p>全体学员训练近期</p>
+                  <p>专注力评估均值</p>
+                </div>
+              </el-col>
+            </el-row>
+            <el-row justify="space-between">
+              <el-col :span="12">
+                <div class="item">
+                  <CircleChart
+                    id="circleChart1"
+                    :key="pieChartData?.front"
+                    :data="pieChartData?.front || 0"
+                    height="200px"
+                    width="200px"
+                    color="#3a7fc2"
+                    bg-color="#e4e7f4"
+                    font-color="#3a7fc2"
+                    font-size="30px"
+                    :round-cap="Boolean(true)" />
+                  <p>初期训练</p>
+                  <p>专注力50以上人数比例</p>
+                </div>
+              </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)" />
+                  <p>近期训练</p>
+                  <p>专注力50以上人数比例</p>
+                </div>
+              </el-col>
+            </el-row>
+          </template>
+          <div v-else class="empty">
+            <img src="../../../assets/empty.png" alt="数据为空" />
+            <p>{{ pieMessage }}</p>
+          </div>
+        </div>
+      </el-col>
+      <!-- 学员专注力评分分级占比分析 -->
+      <el-col :xs="24" :span="16">
+        <div class="charts-item">
+          <p class="title">样本每次训练专注力评分均值整体变化曲线</p>
+          <template v-if="lineStatus">
+            <line-chart
+              id="lineChart1"
+              :key="curveData?.toString()"
+              :data-sets="curveData || [[], []]"
+              height="558px"
+              width="100%" />
+          </template>
+          <div v-else class="empty">
+            <img src="../../../assets/empty.png" alt="数据为空" />
+            <p>{{ lineMessage }}</p>
+          </div>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+  <div class="charts-container">
+    <el-row :gutter="20">
+      <el-col :xs="24" :span="8">
+        <!-- <div class="charts-item">
+          <p class="title pos">学员专注力训练高专注占比分析</p>
+          <template v-if="lineStatus">
+            <AverageBarChart
+              id="averageBarChart1"
+              :key="averageData?.toString()"
+              :data-sets="averageData || [[], []]"
+              :data-max="lineChartData?.max_num || 10"
+              width="520px"
+              height="520px"
+              class="chart" />
+          </template>
+          <div v-else class="empty">
+            <img src="../../../assets/empty.png" alt="数据为空" />
+            <p>{{ lineMessage }}</p>
+          </div>
+          <el-row :gutter="15" class="bottom">
+            <el-col :span="12">
+              <p class="l">
+                <span>训练前期全体学员</span>
+                <span>高专注占比平均值</span>
+                <b>{{ lineChartData?.frontHeight }}</b>
+              </p>
+            </el-col>
+            <el-col :span="12">
+              <p class="r">
+                <span>训练后期全体学员</span>
+                <span>高专注占比平均值</span>
+                <b>{{ lineChartData?.afterHeight }}</b>
+              </p>
+            </el-col>
+          </el-row>
+        </div>-->
+      </el-col>
+      <!-- 学员专注力评分分级占比分析 -->
+      <el-col :xs="24" :span="16">
+        <div class="charts-item">
+          <p class="title">学员专注力评分分级占比分析</p>
+          <el-row v-if="pieStatus" justify="space-between">
+            <el-col :xs="24" :span="12">
+              <div class="bar">
+                <PercentBarChart
+                  id="barChart1"
+                  :key="pieChartData?.frontProportion.toString()"
+                  width="400px"
+                  height="500px"
+                  title="全体学员初期训练专注力评分占比"
+                  :percent="pieChartData?.frontProportion.percentage"
+                  :data="pieChartData?.frontProportion.num"
+                  class="chart" />
+              </div>
+            </el-col>
+            <el-col :xs="24" :span="12">
+              <div class="bar">
+                <PercentBarChart
+                  id="barChart2"
+                  :key="pieChartData?.afterProportion.toString()"
+                  width="400px"
+                  height="500px"
+                  title="全体学员训练近期专注力评分平均占比"
+                  :percent="pieChartData?.afterProportion.percentage"
+                  :data="pieChartData?.afterProportion.num"
+                  class="chart" />
+              </div>
+            </el-col>
+          </el-row>
+          <div v-else class="empty">
+            <img src="../../../assets/empty.png" alt="数据为空" />
+            <p>{{ pieMessage }}</p>
+          </div>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<style scoped lang="scss">
+.charts-container {
+  position: relative;
+  padding: 30px 30px 20px;
+}
+
+.charts-item {
+  position: relative;
+  text-align: center;
+  background: #fff;
+  border: 1px solid #e8eaec;
+  border-radius: 24px;
+
+  .title {
+    height: 78px;
+    margin: 0;
+    font-size: 18px;
+    line-height: 78px;
+    text-align: left;
+    text-indent: 2em;
+
+    &.pos {
+      margin-bottom: -50px;
+    }
+  }
+
+  .item {
+    padding-bottom: 30px;
+  }
+
+  .chart {
+    margin: 0 auto;
+  }
+
+  p {
+    margin: 0;
+    font-size: 16px;
+    line-height: 24px;
+  }
+
+  .bar {
+    margin-top: 60px;
+  }
+
+  .bottom {
+    padding: 0 20px 20px;
+
+    .el-col p {
+      position: relative;
+      box-sizing: border-box;
+      padding: 10px 20px;
+      color: #fff;
+      text-align: left;
+      white-space: nowrap;
+      border-radius: 10px;
+
+      &.l {
+        background: #f8b865;
+      }
+
+      &.r {
+        background: #8877ef;
+      }
+
+      span {
+        display: block;
+      }
+
+      b {
+        position: absolute;
+        top: 22px;
+        right: 20px;
+        font-size: 26px;
+        font-style: normal;
+      }
+    }
+  }
+
+  .empty {
+    padding: 200px 0;
+  }
+}
+</style>

+ 180 - 0
src/views/admin/school/index.vue

@@ -0,0 +1,180 @@
+<script setup lang="ts">
+import {AreaChartParams, SchoolParams} from "@/api/areaboard/types";
+import {GradeList} from "@/api/grade/types";
+import {getGradeSelect} from "@/api/grade";
+import {getAreaSchool} from "@/api/areaboard";
+import {SchoolList} from "@/api/school/types";
+import ComboCharts from "@/views/admin/components/ComboCharts.vue";
+
+defineOptions({
+  name: "DashboardSchool",
+  inheritAttrs: false,
+});
+/**
+ * 筛选条件
+ */
+const dataParams: SchoolParams = reactive({
+  school_id: 0,
+  grade_id: 0,
+  start_time: Math.ceil(Date.parse("2023/1/1 00:00") / 1000),
+  end_time: Math.ceil(Date.now() / 1000),
+});
+const datePicker = ref<number[]>([Date.parse("2023/1/1 00:00"), Date.now()]);
+const schoolData = ref<SchoolList[]>();
+const gradeData = ref<GradeList[]>();
+/**
+ * 获取学校
+ */
+async function getSchoolData() {
+  getAreaSchool(0, 0)
+    .then(({data}) => {
+      schoolData.value = data;
+      schoolData.value?.unshift({num: "", school_id: 0, name: "全部学校"});
+      gradeData.value = [{id: 0, name: "全部班级"}];
+    })
+    .catch((error) => {
+      schoolData.value = [{num: "", school_id: 0, name: "全部学校"}];
+      gradeData.value = [{id: 0, name: "全部班级"}];
+      console.log(error.message);
+    });
+}
+/**
+ * 班级数据
+ */
+async function getGradeData(schoolId: number) {
+  getGradeSelect(schoolId)
+    .then(({data}) => {
+      dataParams.grade_id = 0;
+      gradeData.value = data;
+      gradeData.value?.unshift({id: 0, name: "全部班级"});
+    })
+    .catch((error) => {
+      dataParams.grade_id = 0;
+      gradeData.value = [{id: 0, name: "全部班级"}];
+      console.log(error.message);
+    });
+}
+// 改变时间
+function changeDate() {
+  dataParams.start_time = Math.ceil(datePicker.value[0] / 1000);
+  dataParams.end_time = Math.ceil(datePicker.value[1] / 1000);
+}
+// 获取图表数据条件
+const chartParams: AreaChartParams = reactive({});
+/**
+ * 获取页面数据
+ */
+function getPageData() {
+  chartParams.school_id = dataParams.school_id;
+  chartParams.grade_id = dataParams.grade_id;
+  chartParams.start_time = dataParams.start_time;
+  chartParams.end_time = dataParams.end_time;
+}
+
+onMounted(() => {
+  // 获取学校
+  getSchoolData();
+  gradeData.value = [{id: 0, name: "全部班级"}];
+  // 获取页面数据
+  getPageData();
+});
+</script>
+
+<template>
+  <div class="area-container">
+    <div class="search-box s2">
+      <el-select
+        v-model="dataParams.school_id"
+        placeholder="全部学校"
+        size="large"
+        @change="getGradeData(dataParams.school_id)">
+        <el-option v-for="item in schoolData" :key="item.school_id" :label="item.name" :value="item.school_id" />
+      </el-select>
+      <el-select v-model="dataParams.grade_id" placeholder="全部班级" size="large">
+        <el-option v-for="item in gradeData" :key="item.id" :label="item.name" :value="item.id" />
+      </el-select>
+      <div>
+        <el-date-picker
+          v-model="datePicker"
+          type="daterange"
+          size="large"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          format="YYYY-MM-DD"
+          value-format="x"
+          @change="changeDate()" />
+      </div>
+      <el-button color="#4284f2" size="large" @click="getPageData()">查找</el-button>
+    </div>
+    <!-- Echarts 图表 -->
+    <ComboCharts
+      :key="chartParams?.toString()"
+      :schoolId="chartParams.school_id"
+      :gradeId="chartParams.grade_id"
+      :startTime="chartParams.start_time"
+      :endTime="chartParams.end_time" />
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.area-top {
+  background: #fff;
+}
+
+.card-box {
+  padding: 0 30px 20px;
+}
+
+.search-box {
+  display: flex;
+  padding: 20px 55px;
+  line-height: 40px;
+
+  .el-select {
+    width: 140px;
+    margin-right: 10px;
+  }
+
+  .el-button {
+    padding: 0 26px;
+    margin: 0 20px;
+    font-size: 16px;
+    border-radius: 10px;
+  }
+}
+
+:deep(.el-select),
+:deep(.el-date-editor) {
+  --el-select-input-focus-border-color: none !important;
+
+  width: 300px;
+  margin: 0;
+  overflow: hidden;
+  border: 1px solid #ddd;
+  border-radius: 10px;
+}
+
+:deep(.search-box.s2 .el-select) {
+  border: none;
+}
+
+:deep(.el-date-editor) {
+  --el-select-input-focus-border-color: none !important;
+}
+
+:deep(.el-input__wrapper) {
+  box-shadow: none !important;
+}
+
+:deep(.el-input__wrapper.is-focus) {
+  box-shadow: none !important;
+}
+
+:deep(.el-select:hover:not(.el-select--disabled) .el-input__wrapper) {
+  box-shadow: none !important;
+}
+
+.mobile .el-col {
+  margin-bottom: 10px;
+}
+</style>

+ 0 - 560
src/views/areaboard/index.vue

@@ -1,560 +0,0 @@
-<script setup lang="ts">
-import {DashboardData} from "@/api/dashboard/types";
-import {Area, AreaCard, AreaLineData, AreaParams} from "@/api/areaboard/types";
-import AreaDataCard from "@/views/areaboard/components/AreaDataCard.vue";
-import LiquidChart from "@/components/Charts/LiquidChart.vue";
-import PercentBarChart from "@/components/Charts/PercentBarChart.vue";
-import CircleChart from "@/components/Charts/CircleChart.vue";
-import LineChart from "@/components/Charts/LineChart.vue";
-import AverageBarChart from "@/components/Charts/AverageBarChart.vue";
-import {GradeList} from "@/api/grade/types";
-import {getGradeSelect} from "@/api/grade";
-import {getAreaAddress, getAreaBoardLines, getAreaBoardPies, getAreaCard, getAreaSchool} from "@/api/areaboard";
-import {SchoolList} from "@/api/school/types";
-
-defineOptions({
-  name: "DashboardArea",
-  inheritAttrs: false,
-});
-/**
- * 筛选条件
- */
-const dataParams: AreaParams = reactive({
-  province_id: 0,
-  city_id: 0,
-  school_id: 0,
-  grade_id: 0,
-  start_time: Math.ceil(Date.parse("2023/1/1 00:00") / 1000),
-  end_time: Math.ceil(Date.now() / 1000),
-});
-const datePicker = ref<number[]>([Date.parse("2023/1/1 00:00"), Date.now()]);
-const provinceData = ref<Area[]>();
-const cityData = ref<Area[]>();
-async function getAddressData(id: number) {
-  getAreaAddress(id)
-    .then(({data}) => {
-      dataParams.city_id = 0;
-      if (id == 0) {
-        provinceData.value = data;
-        provinceData.value?.unshift({area_id: 0, area_name: "全部省"});
-        cityData.value = [{area_id: 0, area_name: "全部市"}];
-      } else {
-        cityData.value = data;
-        cityData.value?.unshift({area_id: 0, area_name: "全部市"});
-      }
-      // 重新获取学校
-      getSchoolData(dataParams);
-    })
-    .catch((error) => {
-      console.log(error.message);
-      dataParams.city_id = 0;
-      if (id == 0) {
-        provinceData.value = [{area_id: 0, area_name: "全部省"}];
-      } else {
-        cityData.value = [{area_id: 0, area_name: "全部市"}];
-      }
-    });
-}
-//getAreaSchool
-/**
- * 获取学校
- */
-const schoolData = ref<SchoolList[]>();
-async function getSchoolData(params: AreaParams) {
-  getAreaSchool(params.province_id, params.city_id)
-    .then(({data}) => {
-      schoolData.value = data;
-      schoolData.value?.unshift({num: "", school_id: 0, name: "全部学校"});
-    })
-    .catch((error) => {
-      schoolData.value = [];
-      schoolData.value?.unshift({num: "", school_id: 0, name: "全部学校"});
-      console.log(error.message);
-    });
-}
-/**
- * 班级数据
- */
-const gradeData = ref<GradeList[]>();
-async function getGradeData(schoolId: number) {
-  getGradeSelect(schoolId)
-    .then(({data}) => {
-      dataParams.grade_id = 0;
-      gradeData.value = data;
-      gradeData.value?.unshift({id: 0, name: "全部班级"});
-    })
-    .catch((error) => {
-      dataParams.grade_id = 0;
-      gradeData.value = [];
-      gradeData.value?.unshift({id: 0, name: "全部班级"});
-      console.log(error.message);
-    });
-}
-// 改变时间
-function changeDate() {
-  dataParams.start_time = Math.ceil(datePicker.value[0] / 1000);
-  dataParams.end_time = Math.ceil(datePicker.value[1] / 1000);
-}
-/**
- * 数据卡片
- */
-const cardStatus = ref(false);
-const cards = ref<AreaCard>();
-async function getDataCard(params: AreaParams) {
-  getAreaCard(params)
-    .then(({data}) => {
-      cards.value = data;
-      cardStatus.value = true;
-    })
-    .catch((error) => {
-      console.log(error.message);
-    });
-}
-/**
- * 饼图数据
- */
-const pieStatus = ref(false);
-const pieMessage = ref("加载中...");
-const pieChartData = ref<DashboardData>();
-async function getPieChartData(params: AreaParams) {
-  pieStatus.value = false;
-  getAreaBoardPies(params)
-    .then(({data}) => {
-      pieChartData.value = data;
-      pieStatus.value = true;
-    })
-    .catch((error) => {
-      pieStatus.value = false;
-      pieMessage.value = error.message;
-      console.log(error.message);
-    });
-}
-/**
- * 折线图数据
- */
-const lineStatus = ref(false);
-const lineMessage = ref("加载中...");
-const lineChartData = ref<AreaLineData>();
-const averageData = ref<number[][]>();
-const curveData = ref<number[][]>();
-async function getLineChartData(params: AreaParams) {
-  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;
-    })
-    .catch((error) => {
-      lineStatus.value = false;
-      lineMessage.value = error.message;
-      console.log(error.message);
-    });
-}
-/**
- * 获取页面数据
- */
-function getPageData() {
-  // 数据卡片
-  getDataCard(dataParams);
-  // 饼图数据
-  getPieChartData(dataParams);
-  // 折线图数据
-  getLineChartData(dataParams);
-}
-onMounted(() => {
-  // 获取省份
-  getAddressData(0);
-  cityData.value = [{area_id: 0, area_name: "全部市"}];
-  // 获取学校
-  getSchoolData(dataParams);
-  gradeData.value = [{id: 0, name: "全部班级"}];
-  // 获取页面数据
-  getPageData();
-});
-</script>
-
-<template>
-  <div class="area-container">
-    <div class="area-top">
-      <div class="search-box">
-        <el-select
-          v-model="dataParams.province_id"
-          placeholder="全部省"
-          size="large"
-          @change="getAddressData(dataParams.province_id)">
-          <el-option v-for="item in provinceData" :key="item.area_id" :label="item.area_name" :value="item.area_id" />
-        </el-select>
-        <el-select v-model="dataParams.city_id" placeholder="全部市" size="large" @change="getSchoolData(dataParams)">
-          <el-option v-for="item in cityData" :key="item.area_id" :label="item.area_name" :value="item.area_id" />
-        </el-select>
-        <div>
-          <el-date-picker
-            v-model="datePicker"
-            type="daterange"
-            size="large"
-            start-placeholder="开始日期"
-            end-placeholder="结束日期"
-            format="YYYY-MM-DD"
-            value-format="x"
-            @change="changeDate()" />
-        </div>
-        <el-button color="#4284f2" size="large" @click="getPageData()">查找</el-button>
-      </div>
-      <div class="card-box">
-        <!-- 数据卡片 -->
-        <template v-if="cardStatus">
-          <AreaDataCard
-            :key="cards?.toString()"
-            :schools="cards?.school || 0"
-            :games="cards?.game || 0"
-            :students="cards?.student || 0" />
-        </template>
-      </div>
-    </div>
-    <div class="search-box s2">
-      <el-select
-        v-model="dataParams.school_id"
-        placeholder="全部学校"
-        size="large"
-        @change="getGradeData(dataParams.school_id)">
-        <el-option v-for="item in schoolData" :key="item.school_id" :label="item.name" :value="item.school_id" />
-      </el-select>
-      <el-select v-model="dataParams.grade_id" placeholder="全部班级" size="large">
-        <el-option v-for="item in gradeData" :key="item.id" :label="item.name" :value="item.id" />
-      </el-select>
-      <el-button color="#4284f2" size="large" @click="getPageData()">查找</el-button>
-    </div>
-    <!-- Echarts 图表 -->
-    <div class="charts-container">
-      <el-row :gutter="20">
-        <el-col :xs="24" :span="8">
-          <div class="charts-item">
-            <p class="title">学员专注力平均值整体对比分析</p>
-            <template v-if="pieStatus">
-              <el-row justify="space-between">
-                <el-col :span="12">
-                  <div class="item">
-                    <LiquidChart
-                      id="liquidChart1"
-                      :key="pieChartData?.frontAverage"
-                      :data="pieChartData?.frontAverage || 0"
-                      height="200px"
-                      width="200px"
-                      color="#3a7fc2"
-                      bg-color="#accded"
-                      class="chart" />
-                    <p>全体学员初期</p>
-                    <p>专注力评估均值</p>
-                  </div>
-                </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" />
-                    <p>全体学员训练近期</p>
-                    <p>专注力评估均值</p>
-                  </div>
-                </el-col>
-              </el-row>
-              <el-row justify="space-between">
-                <el-col :span="12">
-                  <div class="item">
-                    <CircleChart
-                      id="circleChart1"
-                      :key="pieChartData?.front"
-                      :data="pieChartData?.front || 0"
-                      height="200px"
-                      width="200px"
-                      color="#3a7fc2"
-                      bg-color="#e4e7f4"
-                      font-color="#3a7fc2"
-                      font-size="30px"
-                      :round-cap="Boolean(true)" />
-                    <p>初期训练</p>
-                    <p>专注力50以上人数比例</p>
-                  </div>
-                </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)" />
-                    <p>近期训练</p>
-                    <p>专注力50以上人数比例</p>
-                  </div>
-                </el-col>
-              </el-row>
-            </template>
-            <div v-else class="empty">
-              <img src="../../assets/empty.png" alt="数据为空" />
-              <p>{{ pieMessage }}</p>
-            </div>
-          </div>
-        </el-col>
-        <!-- 学员专注力评分分级占比分析 -->
-        <el-col :xs="24" :span="16">
-          <div class="charts-item">
-            <p class="title">样本每次训练专注力评分均值整体变化曲线</p>
-            <template v-if="lineStatus">
-              <line-chart
-                id="lineChart1"
-                :key="curveData?.toString()"
-                :data-sets="curveData || [[], []]"
-                height="558px"
-                width="100%" />
-            </template>
-            <div v-else class="empty">
-              <img src="../../assets/empty.png" alt="数据为空" />
-              <p>{{ lineMessage }}</p>
-            </div>
-          </div>
-        </el-col>
-      </el-row>
-    </div>
-    <div class="charts-container">
-      <el-row :gutter="20">
-        <el-col :xs="24" :span="8">
-          <div class="charts-item">
-            <p class="title pos">学员专注力训练高专注占比分析</p>
-            <template v-if="lineStatus">
-              <AverageBarChart
-                id="averageBarChart1"
-                :key="averageData?.toString()"
-                :data-sets="averageData || [[], []]"
-                :data-max="lineChartData?.max_num || 10"
-                width="520px"
-                height="520px"
-                class="chart" />
-            </template>
-            <div v-else class="empty">
-              <img src="../../assets/empty.png" alt="数据为空" />
-              <p>{{ lineMessage }}</p>
-            </div>
-            <el-row :gutter="15" class="bottom">
-              <el-col :span="12">
-                <p class="l">
-                  <span>训练前期全体学员</span>
-                  <span>高专注占比平均值</span>
-                  <b>{{ lineChartData?.frontHeight }}</b>
-                </p>
-              </el-col>
-              <el-col :span="12">
-                <p class="r">
-                  <span>训练后期全体学员</span>
-                  <span>高专注占比平均值</span>
-                  <b>{{ lineChartData?.afterHeight }}</b>
-                </p>
-              </el-col>
-            </el-row>
-          </div>
-        </el-col>
-        <!-- 学员专注力评分分级占比分析 -->
-        <el-col :xs="24" :span="16">
-          <div class="charts-item">
-            <p class="title">学员专注力评分分级占比分析</p>
-            <el-row v-if="pieStatus" justify="space-between">
-              <el-col :xs="24" :span="12">
-                <div class="bar">
-                  <PercentBarChart
-                    id="barChart1"
-                    :key="pieChartData?.frontProportion.toString()"
-                    width="400px"
-                    height="500px"
-                    title="全体学员初期训练专注力评分占比"
-                    :percent="pieChartData?.frontProportion.percentage"
-                    :data="pieChartData?.frontProportion.num"
-                    class="chart" />
-                </div>
-              </el-col>
-              <el-col :xs="24" :span="12">
-                <div class="bar">
-                  <PercentBarChart
-                    id="barChart2"
-                    :key="pieChartData?.afterProportion.toString()"
-                    width="400px"
-                    height="500px"
-                    title="全体学员训练近期专注力评分平均占比"
-                    :percent="pieChartData?.afterProportion.percentage"
-                    :data="pieChartData?.afterProportion.num"
-                    class="chart" />
-                </div>
-              </el-col>
-            </el-row>
-            <div v-else class="empty">
-              <img src="../../assets/empty.png" alt="数据为空" />
-              <p>{{ pieMessage }}</p>
-            </div>
-          </div>
-        </el-col>
-      </el-row>
-    </div>
-  </div>
-</template>
-
-<style lang="scss" scoped>
-.area-top {
-  background: #fff;
-}
-
-.card-box {
-  padding: 0 30px 20px;
-}
-
-.search-box {
-  display: flex;
-  padding: 20px 55px;
-  line-height: 40px;
-
-  .el-select {
-    width: 140px;
-    margin-right: 10px;
-  }
-
-  .el-button {
-    padding: 0 26px;
-    margin: 0 20px;
-    font-size: 16px;
-    border-radius: 10px;
-  }
-}
-
-:deep(.el-select),
-:deep(.el-date-editor) {
-  --el-select-input-focus-border-color: none !important;
-
-  width: 300px;
-  margin: 0;
-  overflow: hidden;
-  border: 1px solid #ddd;
-  border-radius: 10px;
-}
-
-:deep(.search-box.s2 .el-select) {
-  border: none;
-}
-
-:deep(.el-date-editor) {
-  --el-select-input-focus-border-color: none !important;
-}
-
-:deep(.el-input__wrapper) {
-  box-shadow: none !important;
-}
-
-:deep(.el-input__wrapper.is-focus) {
-  box-shadow: none !important;
-}
-
-:deep(.el-select:hover:not(.el-select--disabled) .el-input__wrapper) {
-  box-shadow: none !important;
-}
-
-.charts-container {
-  position: relative;
-  padding: 0 30px 20px;
-}
-
-.charts-item {
-  position: relative;
-  text-align: center;
-  background: #fff;
-  border: 1px solid #e8eaec;
-  border-radius: 24px;
-
-  .title {
-    height: 78px;
-    margin: 0;
-    font-size: 18px;
-    line-height: 78px;
-    text-align: left;
-    text-indent: 2em;
-
-    &.pos {
-      margin-bottom: -50px;
-    }
-  }
-
-  .item {
-    padding-bottom: 30px;
-  }
-
-  .chart {
-    margin: 0 auto;
-  }
-
-  p {
-    margin: 0;
-    font-size: 16px;
-    line-height: 24px;
-  }
-
-  .bar {
-    margin-top: 60px;
-  }
-
-  .bottom {
-    padding: 0 20px 20px;
-
-    .el-col p {
-      position: relative;
-      box-sizing: border-box;
-      padding: 10px 20px;
-      color: #fff;
-      text-align: left;
-      white-space: nowrap;
-      border-radius: 10px;
-
-      &.l {
-        background: #f8b865;
-      }
-
-      &.r {
-        background: #8877ef;
-      }
-
-      span {
-        display: block;
-      }
-
-      b {
-        position: absolute;
-        top: 22px;
-        right: 20px;
-        font-size: 26px;
-        font-style: normal;
-      }
-    }
-  }
-
-  .empty {
-    padding: 200px 0;
-  }
-}
-
-.mobile .el-col {
-  margin-bottom: 10px;
-}
-</style>

+ 5 - 5
src/views/dashboard/components/DataCard.vue → src/views/customer/dashboard/components/DataCard.vue

@@ -123,23 +123,23 @@ watchEffect(() => {
     background-size: 100% auto;
 
     &.c1 {
-      background-image: url("../../../assets/index/grade.png");
+      background-image: url("../../../../assets/index/grade.png");
     }
 
     &.c2 {
-      background-image: url("../../../assets/index/teachers.png");
+      background-image: url("../../../../assets/index/teachers.png");
     }
 
     &.c3 {
-      background-image: url("../../../assets/index/students.png");
+      background-image: url("../../../../assets/index/students.png");
     }
 
     &.c4 {
-      background-image: url("../../../assets/index/equipments.png");
+      background-image: url("../../../../assets/index/equipments.png");
     }
 
     &.c5 {
-      background-image: url("../../../assets/index/trainings.png");
+      background-image: url("../../../../assets/index/trainings.png");
     }
 
     span {

+ 11 - 11
src/views/dashboard/example.vue → src/views/customer/dashboard/example.vue

@@ -9,7 +9,7 @@ defineOptions({
   <div class="example-container">
     <div class="example">
       <div class="title">
-        <img src="../../assets/example/huiwen.png" alt="慧文幼儿园" />
+        <img src="../../../assets/example/huiwen.png" alt="慧文幼儿园" />
         <span>示例学校:深圳市福田区慧文幼儿园</span>
       </div>
       <div class="content">
@@ -20,7 +20,7 @@ defineOptions({
         <p>
           上课形式:前三个环节组织集体上课训练,第四环节【脑电生物反馈】,会将小朋友分成2组,一组进行脑电反馈训练,另一组由助教老师组织进行【学习迁移训练】;约10分钟后交换。
         </p>
-        <img src="../../assets/example/hw01.jpg" alt="慧文幼儿园案例" />
+        <img src="../../../assets/example/hw01.jpg" alt="慧文幼儿园案例" />
       </div>
       <div class="result-title">
         <el-row class="box-card">
@@ -51,7 +51,7 @@ defineOptions({
         <el-col :xs="24" :span="8">
           <div class="charts-item">
             <p class="title">学员专注力平均值整体对比分析</p>
-            <img src="../../assets/example/hw-c1.png" alt="" />
+            <img src="../../../assets/example/hw-c1.png" alt="" />
           </div>
         </el-col>
         <el-col :xs="24" :span="16">
@@ -60,12 +60,12 @@ defineOptions({
             <el-row justify="space-between">
               <el-col :xs="24" :span="12">
                 <div class="bar">
-                  <img src="../../assets/example/hw-c2.png" alt="" />
+                  <img src="../../../assets/example/hw-c2.png" alt="" />
                 </div>
               </el-col>
               <el-col :xs="24" :span="12">
                 <div class="bar">
-                  <img src="../../assets/example/hw-c3.png" alt="" />
+                  <img src="../../../assets/example/hw-c3.png" alt="" />
                 </div>
               </el-col>
             </el-row>
@@ -75,7 +75,7 @@ defineOptions({
     </div>
     <div class="example">
       <div class="title">
-        <img src="../../assets/example/shisha.png" alt="石厦幼儿园" />
+        <img src="../../../assets/example/shisha.png" alt="石厦幼儿园" />
         <span>示例学校:深圳市福田区石厦幼儿园</span>
       </div>
       <div class="content">
@@ -86,8 +86,8 @@ defineOptions({
         <p>
           上课形式:老师按照以下规则整体组织小朋友完成所有流程训练,【脑电生物反馈】训练不分组,没有用到教具的学生被要求在旁安静等待观摩。将【学习迁移训练】布置为家长作业任务课后完成,由家长在群内提交作业。
         </p>
-        <img src="../../assets/example/sx01.png" alt="石厦幼儿园案例" />
-        <img src="../../assets/example/sx02.png" alt="石厦幼儿园案例" />
+        <img src="../../../assets/example/sx01.png" alt="石厦幼儿园案例" />
+        <img src="../../../assets/example/sx02.png" alt="石厦幼儿园案例" />
       </div>
       <div class="result-title">
         <el-row class="box-card">
@@ -118,7 +118,7 @@ defineOptions({
         <el-col :xs="24" :span="8">
           <div class="charts-item">
             <p class="title">学员专注力平均值整体对比分析</p>
-            <img src="../../assets/example/sx-c1.png" alt="" />
+            <img src="../../../assets/example/sx-c1.png" alt="" />
           </div>
         </el-col>
         <el-col :xs="24" :span="16">
@@ -127,12 +127,12 @@ defineOptions({
             <el-row justify="space-between">
               <el-col :xs="24" :span="12">
                 <div class="bar">
-                  <img src="../../assets/example/sx-c2.png" alt="" />
+                  <img src="../../../assets/example/sx-c2.png" alt="" />
                 </div>
               </el-col>
               <el-col :xs="24" :span="12">
                 <div class="bar">
-                  <img src="../../assets/example/sx-c3.png" alt="" />
+                  <img src="../../../assets/example/sx-c3.png" alt="" />
                 </div>
               </el-col>
             </el-row>

+ 3 - 3
src/views/dashboard/index.vue → src/views/customer/dashboard/index.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import DataCard from "@/views/dashboard/components/DataCard.vue";
+import DataCard from "@/views/customer/dashboard/components/DataCard.vue";
 import LiquidChart from "@/components/Charts/LiquidChart.vue";
 import CircleChart from "@/components/Charts/CircleChart.vue";
 import PercentBarChart from "@/components/Charts/PercentBarChart.vue";
@@ -243,7 +243,7 @@ watch(
           <!--            <p>您的学校还没有任何训练数据!</p>-->
           <!--          </div>-->
           <div class="empty">
-            <img src="../../assets/empty.png" alt="数据为空" />
+            <img src="../../../assets/empty.png" alt="数据为空" />
             <p>{{ chartMessage }}</p>
           </div>
         </div>
@@ -262,7 +262,7 @@ watch(
           <!--            <p>您的学校还没有任何训练数据!</p>-->
           <!--          </div>-->
           <div class="empty">
-            <img src="../../assets/empty.png" alt="数据为空" />
+            <img src="../../../assets/empty.png" alt="数据为空" />
             <p>{{ chartMessage }}</p>
           </div>
         </div>

+ 9 - 9
src/views/equipment/index.vue → src/views/customer/equipment/index.vue

@@ -352,7 +352,7 @@ onMounted(() => {
     </template>
     <template v-else>
       <div class="empty">
-        <img src="../../assets/empty.png" alt="数据为空" />
+        <img src="../../../assets/empty.png" alt="数据为空" />
         <p>{{ dataMessage }}</p>
       </div>
     </template>
@@ -463,35 +463,35 @@ onMounted(() => {
         margin: 0 auto;
 
         &.nj {
-          background: url("../../assets/equipment/NJ.png") center center no-repeat;
+          background: url("../../../assets/equipment/NJ.png") center center no-repeat;
         }
 
         &.sw {
-          background: url("../../assets/equipment/SW.png") center center no-repeat;
+          background: url("../../../assets/equipment/SW.png") center center no-repeat;
         }
 
         &.kl {
-          background: url("../../assets/equipment/KL.png") center center no-repeat;
+          background: url("../../../assets/equipment/KL.png") center center no-repeat;
         }
 
         &.suv {
-          background: url("../../assets/equipment/SUV.png") center center no-repeat;
+          background: url("../../../assets/equipment/SUV.png") center center no-repeat;
         }
 
         &.ufo {
-          background: url("../../assets/equipment/UFO.png") center center no-repeat;
+          background: url("../../../assets/equipment/UFO.png") center center no-repeat;
         }
 
         &.ppc {
-          background: url("../../assets/equipment/PPC.png") center center no-repeat;
+          background: url("../../../assets/equipment/PPC.png") center center no-repeat;
         }
 
         &.sc {
-          background: url("../../assets/equipment/SC.png") center center no-repeat;
+          background: url("../../../assets/equipment/SC.png") center center no-repeat;
         }
 
         &.jm {
-          background: url("../../assets/equipment/JM.png") center center no-repeat;
+          background: url("../../../assets/equipment/JM.png") center center no-repeat;
         }
       }
     }

+ 3 - 3
src/views/evaluation/components/EvaluateCard.vue → src/views/customer/evaluation/components/EvaluateCard.vue

@@ -83,7 +83,7 @@ watchEffect(() => {
   }
 
   &.c1 {
-    background: #fef6e9 url("../../../assets/evaluate/student.png") 90% 50% no-repeat;
+    background: #fef6e9 url("../../../../assets/evaluate/student.png") 90% 50% no-repeat;
 
     span.n {
       color: #e08e0a;
@@ -91,7 +91,7 @@ watchEffect(() => {
   }
 
   &.c2 {
-    background: #feeeee url("../../../assets/evaluate/focus.png") 90% 50% no-repeat;
+    background: #feeeee url("../../../../assets/evaluate/focus.png") 90% 50% no-repeat;
 
     span.n {
       color: #ca7676;
@@ -99,7 +99,7 @@ watchEffect(() => {
   }
 
   &.c3 {
-    background: #d0f6f1 url("../../../assets/evaluate/training.png") 90% 50% no-repeat;
+    background: #d0f6f1 url("../../../../assets/evaluate/training.png") 90% 50% no-repeat;
 
     span.n {
       color: #45a498;

+ 4 - 4
src/views/evaluation/index.vue → src/views/customer/evaluation/index.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import EvaluateCard from "@/views/evaluation/components/EvaluateCard.vue";
+import EvaluateCard from "@/views/customer/evaluation/components/EvaluateCard.vue";
 import RadarChart from "@/components/Charts/RadarChart.vue";
 import FocusBarChart from "@/components/Charts/FocusBarChart.vue";
 import RelaxBarChart from "@/components/Charts/RelaxBarChart.vue";
@@ -198,7 +198,7 @@ onMounted(() => {
               class="scroll-item"
               :class="{active: item.id === studentActive}"
               @click="changeStudent(item.id)">
-              <img src="../../assets/evaluate/default.png" alt="头像" />
+              <img src="../../../assets/evaluate/default.png" alt="头像" />
               <p>{{ item.name }}</p>
               <p>{{ item.phone }}</p>
             </div>
@@ -206,7 +206,7 @@ onMounted(() => {
         </div>
         <div v-else class="result">
           <div class="empty">
-            <img src="../../assets/empty.png" alt="数据为空" />
+            <img src="../../../assets/empty.png" alt="数据为空" />
             <p>没有符合搜索条件的记录!</p>
           </div>
         </div>
@@ -310,7 +310,7 @@ onMounted(() => {
       </div>
     </div>
     <div v-else class="evaluate-chart empty">
-      <img src="../../assets/empty.png" alt="数据为空" />
+      <img src="../../../assets/empty.png" alt="数据为空" />
       <p>{{ studentMessage }}</p>
     </div>
   </div>

+ 3 - 2
src/views/grade/index.vue → src/views/customer/grade/index.vue

@@ -1,4 +1,5 @@
 <script setup lang="ts">
+import {CaretBottom} from "@element-plus/icons-vue";
 import {useUserStore} from "@/store/modules/user";
 
 import {getGradeList, getGradeStudents} from "@/api/grade";
@@ -108,7 +109,7 @@ onMounted(() => {
                 <template #empty>
                   <div v-if="grade.count > 0">...</div>
                   <div v-else class="empty">
-                    <img src="../../assets/empty.png" alt="数据为空" />
+                    <img src="../../../assets/empty.png" alt="数据为空" />
                     <p>该班级还未绑定任何学生!</p>
                   </div>
                 </template>
@@ -120,7 +121,7 @@ onMounted(() => {
     </template>
     <template v-else>
       <div class="empty page-empty">
-        <img src="../../assets/empty.png" alt="数据为空" />
+        <img src="../../../assets/empty.png" alt="数据为空" />
         <p v-if="dataStatus == 0">加载中...</p>
         <template v-if="dataStatus == 2">
           <p v-if="gradeType == 0">您的学校还未创建任何班级!</p>

+ 1 - 1
src/views/student/download.vue → src/views/customer/student/download.vue

@@ -522,7 +522,7 @@ const downloadHandle = (name: string) => {
         width: 162px;
         height: 24px;
         margin: 10px auto;
-        background: url("../../assets/student/stars.png") no-repeat;
+        background: url("../../../assets/student/stars.png") no-repeat;
         background-position-x: 0;
 
         &.s1 {

+ 1 - 1
src/views/student/index.vue → src/views/customer/student/index.vue

@@ -123,7 +123,7 @@ onMounted(() => {
         <!-- 无数据插槽 -->
         <template #empty>
           <div class="empty">
-            <img src="../../assets/empty.png" alt="数据为空" />
+            <img src="../../../assets/empty.png" alt="数据为空" />
             <p>{{ dataMessage }}</p>
           </div>
         </template>

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

@@ -504,7 +504,7 @@ onMounted(() => {
         width: 162px;
         height: 24px;
         margin: 10px auto;
-        background: url("../../assets/student/stars.png") no-repeat;
+        background: url("../../../assets/student/stars.png") no-repeat;
         background-position-x: 0;
 
         &.s1 {

+ 2 - 2
src/views/teacher/index.vue → src/views/customer/teacher/index.vue

@@ -1,6 +1,6 @@
 <script setup lang="ts">
+import {CaretBottom} from "@element-plus/icons-vue";
 import {useUserStore} from "@/store/modules/user";
-
 import {getTeacherEquipment, getTeacherGrade, getTeacherManage} from "@/api/teacher";
 import {TeacherItem} from "@/api/teacher/types";
 import {trimInput} from "@/utils";
@@ -176,7 +176,7 @@ onMounted(() => {
     </template>
     <template v-else>
       <div class="empty page-empty">
-        <img src="../../assets/empty.png" alt="数据为空" />
+        <img src="../../../assets/empty.png" alt="数据为空" />
         <p>{{ dataMessage }}</p>
       </div>
     </template>

+ 1 - 1
src/views/training/index.vue → src/views/customer/training/index.vue

@@ -146,7 +146,7 @@ onMounted(() => {
         <!-- 无数据插槽 -->
         <template #empty>
           <div class="empty">
-            <img src="../../assets/empty.png" alt="数据为空" />
+            <img src="../../../assets/empty.png" alt="数据为空" />
             <p>{{ dataMessage }}</p>
           </div>
         </template>

+ 3 - 3
src/views/training/result.vue → src/views/customer/training/result.vue

@@ -332,7 +332,7 @@ onMounted(() => {
   </div>
   <div v-else class="result-container">
     <div class="empty">
-      <img src="../../assets/empty.png" alt="数据为空" />
+      <img src="../../../assets/empty.png" alt="数据为空" />
       <p>{{ dataMessage }}</p>
     </div>
   </div>
@@ -360,7 +360,7 @@ onMounted(() => {
 
       .head {
         padding-left: 70px;
-        background: url("../../assets/student/head.png") left center no-repeat;
+        background: url("../../../assets/student/head.png") left center no-repeat;
       }
     }
 
@@ -451,7 +451,7 @@ onMounted(() => {
         width: 162px;
         height: 24px;
         margin: 10px 0;
-        background: url("../../assets/student/stars.png") no-repeat;
+        background: url("../../../assets/student/stars.png") no-repeat;
         background-position-x: 0;
 
         &.s1 {

+ 0 - 17
vite.config.ts

@@ -1,24 +1,15 @@
 import vue from "@vitejs/plugin-vue";
-
 import {UserConfig, ConfigEnv, loadEnv, defineConfig} from "vite";
-
 import AutoImport from "unplugin-auto-import/vite";
 import Components from "unplugin-vue-components/vite";
 import {ElementPlusResolver} from "unplugin-vue-components/resolvers";
-
 import Icons from "unplugin-icons/vite";
 import IconsResolver from "unplugin-icons/resolver";
-
 import {createSvgIconsPlugin} from "vite-plugin-svg-icons";
-
-import {viteMockServe} from "vite-plugin-mock";
 import visualizer from "rollup-plugin-visualizer";
-
 import UnoCSS from "unocss/vite";
 import path from "path";
-
 import viteCompression from "vite-plugin-compression";
-
 const pathSrc = path.resolve(__dirname, "src");
 
 export default defineConfig(({mode}: ConfigEnv): UserConfig => {
@@ -115,14 +106,6 @@ export default defineConfig(({mode}: ConfigEnv): UserConfig => {
         algorithm: "gzip", // 压缩算法
         ext: ".gz", // 文件类型
       }),
-
-      viteMockServe({
-        ignore: /^\_/,
-        mockPath: "mock",
-        enable: mode === "development",
-        // https://github.com/anncwb/vite-plugin-mock/issues/9
-      }),
-
       visualizer({
         filename: "./stats.html",
         open: false,