Parcourir la source

build: 看板测评页面样式

chaooo il y a 2 ans
Parent
commit
97f17c4b8c

BIN
src/assets/evaluate/focus.png


BIN
src/assets/evaluate/student.png


BIN
src/assets/evaluate/training.png


+ 197 - 0
src/views/base-charts/RadarSingle.vue

@@ -0,0 +1,197 @@
+<!-- 五维雷达图 -->
+<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: "radarSingle",
+    required: true,
+  },
+  className: {
+    type: String,
+    default: "",
+  },
+  width: {
+    type: String,
+    default: "160px",
+  },
+  height: {
+    type: String,
+    default: "160px",
+  },
+  color: {
+    type: String,
+    default: "#2f539b",
+  },
+  bgColor: {
+    type: String,
+    default: "#e6e8f9",
+  },
+  beforeData: {
+    type: String,
+    default: "0,0,0,0,0",
+    required: true,
+  },
+  afterData: {
+    type: String,
+    default: "0,0,0,0,0",
+    required: true,
+  },
+});
+function test(params) {
+  let tag = "";
+  let tagType = "";
+  if (params.dimensionIndex == 0) {
+    // 专注力平均值
+    if (params.value > 62.82) {
+      tag = "优秀";
+      tagType = "t1";
+    } else if (params.value <= 62.82 && params.value > 55.49) {
+      tag = "良好";
+      tagType = "t2";
+    } else if (params.value <= 55.49 && params.value > 48.91) {
+      tag = "轻度不足";
+      tagType = 2;
+    } else if (params.value <= 48.91 && params.value > 41.58) {
+      tag = "中等不足";
+    } else {
+      tag = "重度不足";
+    }
+  }
+  if (params.dimensionIndex == 1) {
+    // 高专注占比
+    if (params.value > 62.82) {
+      tag = "优秀";
+    } else if (params.value <= 62.82 && params.value > 55.49) {
+      tag = "良好";
+    } else if (params.value <= 55.49 && params.value > 48.91) {
+      tag = "轻度不足";
+    } else if (params.value <= 48.91 && params.value > 41.58) {
+      tag = "中等不足";
+    } else {
+      tag = "重度不足";
+    }
+  }
+  console.log(params.dimensionIndex);
+  return ["{title|" + params.value + "}", "{flag|" + tag + "}"].join("");
+}
+const options = {
+  color: ["#937dff", "#ffb72d"],
+  legend: {
+    right: "5%",
+    top: "5%",
+    data: [
+      { name: "训练前", icon: "circle" },
+      { name: "训练后", icon: "circle" },
+    ],
+    textStyle: {
+      fontSize: 15,
+    },
+  },
+  radar: {
+    radius: "50%",
+    center: ["50%", "56%"],
+    indicator: [
+      { name: "专注力平均值", max: 100 },
+      { name: "高专注占比", max: 100 },
+      { name: "专注唤醒效率", max: 100 },
+      { name: "整体和谐度", max: 100 },
+      { name: "专注力稳定度", max: 100 },
+    ],
+    axisName: {
+      color: "#2456a3",
+      fontSize: 15,
+    },
+  },
+  series: [
+    {
+      name: "训练前 vs 训练后",
+      type: "radar",
+      symbolSize: 8,
+      data: [
+        {
+          value: props.beforeData?.split(","),
+          name: "训练前",
+          label: {
+            show: true,
+            position: "right",
+            color: "#937dff",
+            fontSize: 12,
+            formatter: function (params) {
+              return params.value > 0 ? params.value : "";
+            },
+          },
+          areaStyle: {
+            color: "rgba(147, 125, 255, .8)",
+          },
+        },
+        {
+          value: props.afterData?.split(","),
+          name: "训练后",
+          label: {
+            show: true,
+            // 在文本中,可以对部分文本采用 rich 中定义样式。
+            // 这里需要在文本中使用标记符号:
+            // `{styleName|text content text content}` 标记样式名。
+            // 注意,换行仍是使用 '\n'。
+            // formatter: (a, b) => {
+            // 	i++;
+            // 	return `{title|${a}}\n{flag|${params[i]}}`
+            // }
+            formatter: function (params) {
+              return test(params);
+            },
+            rich: {
+              t0: { color: "#247eff" },
+              t1: {
+                backgroundColor: "#03c5ec",
+                padding: [2, 10, 2, 10],
+                borderRadius: 5,
+              },
+              t2: {
+                backgroundColor: "#53be07",
+                padding: [2, 10, 2, 10],
+                borderRadius: 5,
+              },
+              t3: {
+                backgroundColor: "#edcb00",
+                padding: [2, 5, 2, 5],
+                borderRadius: 5,
+              },
+              t4: {
+                backgroundColor: "#ff9f29",
+                padding: [2, 5, 2, 5],
+                borderRadius: 5,
+              },
+              t5: {
+                backgroundColor: "#f45028",
+                padding: [2, 5, 2, 5],
+                borderRadius: 5,
+              },
+            },
+          },
+          areaStyle: {
+            color: "rgba(255, 183, 45, .5)",
+          },
+        },
+      ],
+    },
+  ],
+};
+
+onMounted(() => {
+  const chart = echarts.init(
+    document.getElementById(<string>props.id) as HTMLDivElement
+  );
+  chart.setOption(options);
+
+  window.addEventListener("resize", () => {
+    chart.resize();
+  });
+});
+</script>

+ 103 - 0
src/views/evaluation/components/EvaluateCard.vue

@@ -0,0 +1,103 @@
+<!-- 数据卡片 -->
+<script setup lang="ts">
+import { TransitionPresets, useTransition } from "@vueuse/core";
+
+const props = defineProps({
+  students: {
+    type: Number,
+    default: 0,
+    required: true,
+  },
+  focuses: {
+    type: Number,
+    default: 0,
+    required: true,
+  },
+  trainings: {
+    type: Number,
+    default: 0,
+    required: true,
+  },
+});
+// 卡片数字动效
+function countNumber(number) {
+  return useTransition(number, {
+    duration: 5000,
+    transition: TransitionPresets.easeOutExpo,
+  });
+}
+// 学生
+const studentCount = ref(0);
+const studentCountOutput = countNumber(studentCount);
+// 脑电专注力测评次数
+const focusCount = ref(0);
+const focusCountOutput = countNumber(focusCount);
+// 脑电检测次数
+const trainingCount = ref(0);
+const trainingCountOutput = countNumber(trainingCount);
+onMounted(() => {
+  studentCount.value = <number>props.students;
+  focusCount.value = <number>props.focuses;
+  trainingCount.value = <number>props.trainings;
+});
+</script>
+<template>
+  <div class="clear">
+    <div class="data-card c1">
+      <span class="n">{{ Math.round(studentCountOutput) }}</span
+      ><span>参与测评学生总计</span>
+    </div>
+    <div class="data-card c2">
+      <span class="n">{{ Math.round(focusCountOutput) }}</span
+      ><span>脑电专注力测评次数</span>
+    </div>
+    <div class="data-card c3">
+      <span class="n">{{ Math.round(trainingCountOutput) }}</span
+      ><span>脑电检测次数</span>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.data-card {
+  float: left;
+  box-sizing: border-box;
+  width: 300px;
+  height: 140px;
+  padding: 30px 0 0 30px;
+  border: 1px solid #e6e8eb;
+  margin: 0 20px 20px 0;
+  border-radius: 30px;
+  span {
+    display: block;
+    font-size: 18px;
+    color: #23283c;
+    &.n {
+      font-size: 24px;
+      font-weight: bold;
+      margin-bottom: 15px;
+    }
+  }
+  &.c1 {
+    background: #fef6e9 url("../../../assets/evaluate/student.png") 90% 50%
+      no-repeat;
+    span.n {
+      color: #e08e0a;
+    }
+  }
+  &.c2 {
+    background: #feeeee url("../../../assets/evaluate/focus.png") 90% 50%
+      no-repeat;
+    span.n {
+      color: #ca7676;
+    }
+  }
+  &.c3 {
+    background: #d0f6f1 url("../../../assets/evaluate/training.png") 90% 50%
+      no-repeat;
+    span.n {
+      color: #45a498;
+    }
+  }
+}
+</style>

+ 159 - 6
src/views/evaluation/index.vue

@@ -1,10 +1,13 @@
 <script setup lang="ts">
+import { watch } from "vue";
+import { useUserStore } from "@/store/modules/user";
+import EvaluateCard from "@/views/evaluation/components/EvaluateCard.vue";
+import RadarSingle from "@/views/base-charts/RadarSingle.vue";
+
 defineOptions({
   name: "EvaluateIndex",
   inheritAttrs: false,
 });
-import { watch } from "vue";
-import { useUserStore } from "@/store/modules/user";
 const userStore = useUserStore();
 watch(
   () => userStore.schoolId,
@@ -12,13 +15,163 @@ watch(
     console.log(newValue, oldValue);
   }
 );
+/**
+ * 数据卡片
+ */
+// 全部学生
+const studentCount = 600;
+// 设备套数
+const focusCount = 50;
+// 累计训练次数
+const trainingCount = 200;
+
+let studentInfo = ref("");
 </script>
 
 <template>
-  <div class="container">
-    <h1>测评数据看板</h1>
-    <div>{{ userStore.schoolId }}</div>
+  <div class="evaluate-container">
+    <!-- 数据卡片 -->
+    <EvaluateCard
+      :students="studentCount"
+      :focuses="focusCount"
+      :trainings="trainingCount"
+    />
+    <div class="evaluate-chart">
+      <!-- 学生查找 -->
+      <div class="student-search">
+        <div class="search">
+          <el-input
+            v-model="studentInfo"
+            size="large"
+            placeholder="请输入学生名称或手机号码"
+          />
+          <el-button size="large" type="primary">查找</el-button>
+        </div>
+        <div class="result">
+          <ul>
+            <li>
+              <img src="" alt="" />
+              <p>风间彻</p>
+              <p>13726267788</p>
+            </li>
+            <li></li>
+          </ul>
+        </div>
+      </div>
+      <!-- 图表展示-->
+      <div class="student-chart">
+        <div class="title">儿童脑电专注力测评数据分析</div>
+        <el-row :gutter="10">
+          <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8">
+            <div class="box-card">
+              <RadarSingle
+                id="radarChart"
+                after-data="78,88,65,82,65"
+                width="350px"
+                height="300px"
+                class="chart"
+              />
+            </div>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8">
+            <div class="box-card"></div>
+          </el-col>
+          <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8"></el-col>
+        </el-row>
+        <div class="title">脑电检测分析</div>
+      </div>
+    </div>
   </div>
 </template>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.evaluate-container {
+  position: relative;
+  padding: 30px;
+}
+.evaluate-chart {
+  width: 100%;
+  border-radius: 30px;
+  background: #fff;
+  position: relative;
+  padding-left: 386px;
+}
+:deep(.el-input__wrapper) {
+  background: #ffffff;
+  border-radius: 12px;
+}
+:deep(.el-input__wrapper) {
+  box-shadow: none !important;
+}
+.student-search {
+  box-sizing: border-box;
+  width: 342px;
+  border: 1px solid #e6e8eb;
+  border-radius: 30px;
+  padding-top: 34px;
+  overflow: hidden;
+  position: absolute;
+  left: 0;
+  top: 0;
+  .el-input {
+    width: 220px;
+    border: 1px solid #e6e8eb;
+    border-radius: 12px;
+    margin: 0 10px 0 15px;
+  }
+  :deep(.el-input__inner) {
+    font-size: 14px;
+  }
+  .el-button {
+    font-size: 14px;
+    padding: 0 24px;
+    border-radius: 12px;
+  }
+  .result {
+    margin-top: 15px;
+    li {
+      position: relative;
+      box-sizing: border-box;
+      width: 100%;
+      height: 70px;
+      padding: 8px 0 0 90px;
+      color: #23283c;
+      cursor: pointer;
+      &:hover {
+        background: #e5eefe;
+      }
+      .active {
+        color: #4284f2;
+        background: #e5eefe;
+      }
+      p {
+        line-height: 27px;
+        margin: 0;
+      }
+      img {
+        position: absolute;
+        left: 22px;
+        top: 8px;
+        width: 54px;
+        height: 54px;
+        background: #999999;
+        border-radius: 5px;
+        border: none;
+      }
+    }
+  }
+}
+.student-chart {
+  .title {
+    height: 54px;
+    line-height: 54px;
+    font-size: 18px;
+    color: #23283c;
+  }
+  .box-card {
+    box-sizing: border-box;
+    background: #f3f6fd;
+    border-radius: 20px;
+  }
+}
+</style>