Browse Source

build: 报告详情图表调试

chaooo 2 years ago
parent
commit
3292eb5a7e

BIN
src/assets/student/head.png


+ 2 - 0
src/layout/components/Sidebar/SidebarItem.vue

@@ -134,6 +134,7 @@ if (onMounted) {
           <svg-icon
             v-if="onlyOneChild.meta && onlyOneChild.meta.icon"
             :icon-class="onlyOneChild.meta.icon"
+						size="1.25rem"
           />
           <template #title>
             <span>{{ onlyOneChild.meta.title }}</span>
@@ -147,6 +148,7 @@ if (onMounted) {
         <svg-icon
           v-if="itemRoute.meta && itemRoute.meta.icon"
           :icon-class="itemRoute.meta.icon"
+					size="1.25rem"
         />
         <span v-if="itemRoute.meta && itemRoute.meta.title">{{
           itemRoute.meta.title

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

@@ -170,6 +170,11 @@ const schoolRoutes: RouteRecordRaw[] = JSON.parse(
             breadcrumb: false,
           },
         },
+				{
+					path: "result",
+					component: "training/result",
+					meta: { title: "报告详情", name: "TrainingResult", hidden: true },
+				},
       ],
     },
     {

+ 2 - 2
src/store/modules/user.ts

@@ -53,8 +53,8 @@ export const useUserStore = defineStore("user", () => {
     nickname.value = data.name;
     phone.value = data.phone;
     schoolNum.value = data.num;
-    //role.value = data.role;
-    role.value = "ADMIN";
+    role.value = data.role;
+    //role.value = "ADMIN";
     perms.value = data.perms;
     return role.value;
   }

+ 99 - 0
src/views/charts-components/CurveLineChart.vue

@@ -0,0 +1,99 @@
+<!-- 圆饼图 -->
+<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: "curveLineChart",
+		required: true,
+	},
+	className: {
+		type: String,
+		default: "chart",
+	},
+	width: {
+		type: String,
+		default: "400px",
+	},
+	height: {
+		type: String,
+		default: "300px",
+	},
+	title: {
+		type: String,
+		default: "",
+	},
+	// dataSets:[[1,2,5,6,3,4],[6,3,4,1,2,5],[1,2,3,4,5,6]]
+	dataSets: {
+		type: Array,
+		default: [] as Array<number>,
+	},
+});
+/**
+ * 配置项
+ */
+const options = {
+	grid: {
+		x: "6%",
+		y: "22%",
+		x2: "0",
+		y2: "16%",
+	},
+	xAxis: {
+		type: "category",
+	},
+	yAxis: {
+		type: "value",
+		offset: -6,
+	},
+	legend: {
+		data: ["Att(专注度)","Med(放松度)","Amp(和谐度)"],
+		top: "6%",
+		right: "0",
+	},
+	color: [
+		"#FAB615",
+		"#40FF31",
+		"#D4327A"
+	],
+	series: [{
+		name: "Att(专注度)",
+		type: "line",
+		symbol: "none",
+		smooth: true,
+		data: props.dataSets?.[0],
+	},
+		{
+			name: "Med(放松度)",
+			type: "line",
+			symbol: "none",
+			smooth: true,
+			data: props.dataSets?.[1],
+		},
+		{
+			name: "Amp(和谐度)",
+			type: "line",
+			symbol: "none",
+			smooth: true,
+			data: props.dataSets?.[2],
+		}
+	]
+};
+
+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/charts-components/FocusCircleChart.vue

@@ -0,0 +1,126 @@
+<!-- 圆形进度图 -->
+<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: "focusCircleChart",
+		required: true,
+	},
+	className: {
+		type: String,
+		default: "chart",
+	},
+	width: {
+		type: String,
+		default: "200px",
+	},
+	height: {
+		type: String,
+		default: "200px",
+	},
+	color: {
+		type: String,
+		default: "#2f539b",
+	},
+	bgColor: {
+		type: String,
+		default: "#e6e8f9",
+	},
+	data: {
+		type: Number,
+		default: 0,
+		required: true,
+	},
+});
+
+const options = {
+	animation: true,
+	title: {
+		show: true,
+		//text: props.data + "%",
+		text: [`{t1|${props.data}}`,"{t2|%}"].join(''),
+		subtext: "高专注占比",
+		x: "center",
+		y: "35%",
+		textStyle: {
+			color: props.color,
+			rich:{
+				t1:{
+					fontSize: "30px",
+					fontWeight: "bold",
+				},
+				t2:{
+					fontSize: "14px",
+				}
+			},
+		},
+		subtextStyle:{
+			fontSize: "16px",
+			color: "#09132e",
+		}
+	},
+	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,
+				},
+			},
+			axisLine: {
+				// 背景环
+				roundCap: false,
+				lineStyle: {
+					width: 20,
+					color: [
+						[0, props.bgColor],
+						[1, props.bgColor],
+					],
+				},
+			},
+			avoidLabelOverlap: true,
+			label: { show: false },
+			labelLine: {
+				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>

+ 1 - 0
src/views/charts-components/PieChart.vue

@@ -38,6 +38,7 @@ const props = defineProps({
  * 配置项
  */
 const options = {
+	color:["#ed6767","#f6bb34","#8bc86f","#546fc6","#38c6ff"],
   title: {
     text: props.title,
     left: "39%",

+ 82 - 0
src/views/charts-components/SimplePieChart.vue

@@ -0,0 +1,82 @@
+<!-- 圆饼图 -->
+<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: "simplePieChart",
+		required: true,
+	},
+	className: {
+		type: String,
+		default: "chart",
+	},
+	width: {
+		type: String,
+		default: "400px",
+	},
+	height: {
+		type: String,
+		default: "300px",
+	},
+	title: {
+		type: String,
+		default: "",
+	},
+	// data:[78,88,65,82,65]
+	data: {
+		type: Array,
+		default: [] as Array<number>,
+	},
+});
+/**
+ * 配置项
+ */
+const options = {
+	color:["#ed6767","#f6bb34","#8bc86f","#546fc6","#38c6ff"],
+	title: {
+		text: ["专注力数值","比例"].join("\n"),
+		left: "47%",
+		top: "40%",
+		textStyle: {
+			fontSize: "1rem",
+			fontWeight: "normal",
+			color: "#666666",
+		},
+		textAlign:"center",
+	},
+	series: [
+		{
+			type: "pie",
+			radius: ["60%", "90%"],
+			avoidLabelOverlap: false,
+			label: {show: false,},
+			center: ["50%", "50%"],
+			data: [
+				{ value: props.data?.[0], name: "0-20" },
+				{ value: props.data?.[1], name: "21-40" },
+				{ value: props.data?.[2], name: "41-60" },
+				{ value: props.data?.[3], name: "61-80" },
+				{ value: props.data?.[4], name: "81-100" },
+			],
+		},
+	],
+};
+
+onMounted(() => {
+	// 图表初始化
+	const chart = echarts.init(
+		document.getElementById(<string>props.id) as HTMLDivElement
+	);
+	chart.setOption(options);
+	// 大小自适应
+	window.addEventListener("resize", () => {
+		chart.resize();
+	});
+});
+</script>

+ 1 - 4
src/views/student/index.vue

@@ -65,10 +65,7 @@ const tableData = ref<any>([
         <el-table-column prop="times" label="训练次数" align="center" />
         <el-table-column />
         <el-table-column label="操作" align="center">
-          <router-link to="/student/result" class="table-btn"
-            >训练效果分析</router-link
-          >
-          <!--					<a href="javascript:void(0);" class="table-btn disabled">训练效果分析</a>-->
+          <router-link to="/student/result" class="table-btn">训练效果分析</router-link>
         </el-table-column>
       </el-table>
     </div>

+ 0 - 15
src/views/training/components/DialogData.vue

@@ -1,15 +0,0 @@
-<script setup lang="ts">
-const props = defineProps({
-  data: {
-    type: String,
-    default: "dialog",
-    required: true,
-  },
-});
-</script>
-
-<template>
-  <div>{{ props.data }}</div>
-</template>
-
-<style scoped lang="scss"></style>

+ 1 - 13
src/views/training/index.vue

@@ -36,7 +36,6 @@ const tableData = ref<any>([
     cls: "向日葵小班",
   },
 ]);
-let dialogVisible = ref(false);
 </script>
 
 <template>
@@ -85,12 +84,6 @@ let dialogVisible = ref(false);
           label="放松模式(脑机放松度训练,即正念)"
         ></el-option>
       </el-select>
-      <!--			<el-input-->
-      <!--						v-model="studentInfo"-->
-      <!--						size="large"-->
-      <!--						placeholder="请输入学生名称或手机号码"-->
-      <!--			/>-->
-      <!--			<el-button size="large" type="primary">查找</el-button>-->
     </div>
     <!-- 学生数据 -->
     <div class="list-table">
@@ -104,16 +97,11 @@ let dialogVisible = ref(false);
         <el-table-column prop="cls" label="所在班级" align="center" />
         <el-table-column />
         <el-table-column label="操作" align="center">
-          <el-button text class="table-btn" @click="dialogVisible = true">
-            报告详情
-          </el-button>
+					<router-link to="/training/result" class="table-btn">报告详情</router-link>
         </el-table-column>
       </el-table>
     </div>
   </div>
-  <el-dialog v-model="dialogVisible">
-    <DialogData data="1sdgfsdaf" />
-  </el-dialog>
 </template>
 
 <style lang="scss" scoped>

+ 386 - 0
src/views/training/result.vue

@@ -0,0 +1,386 @@
+<script setup lang="ts">
+import RadarChart from "@/views/charts-components/RadarChart.vue";
+import {watch} from "vue";
+import {useUserStore} from "@/store/modules/user";
+import FocusCircleChart from "@/views/charts-components/FocusCircleChart.vue";
+import CurveLineChart from "@/views/charts-components/CurveLineChart.vue";
+import SimplePieChart from "@/views/charts-components/SimplePieChart.vue";
+
+defineOptions({
+  name: "TrainingResult",
+  inheritAttrs: false,
+});
+const userStore = useUserStore();
+watch(
+  () => userStore.schoolId,
+  (newValue, oldValue) => {
+    console.log(newValue, oldValue);
+  }
+);
+// 五维雷达图
+const radarData = ref([
+	[78, 88, 65, 82, 65],
+	[28, 38, 45, 32, 25],
+]);
+const radarStar = ref([1, 2, 3, 4, 5]);
+const radarTag = true;
+// 专注力分布饼图
+const curveData = ref([
+	[78, 88, 65, 82, 65],
+	[28, 38, 45, 32, 25],
+	[12, 18, 20, 28, 22]
+]);
+// 专注力分布饼图
+const pieData = ref([12, 18, 20, 28, 22]);
+</script>
+
+<template>
+  <div class="result-container">
+    <div class="result-title">
+      <el-row class="box-card">
+				<el-col :sm="12" :md="6" class="head">
+					<div class="l1"><span>风间彻</span></div>
+					<div class="l2">13726628766</div>
+				</el-col>
+        <el-col :sm="12" :md="4">
+          <div class="l1">30秒</div>
+          <div class="l2">训练总时长</div>
+        </el-col>
+        <el-col :sm="6" :md="4">
+          <div class="l1">智脑水舞</div>
+          <div class="l2">训练场景</div>
+        </el-col>
+        <el-col :sm="6" :md="4">
+          <div class="l1">专注力</div>
+          <div class="l2">训练模式</div>
+        </el-col>
+        <el-col :sm="12" :md="6">
+          <div class="l1">2023-12-52 12:11:11</div>
+          <div class="l2">训练时间</div>
+        </el-col>
+      </el-row>
+    </div>
+
+    <el-row class="result-chart" :gutter="15">
+			<el-col :xs="24" :sm="12" :md="8">
+				<div class="box-card">
+					<div class="charts p-5">
+						<FocusCircleChart
+								id="focusCircleChart"
+								key="38.0"
+								data="38.0"
+								height="200px"
+								width="200px"
+								color="#4284f2"
+								bg-color="#e4e7f4"
+						/>
+					</div>
+					<el-row class="infos">
+						<el-col :span="8">
+							<div class="l1">96.12</div>
+							<div class="l2">平均专注力</div>
+						</el-col>
+						<el-col :span="8">
+							<div class="l1">35</div>
+							<div class="l2">专注力维持区间</div>
+						</el-col>
+						<el-col :span="8">
+							<div class="l1">30<i>次</i></div>
+							<div class="l2">受干扰次数</div>
+						</el-col>
+					</el-row>
+				</div>
+			</el-col>
+			<el-col :xs="24" :sm="12" :md="8">
+        <div class="box-card">
+          <div class="chart-title">5D脑电数据模型</div>
+					<div class="charts">
+						<RadarChart
+								id="radarChart1"
+								:data-sets="radarData"
+								:star="radarStar"
+								:tag="radarTag"
+								width="450px"
+								height="350px"
+								class="chart"
+						/>
+					</div>
+        </div>
+      </el-col>
+			<el-col :xs="24" :sm="12" :md="8">
+				<div class="box-card">
+					<div class="chart-title">脑电数值曲线</div>
+					<div class="charts">
+						<CurveLineChart
+								id="curveLineChart"
+								:data-sets="curveData"
+								width="450px"
+								height="350px"
+								class="chart"
+						/>
+					</div>
+				</div>
+			</el-col>
+    </el-row>
+
+    <div class="note-box">
+      <el-row :gutter="15">
+        <el-col :xs="24" :sm="12" :md="8">
+          <div class="box-card">
+            <div class="tit">专注力平均值</div>
+						<div class="content">
+							<div class="star s1"></div>
+							<p>
+								这个阶段XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。
+							</p>
+							<p class="note">
+								通过脑电检测技术,将各项脑波数值的AI算法分析得出专注力平均值,反应了大脑专注集中在某件事上的程度。
+							</p>
+						</div>
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :md="8">
+          <div class="box-card">
+            <div class="tit">高专注力占比</div>
+						<div class="content">
+							<div class="star s2"></div>
+							<p>
+								这个阶段XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。
+							</p>
+							<p class="note">
+								在进行学习和生活任务时,需要主观意志的努力,此时脑电静息电位会提高,专注度也会显示为60分以上,因此,将专注力60分以上定义为高专注区间,这代表高专注区间在整次训练中的占比。
+							</p>
+						</div>
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :md="8">
+          <div class="box-card">
+            <div class="tit">专注力稳定度</div>
+						<div class="content">
+							<div class="star s3"></div>
+							<p>
+								这个阶段XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。
+							</p>
+							<p class="note">
+								在专注平均值相同时,第一种是专注值高低错落,跳跃明显。第二种是无限接近平均值,显然此种状态代表专注力更加稳定,操控专注力能力更强;在平均专注值高时,稳定度越高越好。
+							</p>
+						</div>
+          </div>
+        </el-col>
+
+        <el-col :xs="24" :sm="12" :md="8">
+          <div class="box-card">
+            <div class="tit">专注唤醒效率</div>
+						<div class="content">
+							<div class="star s4"></div>
+							<p>
+								这个阶段XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。
+							</p>
+							<p class="note">
+								通过脑电检测技术,将各项脑波数值的AI算法分析得出专注力平均值,反应了大脑专注集中在某件事上的程度。
+							</p>
+						</div>
+          </div>
+        </el-col>
+        <el-col :xs="24" :sm="12" :md="8">
+          <div class="box-card">
+            <div class="tit">整体和谐度</div>
+						<div class="content">
+							<div class="star s5"></div>
+							<p>
+								这个阶段XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。
+							</p>
+							<p class="note">
+								既专注又紧张,这种状态在考试和上台表演中比较常见,耗能过高不能长期保持;既专注又轻松,此种状态情绪相对稳定,焦虑值更低,提倡长期保持。和谐度记录的是专注值和放松值的同步率,和谐度越高越好。
+							</p>
+						</div>
+          </div>
+        </el-col>
+      </el-row>
+    </div>
+
+		<div class="note-box">
+			<el-row :gutter="15">
+				<el-col :xs="24" :sm="12" :md="8">
+					<div class="box-card">
+						<div class="tit btm">大脑发展小贴士</div>
+						<div class="content">
+							<p>
+								这个阶段XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。
+								通过脑电检测技术,将各项脑波数值的AI算法分析得出专注力平均值,反应了大脑专注集中在某件事上的程度。
+							</p>
+						</div>
+					</div>
+				</el-col>
+				<el-col :xs="24" :sm="12" :md="8">
+					<div class="box-card">
+						<div class="tit btm">专注力数值累计比例</div>
+						<div class="content flex">
+							<SimplePieChart
+									id="pieChart"
+									:data="pieData"
+									width="200px"
+									height="200px"
+									class="chart"
+									title="专注力数值比例"
+							/>
+							<div class="data">
+								<p><span class="tag">81-100</span>12分50秒 (8%)</p>
+								<p><span class="tag">61-80</span>12分50秒 (8%)</p>
+								<p><span class="tag">41-60</span>12分50秒 (8%)</p>
+								<p><span class="tag">21-40</span>12分50秒 (8%)</p>
+								<p><span class="tag">0-20</span>12分50秒 (8%)</p>
+							</div>
+						</div>
+					</div>
+				</el-col>
+			</el-row>
+		</div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.result-container {
+  position: relative;
+  padding: 30px;
+  .box-card {
+    background: #ffffff;
+    border-radius: 30px;
+    border: 1px solid #e6e8eb;
+    position: relative;
+  }
+  .result-title {
+    width: 950px;
+    white-space: nowrap;
+    .box-card {
+      padding: 20px 0 20px 40px;
+	  	line-height: 30px;
+			.head{
+				background: url("../../assets/student/head.png") left center no-repeat;
+				padding-left: 70px;
+			}
+    }
+    .l1 {
+	  	font-size: 18px;
+      color: #4284f2;
+      span {
+				color:#09132e
+      }
+    }
+    .l2 {
+	  	font-size: 16px;
+    }
+  }
+}
+.result-chart {
+  margin-top: 12px;
+  .chart-title {
+	position: absolute;
+	top: 20px;
+	left: 30px;
+	font-size: 18px;
+	color: #09132e;
+  }
+  .charts {
+    position: relative;
+		box-sizing: border-box;
+		width:450px;
+		margin:0 auto;
+    .chart {
+      margin: 0 auto;
+    }
+  }
+	.infos{
+		border-top: 1px solid #e6e8eb;
+		width:450px;
+		margin:0 auto;
+		text-align: center;
+		padding:28px 0 30px 0;
+		.l1 {
+			font-size: 20px;
+			font-weight:bold;
+			color: #4284f2;
+			i {
+				font-size: 14px;
+				font-style: normal;
+				font-weight: normal;
+			}
+		}
+		.l2 {
+			font-size: 16px;
+		}
+	}
+}
+.note-box {
+  margin-top: 12px;
+  .box-card {
+    padding: 15px 34px;
+    position: relative;
+    margin-bottom: 15px;
+    .tit {
+      color: #4284f2;
+      margin-bottom: 20px;
+			&.btm{
+				font-size:20px;
+				color: #09132e;
+			}
+    }
+		.content {
+	  	height:224px;
+			.star {
+				width: 162px;
+				height: 24px;
+				margin: 10px 0;
+				background: url("../../assets/student/stars.png") no-repeat;
+				background-position-x: 0;
+				&.s1 {
+					background-position-y: 0;
+				}
+				&.s2 {
+					background-position-y: -40px;
+				}
+				&.s3 {
+					background-position-y: -80px;
+				}
+				&.s4 {
+					background-position-y: -120px;
+				}
+				&.s5 {
+					background-position-y: -160px;
+				}
+			}
+			p {
+				line-height: 28px;
+				color: #09132e;
+				font-size: 14px;
+				margin: 0;
+				word-break: break-all;
+			}
+			.note {
+				margin-top: 10px;
+				padding-top: 10px;
+				border-top: 1px solid #e6e8eb;
+				color:#999999;
+			}
+			.data{
+				padding: 10px 0 0 35px;
+				p{margin-top:10px;line-height:24px;color:#666666;}
+				.tag{
+					display:inline-block;
+					width:72px;
+					height:24px;
+					line-height:24px;
+					color:#ffffff;
+					border-radius:5px;
+					text-align: center;
+				}
+				p:nth-child(1) .tag{background: #38c6ff;}
+				p:nth-child(2) .tag{background: #546fc6;}
+				p:nth-child(3) .tag{background: #8bc86f;}
+				p:nth-child(4) .tag{background: #f6bb34;}
+				p:nth-child(5) .tag{background: #ed6767;}
+			}
+		}
+  }
+}
+</style>