init
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import * as echarts from "echarts";
|
||||
import "echarts/lib/chart/pie";
|
||||
import "echarts/lib/component/tooltip";
|
||||
|
||||
const AttendanceRingChart = ({
|
||||
data = [],
|
||||
centerContent = null, // 新增参数,用于传入中间的自定义内容
|
||||
centerContentStyle = {}, // 新增参数,用于自定义中间内容的样式
|
||||
}) => {
|
||||
const chartRef = useRef(null);
|
||||
const [chartInstance, setChartInstance] = useState(null);
|
||||
const containerRef = useRef(null); // 新增容器ref
|
||||
// 初始化/更新图表
|
||||
useEffect(() => {
|
||||
if (!chartRef.current) return;
|
||||
|
||||
// 销毁旧实例
|
||||
if (chartInstance) {
|
||||
chartInstance.dispose();
|
||||
}
|
||||
|
||||
// 创建新实例
|
||||
const newChart = echarts.init(chartRef.current);
|
||||
setChartInstance(newChart);
|
||||
|
||||
// 配置图表选项
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: "pie",
|
||||
radius: ["90%", "80%"],
|
||||
avoidLabelOverlap: false,
|
||||
padAngle: 5,
|
||||
itemStyle: {
|
||||
borderRadius: 30,
|
||||
},
|
||||
label: {
|
||||
show: false,
|
||||
},
|
||||
emphasis: {
|
||||
label: { show: false },
|
||||
},
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
data,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
newChart.setOption(option);
|
||||
// 监听窗口变化自动调整大小
|
||||
window.addEventListener("resize", () => newChart.resize());
|
||||
return () => {
|
||||
window.removeEventListener("resize", () => newChart.resize());
|
||||
newChart.dispose();
|
||||
};
|
||||
}, [data]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
style={{
|
||||
position: "relative",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
ref={chartRef}
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
/>
|
||||
{centerContent && (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
textAlign: "center",
|
||||
...centerContentStyle,
|
||||
}}
|
||||
>
|
||||
{centerContent}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AttendanceRingChart;
|
||||
153
src/pages/PersonalProfile/components/ProfileCard/index.css
Normal file
153
src/pages/PersonalProfile/components/ProfileCard/index.css
Normal file
@@ -0,0 +1,153 @@
|
||||
.profile-card-wrapper {
|
||||
width: 100%;
|
||||
height: 374px;
|
||||
border-radius: 8px;
|
||||
background-image: url("@/assets/images/PersonalProfile/personal_profile_bg.png");
|
||||
background-size: 100% 100%;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
padding: 16px;
|
||||
|
||||
.profile-card-user-info {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.profile-card-user-avatar {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.profile-card-user-name {
|
||||
width: 200px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
|
||||
.profile-card-user-name-text {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #1d2129;
|
||||
margin-bottom: 5px;
|
||||
position: relative;
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: -25px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background-image: url("@/assets/images/PersonalProfile/male_icon.png");
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-card-user-name-student-id {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: #4e5969;
|
||||
}
|
||||
}
|
||||
}
|
||||
.profile-card-achievement-info {
|
||||
width: 328px;
|
||||
height: 47px;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.profile-card-achievement-info-item {
|
||||
width: 80px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
.profile-card-achievement-info-item-title {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #4e5969;
|
||||
}
|
||||
|
||||
.profile-card-achievement-info-item-text {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #1d2129;
|
||||
}
|
||||
}
|
||||
}
|
||||
.profile-card-class-info {
|
||||
width: 328px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #ffffff;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
/* 投影(box-shadow) */
|
||||
box-shadow: 2px 2px 16.4px 0 rgba(103, 162, 247, 0.25);
|
||||
|
||||
.profile-card-class-info-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.profile-card-class-info-item {
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.profile-card-class-info-item-icon {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.icon-school {
|
||||
background-image: url("@/assets/images/PersonalProfile/school_icon.png");
|
||||
}
|
||||
.icon-major {
|
||||
background-image: url("@/assets/images/PersonalProfile/major_icon.png");
|
||||
}
|
||||
.icon-location {
|
||||
background-image: url("@/assets/images/PersonalProfile/location_icon.png");
|
||||
}
|
||||
.icon-course {
|
||||
background-image: url("@/assets/images/PersonalProfile/course_icon.png");
|
||||
}
|
||||
|
||||
.profile-card-class-info-item-title {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #4e5969;
|
||||
position: absolute;
|
||||
left: 40px;
|
||||
}
|
||||
|
||||
.profile-card-class-info-item-text {
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
color: #1d2129;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
82
src/pages/PersonalProfile/components/ProfileCard/index.jsx
Normal file
82
src/pages/PersonalProfile/components/ProfileCard/index.jsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import { Avatar } from "@arco-design/web-react";
|
||||
import { mockData } from "@/data/mockData";
|
||||
import "./index.css";
|
||||
|
||||
const ProfileCard = () => {
|
||||
const { profile } = mockData;
|
||||
|
||||
return (
|
||||
<div className="profile-card-wrapper">
|
||||
<div className="profile-card-user-info">
|
||||
<Avatar className="profile-card-user-avatar">
|
||||
<img
|
||||
alt="avatar"
|
||||
src="//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/3ee5f13fb09879ecb5185e440cef6eb9.png~tplv-uwbnlip3yd-webp.webp"
|
||||
/>
|
||||
</Avatar>
|
||||
<div className="profile-card-user-name">
|
||||
<span className="profile-card-user-name-text">{profile.name}</span>
|
||||
<p className="profile-card-user-name-student-id">
|
||||
学号: {profile.studentId}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<ul className="profile-card-achievement-info">
|
||||
<li className="profile-card-achievement-info-item">
|
||||
<span className="profile-card-achievement-info-item-title">学分</span>
|
||||
<span className="profile-card-achievement-info-item-text">
|
||||
{profile?.badges?.credits}
|
||||
</span>
|
||||
</li>
|
||||
<li className="profile-card-achievement-info-item">
|
||||
<span className="profile-card-achievement-info-item-title">
|
||||
班级排名
|
||||
</span>
|
||||
<span className="profile-card-achievement-info-item-text">
|
||||
{profile?.badges?.classRank}
|
||||
</span>
|
||||
</li>
|
||||
<li className="profile-card-achievement-info-item">
|
||||
<span className="profile-card-achievement-info-item-title">MBTI</span>
|
||||
<span className="profile-card-achievement-info-item-text">
|
||||
{profile?.badges?.mbti}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<ul className="profile-card-class-info">
|
||||
<li className="profile-card-class-info-item">
|
||||
<i className="profile-card-class-info-item-icon icon-school" />
|
||||
<span className="profile-card-class-info-item-title">学校</span>
|
||||
<span className="profile-card-class-info-item-text">
|
||||
{profile?.school}
|
||||
</span>
|
||||
</li>
|
||||
<li className="profile-card-class-info-item">
|
||||
<i className="profile-card-class-info-item-icon icon-major" />
|
||||
<span className="profile-card-class-info-item-title">专业</span>
|
||||
<span className="profile-card-class-info-item-text">
|
||||
{profile?.major}
|
||||
</span>
|
||||
</li>
|
||||
<li className="profile-card-class-info-item">
|
||||
<i className="profile-card-class-info-item-icon icon-location" />
|
||||
<span className="profile-card-class-info-item-title">
|
||||
就业管家课程
|
||||
</span>
|
||||
<span className="profile-card-class-info-item-text">
|
||||
{profile?.course}
|
||||
</span>
|
||||
</li>
|
||||
<li className="profile-card-class-info-item">
|
||||
<i className="profile-card-class-info-item-icon icon-course" />
|
||||
<span className="profile-card-class-info-item-title">垂直方向</span>
|
||||
<span className="profile-card-class-info-item-text">
|
||||
{profile?.course}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProfileCard;
|
||||
130
src/pages/PersonalProfile/components/ScoreRingChart/index.jsx
Normal file
130
src/pages/PersonalProfile/components/ScoreRingChart/index.jsx
Normal file
@@ -0,0 +1,130 @@
|
||||
import React, { useRef, useEffect } from "react";
|
||||
import * as echarts from "echarts";
|
||||
const screenWidth = window.screen.width; // 物理屏幕宽度(单位:像素)
|
||||
|
||||
const ScoreRingChart = ({
|
||||
className = "",
|
||||
ringData = [], // 数据
|
||||
title = "",
|
||||
bgColor = "#F7F8FA", // 未填充部分背景色
|
||||
}) => {
|
||||
// 创建图表容器引用
|
||||
const chartRef = useRef(null);
|
||||
// 图表实例引用
|
||||
const chartInstance = useRef(null);
|
||||
|
||||
// 初始化图表
|
||||
const initChart = () => {
|
||||
if (!chartRef.current) return;
|
||||
|
||||
// 销毁已存在的图表实例
|
||||
if (chartInstance.current) {
|
||||
chartInstance.current.dispose();
|
||||
}
|
||||
|
||||
// 创建新图表实例
|
||||
chartInstance.current = echarts.init(chartRef.current);
|
||||
|
||||
// 配置图表
|
||||
const option = {
|
||||
series: [
|
||||
{
|
||||
type: "gauge",
|
||||
startAngle: 90,
|
||||
endAngle: -270,
|
||||
radius: (80 / 1440) * screenWidth,
|
||||
pointer: {
|
||||
show: false,
|
||||
},
|
||||
progress: {
|
||||
show: true,
|
||||
overlap: false,
|
||||
roundCap: true,
|
||||
clip: false,
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
width: 20,
|
||||
color: [[1, bgColor]],
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
show: false,
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
show: false,
|
||||
},
|
||||
data: [ringData[0]],
|
||||
title: {
|
||||
fontSize: 14,
|
||||
},
|
||||
detail: {
|
||||
fontSize: 16,
|
||||
color: "#1D2129",
|
||||
formatter: title,
|
||||
lineHeight: 20,
|
||||
height: 40,
|
||||
offsetCenter: [0, 0],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "gauge",
|
||||
startAngle: 90,
|
||||
endAngle: -270,
|
||||
radius: (55 / 1440) * screenWidth,
|
||||
pointer: {
|
||||
show: false,
|
||||
},
|
||||
progress: {
|
||||
show: true,
|
||||
overlap: false,
|
||||
roundCap: true,
|
||||
clip: false,
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
width: 20,
|
||||
color: [[1, bgColor]],
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
show: false,
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
show: false,
|
||||
},
|
||||
data: [ringData[1]],
|
||||
title: {
|
||||
fontSize: 14,
|
||||
},
|
||||
detail: { show: false },
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// 设置图表配置
|
||||
chartInstance.current.setOption(option);
|
||||
};
|
||||
|
||||
// 组件挂载和更新时初始化图表
|
||||
useEffect(() => {
|
||||
initChart();
|
||||
|
||||
return () => {
|
||||
if (chartInstance.current) {
|
||||
chartInstance.current.dispose();
|
||||
chartInstance.current = null;
|
||||
}
|
||||
};
|
||||
}, [ringData, title, bgColor]);
|
||||
|
||||
return <div ref={chartRef} className={className} />;
|
||||
};
|
||||
|
||||
export default ScoreRingChart;
|
||||
235
src/pages/PersonalProfile/components/StudyProgress/index.jsx
Normal file
235
src/pages/PersonalProfile/components/StudyProgress/index.jsx
Normal file
@@ -0,0 +1,235 @@
|
||||
import { useRef, useEffect } from "react";
|
||||
import * as echarts from "echarts";
|
||||
const screenWidth = window.screen.width; // 物理屏幕宽度(单位:像素)
|
||||
|
||||
const StudyProgress = ({
|
||||
value = 0, // 默认值78%
|
||||
width = (180 / 1440) * screenWidth,
|
||||
height = (180 / 1440) * screenWidth,
|
||||
className = "",
|
||||
}) => {
|
||||
// 创建图表容器引用
|
||||
const chartRef = useRef(null);
|
||||
// 图表实例引用
|
||||
const chartInstance = useRef(null);
|
||||
|
||||
// 图表配置常量
|
||||
const ROOT_PATH = "https://echarts.apache.org/examples";
|
||||
const _panelImageURL = ROOT_PATH + "/data/asset/img/custom-gauge-panel.png";
|
||||
const _animationDuration = 1000;
|
||||
const _animationDurationUpdate = 1000;
|
||||
const _animationEasingUpdate = "quarticInOut";
|
||||
const _valOnRadianMax = 200;
|
||||
const _outerRadius = Math.min(width, height) / 2;
|
||||
const _innerRadius = _outerRadius * 0.85;
|
||||
const _pointerInnerRadius = _outerRadius * 0.2;
|
||||
const _insidePanelRadius = _outerRadius * 0.7;
|
||||
|
||||
// 转换为极坐标点
|
||||
const convertToPolarPoint = (renderItemParams, radius, radian) => {
|
||||
return [
|
||||
Math.cos(radian) * radius + renderItemParams.coordSys.cx,
|
||||
-Math.sin(radian) * radius + renderItemParams.coordSys.cy,
|
||||
];
|
||||
};
|
||||
|
||||
// 创建指针点
|
||||
const makePionterPoints = (renderItemParams, polarEndRadian) => {
|
||||
return [
|
||||
convertToPolarPoint(renderItemParams, _outerRadius, polarEndRadian),
|
||||
convertToPolarPoint(
|
||||
renderItemParams,
|
||||
_outerRadius,
|
||||
polarEndRadian + Math.PI * 0.03
|
||||
),
|
||||
convertToPolarPoint(
|
||||
renderItemParams,
|
||||
_pointerInnerRadius,
|
||||
polarEndRadian
|
||||
),
|
||||
];
|
||||
};
|
||||
|
||||
// 生成文本
|
||||
const makeText = (valOnRadian) => {
|
||||
if (valOnRadian < -10) {
|
||||
console.error("非法值:", valOnRadian);
|
||||
}
|
||||
return ((valOnRadian / _valOnRadianMax) * 100).toFixed(0) + "%";
|
||||
};
|
||||
|
||||
// 渲染项函数
|
||||
const renderItem = (params, api) => {
|
||||
// 将百分比转换为弧度值
|
||||
const valOnRadian = (value / 100) * _valOnRadianMax;
|
||||
const coords = api.coord([api.value(0), valOnRadian]);
|
||||
const polarEndRadian = coords[3];
|
||||
const imageStyle = {
|
||||
image: _panelImageURL,
|
||||
x: params.coordSys.cx - _outerRadius,
|
||||
y: params.coordSys.cy - _outerRadius,
|
||||
width: _outerRadius * 2,
|
||||
height: _outerRadius * 2,
|
||||
};
|
||||
|
||||
return {
|
||||
type: "group",
|
||||
children: [
|
||||
{
|
||||
type: "image",
|
||||
style: imageStyle,
|
||||
clipPath: {
|
||||
type: "sector",
|
||||
shape: {
|
||||
cx: params.coordSys.cx,
|
||||
cy: params.coordSys.cy,
|
||||
r: _outerRadius,
|
||||
r0: _innerRadius,
|
||||
startAngle: 0,
|
||||
endAngle: -polarEndRadian,
|
||||
transition: "endAngle",
|
||||
enterFrom: { endAngle: 0 },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "image",
|
||||
style: imageStyle,
|
||||
clipPath: {
|
||||
type: "polygon",
|
||||
shape: {
|
||||
points: makePionterPoints(params, polarEndRadian),
|
||||
},
|
||||
extra: {
|
||||
polarEndRadian: polarEndRadian,
|
||||
transition: "polarEndRadian",
|
||||
enterFrom: { polarEndRadian: 0 },
|
||||
},
|
||||
during: function (apiDuring) {
|
||||
apiDuring.setShape(
|
||||
"points",
|
||||
makePionterPoints(params, apiDuring.getExtra("polarEndRadian"))
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "circle",
|
||||
shape: {
|
||||
cx: params.coordSys.cx,
|
||||
cy: params.coordSys.cy,
|
||||
r: _insidePanelRadius,
|
||||
},
|
||||
style: {
|
||||
fill: "#fff",
|
||||
shadowBlur: 25,
|
||||
shadowOffsetX: 0,
|
||||
shadowOffsetY: 0,
|
||||
shadowColor: "rgba(76,107,167,0.4)",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
extra: {
|
||||
valOnRadian: valOnRadian,
|
||||
transition: "valOnRadian",
|
||||
enterFrom: { valOnRadian: 0 },
|
||||
},
|
||||
style: {
|
||||
text: makeText(valOnRadian),
|
||||
fontSize: Math.min(width, height) / 8,
|
||||
fontWeight: 700,
|
||||
x: params.coordSys.cx,
|
||||
y: params.coordSys.cy,
|
||||
fill: "rgb(0,50,190)",
|
||||
align: "center",
|
||||
verticalAlign: "middle",
|
||||
enterFrom: { opacity: 0 },
|
||||
},
|
||||
during: function (apiDuring) {
|
||||
apiDuring.setStyle(
|
||||
"text",
|
||||
makeText(apiDuring.getExtra("valOnRadian"))
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
// 图表选项配置
|
||||
const getChartOption = () => ({
|
||||
animationEasing: _animationEasingUpdate,
|
||||
animationDuration: _animationDuration,
|
||||
animationDurationUpdate: _animationDurationUpdate,
|
||||
animationEasingUpdate: _animationEasingUpdate,
|
||||
dataset: {
|
||||
source: [[1, (value / 100) * _valOnRadianMax]],
|
||||
},
|
||||
tooltip: {},
|
||||
angleAxis: {
|
||||
type: "value",
|
||||
startAngle: 0,
|
||||
show: false,
|
||||
min: 0,
|
||||
max: _valOnRadianMax,
|
||||
},
|
||||
radiusAxis: {
|
||||
type: "value",
|
||||
show: false,
|
||||
},
|
||||
polar: {},
|
||||
series: [
|
||||
{
|
||||
type: "custom",
|
||||
coordinateSystem: "polar",
|
||||
renderItem: renderItem,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// 初始化和更新图表
|
||||
useEffect(() => {
|
||||
// 确保DOM已经渲染
|
||||
if (chartRef.current && !chartInstance.current) {
|
||||
chartInstance.current = echarts.init(chartRef.current);
|
||||
chartInstance.current.setOption(getChartOption());
|
||||
}
|
||||
|
||||
// 更新图表
|
||||
if (chartInstance.current) {
|
||||
chartInstance.current.setOption(getChartOption());
|
||||
}
|
||||
|
||||
// 处理窗口大小变化
|
||||
const handleResize = () => {
|
||||
if (chartInstance.current) {
|
||||
chartInstance.current.resize();
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("resize", handleResize);
|
||||
|
||||
// 组件卸载时清理
|
||||
return () => {
|
||||
window.removeEventListener("resize", handleResize);
|
||||
if (chartInstance.current) {
|
||||
chartInstance.current.dispose();
|
||||
chartInstance.current = null;
|
||||
}
|
||||
};
|
||||
}, [value, width, height]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={chartRef}
|
||||
className={className}
|
||||
style={{
|
||||
width: width,
|
||||
height: height,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default StudyProgress;
|
||||
196
src/pages/PersonalProfile/components/StudyStudes/index.css
Normal file
196
src/pages/PersonalProfile/components/StudyStudes/index.css
Normal file
@@ -0,0 +1,196 @@
|
||||
.study-studes-card-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 8px;
|
||||
background-color: #fff;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
|
||||
.study-studes-card-title {
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 30px;
|
||||
color: #262626;
|
||||
}
|
||||
|
||||
.study-studes-card-list {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.study-studes-card-study-info {
|
||||
flex-shrink: 0;
|
||||
width: 338px;
|
||||
height: 308px;
|
||||
position: relative;
|
||||
background-image: url("@/assets/images/PersonalProfile/study_study_bg.png");
|
||||
background-size: 100% 100%;
|
||||
margin-bottom: 37px;
|
||||
|
||||
.study-studes-card-time-wrapper {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
border-radius: 8px;
|
||||
border: 1px solid #fff;
|
||||
width: 314px;
|
||||
height: 156px;
|
||||
background-color: #fff;
|
||||
box-shadow: 2px 2px 16.4px 0px rgba(103, 162, 247, 0.25);
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
.study-studes-card-study-time-wrapper {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
|
||||
.study-studes-card-study-info-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #4e5969;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.study-studes-card-study-time-line-class {
|
||||
> i {
|
||||
background: linear-gradient(
|
||||
to right,
|
||||
#4564ff,
|
||||
#ab2cff
|
||||
) !important;
|
||||
}
|
||||
}
|
||||
.study-studes-card-study-time-line {
|
||||
width: 265px;
|
||||
height: 10px;
|
||||
border-radius: 12px;
|
||||
background-color: #cedefa;
|
||||
position: relative;
|
||||
|
||||
> i {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(to right, #2c7aff, #00aeff);
|
||||
|
||||
> span {
|
||||
position: absolute;
|
||||
display: block;
|
||||
right: 0;
|
||||
top: 30%;
|
||||
transform: translate(50%, 30%);
|
||||
font-style: normal;
|
||||
width: 38px;
|
||||
height: 21px;
|
||||
line-height: 22px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #2358ed;
|
||||
background-image: url("@/assets/images/PersonalProfile/line_icon.png");
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.study-studes-card-study-progress {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
height: 308px;
|
||||
width: 330px;
|
||||
border-radius: 8px;
|
||||
margin-left: 20px;
|
||||
|
||||
.study-studes-card-study-progress-chart {
|
||||
width: 250px;
|
||||
height: 250px;
|
||||
margin-top: 50px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.study-studes-card-study-progress-title {
|
||||
color: #1d2129;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
.study-studes-card-curriculum-homework {
|
||||
margin-left: 40px;
|
||||
margin-right: 40px;
|
||||
}
|
||||
.study-studes-card-curriculum {
|
||||
width: 194px;
|
||||
height: 350px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
margin-top: 20px;
|
||||
|
||||
.study-studes-card-curriculum-chart {
|
||||
width: 194px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.study-studes-card-curriculum-info {
|
||||
width: 194px;
|
||||
height: 69px;
|
||||
border-radius: 8px;
|
||||
background-color: #f7f8fa;
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
> p {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #4e5969;
|
||||
}
|
||||
> span {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.study-studes-card-curriculum-info-span1 {
|
||||
color: #0aa4ff;
|
||||
}
|
||||
.study-studes-card-curriculum-info-span2 {
|
||||
color: #5e57ff;
|
||||
}
|
||||
.study-studes-card-curriculum-info-span3 {
|
||||
color: #ff9d2c;
|
||||
}
|
||||
}
|
||||
}
|
||||
.study-studes-card-curriculum-chart-center-content {
|
||||
width: 127px;
|
||||
height: 127px;
|
||||
border-radius: 50%;
|
||||
line-height: 127px;
|
||||
color: #1d2129;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
background-color: #e8f3ff;
|
||||
box-shadow: inset 0 0 15.6px 0 rgba(0, 172, 255, 0.2); /* #0AC3FF 转 rgba,20% 透明度 */
|
||||
}
|
||||
}
|
||||
}
|
||||
148
src/pages/PersonalProfile/components/StudyStudes/index.jsx
Normal file
148
src/pages/PersonalProfile/components/StudyStudes/index.jsx
Normal file
@@ -0,0 +1,148 @@
|
||||
import * as echarts from "echarts";
|
||||
import StudyProgress from "../StudyProgress";
|
||||
import ScoreRingChart from "../ScoreRingChart";
|
||||
import AttendanceRingChart from "../AttendanceRingChart";
|
||||
import "./index.css";
|
||||
|
||||
const ringData = [
|
||||
{
|
||||
value: 80,
|
||||
name: "我的",
|
||||
title: {
|
||||
offsetCenter: ["-30%", "-90%"],
|
||||
},
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 1, 1, [
|
||||
{ offset: 0, color: "#2C7AFF" },
|
||||
{ offset: 1, color: "#00AEFF" },
|
||||
]),
|
||||
},
|
||||
}, // 外环
|
||||
{
|
||||
value: 60,
|
||||
name: "班级",
|
||||
title: {
|
||||
offsetCenter: ["-60%", "-90%"],
|
||||
},
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 1, 1, [
|
||||
{ offset: 0, color: "#4564FF" },
|
||||
{ offset: 1, color: "#AB2CFF" },
|
||||
]),
|
||||
},
|
||||
}, // 中环
|
||||
];
|
||||
|
||||
const attendanceData = [
|
||||
{
|
||||
name: "出勤率",
|
||||
value: 22,
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 1, 1, [
|
||||
{ offset: 0, color: "#2C7AFF" },
|
||||
{ offset: 1, color: "#00D5FF" },
|
||||
]),
|
||||
},
|
||||
},
|
||||
{ name: "缺勤率", value: 8, itemStyle: { color: "#FF9D2C" } },
|
||||
// 可添加更多状态(如迟到、早退、缺勤等)
|
||||
];
|
||||
|
||||
const StudyStudes = () => {
|
||||
return (
|
||||
<div className="study-studes-card-wrapper">
|
||||
<p className="study-studes-card-title">学习情况</p>
|
||||
<ul className="study-studes-card-list">
|
||||
{/* 时长 */}
|
||||
<li className="study-studes-card-study-info">
|
||||
<div className="study-studes-card-time-wrapper">
|
||||
<div className="study-studes-card-study-time-wrapper">
|
||||
<p className="study-studes-card-study-info-title">
|
||||
个人学习时长(h)
|
||||
</p>
|
||||
<p className="study-studes-card-study-time-line">
|
||||
<i style={{ width: "70%" }}>
|
||||
<span>145</span>
|
||||
</i>
|
||||
</p>
|
||||
</div>
|
||||
<div className="study-studes-card-study-time-wrapper">
|
||||
<p className="study-studes-card-study-info-title">
|
||||
班级平均学习时长(h)
|
||||
</p>
|
||||
<p className="study-studes-card-study-time-line study-studes-card-study-time-line-class">
|
||||
<i style={{ width: "80%" }}>
|
||||
<span>145</span>
|
||||
</i>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{/* 进度 */}
|
||||
<li className="study-studes-card-study-progress">
|
||||
<StudyProgress
|
||||
value={75}
|
||||
className="study-studes-card-study-progress-chart"
|
||||
/>
|
||||
<p className="study-studes-card-study-progress-title">
|
||||
整体课程完成进度
|
||||
</p>
|
||||
</li>
|
||||
{/* 课程整体完成情况 */}
|
||||
<li className="study-studes-card-curriculum">
|
||||
<ScoreRingChart
|
||||
title={`整体课程\n完成情况`}
|
||||
ringData={ringData}
|
||||
className="study-studes-card-curriculum-chart"
|
||||
/>
|
||||
<div className="study-studes-card-curriculum-info">
|
||||
<p>班级平均进度</p>
|
||||
<span className="study-studes-card-curriculum-info-span1">60%</span>
|
||||
</div>
|
||||
<div className="study-studes-card-curriculum-info">
|
||||
<p>我的进度</p>
|
||||
<span className="study-studes-card-curriculum-info-span2">60%</span>
|
||||
</div>
|
||||
</li>
|
||||
{/* 课后作业完成情况 */}
|
||||
<li className="study-studes-card-curriculum-homework study-studes-card-curriculum">
|
||||
<ScoreRingChart
|
||||
title={`课后作业\n完成情况`}
|
||||
ringData={ringData}
|
||||
className="study-studes-card-curriculum-chart"
|
||||
/>
|
||||
<div className="study-studes-card-curriculum-info">
|
||||
<p>班级平均进度</p>
|
||||
<span className="study-studes-card-curriculum-info-span1">60%</span>
|
||||
</div>
|
||||
<div className="study-studes-card-curriculum-info">
|
||||
<p>我的进度</p>
|
||||
<span className="study-studes-card-curriculum-info-span2">60%</span>
|
||||
</div>
|
||||
</li>
|
||||
{/* 考勤情况 */}
|
||||
<li className="study-studes-card-curriculum">
|
||||
<AttendanceRingChart
|
||||
data={attendanceData}
|
||||
centerContent={
|
||||
<div className="study-studes-card-curriculum-chart-center-content">
|
||||
考勤情况
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="study-studes-card-curriculum-info">
|
||||
<p>出勤率</p>
|
||||
<span className="study-studes-card-curriculum-info-span1">60%</span>
|
||||
</div>
|
||||
<div className="study-studes-card-curriculum-info">
|
||||
<p>缺勤率</p>
|
||||
<span className="study-studes-card-curriculum-info-span3">60%</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default StudyStudes;
|
||||
41
src/pages/PersonalProfile/index.css
Normal file
41
src/pages/PersonalProfile/index.css
Normal file
@@ -0,0 +1,41 @@
|
||||
/* 个人档案页面样式 */
|
||||
.personal-profile {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* 统一布局系统 */
|
||||
.unified-profile-layout {
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
width: 100%;
|
||||
height: 781px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.unified-profile-left {
|
||||
width: 360px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.unified-profile-rank {
|
||||
height: 385px;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.unified-profile-right {
|
||||
width: 744px;
|
||||
height: 100%;
|
||||
border-radius: 8px;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
26
src/pages/PersonalProfile/index.jsx
Normal file
26
src/pages/PersonalProfile/index.jsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import ProfileCard from "./components/ProfileCard";
|
||||
import Rank from "@/components/Rank";
|
||||
import StageProgress from "@/components/StageProgress";
|
||||
import StudyStudes from "./components/StudyStudes";
|
||||
import "./index.css";
|
||||
|
||||
const PersonalProfile = () => {
|
||||
return (
|
||||
<div className="personal-profile">
|
||||
<StageProgress />
|
||||
|
||||
{/* 统一布局内容区域 */}
|
||||
<div className="unified-profile-layout">
|
||||
<div className="unified-profile-left">
|
||||
<ProfileCard />
|
||||
<Rank className="unified-profile-rank" />
|
||||
</div>
|
||||
<div className="unified-profile-right">
|
||||
<StudyStudes />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PersonalProfile;
|
||||
Reference in New Issue
Block a user