feat(学生信息): 在多个页面添加学员ID显示及相关功能

- 在笔记评价、学习概览、在线学习监控、排行榜和英语单词报告页面添加学员ID显示
- 修改表格列配置逻辑确保新列能被正确显示
- 更新导出功能包含学员ID字段
- 调整相关样式和布局以适应新增内容
This commit is contained in:
YangQiang 2026-04-23 17:30:42 +08:00
parent c3b0df2e28
commit 829fe7673d
6 changed files with 145 additions and 43 deletions

View File

@ -2,9 +2,9 @@
"projectName": "aixuediebian-kanban",
"projectId": "pages-eip23arpzoar",
"deployUrl": "https://aixuediebian-kanban-3fzkam9s.edgeone.cool",
"previewUrl": "https://aixuediebian-kanban-3fzkam9s.edgeone.cool?eo_token=cb14dd055e9800e60bec15a6d7609f0a&eo_time=1776851825",
"previewUrl": "https://aixuediebian-kanban-3fzkam9s.edgeone.cool?eo_token=edea63080e89e3c90243155bd3d9215f&eo_time=1776932577",
"consoleUrl": "https://console.cloud.tencent.com/edgeone/pages/project/pages-eip23arpzoar/index",
"deploymentUrl": "https://console.cloud.tencent.com/edgeone/pages/project/pages-eip23arpzoar/deployment/qmtywlqsh0",
"deployId": "qmtywlqsh0",
"lastDeployTime": 1776851825
"deploymentUrl": "https://console.cloud.tencent.com/edgeone/pages/project/pages-eip23arpzoar/deployment/uy6q5m63n4",
"deployId": "uy6q5m63n4",
"lastDeployTime": 1776932577
}

View File

@ -363,7 +363,7 @@
<t-dialog
v-model:visible="classDetailVisible"
:header="selectedClassData ? `${selectedClassData.subject} - 学生详情` : '班级详情'"
:width="900"
:width="1100"
:footer="false"
@close="closeClassDetail"
class="class-detail-dialog"
@ -920,16 +920,16 @@ const overviewColumns = [
//
const accuracyRankData = ref([
{ rank: 1, name: '张晓雯', cloud: '广东云校', school: '第一中学', grade: '高二', class: '高二1班', totalCount: 200, correctCount: 195, accuracy: '97.5%' },
{ rank: 2, name: '李明浩', cloud: '广东云校', school: '第一中学', grade: '高一', class: '高一2班', totalCount: 200, correctCount: 192, accuracy: '96.0%' },
{ rank: 3, name: '王思琪', cloud: '广东云校', school: '第一中学', grade: '高二', class: '高二2班', totalCount: 200, correctCount: 191, accuracy: '95.5%' },
{ rank: 4, name: '陈子涵', cloud: '广东云校', school: '第一中学', grade: '高一', class: '高一1班', totalCount: 200, correctCount: 188, accuracy: '94.0%' },
{ rank: 5, name: '刘雨桐', cloud: '广东云校', school: '第一中学', grade: '高二', class: '高二1班', totalCount: 200, correctCount: 187, accuracy: '93.5%' },
{ rank: 6, name: '赵佳怡', cloud: '广东云校', school: '第一中学', grade: '高一', class: '高一2班', totalCount: 200, correctCount: 184, accuracy: '92.0%' },
{ rank: 7, name: '孙浩然', cloud: '广东云校', school: '第一中学', grade: '高二', class: '高二2班', totalCount: 200, correctCount: 183, accuracy: '91.5%' },
{ rank: 8, name: '周梦琳', cloud: '广东云校', school: '第一中学', grade: '高一', class: '高一1班', totalCount: 200, correctCount: 181, accuracy: '90.5%' },
{ rank: 9, name: '吴天宇', cloud: '广东云校', school: '第一中学', grade: '高二', class: '高二1班', totalCount: 200, correctCount: 179, accuracy: '89.5%' },
{ rank: 10, name: '郑欣怡', cloud: '广东云校', school: '第一中学', grade: '高一', class: '高一2班', totalCount: 200, correctCount: 176, accuracy: '88.0%' },
{ rank: 1, name: '张晓雯', studentId: 2000000000001, cloud: '广东云校', school: '第一中学', grade: '高二', class: '高二1班', totalCount: 200, correctCount: 195, accuracy: '97.5%' },
{ rank: 2, name: '李明浩', studentId: 2000000000002, cloud: '广东云校', school: '第一中学', grade: '高一', class: '高一2班', totalCount: 200, correctCount: 192, accuracy: '96.0%' },
{ rank: 3, name: '王思琪', studentId: 2000000000003, cloud: '广东云校', school: '第一中学', grade: '高二', class: '高二2班', totalCount: 200, correctCount: 191, accuracy: '95.5%' },
{ rank: 4, name: '陈子涵', studentId: 2000000000004, cloud: '广东云校', school: '第一中学', grade: '高一', class: '高一1班', totalCount: 200, correctCount: 188, accuracy: '94.0%' },
{ rank: 5, name: '刘雨桐', studentId: 2000000000005, cloud: '广东云校', school: '第一中学', grade: '高二', class: '高二1班', totalCount: 200, correctCount: 187, accuracy: '93.5%' },
{ rank: 6, name: '赵佳怡', studentId: 2000000000006, cloud: '广东云校', school: '第一中学', grade: '高一', class: '高一2班', totalCount: 200, correctCount: 184, accuracy: '92.0%' },
{ rank: 7, name: '孙浩然', studentId: 2000000000007, cloud: '广东云校', school: '第一中学', grade: '高二', class: '高二2班', totalCount: 200, correctCount: 183, accuracy: '91.5%' },
{ rank: 8, name: '周梦琳', studentId: 2000000000008, cloud: '广东云校', school: '第一中学', grade: '高一', class: '高一1班', totalCount: 200, correctCount: 181, accuracy: '90.5%' },
{ rank: 9, name: '吴天宇', studentId: 2000000000009, cloud: '广东云校', school: '第一中学', grade: '高二', class: '高二1班', totalCount: 200, correctCount: 179, accuracy: '89.5%' },
{ rank: 10, name: '郑欣怡', studentId: 2000000000010, cloud: '广东云校', school: '第一中学', grade: '高一', class: '高一2班', totalCount: 200, correctCount: 176, accuracy: '88.0%' },
])
const medalColors = ['#f5a623', '#94a3b8', '#cd7f32']
@ -952,6 +952,7 @@ const accuracyRankColumns = [
return h('span', { style: { color: '#64748b', fontWeight: 700, fontSize: '15px' } }, String(row.rank))
}
},
{ colKey: 'studentId', title: '学员ID', width: 130, align: 'center' },
{ colKey: 'name', title: '学生姓名', minWidth: 110 },
{ colKey: 'cloud', title: '云校', minWidth: 130 },
{ colKey: 'school', title: '学校', minWidth: 130 },
@ -1963,6 +1964,7 @@ const generateClassStudentsData = (classRow) => {
return {
id: `student_${classRow.id}_${index}`,
name: name,
studentId: 2000000000000 + parseInt(classRow.id.split('-')[1]) * 100 + index,
onlineDays: Math.floor(Math.random() * 10) + 20,
onlineRate: `${(Math.random() * 15 + 80).toFixed(1)}%`,
totalAnswerCount: totalAnswerCount,
@ -1995,12 +1997,13 @@ const exportStudentsData = async () => {
await new Promise(resolve => setTimeout(resolve, 800))
// CSV
const headers = ['姓名', '在线天数', '在线率', '总答题数', '完成率', '答题进度', '正确答题数', '正确率']
const headers = ['学员ID', '姓名', '在线天数', '在线率', '总答题数', '完成率', '答题进度', '正确答题数', '正确率']
// CSV
const csvContent = [
headers.join(','),
...classStudentsData.value.map(student => [
student.studentId,
student.name,
student.onlineDays,
student.onlineRate,
@ -2032,8 +2035,15 @@ const exportStudentsData = async () => {
}
}
// - 线线
// - ID线线
const studentColumns = [
{
colKey: 'studentId',
title: '学员ID',
width: 130,
align: 'center',
fixed: 'left'
},
{
colKey: 'name',
title: '姓名',

View File

@ -224,7 +224,10 @@
<a-avatar :style="{ backgroundColor: getAvatarColor(record.name) }">
{{ record.name.charAt(0) }}
</a-avatar>
<span class="user-name">{{ record.name }}</span>
<div class="user-info">
<span class="user-name">{{ record.name }}</span>
<span class="user-id">ID: {{ record.studentId }}</span>
</div>
</div>
</template>
<template v-else-if="column.key === 'totalPoints'">
@ -295,7 +298,10 @@
<a-avatar :style="{ backgroundColor: getAvatarColor(record.name) }">
{{ record.name.charAt(0) }}
</a-avatar>
<span class="user-name">{{ record.name }}</span>
<div class="user-info">
<span class="user-name">{{ record.name }}</span>
<span class="user-id">ID: {{ record.studentId }}</span>
</div>
</div>
</template>
<template v-else-if="column.key === 'totalCourses'">
@ -366,7 +372,10 @@
<a-avatar :style="{ backgroundColor: getAvatarColor(record.name) }">
{{ record.name.charAt(0) }}
</a-avatar>
<span class="user-name">{{ record.name }}</span>
<div class="user-info">
<span class="user-name">{{ record.name }}</span>
<span class="user-id">ID: {{ record.studentId }}</span>
</div>
</div>
</template>
<template v-else-if="column.key === 'totalLikes'">
@ -437,7 +446,10 @@
<a-avatar :style="{ backgroundColor: getAvatarColor(record.name) }">
{{ record.name.charAt(0) }}
</a-avatar>
<span class="user-name">{{ record.name }}</span>
<div class="user-info">
<span class="user-name">{{ record.name }}</span>
<span class="user-id">ID: {{ record.studentId }}</span>
</div>
</div>
</template>
<template v-else-if="column.key === 'totalAnswers'">
@ -802,6 +814,7 @@ const pointsTableData = computed(() => {
key: item.key,
rank: item.rank,
name: item.user,
studentId: item.studentId,
school: item.school,
grade: item.grade,
class: item.class,
@ -838,6 +851,7 @@ const coursesTableData = computed(() => {
key: item.key,
rank: item.rank,
name: item.user,
studentId: item.studentId,
school: item.school,
grade: item.grade,
class: item.class,
@ -872,6 +886,7 @@ const likesTableData = computed(() => {
key: item.key,
rank: item.rank,
name: item.user,
studentId: item.studentId,
school: item.school,
grade: item.grade,
class: item.class,
@ -906,6 +921,7 @@ const answersTableData = computed(() => {
key: item.key,
rank: item.rank,
name: item.user,
studentId: item.studentId,
school: item.school,
grade: item.grade,
class: item.class,
@ -982,6 +998,7 @@ function generateMockData(type) {
key: keyCounter++,
rank: 0,
user: name,
studentId: 2000000000000 + keyCounter,
school: schoolLabel,
cloudSchool: cloudSchoolValue,
grade: gradeLabel,
@ -1578,11 +1595,21 @@ function handleExport(type) {
gap: 12px;
}
.user-info {
display: flex;
flex-direction: column;
}
.user-name {
font-weight: 500;
color: #1e293b;
}
.user-id {
font-size: 12px;
color: #94a3b8;
}
/* 数值单元格样式 */
.value-cell {
font-weight: 600;

View File

@ -145,10 +145,10 @@
/>
</div>
<div class="filter-item">
<span class="filter-label">姓名:</span>
<span class="filter-label">姓名:</span>
<t-input
v-model="filters.studentName"
placeholder="请输入学姓名"
placeholder="请输入学姓名"
class="filter-input"
clearable
/>
@ -590,7 +590,16 @@ const COLUMN_ORDER_KEY = 'learning_overview_column_order'
//
const allColumns = [
{
title: '学生姓名',
title: '学员ID',
dataIndex: 'studentId',
key: 'studentId',
width: 130,
fixed: 'left',
align: 'center',
description: '学员唯一标识'
},
{
title: '学员姓名',
dataIndex: 'studentName',
key: 'studentName',
width: 90,
@ -751,15 +760,17 @@ const saveColumnOrder = () => {
//
const openColumnEditor = () => {
//
tempColumnList.value = columnConfig.value.map(cfg => {
const column = allColumns.find(col => col.key === cfg.key)
return {
key: cfg.key,
title: column?.title || cfg.key,
visible: cfg.visible
}
// - 使 allColumns
const configMap = {}
columnConfig.value.forEach(cfg => {
configMap[cfg.key] = cfg.visible
})
tempColumnList.value = allColumns.map(col => ({
key: col.key,
title: col.title,
visible: configMap[col.key] !== undefined ? configMap[col.key] : true
}))
showColumnEditorModal.value = true
}
@ -821,7 +832,25 @@ const columns = computed(() => {
}
})
return result
// IDID
const fixedCols = result.filter(col => col.fixed === 'left')
const otherCols = result.filter(col => col.fixed !== 'left')
// ID
const sortedFixedCols = []
const studentIdCol = fixedCols.find(col => col.key === 'studentId')
const studentNameCol = fixedCols.find(col => col.key === 'studentName')
if (studentIdCol) sortedFixedCols.push(studentIdCol)
if (studentNameCol) sortedFixedCols.push(studentNameCol)
//
fixedCols.forEach(col => {
if (col.key !== 'studentId' && col.key !== 'studentName') {
sortedFixedCols.push(col)
}
})
return [...sortedFixedCols, ...otherCols]
})
//
@ -899,6 +928,7 @@ const generateMockData = () => {
data.push({
id: i,
studentName: studentName,
studentId: 2000000000000 + i,
cloudSchool: cloudSchools[Math.floor(Math.random() * cloudSchools.length)],
school: schools[Math.floor(Math.random() * schools.length)],
grade: grade,

View File

@ -353,6 +353,7 @@
</div>
<div class="moment-content">
<div class="moment-name">{{ student.name }}</div>
<div class="moment-student-id">学员ID: {{ student.studentId }}</div>
<div v-if="student.content" class="moment-text">{{ student.content }}</div>
<!-- 图片墙超9张只显示前9张第9格显示查看全部遮罩 -->
@ -680,6 +681,7 @@
<img :src="detailModal.student.avatar" class="dm-avatar" />
<div class="dm-header-info">
<div class="dm-name">{{ detailModal.student.name }}</div>
<div class="dm-student-id">学员ID: {{ detailModal.student.studentId }}</div>
<div class="dm-time">{{ detailModal.student.submitTime }}</div>
</div>
<div v-if="detailModal.student.isExcellent" class="dm-excellent-tag">
@ -1151,6 +1153,7 @@ const mockStudentAssignments = ref(
const isExcellent = id % 7 === 0
return {
id,
studentId: 2000000000000 + id,
name,
avatar: `https://api.dicebear.com/7.x/avataaars/svg?seed=${name}`,
content: generateAssignmentContent(id),
@ -2666,6 +2669,12 @@ const goBack = () => {
font-size: 16px;
font-weight: 600;
color: #576B95; /* 微信朋友圈昵称颜色 */
margin-bottom: 4px;
}
.moment-student-id {
font-size: 12px;
color: #94A3B8;
margin-bottom: 6px;
}
@ -4809,6 +4818,12 @@ const goBack = () => {
line-height: 1.3;
}
.dm-student-id {
font-size: 12px;
color: #94A3B8;
margin-top: 2px;
}
.dm-time {
font-size: 12px;
color: #94A3B8;

View File

@ -312,7 +312,7 @@
:columns="studentColumns"
:data-source="filteredStudentData"
:pagination="{ pageSize: 10 }"
:scroll="{ x: 1200 }"
:scroll="{ x: 1300 }"
size="middle"
row-key="id"
class="student-table"
@ -835,6 +835,10 @@
<!-- 模态框内容 -->
<div class="student-detail-body">
<div class="student-detail-info">
<div class="info-item">
<span class="info-label">学员ID</span>
<span class="info-value">{{ currentStudentDetail?.id }}</span>
</div>
<div class="info-item">
<span class="info-label">姓名</span>
<span class="info-value">{{ currentStudentDetail?.name }}</span>
@ -1101,6 +1105,14 @@ const tableFilters = reactive({
// - 使
const studentColumns = computed(() => [
{
title: '学员ID',
dataIndex: 'id',
key: 'id',
width: 90,
fixed: 'left',
align: 'center'
},
{
title: '姓名',
dataIndex: 'name',
@ -1138,7 +1150,7 @@ const studentColumns = computed(() => [
align: 'center'
},
{
title: '仅学无交',
title: '仅学无交',
dataIndex: 'hasStudyNoSubmit',
key: 'hasStudyNoSubmit',
width: 80,
@ -1207,7 +1219,7 @@ const generateStudentData = (courseIndex) => {
const hasStudyNoSubmit = isOnline === '是' ? (Math.random() > 0.7 ? '是' : '否') : '否';
data.push({
id: `${courseIndex}-${i}`,
id: 2000000000000 + courseIndex * 100 + i,
name: names[i % names.length] + (i >= names.length ? i : ''),
comprehensiveLevel: levels[Math.floor(Math.random() * levels.length)],
subjectLevel: levels[Math.floor(Math.random() * levels.length)],
@ -1664,7 +1676,13 @@ const summaryColumns = [
customRender: ({ index }) => index + 1
},
{
title: '姓名',
title: '学员ID',
dataIndex: 'studentId',
key: 'studentId',
width: 130
},
{
title: '学员姓名',
dataIndex: 'name',
key: 'name',
width: 100
@ -1676,9 +1694,9 @@ const summaryColumns = [
width: 100
},
{
title: '学',
dataIndex: 'studentNo',
key: 'studentNo',
title: '学',
dataIndex: 'school',
key: 'school',
width: 120
}
];
@ -1686,14 +1704,16 @@ const summaryColumns = [
//
const generateSummaryData = () => {
const names = ['张三', '李四', '王五', '赵六', '钱七', '孙八', '周九', '吴十', '郑十一', '陈十二', '刘明', '黄强', '林娜', '杨帆', '何静', '王芳', '李华', '张强', '刘伟', '陈静'];
const schools = ['第一中学', '第二中学', '实验中学', '外国语学校', '师范大学附属中学'];
const data = [];
for (let i = 0; i < 20; i++) {
data.push({
id: `student-${i}`,
studentId: 2000000000001 + i,
name: names[i],
className: '高一(1)班',
studentNo: `2025${String(i + 1).padStart(3, '0')}`
school: schools[i % schools.length]
});
}
return data;
@ -1734,8 +1754,8 @@ const exportData = () => {
}
// CSV
const headers = ['序号', '姓名', '班级', '学'];
const rows = data.map((item, index) => [index + 1, item.name, item.className, item.studentNo]);
const headers = ['序号', '学员ID', '学员姓名', '班级', '学'];
const rows = data.map((item, index) => [index + 1, item.studentId, item.name, item.className, item.school]);
const csvContent = [headers.join(','), ...rows.map(row => row.join(','))].join('\n');
//