فهرست منبع

build: 初始化项目及看板首页框架

chaooo 2 سال پیش
والد
کامیت
6d6bd58694

+ 5 - 6
package.json

@@ -28,11 +28,9 @@
     ],
     "*.{vue,html}": [
       "eslint --fix",
-      "prettier --write",
-      "stylelint --fix"
+      "prettier --write"
     ],
     "*.{scss,css}": [
-      "stylelint --fix",
       "prettier --write"
     ],
     "*.md": [
@@ -48,6 +46,7 @@
     "axios": "^1.4.0",
     "codemirror": "^5.65.13",
     "echarts": "^5.2.2",
+    "echarts-liquidfill": "^3.1.0",
     "element-plus": "^2.3.6",
     "lodash-es": "^4.17.21",
     "nprogress": "^0.2.0",
@@ -95,11 +94,11 @@
     "unplugin-auto-import": "^0.15.3",
     "unplugin-icons": "^0.16.1",
     "unplugin-vue-components": "^0.24.1",
-    "vite": "^4.3.5",
+    "vite": "4.3.9",
     "vite-plugin-svg-icons": "^2.0.1",
     "vue-tsc": "^1.6.5 "
   },
-  "repository": "https://gitee.com/youlaiorg/vue3-element-admin.git",
-  "author": "有来开源组织",
+  "repository": "http://120.78.146.64:3000/shuimuai/shuimu-dashboard-h5/src/developer",
+  "author": "索隆",
   "license": "MIT"
 }

+ 49 - 41
src/layout/components/Navbar.vue

@@ -4,17 +4,15 @@ import { useRoute, useRouter } from "vue-router";
 import { useAppStore } from "@/store/modules/app";
 import { useTagsViewStore } from "@/store/modules/tagsView";
 import { useUserStore } from "@/store/modules/user";
-import {SchoolList} from "@/api/school/types";
-import {getSchoolList} from "@/api/school";
-import {watch} from "vue";
+import { SchoolList } from "@/api/school/types";
+import { getSchoolList } from "@/api/school";
+import { watch } from "vue";
 
 const appStore = useAppStore();
 const tagsViewStore = useTagsViewStore();
 const userStore = useUserStore();
-
 const route = useRoute();
 const router = useRouter();
-
 const { device } = storeToRefs(appStore); // 设备类型:desktop-宽屏设备 || mobile-窄屏设备
 
 /**
@@ -23,12 +21,10 @@ const { device } = storeToRefs(appStore); // 设备类型:desktop-宽屏设备
 function toggleSideBar() {
   appStore.toggleSidebar(true);
 }
-
 /**
  * vueUse 全屏
  */
 const { isFullscreen, toggle } = useFullscreen();
-
 /**
  * 注销
  */
@@ -51,29 +47,36 @@ function logout() {
 /**
  * 学校数据
  */
-const schoolData = ref<SchoolList[]>([{
-	school_id: 1,
-	name: "全部学校",
-},{
-	school_id: 2,
-	name: "全部学校2",
-}]);
+const schoolData = ref<SchoolList[]>([
+  {
+    school_id: 1,
+    name: "全部学校",
+  },
+  {
+    school_id: 2,
+    name: "全部学校2",
+  },
+]);
 const schoolNumber = ref(0);
 function querySchoolList() {
-	getSchoolList().then(({ data }) => {
-	  schoolData.value.concat(data);
-	}).catch(error => {
-		console.log(error)
-	});
+  getSchoolList()
+    .then(({ data }) => {
+      schoolData.value.concat(data);
+    })
+    .catch((error) => {
+      console.log(error);
+    });
 }
 onMounted(() => {
-	// querySchoolList();
-	// changeSchool();
+  // querySchoolList();
 });
-watch(() => schoolNumber.value, (newValue, oldValue) => {
-	//console.log("NAV-watch", newValue, oldValue);
-	userStore.changeSchool(schoolNumber.value);
-})
+watch(
+  () => schoolNumber.value,
+  (newValue, oldValue) => {
+    console.log("schoolNumber", newValue, oldValue);
+    userStore.changeSchool(schoolNumber.value);
+  }
+);
 </script>
 
 <template>
@@ -81,19 +84,23 @@ watch(() => schoolNumber.value, (newValue, oldValue) => {
   <div class="navbar">
     <!-- 左侧面包屑 -->
     <div class="flex">
-      <hamburger :is-active="appStore.sidebar.opened" @toggle-click="toggleSideBar" />
+      <hamburger
+        :is-active="appStore.sidebar.opened"
+        @toggle-click="toggleSideBar"
+      />
       <breadcrumb />
     </div>
-		<div class="flex">
-		  <el-select v-model="schoolNumber" class="m-2" placeholder="全部学校">
-			  <el-option
-					  v-for="item in schoolData"
-					  :key="item.school_id"
-					  :label="item.name"
-					  :value="item.school_id"
-			  />
-		  </el-select>
-		</div>
+    <!-- 学校选择下拉框 -->
+    <div class="flex">
+      <el-select v-model="schoolNumber" class="m-2" placeholder="全部学校">
+        <el-option
+          v-for="item in schoolData"
+          :key="item.school_id"
+          :label="item.name"
+          :value="item.school_id"
+        />
+      </el-select>
+    </div>
     <!-- 右侧导航设置 -->
     <div class="flex">
       <!-- 导航栏设置(窄屏隐藏)-->
@@ -109,13 +116,12 @@ watch(() => schoolNumber.value, (newValue, oldValue) => {
           <size-select class="setting-item" />
         </el-tooltip>
       </div>
-
       <!-- 用户头像 -->
       <el-dropdown trigger="click">
         <div class="avatar-container">
-					<span class="ml-[10px] text-[16px]">
-						{{ userStore.nickname }}
-					</span>
+          <span class="ml-[10px] text-[16px]">
+            {{ userStore.nickname }}
+          </span>
           <img :src="userStore.avatar + '?imageView2/1/w/80/h/80'" />
           <i-ep-caret-bottom class="w-3 h-3" />
         </div>
@@ -124,7 +130,9 @@ watch(() => schoolNumber.value, (newValue, oldValue) => {
             <router-link to="/">
               <el-dropdown-item>首页</el-dropdown-item>
             </router-link>
-            <el-dropdown-item divided @click="logout">退出登录</el-dropdown-item>
+            <el-dropdown-item divided @click="logout"
+              >退出登录</el-dropdown-item
+            >
           </el-dropdown-menu>
         </template>
       </el-dropdown>

+ 5 - 5
src/store/modules/permission.ts

@@ -13,11 +13,11 @@ const schoolRoutes: RouteRecordRaw[] = JSON.parse(
     {
       path: "/",
       component: "AdminIndex",
-      redirect: "/area",
+      redirect: "/areaboard",
       children: [
         {
-          path: "area",
-          component: "area/index",
+          path: "areaboard",
+          component: "areaboard",
           meta: { title: "区域级数据看板", icon: "homepage", keepAlive: true },
         },
       ],
@@ -63,8 +63,8 @@ const adminRoutes: RouteRecordRaw[] = JSON.parse(
           meta: { title: "训练管理", icon: "menu", keepAlive: true },
         },
         {
-          path: "board",
-          component: "board",
+          path: "evaluation",
+          component: "evaluation",
           meta: { title: "测评数据看板", icon: "menu", keepAlive: true },
         },
       ],

+ 4 - 10
src/views/area/index.vue → src/views/areaboard/index.vue

@@ -1,20 +1,14 @@
 <!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
 <script lang="ts">
 export default {
-	name: "",
+  name: "",
 };
 </script>
 
-<script setup lang="ts">
-
-</script>
+<script setup lang="ts"></script>
 
 <template>
-	<div class="container">
-
-	</div>
+  <div class="container"></div>
 </template>
 
-<style lang="scss" scoped>
-
-</style>
+<style lang="scss" scoped></style>

+ 0 - 20
src/views/board/index.vue

@@ -1,20 +0,0 @@
-<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
-<script lang="ts">
-export default {
-	name: "",
-};
-</script>
-
-<script setup lang="ts">
-
-</script>
-
-<template>
-	<div class="container">
-	<h1>测评数据看板</h1>
-	</div>
-</template>
-
-<style lang="scss" scoped>
-
-</style>

+ 17 - 29
src/views/class/index.vue

@@ -1,36 +1,24 @@
-<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
-<script lang="ts">
-
-// export default {
-// 	name: "",
-// 	data() {
-// 		return {
-//
-// 		}
-// 	},
-// 	mounted() {
-//
-// 	}
-// };
-</script>
-
 <script setup lang="ts">
-//import { watch } from 'vue';
-import {useUserStore} from "@/store/modules/user";
+defineOptions({
+  name: "ClassManage",
+  inheritAttrs: false,
+});
+import { watch } from "vue";
+import { useUserStore } from "@/store/modules/user";
 const userStore = useUserStore();
-
-// watch(() => userStore.schoolId, (newValue, oldValue) => {
-// 	console.log(newValue, oldValue);
-// })
+watch(
+  () => userStore.schoolId,
+  (newValue, oldValue) => {
+    console.log(newValue, oldValue);
+  }
+);
 </script>
 
 <template>
-	<div class="container">
-		<h1>班级管理</h1>
-<div>{{userStore.schoolId}}</div>
-	</div>
+  <div class="container">
+    <h1>班级管理</h1>
+    <div>{{ userStore.schoolId }}</div>
+  </div>
 </template>
 
-<style lang="scss" scoped>
-
-</style>
+<style lang="scss" scoped></style>

+ 0 - 146
src/views/dashboard/components/BarChart.vue

@@ -1,146 +0,0 @@
-<!--  线 + 柱混合图 -->
-<template>
-  <el-card>
-    <template #header> 业绩柱状图 </template>
-    <div :id="id" :class="className" :style="{ height, width }" />
-  </el-card>
-</template>
-
-<script setup lang="ts">
-import * as echarts from 'echarts';
-
-const props = defineProps({
-  id: {
-    type: String,
-    default: 'barChart'
-  },
-  className: {
-    type: String,
-    default: ''
-  },
-  width: {
-    type: String,
-    default: '200px',
-    required: true
-  },
-  height: {
-    type: String,
-    default: '200px',
-    required: true
-  }
-});
-
-const options = {
-  grid: {
-    left: '2%',
-    right: '2%',
-    bottom: '10%',
-    containLabel: true
-  },
-  tooltip: {
-    trigger: 'axis',
-    axisPointer: {
-      type: 'cross',
-      crossStyle: {
-        color: '#999'
-      }
-    }
-  },
-  legend: {
-    x: 'center',
-    y: 'bottom',
-    data: ['收入', '毛利润', '收入增长率', '利润增长率'],
-    textStyle: {
-      color: '#999'
-    }
-  },
-  xAxis: [
-    {
-      type: 'category',
-      data: ['浙江', '北京', '上海', '广东', '深圳'],
-      axisPointer: {
-        type: 'shadow'
-      }
-    }
-  ],
-  yAxis: [
-    {
-      type: 'value',
-      min: 0,
-      max: 10000,
-      interval: 2000,
-      axisLabel: {
-        formatter: '{value} '
-      }
-    },
-    {
-      type: 'value',
-      min: 0,
-      max: 100,
-      interval: 20,
-      axisLabel: {
-        formatter: '{value}%'
-      }
-    }
-  ],
-  series: [
-    {
-      name: '收入',
-      type: 'bar',
-      data: [7000, 7100, 7200, 7300, 7400],
-      barWidth: 20,
-      itemStyle: {
-        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-          { offset: 0, color: '#83bff6' },
-          { offset: 0.5, color: '#188df0' },
-          { offset: 1, color: '#188df0' }
-        ])
-      }
-    },
-    {
-      name: '毛利润',
-      type: 'bar',
-      data: [8000, 8200, 8400, 8600, 8800],
-      barWidth: 20,
-      itemStyle: {
-        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-          { offset: 0, color: '#25d73c' },
-          { offset: 0.5, color: '#1bc23d' },
-          { offset: 1, color: '#179e61' }
-        ])
-      }
-    },
-    {
-      name: '收入增长率',
-      type: 'line',
-      yAxisIndex: 1,
-      data: [60, 65, 70, 75, 80],
-      itemStyle: {
-        color: '#67C23A'
-      }
-    },
-    {
-      name: '利润增长率',
-      type: 'line',
-      yAxisIndex: 1,
-      data: [70, 75, 80, 85, 90],
-      itemStyle: {
-        color: '#409EFF'
-      }
-    }
-  ]
-};
-
-onMounted(() => {
-  // 图表初始化
-  const chart = echarts.init(
-    document.getElementById(props.id) as HTMLDivElement
-  );
-  chart.setOption(options);
-
-  // 大小自适应
-  window.addEventListener('resize', () => {
-    chart.resize();
-  });
-});
-</script>

+ 135 - 0
src/views/dashboard/components/CircleChart.vue

@@ -0,0 +1,135 @@
+<!-- 圆形进度图 -->
+<template>
+  <div :id="id" :class="className" :style="{ height, width }" />
+</template>
+
+<script setup lang="ts">
+import * as echarts from "echarts";
+
+const props = defineProps({
+  id: {
+    type: String,
+    default: "funnelChart",
+  },
+  data: {
+    type: Number,
+    default: 0,
+  },
+  className: {
+    type: String,
+    default: "",
+  },
+  width: {
+    type: String,
+    default: "200px",
+    required: true,
+  },
+  height: {
+    type: String,
+    default: "200px",
+    required: true,
+  },
+  color: {
+    type: String,
+    default: "#2f539b",
+    required: true,
+  },
+  bgColor: {
+    type: String,
+    default: "#e6e8f9",
+    required: true,
+  },
+});
+
+const options = {
+  animation: true,
+  title: {
+    show: true,
+    text: props.data,
+    x: "center",
+    y: "center",
+    textStyle: {
+      fontSize: "30",
+      // fontWeight: 'normal',
+      color: props.color,
+    },
+  },
+  series: [
+    {
+      type: "gauge", // 仪表盘图
+      startAngle: 90,
+      endAngle: -270,
+      min: 0,
+      max: 1,
+      radius: "90%",
+      center: ["50%", "50%"],
+      progress: {
+        // 进度环
+        roundCap: "true",
+        show: true,
+        width: 20,
+        itemStyle: {
+          color: props.color,
+          // color: {
+          // 	type: 'linear',
+          // 	x:0, y: 0, x2: 0, y2: 1,
+          // 	colorStops: [{ //进度环的渐变色
+          // 		offset: 0, color: '#2ce385' // 0% 处的颜色
+          // 	}, {
+          // 		offset: 1, color: '#00b056' // 100% 处的颜色
+          // 	}]
+          // }
+        },
+      },
+      axisLine: {
+        // 背景环
+        roundCap: "true",
+        lineStyle: {
+          width: 20,
+          color: [
+            [0, props.bgColor],
+            [1, props.bgColor],
+          ],
+        },
+      },
+      avoidLabelOverlap: true,
+      hoverAnimation: false,
+      label: {
+        normal: {
+          show: false,
+          position: "center",
+        },
+        emphasis: {
+          show: false,
+        },
+      },
+      labelLine: {
+        normal: {
+          show: false,
+        },
+      },
+      pointer: { show: false },
+      axisTick: { show: false },
+      splitLine: { show: false },
+      axisLabel: { show: false },
+      detail: { show: false },
+      data: [
+        {
+          value: props.data / 100, // 进度值,最高为1
+        },
+      ],
+    },
+  ],
+};
+
+onMounted(() => {
+  const chart = echarts.init(
+    document.getElementById(<string>props.id) as HTMLDivElement
+  );
+  chart.setOption(options);
+
+  window.addEventListener("resize", () => {
+    chart.resize();
+  });
+});
+</script>

+ 126 - 0
src/views/dashboard/components/DataCard.vue

@@ -0,0 +1,126 @@
+<!-- 数据卡片 -->
+<script setup lang="ts">
+import SvgIcon from "@/components/SvgIcon/index.vue";
+const props = defineProps({
+  classes: {
+    type: Number,
+    default: 0,
+    required: true,
+  },
+  teachers: {
+    type: Number,
+    default: 0,
+    required: true,
+  },
+  students: {
+    type: Number,
+    default: 0,
+    required: true,
+  },
+  equipments: {
+    type: Number,
+    default: 0,
+    required: true,
+  },
+  trainings: {
+    type: Number,
+    default: 0,
+    required: true,
+  },
+});
+</script>
+<template>
+  <el-row :gutter="40" class="mb-4">
+    <el-col :xs="24" :sm="8" :lg="5" class="mb-4">
+      <div class="data-box">
+        <div
+          class="text-[#40c9c6] hover:!text-white hover:bg-[#40c9c6] p-3 rounded"
+        >
+          <svg-icon icon-class="uv" size="3em" />
+        </div>
+        <div class="flex flex-col space-y-3">
+          <div class="text-[var(--el-text-color-secondary)]">全部班级</div>
+          <div class="text-lg">{{ Math.round(classes) }}</div>
+        </div>
+      </div>
+    </el-col>
+    <el-col :xs="24" :sm="8" :lg="5" class="mb-4">
+      <div class="data-box">
+        <div
+          class="text-[#40c9c6] hover:!text-white hover:bg-[#40c9c6] p-3 rounded"
+        >
+          <svg-icon icon-class="uv" size="3em" />
+        </div>
+        <div class="flex flex-col space-y-3">
+          <div class="text-[var(--el-text-color-secondary)]">全部教师</div>
+          <div class="text-lg">{{ Math.round(teachers) }}</div>
+        </div>
+      </div>
+    </el-col>
+    <el-col :xs="24" :sm="8" :lg="5" class="mb-4">
+      <div class="data-box">
+        <div
+          class="text-[#40c9c6] hover:!text-white hover:bg-[#40c9c6] p-3 rounded"
+        >
+          <svg-icon icon-class="uv" size="3em" />
+        </div>
+        <div class="flex flex-col space-y-3">
+          <div class="text-[var(--el-text-color-secondary)]">全部学生</div>
+          <div class="text-lg">{{ Math.round(students) }}</div>
+        </div>
+      </div>
+    </el-col>
+    <el-col :xs="24" :sm="8" :lg="5" class="mb-4">
+      <div class="data-box">
+        <div
+          class="text-[#36a3f7] hover:!text-white hover:bg-[#36a3f7] p-3 rounded"
+        >
+          <svg-icon icon-class="message" size="3em" />
+        </div>
+        <div class="flex flex-col space-y-3">
+          <div class="text-[var(--el-text-color-secondary)]">设备套数</div>
+          <div class="text-lg">
+            {{ Math.round(equipments) }}
+          </div>
+        </div>
+      </div>
+    </el-col>
+    <el-col :xs="24" :sm="8" :lg="5" class="mb-4">
+      <div class="data-box">
+        <div
+          class="text-[#f4516c] hover:!text-white hover:bg-[#f4516c] p-3 rounded"
+        >
+          <svg-icon icon-class="money" size="3em" />
+        </div>
+        <div class="flex flex-col space-y-3">
+          <div class="text-[var(--el-text-color-secondary)]">累计训练次数</div>
+          <div class="text-lg">
+            {{ Math.round(trainings) }}
+          </div>
+        </div>
+      </div>
+    </el-col>
+  </el-row>
+</template>
+<style lang="scss" scoped>
+@media only screen and (min-width: 1200px) {
+  .el-col-lg-5 {
+    display: block;
+    max-width: 20%;
+    flex: 0 0 20%;
+  }
+}
+.data-box {
+  display: flex;
+  justify-content: space-between;
+  padding: 20px;
+  font-weight: bold;
+  color: var(--el-text-color-regular);
+  background: var(--el-bg-color-overlay);
+  border-color: var(--el-border-color);
+  box-shadow: var(--el-box-shadow-dark);
+}
+.svg-icon {
+  fill: currentcolor !important;
+}
+</style>

+ 23 - 0
src/views/dashboard/components/ExampleDialog.vue

@@ -0,0 +1,23 @@
+<!-- 优秀教学效果示例弹出层 -->
+<template>
+  <div>
+    <div>
+      <h6>示例学校:深圳市福田区惠文幼儿园</h6>
+      <el-image src="" fit="contain" />
+      <p>样本描述:样本数量,课时,课上教师规模。</p>
+      <p>
+        教学场景和特色:文字描述该校教学方式,课时,服务时长,课上教师规模,训练方法,训练效果等
+      </p>
+    </div>
+    <div>
+      <h6>示例学校:深圳市福田区石厦幼儿园</h6>
+      <el-image src="" fit="contain" />
+      <p>样本描述:样本数量,课时,课上教师规模。</p>
+      <p>
+        教学场景和特色:文字描述该校教学方式,课时,服务时长,课上教师规模,训练方法,训练效果等
+      </p>
+    </div>
+  </div>
+</template>
+<script setup></script>
+<style lang="scss" scoped></style>

+ 0 - 106
src/views/dashboard/components/FunnelChart.vue

@@ -1,106 +0,0 @@
-<!-- 漏斗图 -->
-<template>
-  <div :id="id" :class="className" :style="{ height, width }" />
-</template>
-
-<script setup lang="ts">
-import * as echarts from 'echarts';
-
-const props = defineProps({
-  id: {
-    type: String,
-    default: 'funnelChart'
-  },
-  className: {
-    type: String,
-    default: ''
-  },
-  width: {
-    type: String,
-    default: '200px',
-    required: true
-  },
-  height: {
-    type: String,
-    default: '200px',
-    required: true
-  }
-});
-
-const options = {
-  title: {
-    show: true,
-    text: '订单线索转化漏斗图',
-    x: 'center',
-    padding: 15,
-    textStyle: {
-      fontSize: 18,
-      fontStyle: 'normal',
-      fontWeight: 'bold',
-      color: '#337ecc'
-    }
-  },
-  grid: {
-    left: '2%',
-    right: '2%',
-    bottom: '10%',
-    containLabel: true
-  },
-  legend: {
-    x: 'center',
-    y: 'bottom',
-    data: ['Show', 'Click', 'Visit', 'Inquiry', 'Order']
-  },
-
-  series: [
-    {
-      name: 'Funnel',
-      type: 'funnel',
-      left: '20%',
-      top: 60,
-      bottom: 60,
-      width: '60%',
-      sort: 'descending',
-      gap: 2,
-      label: {
-        show: true,
-        position: 'inside'
-      },
-      labelLine: {
-        length: 10,
-        lineStyle: {
-          width: 1,
-          type: 'solid'
-        }
-      },
-      itemStyle: {
-        borderColor: '#fff',
-        borderWidth: 1
-      },
-      emphasis: {
-        label: {
-          fontSize: 20
-        }
-      },
-      data: [
-        { value: 60, name: 'Visit' },
-        { value: 40, name: 'Inquiry' },
-        { value: 20, name: 'Order' },
-        { value: 80, name: 'Click' },
-        { value: 100, name: 'Show' }
-      ]
-    }
-  ]
-};
-
-onMounted(() => {
-  const chart = echarts.init(
-    document.getElementById(props.id) as HTMLDivElement
-  );
-  chart.setOption(options);
-
-  window.addEventListener('resize', () => {
-    chart.resize();
-  });
-});
-</script>

+ 0 - 79
src/views/dashboard/components/PieChart.vue

@@ -1,79 +0,0 @@
-<!-- 饼图 -->
-<template>
-  <el-card>
-    <template #header> 产品分类饼图 </template>
-    <div :id="id" :class="className" :style="{ height, width }" />
-  </el-card>
-</template>
-
-<script setup lang="ts">
-import * as echarts from 'echarts';
-
-const props = defineProps({
-  id: {
-    type: String,
-    default: 'pieChart'
-  },
-  className: {
-    type: String,
-    default: ''
-  },
-  width: {
-    type: String,
-    default: '200px',
-    required: true
-  },
-  height: {
-    type: String,
-    default: '200px',
-    required: true
-  }
-});
-const options = {
-  grid: {
-    left: '2%',
-    right: '2%',
-    bottom: '10%',
-    containLabel: true
-  },
-  legend: {
-    top: 'bottom',
-    textStyle: {
-      color: '#999'
-    }
-  },
-  series: [
-    {
-      name: 'Nightingale Chart',
-      type: 'pie',
-      radius: [50, 130],
-      center: ['50%', '50%'],
-      roseType: 'area',
-      itemStyle: {
-        borderRadius: 1,
-        color: function (params: any) {
-          //自定义颜色
-          const colorList = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C'];
-          return colorList[params.dataIndex];
-        }
-      },
-      data: [
-        { value: 26, name: '家用电器' },
-        { value: 27, name: '户外运动' },
-        { value: 24, name: '汽车用品' },
-        { value: 23, name: '手机数码' }
-      ]
-    }
-  ]
-};
-
-onMounted(() => {
-  const chart = echarts.init(
-    document.getElementById(props.id) as HTMLDivElement
-  );
-  chart.setOption(options);
-  window.addEventListener('resize', () => {
-    chart.resize();
-  });
-});
-</script>

+ 0 - 100
src/views/dashboard/components/RadarChart.vue

@@ -1,100 +0,0 @@
-<!-- 雷达图 -->
-<template>
-  <el-card>
-    <template #header> 订单状态雷达图 </template>
-    <div :id="id" :class="className" :style="{ height, width }" />
-  </el-card>
-</template>
-
-<script setup lang="ts">
-import * as echarts from 'echarts';
-
-const props = defineProps({
-  id: {
-    type: String,
-    default: 'radarChart'
-  },
-  className: {
-    type: String,
-    default: ''
-  },
-  width: {
-    type: String,
-    default: '200px',
-    required: true
-  },
-  height: {
-    type: String,
-    default: '200px',
-    required: true
-  }
-});
-
-const options = {
-  grid: {
-    left: '2%',
-    right: '2%',
-    bottom: '10%',
-    containLabel: true
-  },
-  legend: {
-    x: 'center',
-    y: 'bottom',
-    data: ['预定数量', '下单数量', '发货数量'],
-    textStyle: {
-      color: '#999'
-    }
-  },
-  radar: {
-    // shape: 'circle',
-    radius: '60%',
-    indicator: [
-      { name: '家用电器' },
-      { name: '服装箱包' },
-      { name: '运动户外' },
-      { name: '手机数码' },
-      { name: '汽车用品' },
-      { name: '家具厨具' }
-    ]
-  },
-  series: [
-    {
-      name: 'Budget vs spending',
-      type: 'radar',
-      itemStyle: {
-        borderRadius: 6,
-        color: function (params: any) {
-          //自定义颜色
-          const colorList = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C'];
-          return colorList[params.dataIndex];
-        }
-      },
-      data: [
-        {
-          value: [400, 400, 400, 400, 400, 400],
-          name: '预定数量'
-        },
-        {
-          value: [300, 300, 300, 300, 300, 300],
-          name: '下单数量'
-        },
-        {
-          value: [200, 200, 200, 200, 200, 200],
-          name: '发货数量'
-        }
-      ]
-    }
-  ]
-};
-
-onMounted(() => {
-  const chart = echarts.init(
-    document.getElementById(props.id) as HTMLDivElement
-  );
-  chart.setOption(options);
-
-  window.addEventListener('resize', () => {
-    chart.resize();
-  });
-});
-</script>

+ 101 - 0
src/views/dashboard/components/liquidChart.vue

@@ -0,0 +1,101 @@
+<!-- 水球图 -->
+<template>
+  <div :id="id" :class="className" :style="{ height, width }" />
+</template>
+
+<script setup lang="ts">
+import * as echarts from "echarts";
+import "echarts-liquidfill";
+
+const props = defineProps({
+  id: {
+    type: String,
+    default: "funnelChart",
+  },
+  data: {
+    type: Number,
+    default: 0,
+  },
+  className: {
+    type: String,
+    default: "",
+  },
+  width: {
+    type: String,
+    default: "200px",
+    required: true,
+  },
+  height: {
+    type: String,
+    default: "200px",
+    required: true,
+  },
+  color: {
+    type: String,
+    default: "#2f539b",
+    required: true,
+  },
+  bgColor: {
+    type: String,
+    default: "#e6e8f9",
+    required: true,
+  },
+});
+
+const options = {
+  // backgroundColor: '#ffffff',
+  // tooltip: {
+  // 	show: true
+  // },
+  series: [
+    {
+      // name: '全体学员初期专注力评估均值',
+      type: "liquidFill", // 水球图样式
+      radius: "90%",
+      center: ["50%", "50%"], // 水球图位置
+      amplitude: 5, // 波浪波动起伏大小
+      waveLength: "50%", // 波浪长度
+      color: [props.bgColor], // 波浪颜色
+      itemStyle: {
+        opacity: 1, //波浪透明度
+        shadowBlur: 0, //波浪阴影
+      },
+      backgroundStyle: {
+        backgroundColor: "#ffffff",
+        color: "#ffffff", // 内部球背景颜色
+        borderWidth: 0, // 内部球边框宽度
+        borderColor: "#ffffff", // 内部球边框颜色
+      },
+      outline: {
+        borderDistance: 5, // 外边框与内边框间的距离
+        itemStyle: {
+          borderWidth: 5, // 外边框的宽度
+          borderColor: props.color,
+        },
+      },
+      label: {
+        normal: {
+          formatter: "60", // 内部文字内容
+          textStyle: {
+            color: props.color, // 在波浪上方时的文字颜色
+            insideColor: "#ffffff", // 在波浪下方时的文字颜色
+            fontSize: 30, // 文字大小
+          },
+        },
+      },
+      data: [props.data / 100], // 水球的注满度 60%
+    },
+  ],
+};
+
+onMounted(() => {
+  const chart = echarts.init(
+    document.getElementById(<string>props.id) as HTMLDivElement
+  );
+  chart.setOption(options);
+
+  window.addEventListener("resize", () => {
+    chart.resize();
+  });
+});
+</script>

+ 105 - 169
src/views/dashboard/index.vue

@@ -1,63 +1,42 @@
 <script setup lang="ts">
-// defineOptions({
-//   // eslint-disable-next-line vue/no-reserved-component-names
-//   name: "Dashboard",
-//   inheritAttrs: false,
-// });
-import SvgIcon from "@/components/SvgIcon/index.vue";
-import BarChart from "./components/BarChart.vue";
-import PieChart from "./components/PieChart.vue";
-import RadarChart from "./components/RadarChart.vue";
-import { useTransition, TransitionPresets } from "@vueuse/core";
-import {getClassList, getSchoolList} from "@/api/school";
-import {ClassList} from "@/api/school/types";
-
-const duration = 5000;
+import DataCard from "@/views/dashboard/components/DataCard.vue";
+import ExampleDialog from "@/views/dashboard/components/ExampleDialog.vue";
+import LiquidChart from "@/views/dashboard/components/liquidChart.vue";
+import CircleChart from "@/views/dashboard/components/CircleChart.vue";
+defineOptions({
+  // eslint-disable-next-line vue/no-reserved-component-names
+  name: "Dashboard",
+  inheritAttrs: false,
+});
+import { getClassList, getSchoolList } from "@/api/school";
+import { ClassList } from "@/api/school/types";
+import { watch } from "vue";
+import { useUserStore } from "@/store/modules/user";
+const userStore = useUserStore();
+watch(
+  () => userStore.schoolId,
+  (newValue, oldValue) => {
+    console.log("userStore.schoolId", newValue, oldValue);
+    // 学校切换后重新加载数据
+  }
+);
 /**
  * 数据卡片
  */
 // 全部班级
 const classCount = ref(0);
-const classCountOutput = useTransition(classCount, {
-  duration: duration,
-  transition: TransitionPresets.easeOutExpo,
-});
-classCount.value = 2000;
-
 // 全部教师
 const teacherCount = ref(0);
-const teacherCountOutput = useTransition(teacherCount, {
-  duration: duration,
-  transition: TransitionPresets.easeOutExpo,
-});
-teacherCount.value = 2000;
-
 // 全部学生
 const studentCount = ref(0);
-const studentCountOutput = useTransition(studentCount, {
-  duration: duration,
-  transition: TransitionPresets.easeOutExpo,
-});
-studentCount.value = 2000;
-
 // 设备套数
 const equipmentCount = ref(0);
-const equipmentCountOutput = useTransition(equipmentCount, {
-  duration: duration,
-  transition: TransitionPresets.easeOutExpo,
-});
-equipmentCount.value = 2000;
-
 // 累计训练次数
 const trainingCount = ref(0);
-const trainingCountOutput = useTransition(trainingCount, {
-	duration: duration,
-	transition: TransitionPresets.easeOutExpo,
-});
-trainingCount.value = 2000;
 /**
  * 班级数据
  */
+// 班级编号
 let classNumber = ref(0);
 const classData = ref<ClassList[]>([]);
 // function queryClassList() {
@@ -65,126 +44,112 @@ const classData = ref<ClassList[]>([]);
 // 		classData.value = data;
 // 	});
 // }
+watch(
+  () => classNumber,
+  (newValue, oldValue) => {
+    console.log("userStore.schoolId", newValue, oldValue);
+    // 班级切换后重新加载班级数据
+  }
+);
 onMounted(() => {
-	//queryClassList();
+  //queryClassList();
 });
+// 优秀教学效果示例
+const dialogVisible = ref(false);
+// 学员专注力平均值整体对比分析
 </script>
 
 <template>
   <div class="dashboard-container">
     <!-- 数据卡片 -->
-    <el-row :gutter="40" class="mb-4">
-      <el-col :xs="24" :sm="8" :lg="5" class="mb-4">
-        <div class="data-box">
-          <div class="text-[#40c9c6] hover:!text-white hover:bg-[#40c9c6] p-3 rounded">
-            <svg-icon icon-class="uv" size="3em" />
-          </div>
-          <div class="flex flex-col space-y-3">
-            <div class="text-[var(--el-text-color-secondary)]">全部班级</div>
-            <div class="text-lg">{{ Math.round(classCountOutput) }}</div>
-          </div>
-        </div>
-      </el-col>
-			<el-col :xs="24" :sm="8" :lg="5" class="mb-4">
-				<div class="data-box">
-					<div class="text-[#40c9c6] hover:!text-white hover:bg-[#40c9c6] p-3 rounded">
-						<svg-icon icon-class="uv" size="3em" />
-					</div>
-					<div class="flex flex-col space-y-3">
-						<div class="text-[var(--el-text-color-secondary)]">全部教师</div>
-						<div class="text-lg">{{ Math.round(teacherCountOutput) }}</div>
-					</div>
-				</div>
-			</el-col>
-			<el-col :xs="24" :sm="8" :lg="5" class="mb-4">
-				<div class="data-box">
-					<div class="text-[#40c9c6] hover:!text-white hover:bg-[#40c9c6] p-3 rounded">
-						<svg-icon icon-class="uv" size="3em" />
-					</div>
-					<div class="flex flex-col space-y-3">
-						<div class="text-[var(--el-text-color-secondary)]">全部学生</div>
-						<div class="text-lg">{{ Math.round(studentCountOutput) }}</div>
-					</div>
-				</div>
-			</el-col>
-      <el-col :xs="24" :sm="8" :lg="5" class="mb-4">
-        <div class="data-box">
-          <div
-            class="text-[#36a3f7] hover:!text-white hover:bg-[#36a3f7] p-3 rounded"
-          >
-            <svg-icon icon-class="message" size="3em" />
-          </div>
-          <div class="flex flex-col space-y-3">
-            <div class="text-[var(--el-text-color-secondary)]">设备套数</div>
-            <div class="text-lg">
-              {{ Math.round(equipmentCountOutput) }}
-            </div>
-          </div>
-        </div>
+    <DataCard
+      :classes="classCount"
+      :teachers="teacherCount"
+      :students="studentCount"
+      :equipments="equipmentCount"
+      :trainings="trainingCount"
+    />
+
+    <!-- 班级选择 及 案例展示 -->
+    <el-row class="row-bg" justify="space-between">
+      <el-col :span="12">
+        <el-select v-model="classNumber" class="m-2" placeholder="全部班级">
+          <el-option
+            v-for="item in classData"
+            :key="item.id"
+            :label="item.name"
+            :value="item.id"
+          />
+        </el-select>
       </el-col>
-      <el-col :xs="24" :sm="8" :lg="5" class="mb-4">
-        <div class="data-box">
-          <div
-            class="text-[#f4516c] hover:!text-white hover:bg-[#f4516c] p-3 rounded"
-          >
-            <svg-icon icon-class="money" size="3em" />
-          </div>
-          <div class="flex flex-col space-y-3">
-            <div class="text-[var(--el-text-color-secondary)]">累计训练次数</div>
-            <div class="text-lg">
-              {{ Math.round(trainingCountOutput) }}
-            </div>
-          </div>
-        </div>
+      <el-col :span="12">
+        <el-button text @click="dialogVisible = true"
+          >优秀教学效果示例</el-button
+        >
       </el-col>
     </el-row>
-	  <!-- 班级选择 及 案例展示 -->
-	  <el-row class="row-bg" justify="space-between">
-		  <el-col :span="12">
-				<el-select v-model="classNumber" class="m-2" placeholder="全部班级">
-					<el-option
-							v-for="item in classData"
-							:key="item.id"
-							:label="item.name"
-							:value="item.id"
-					/>
-				</el-select>
-			</el-col>
-		  <el-col :span="12">
-		  	<el-link href="#" type="primary">优秀教学效果示例</el-link>
-			</el-col>
-	  </el-row>
-
 
     <!-- Echarts 图表 -->
     <el-row :gutter="40">
-      <el-col :sm="24" :lg="8" class="mb-4">
-        <BarChart
-          id="barChart"
-          height="400px"
-          width="100%"
+      <el-col :sm="24" :lg="6" class="mb-4">
+        <LiquidChart
+          id="liquidChart1"
+          data="37.5"
+          height="200px"
+          width="200px"
+          color="#56a2ff"
+          bg-color="#e6edf9"
           class="bg-[var(--el-bg-color-overlay)]"
         />
       </el-col>
-
-      <el-col :xs="24" :sm="12" :lg="8" class="mb-4">
-        <PieChart
-          id="pieChart"
-          height="400px"
-          width="100%"
+      <el-col :sm="24" :lg="6" class="mb-4">
+        <LiquidChart
+          id="liquidChart2"
+          data="57.6"
+          height="200px"
+          width="200px"
+          color="#646bfa"
+          bg-color="#e6e8f9"
           class="bg-[var(--el-bg-color-overlay)]"
         />
       </el-col>
-
-      <el-col :xs="24" :sm="12" :lg="8" class="mb-4">
-        <RadarChart
-          id="radarChart"
-          height="400px"
-          width="100%"
+      <el-col :sm="24" :lg="6" class="mb-4">
+        <CircleChart
+          id="circleChart1"
+          data="37.5"
+          height="200px"
+          width="200px"
+          color="#56a2ff"
+          bg-color="#e6edf9"
+          class="bg-[var(--el-bg-color-overlay)]"
+        />
+      </el-col>
+      <el-col :sm="24" :lg="6" class="mb-4">
+        <CircleChart
+          id="circleChart2"
+          data="57.6"
+          height="200px"
+          width="200px"
+          color="#646bfa"
+          bg-color="#e6e8f9"
           class="bg-[var(--el-bg-color-overlay)]"
         />
       </el-col>
     </el-row>
+
+    <!-- 优秀教学效果示例弹出层 -->
+    <el-dialog
+      v-model="dialogVisible"
+      title="学员每次训练专注力评分均值整体变化曲线"
+      center
+    >
+      <ExampleDialog />
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="dialogVisible = false">关闭</el-button>
+        </span>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
@@ -192,34 +157,5 @@ onMounted(() => {
 .dashboard-container {
   position: relative;
   padding: 24px;
-
-  .user-avatar {
-    width: 40px;
-    height: 40px;
-    border-radius: 50%;
-  }
-
-  @media only screen and (min-width: 1200px){
-		.el-col-lg-5 {
-			display: block;
-			max-width: 20%;
-			flex: 0 0 20%;
-		}
-	}
-
-  .data-box {
-    display: flex;
-    justify-content: space-between;
-    padding: 20px;
-    font-weight: bold;
-    color: var(--el-text-color-regular);
-    background: var(--el-bg-color-overlay);
-    border-color: var(--el-border-color);
-    box-shadow: var(--el-box-shadow-dark);
-  }
-
-  .svg-icon {
-    fill: currentcolor !important;
-  }
 }
 </style>

+ 18 - 14
src/views/equipment/index.vue

@@ -1,20 +1,24 @@
-<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
-<script lang="ts">
-export default {
-	name: "",
-};
-</script>
-
 <script setup lang="ts">
-
+defineOptions({
+  name: "EquipmentManage",
+  inheritAttrs: false,
+});
+import { watch } from "vue";
+import { useUserStore } from "@/store/modules/user";
+const userStore = useUserStore();
+watch(
+  () => userStore.schoolId,
+  (newValue, oldValue) => {
+    console.log(newValue, oldValue);
+  }
+);
 </script>
 
 <template>
-	<div class="container">
-		<h1>设备管理</h1>
-	</div>
+  <div class="container">
+    <h1>设备管理</h1>
+    <div>{{ userStore.schoolId }}</div>
+  </div>
 </template>
 
-<style lang="scss" scoped>
-
-</style>
+<style lang="scss" scoped></style>

+ 24 - 0
src/views/evaluation/index.vue

@@ -0,0 +1,24 @@
+<script setup lang="ts">
+defineOptions({
+  name: "EvaluationViews",
+  inheritAttrs: false,
+});
+import { watch } from "vue";
+import { useUserStore } from "@/store/modules/user";
+const userStore = useUserStore();
+watch(
+  () => userStore.schoolId,
+  (newValue, oldValue) => {
+    console.log(newValue, oldValue);
+  }
+);
+</script>
+
+<template>
+  <div class="container">
+    <h1>测评数据看板</h1>
+    <div>{{ userStore.schoolId }}</div>
+  </div>
+</template>
+
+<style lang="scss" scoped></style>

+ 2 - 2
src/views/redirect/index.vue → src/views/login/redirect.vue

@@ -3,7 +3,7 @@
 </template>
 
 <script setup lang="ts">
-import { useRoute, useRouter } from 'vue-router';
+import { useRoute, useRouter } from "vue-router";
 
 const route = useRoute();
 const router = useRouter();
@@ -11,5 +11,5 @@ const router = useRouter();
 const { params, query } = route;
 const { path } = params;
 
-router.replace({ path: '/' + path, query });
+router.replace({ path: "/" + path, query });
 </script>

+ 18 - 14
src/views/student/index.vue

@@ -1,20 +1,24 @@
-<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
-<script lang="ts">
-export default {
-	name: "",
-};
-</script>
-
 <script setup lang="ts">
-
+defineOptions({
+  name: "StudentManage",
+  inheritAttrs: false,
+});
+import { watch } from "vue";
+import { useUserStore } from "@/store/modules/user";
+const userStore = useUserStore();
+watch(
+  () => userStore.schoolId,
+  (newValue, oldValue) => {
+    console.log(newValue, oldValue);
+  }
+);
 </script>
 
 <template>
-	<div class="container">
-		<h1>学生管理</h1>
-	</div>
+  <div class="container">
+    <h1>学生管理</h1>
+    <div>{{ userStore.schoolId }}</div>
+  </div>
 </template>
 
-<style lang="scss" scoped>
-
-</style>
+<style lang="scss" scoped></style>

+ 18 - 14
src/views/teacher/index.vue

@@ -1,20 +1,24 @@
-<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
-<script lang="ts">
-export default {
-	name: "",
-};
-</script>
-
 <script setup lang="ts">
-
+defineOptions({
+  name: "TeacherManage",
+  inheritAttrs: false,
+});
+import { watch } from "vue";
+import { useUserStore } from "@/store/modules/user";
+const userStore = useUserStore();
+watch(
+  () => userStore.schoolId,
+  (newValue, oldValue) => {
+    console.log(newValue, oldValue);
+  }
+);
 </script>
 
 <template>
-	<div class="container">
-		<h1>教师管理</h1>
-	</div>
+  <div class="container">
+    <h1>教师管理</h1>
+    <div>{{ userStore.schoolId }}</div>
+  </div>
 </template>
 
-<style lang="scss" scoped>
-
-</style>
+<style lang="scss" scoped></style>

+ 18 - 14
src/views/training/index.vue

@@ -1,20 +1,24 @@
-<!-- setup 无法设置组件名称,组件名称keepAlive必须 -->
-<script lang="ts">
-export default {
-	name: "",
-};
-</script>
-
 <script setup lang="ts">
-
+defineOptions({
+  name: "TrainingManage",
+  inheritAttrs: false,
+});
+import { watch } from "vue";
+import { useUserStore } from "@/store/modules/user";
+const userStore = useUserStore();
+watch(
+  () => userStore.schoolId,
+  (newValue, oldValue) => {
+    console.log(newValue, oldValue);
+  }
+);
 </script>
 
 <template>
-	<div class="container">
-		<h1>训练管理</h1>
-	</div>
+  <div class="container">
+    <h1>训练管理</h1>
+    <div>{{ userStore.schoolId }}</div>
+  </div>
 </template>
 
-<style lang="scss" scoped>
-
-</style>
+<style lang="scss" scoped></style>