diff --git a/app.json b/app.json
index 778614a..3f406ee 100644
--- a/app.json
+++ b/app.json
@@ -71,7 +71,8 @@
"teacher/report-detail/report-detail",
"user/apply-school/apply-school",
"user/redeem-class/redeem-class",
- "parent/fitness-detail/fitness-detail"
+ "parent/fitness-detail/fitness-detail",
+ "teacher/student-fitness-detail/student-fitness-detail"
]
}
],
diff --git a/pages/teacher/count/count.js b/pages/teacher/count/count.js
index 74e5a61..2310b4a 100644
--- a/pages/teacher/count/count.js
+++ b/pages/teacher/count/count.js
@@ -38,6 +38,12 @@ Page({
cWidth: 330,
cHeight: 280,
pixelRatio: 2,
+ // 体测报告
+ activeTab: 0, // 0-课堂报告 1-体测报告
+ fitnessClassList: [], // 体测班级列表
+ nowFitnessClass: {}, // 当前体测班级
+ fitnessStudentList: [], // 体测学生列表
+ fitnessLoading: false,
},
@@ -50,12 +56,55 @@ Page({
})
if (wx.getStorageSync('roleId') && wx.getStorageSync('roleId') == 4) {
await this.getTrainClass(true)
+ await this.getFitnessClasses()
} else {
await this.getClass()
}
wx.hideLoading()
},
+ // 切换 Tab
+ switchTab(e) {
+ const tab = e.currentTarget.dataset.tab
+ this.setData({ activeTab: tab })
+ },
+
+ // 获取体测班级列表
+ async getFitnessClasses() {
+ const res = await getClassList()
+ if (res && res.data && res.data.length > 0) {
+ this.setData({
+ fitnessClassList: res.data,
+ nowFitnessClass: res.data[0]
+ }, () => {
+ this.getFitnessStudents()
+ })
+ }
+ },
+
+ // 体测班级切换
+ fitnessPicker(e) {
+ const nowFitnessClass = this.data.fitnessClassList[Number(e.detail.value)]
+ this.setData({ nowFitnessClass }, () => {
+ this.getFitnessStudents()
+ })
+ },
+
+ // 获取体测学生列表
+ async getFitnessStudents() {
+ if (!this.data.nowFitnessClass.classId) return
+ this.setData({ fitnessLoading: true })
+ const res = await getStudentList({
+ pageIndex: 1,
+ pageSize: 200,
+ classId: this.data.nowFitnessClass.classId
+ })
+ this.setData({
+ fitnessStudentList: (res && res.data && res.data.datas) ? res.data.datas : (res && res.data ? res.data : []),
+ fitnessLoading: false
+ })
+ },
+
clickCouse(e) {
this.setData({
clickCouse: e.currentTarget.dataset.item
@@ -115,7 +164,7 @@ Page({
pageIndex: this.data.page,
PageSize: 20,
})
- if(!this.data.nowCourse.id){
+ if(!this.data.nowCourse.id && res.data.datas.length > 0){
const detail = await getClassRoomReportDetails(res.data.datas[0].id)
this.setData({
nowCourseDetail:this.data.nowCourse.id ? this.data.nowCourseDetail: detail.data
@@ -133,6 +182,7 @@ Page({
//获取项目列表
async getProject() {
+ if(!this.data.nowClass || !this.data.nowClass.gradeId) return
const res = await getProjectList(this.data.nowClass.gradeId)
this.setData({
projectList: res.data,
@@ -142,6 +192,7 @@ Page({
//获取学生列表 刷新 加载更多
async getStudent(isRefresh) {
+ if (!this.data.nowClass || !this.data.nowClass.classId) return
if (!this.data.hasMore && !isRefresh) return //非刷新且没有
const res = await getTongji({
ClassId: this.data.nowClass.classId,
@@ -294,9 +345,14 @@ Page({
wx.navigateTo({
url: '/subpackage/teacher/report-detail/report-detail?id='+this.data.nowCourse.id +'&studentNo='+e.currentTarget.dataset.item.studentNo,
})
- // wx.navigateTo({
- // url: '/subpackage/teacher/report-list/report-list?studentNo='+e.currentTarget.dataset.item.studentNo,
- // })
+ },
+
+ // 体测报告 - 跳转学生体测详情
+ goFitnessDetail(e) {
+ const item = e.currentTarget.dataset.item
+ wx.navigateTo({
+ url: '/subpackage/teacher/student-fitness-detail/student-fitness-detail?studentNo=' + item.studentNo + '&classId=' + this.data.nowFitnessClass.classId
+ })
},
/**
diff --git a/pages/teacher/count/count.wxml b/pages/teacher/count/count.wxml
index f84333c..f4b7e08 100644
--- a/pages/teacher/count/count.wxml
+++ b/pages/teacher/count/count.wxml
@@ -59,6 +59,18 @@
+
+
+
+ 课堂报告
+
+
+ 体测报告
+
+
+
+
+
{{nowCourse.startingEndingTime}}
@@ -90,21 +102,6 @@
-
-
学生列表
@@ -114,9 +111,7 @@
{{item.studentName}}
-
-
@@ -131,7 +126,6 @@
-
加载中...
没有更多数据了
@@ -141,5 +135,58 @@
+
+
+
+
+
+
+
+
+
+
+ 加载中...
+
+
+
+
+
+
+
+
+
+
+ {{item.studentName || item.name}}
+
+
+
+ 学号:{{item.studentNo}}
+
+
+
+
+
+
+
+
+
+
+ 📋
+ 暂无学生数据
+
+
\ No newline at end of file
diff --git a/pages/teacher/count/count.wxss b/pages/teacher/count/count.wxss
index e8bcb7b..2681acb 100644
--- a/pages/teacher/count/count.wxss
+++ b/pages/teacher/count/count.wxss
@@ -1,4 +1,180 @@
/* pages/teacher/count/count.wxss */
+
+/* ===== Tab 切换 ===== */
+.report-tabs {
+ display: flex;
+ margin: 24rpx 30rpx 0;
+ background-color: #EAF4FF;
+ border-radius: 60rpx;
+ padding: 6rpx;
+ box-sizing: border-box;
+}
+
+.report-tab-item {
+ flex: 1;
+ height: 68rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 54rpx;
+ font-size: 28rpx;
+ color: #26A5F6;
+ transition: all 0.25s;
+}
+
+.report-tab-active {
+ background: linear-gradient(135deg, #26A5F6 0%, #1478D4 100%);
+ color: #fff;
+ font-weight: bold;
+ box-shadow: 0 4rpx 16rpx rgba(38, 165, 246, 0.35);
+}
+
+/* ===== 体测报告 header ===== */
+.fitness-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin: 30rpx 30rpx 16rpx;
+}
+
+.fitness-class-picker {
+ flex: 1;
+ margin-right: 20rpx;
+}
+
+.fitness-picker-btn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 72rpx;
+ background: linear-gradient(135deg, #26A5F6 0%, #1478D4 100%);
+ border-radius: 50rpx;
+ padding: 0 24rpx;
+ box-shadow: 0 4rpx 16rpx rgba(38, 165, 246, 0.3);
+}
+
+.fitness-picker-btn text {
+ color: #fff;
+ font-size: 26rpx;
+ font-weight: bold;
+ flex: 1;
+ text-align: center;
+}
+
+.picker-icon {
+ display: none;
+}
+
+.picker-arrow {
+ width: 24rpx;
+ height: 24rpx;
+ filter: brightness(10);
+}
+
+.fitness-count-badge {
+ background-color: #EAF4FF;
+ border: 2rpx solid #26A5F6;
+ border-radius: 30rpx;
+ padding: 8rpx 24rpx;
+ white-space: nowrap;
+}
+
+.fitness-count-badge text {
+ font-size: 24rpx;
+ color: #26A5F6;
+}
+
+/* ===== 体测学生卡片 ===== */
+.fitness-student-card {
+ display: flex;
+ align-items: center;
+ background-color: #fff;
+ border-radius: 20rpx;
+ margin: 18rpx 30rpx;
+ padding: 24rpx 28rpx;
+ box-shadow: 0 4rpx 20rpx rgba(38, 165, 246, 0.08);
+ border-left: 6rpx solid #26A5F6;
+}
+
+.fsc-avatar-wrap {
+ width: 88rpx;
+ height: 88rpx;
+ border-radius: 50%;
+ background: linear-gradient(135deg, #74C7FF 0%, #26A5F6 100%);
+ padding: 4rpx;
+ box-sizing: border-box;
+ flex-shrink: 0;
+}
+
+.fsc-avatar {
+ width: 100%;
+ height: 100%;
+ border-radius: 50%;
+ border: 3rpx solid #fff;
+ background-color: #e8f5ff;
+}
+
+.fsc-info {
+ flex: 1;
+ margin-left: 24rpx;
+}
+
+.fsc-name-row {
+ display: flex;
+ align-items: center;
+}
+
+.fsc-name {
+ font-size: 30rpx;
+ font-weight: bold;
+ color: #222;
+}
+
+.fsc-sex {
+ width: 36rpx;
+ height: 36rpx;
+ margin-left: 12rpx;
+}
+
+.fsc-meta {
+ margin-top: 8rpx;
+}
+
+.fsc-no {
+ font-size: 22rpx;
+ color: #999;
+}
+
+.fsc-arrow {
+ flex-shrink: 0;
+ margin-left: 12rpx;
+}
+
+/* ===== 加载中 ===== */
+.fitness-loading {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 80rpx 0;
+ color: #26A5F6;
+ font-size: 26rpx;
+}
+
+/* ===== 空状态 ===== */
+.fitness-empty {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 120rpx 0 60rpx;
+ color: #bbb;
+ font-size: 26rpx;
+}
+
+.fitness-empty-icon {
+ font-size: 80rpx;
+ margin-bottom: 20rpx;
+}
+
.card{
background-color: #fff;
box-shadow: 0 0 10rpx rgb(223, 222, 222);
diff --git a/subpackage/teacher/student-fitness-detail/student-fitness-detail.js b/subpackage/teacher/student-fitness-detail/student-fitness-detail.js
new file mode 100644
index 0000000..bccbb8f
--- /dev/null
+++ b/subpackage/teacher/student-fitness-detail/student-fitness-detail.js
@@ -0,0 +1,148 @@
+// subpackage/teacher/student-fitness-detail/student-fitness-detail.js
+import uCharts from '../../../utils/chart/u-charts';
+import { getReport } from '../../../utils/serve/parent';
+
+var uChartsInstance = {};
+
+const UNIT_MAP = {
+ 'BMI': 'kg/m²',
+ '肺活量': 'ml',
+ '坐位体前屈': 'cm',
+ '立定跳远': 'cm',
+ '一分钟跳绳': '个',
+ '一分钟仰卧起坐': '个',
+};
+
+Page({
+ data: {
+ fitnessItems: [],
+ fitnessReport: [],
+ radarCWidth: 300,
+ radarCHeight: 300,
+ pixelRatio: 2,
+ showFitnessPopup: false,
+ selectedFitnessItem: null,
+ studentNo: '',
+ readyFired: false,
+ },
+
+ async onLoad(options) {
+ wx.showLoading({ title: '加载中' });
+ this.setData({ studentNo: options.studentNo || '' });
+ try {
+ const res = await getReport({ studentNo: options.studentNo });
+ const list = (res.data && res.data.categoryScoreList) || [];
+ const fitnessItems = list.map(item => ({
+ ...item,
+ unit: UNIT_MAP[item.name] || '',
+ }));
+ this.setData({
+ fitnessReport: list,
+ fitnessItems,
+ }, () => {
+ // 如果 onReady 已经触发,数据到位后立即绘图
+ if (this.data.readyFired) {
+ this.drawRadarChart(this);
+ }
+ });
+ } catch (e) {
+ this.setData({ fitnessItems: [] });
+ }
+ wx.hideLoading();
+ },
+
+ onReady() {
+ const info = wx.getWindowInfo();
+ const pixelRatio = info.pixelRatio;
+ const radarCWidth = info.windowWidth * 0.86;
+ const radarCHeight = info.windowWidth * 0.86;
+ this.setData({ radarCWidth, radarCHeight, pixelRatio, readyFired: true }, () => {
+ // 如果数据已经加载完,直接绘图;否则等 onLoad 回调里触发
+ if (this.data.fitnessReport && this.data.fitnessReport.length > 0) {
+ this.drawRadarChart(this);
+ }
+ });
+ },
+
+ drawRadarChart(that) {
+ const list = that.data.fitnessReport || [];
+ const categories = list.map(i => i.name);
+ const prevData = list.map(i => i.prevScore || 0);
+ const currentData = list.map(i => i.lastScore || 0);
+
+ const query = wx.createSelectorQuery().in(that);
+ query.select('#radarCanvas').fields({ node: true, size: true }).exec(res => {
+ if (!res[0]) return;
+ const canvas = res[0].node;
+ const ctx = canvas.getContext('2d');
+ canvas.width = (res[0].width + 20) * that.data.pixelRatio;
+ canvas.height = (res[0].height + 20) * that.data.pixelRatio;
+ uChartsInstance['radarCanvas'] = new uCharts({
+ type: 'radar',
+ context: ctx,
+ width: that.data.radarCWidth * that.data.pixelRatio,
+ height: that.data.radarCHeight * that.data.pixelRatio,
+ categories,
+ series: [
+ { name: '上次成绩', data: prevData, color: '#4A90E2' },
+ { name: '本次成绩', data: currentData, color: '#E74C3C' },
+ ],
+ pixelRatio: that.data.pixelRatio,
+ animation: true,
+ background: 'rgba(0,0,0,0)',
+ color: ['#4A90E2', '#E74C3C'],
+ padding: [0, 0, 0, 10],
+ legend: {
+ show: true,
+ position: 'bottom',
+ float: 'center',
+ fontSize: 12,
+ lineHeight: 11,
+ margin: 5,
+ itemGap: 20,
+ },
+ extra: {
+ radar: {
+ gridType: 'radar',
+ gridColor: '#CCCCCC',
+ gridCount: 4,
+ opacity: 0.15,
+ gridEvenShow: true,
+ gridOddShow: true,
+ labelShow: true,
+ labelColor: '#333',
+ fontSize: 13,
+ labelPointShow: false,
+ max: 100,
+ },
+ },
+ });
+ });
+ },
+
+ showFitnessScore(e) {
+ const item = e.currentTarget.dataset.item;
+ this.setData({ selectedFitnessItem: item, showFitnessPopup: true });
+ },
+
+ closeFitnessPopup() {
+ this.setData({ showFitnessPopup: false, selectedFitnessItem: null });
+ },
+
+ goFitnessDetail() {
+ const item = this.data.selectedFitnessItem;
+ if (!item) return;
+ this.setData({ showFitnessPopup: false });
+ wx.setStorageSync('fitnessDetailItem', item);
+ wx.navigateTo({
+ url: '/subpackage/parent/fitness-detail/fitness-detail',
+ });
+ },
+
+ onShow() {},
+ onHide() {},
+ onUnload() {},
+ onPullDownRefresh() {},
+ onReachBottom() {},
+ onShareAppMessage() {},
+})
diff --git a/subpackage/teacher/student-fitness-detail/student-fitness-detail.json b/subpackage/teacher/student-fitness-detail/student-fitness-detail.json
new file mode 100644
index 0000000..48e4106
--- /dev/null
+++ b/subpackage/teacher/student-fitness-detail/student-fitness-detail.json
@@ -0,0 +1,9 @@
+{
+ "usingComponents": {
+ "mp-bar": "weui-miniprogram/navigation-bar/navigation-bar",
+ "mp-icon": "weui-miniprogram/icon/icon"
+ },
+ "backgroundColorContent": "#f0f7ff",
+ "backgroundColor": "#f0f7ff",
+ "navigationStyle": "custom"
+}
diff --git a/subpackage/teacher/student-fitness-detail/student-fitness-detail.wxml b/subpackage/teacher/student-fitness-detail/student-fitness-detail.wxml
new file mode 100644
index 0000000..2d4085d
--- /dev/null
+++ b/subpackage/teacher/student-fitness-detail/student-fitness-detail.wxml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+ 体测成绩对比
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+ {{item.lastScore}} {{item.unit}}
+
+
+
+
+ 暂无体测数据
+
+
+
+
+
+
+
diff --git a/subpackage/teacher/student-fitness-detail/student-fitness-detail.wxss b/subpackage/teacher/student-fitness-detail/student-fitness-detail.wxss
new file mode 100644
index 0000000..8ba3821
--- /dev/null
+++ b/subpackage/teacher/student-fitness-detail/student-fitness-detail.wxss
@@ -0,0 +1,377 @@
+/* subpackage/teacher/student-fitness-detail/student-fitness-detail.wxss */
+
+/* ===== 成绩弹窗 ===== */
+.popup-mask {
+ position: fixed;
+ top: 0; left: 0; right: 0; bottom: 0;
+ background: rgba(0,0,0,0.45);
+ z-index: 999;
+}
+
+.score-popup {
+ position: fixed;
+ left: 0; right: 0; bottom: 0;
+ background: #fff;
+ border-radius: 36rpx 36rpx 0 0;
+ padding: 36rpx 40rpx 60rpx;
+ z-index: 9999;
+ transform: translateY(100%);
+ transition: transform 0.3s ease;
+ box-shadow: 0 -8rpx 40rpx rgba(73,165,252,0.18);
+}
+
+.popup-show {
+ transform: translateY(0);
+}
+
+.popup-header {
+ display: flex;
+ align-items: center;
+ margin-bottom: 36rpx;
+}
+
+.popup-icon {
+ width: 88rpx;
+ height: 88rpx;
+ margin-right: 20rpx;
+ border-radius: 50%;
+ /* background: linear-gradient(135deg, #8dcfff, #49a5fc); */
+ /* padding: 14rpx; */
+ box-sizing: border-box;
+}
+
+.popup-title {
+ flex: 1;
+ font-size: 34rpx;
+ font-weight: bold;
+ color: #18394D;
+}
+
+.popup-close {
+ width: 56rpx;
+ height: 56rpx;
+ border-radius: 50%;
+ background: #f0f4f8;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 26rpx;
+ color: #999;
+}
+
+.score-rows {
+ background: #f7fbff;
+ border-radius: 20rpx;
+ padding: 8rpx 30rpx;
+ margin-bottom: 36rpx;
+}
+
+.score-row {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 24rpx 0;
+ border-bottom: 1rpx solid #eef2f8;
+}
+
+.score-row:last-child {
+ border-bottom: none;
+}
+
+.score-divider {
+ height: 2rpx;
+ background: linear-gradient(90deg, transparent, #d0e8ff, transparent);
+ margin: 4rpx 0;
+}
+
+.score-label {
+ font-size: 28rpx;
+ color: #666;
+}
+
+.score-value {
+ font-size: 34rpx;
+ font-weight: bold;
+ color: #333;
+}
+
+.score-highlight {
+ color: #1d78e8;
+ font-size: 40rpx;
+}
+
+.score-unit {
+ font-size: 22rpx;
+ color: #999;
+ font-weight: normal;
+}
+
+.popup-btn {
+ background: linear-gradient(135deg, #49a5fc, #1d78e8);
+ color: #fff;
+ text-align: center;
+ padding: 28rpx 0;
+ border-radius: 50rpx;
+ font-size: 30rpx;
+ font-weight: bold;
+ box-shadow: 0 6rpx 20rpx rgba(73,165,252,0.4);
+ letter-spacing: 2rpx;
+}
+
+/* ===== 体测报告卡片 ===== */
+.fitness-card {
+ background: #fff;
+ border-radius: 24rpx;
+ padding: 30rpx 20rpx 10rpx;
+ box-shadow: 0 4rpx 20rpx rgba(73,165,252,0.12);
+ margin-bottom: 30rpx;
+ margin-top: 20rpx;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.fitness-chart-title {
+ font-size: 30rpx;
+ font-weight: bold;
+ color: #18394D;
+ margin-bottom: 16rpx;
+ position: relative;
+ padding: 0 30rpx;
+}
+
+.fitness-chart-title::before,
+.fitness-chart-title::after {
+ content: '';
+ display: inline-block;
+ width: 60rpx;
+ height: 4rpx;
+ background: linear-gradient(90deg, transparent, #49a5fc);
+ vertical-align: middle;
+ margin-right: 16rpx;
+ border-radius: 2rpx;
+}
+
+.fitness-chart-title::after {
+ background: linear-gradient(90deg, #49a5fc, transparent);
+ margin-right: 0;
+ margin-left: 16rpx;
+}
+
+.radar-wrap {
+ overflow: hidden;
+}
+
+/* ===== 六项指标网格 ===== */
+.fitness-grid {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 20rpx;
+ margin-bottom: 10rpx;
+}
+
+.fitness-item {
+ width: calc(33.33% - 14rpx);
+ background: #fff;
+ border-radius: 20rpx;
+ box-shadow: 0 4rpx 16rpx rgba(73,165,252,0.12);
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 30rpx 10rpx 24rpx;
+ box-sizing: border-box;
+ active-opacity: 0.7;
+}
+
+.fitness-item:active {
+ transform: scale(0.96);
+}
+
+.fitness-icon {
+ width: 88rpx;
+ height: 88rpx;
+}
+
+.fitness-name {
+ font-size: 24rpx;
+ color: #333;
+ font-weight: 500;
+ text-align: center;
+ margin-bottom: 8rpx;
+}
+
+.fitness-score {
+ font-size: 30rpx;
+ font-weight: bold;
+ color: #1d78e8;
+}
+
+.fitness-unit {
+ font-size: 20rpx;
+ color: #999;
+ font-weight: normal;
+}
+
+/* ===== 空状态 ===== */
+.empty-tip {
+ text-align: center;
+ padding: 80rpx 0;
+ color: #bbb;
+ font-size: 26rpx;
+
+ flex-wrap: wrap;
+ gap: 10rpx;
+}
+
+.meta-tag {
+ background-color: rgba(255, 255, 255, 0.25);
+ border-radius: 20rpx;
+ padding: 4rpx 18rpx;
+ font-size: 22rpx;
+ color: #fff;
+}
+
+.score-wrap {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ background-color: rgba(255, 255, 255, 0.2);
+ border-radius: 20rpx;
+ padding: 16rpx 28rpx;
+ flex-shrink: 0;
+}
+
+.score-num {
+ font-size: 52rpx;
+ font-weight: bold;
+ color: #fff;
+ line-height: 1;
+}
+
+
+/* ===== 章节标题 ===== */
+.section-title {
+ display: flex;
+ align-items: center;
+ margin: 36rpx 30rpx 16rpx;
+ font-size: 28rpx;
+ font-weight: bold;
+ color: #222;
+}
+
+.title-bar {
+ width: 6rpx;
+ height: 28rpx;
+ border-radius: 6rpx;
+ background: linear-gradient(180deg, #26A5F6, #1478D4);
+ margin-right: 16rpx;
+}
+
+/* ===== 成绩表格 ===== */
+.table-card {
+ background-color: #fff;
+ border-radius: 24rpx;
+ margin: 0 30rpx 40rpx;
+ overflow: hidden;
+ box-shadow: 0 4rpx 20rpx rgba(38, 165, 246, 0.1);
+}
+
+.table-row {
+ display: grid;
+ grid-template-columns: 2fr 1.5fr 1fr 1.2fr;
+ align-items: center;
+ padding: 0 24rpx;
+ min-height: 90rpx;
+}
+
+.table-header {
+ background: linear-gradient(90deg, #EAF4FF, #f5faff);
+ font-size: 24rpx;
+ font-weight: bold;
+ color: #26A5F6;
+ min-height: 72rpx;
+ border-bottom: 2rpx solid #e8f3ff;
+}
+
+.row-even {
+ background-color: #fff;
+ border-bottom: 2rpx solid #f5f5f5;
+}
+
+.row-odd {
+ background-color: #f8fcff;
+ border-bottom: 2rpx solid #f5f5f5;
+}
+
+.col-name {
+ font-size: 26rpx;
+ color: #333;
+ padding-right: 10rpx;
+ word-break: break-all;
+}
+
+.col {
+ font-size: 25rpx;
+ color: #555;
+ text-align: center;
+}
+
+.col-score {
+ font-weight: bold;
+ color: #26A5F6;
+}
+
+.col-rank {
+ text-align: center;
+ border-radius: 20rpx;
+ font-size: 22rpx;
+ padding: 4rpx 0;
+}
+
+.col-rank.rank-1 {
+ color: #1aad19;
+ background-color: #e8f9e8;
+}
+
+.col-rank.rank-2 {
+ color: #26A5F6;
+ background-color: #eaf4ff;
+}
+
+.col-rank.rank-3 {
+ color: #ff9900;
+ background-color: #fff7e8;
+}
+
+.col-rank.rank-4 {
+ color: #e64340;
+ background-color: #fff0f0;
+}
+
+/* ===== 空状态 ===== */
+.empty {
+ text-align: center;
+ padding: 80rpx 0;
+ color: #bbb;
+ font-size: 26rpx;
+}
+
+/* ===== 加载骨架 ===== */
+.skeleton {
+ padding: 24rpx 30rpx;
+}
+
+.sk-header {
+ height: 160rpx;
+ background: linear-gradient(90deg, #dbeeff 25%, #c8e5ff 50%, #dbeeff 75%);
+ border-radius: 24rpx;
+ margin-bottom: 40rpx;
+}
+
+.sk-row {
+ height: 80rpx;
+ background: linear-gradient(90deg, #f0f0f0 25%, #e8e8e8 50%, #f0f0f0 75%);
+ border-radius: 12rpx;
+ margin-bottom: 16rpx;
+}