11 KiB
11 KiB
班主任批量申请奖学金页面名额信息显示功能实现
变更日期: 2025-01-27 15:30:00
操作人员: AI Assistant
变更类型: 功能增强
影响模块: 奖学金申请管理
📋 变更概述
在班主任批量申请奖学金页面中新增名额信息显示功能,让班主任能够清楚地看到每个奖学金类型的名额分配情况,包括总名额、已用名额、可用名额等信息。
🎯 需求背景
班主任在进行批量申请奖学金时,需要了解每个奖学金类型的名额情况,以便合理分配和选择,避免申请时才发现名额不足的问题。
🛠️ 技术实现
1. API调用优化
文件: web/src/views/jcbt/scholarship/application/index.vue
变更内容:
- 修改
handleBatchChange方法,使用getScholarshipTypesWithQuota接口替代getScholarshipTypesByBatch - 新接口能够返回带名额信息的奖学金类型数据
// 变更前
const res: any = await getScholarshipTypesByBatch(batch.id);
// 变更后
if (classInfo.value.classId) {
const res: any = await getScholarshipTypesWithQuota(batch.id, classInfo.value.classId);
} else {
const res: any = await getScholarshipTypesByBatch(batch.id);
}
2. 名额显示逻辑
新增方法:
/** 获取名额状态对应的标签类型 */
const getQuotaStatusType = (type: any) => {
if (!type.hasQuota && type.quotaStatus === 'unlimited') {
return 'info'; // 无限制名额
}
switch (type.quotaStatus) {
case 'available': return 'success'; // 有可用名额
case 'full': return 'warning'; // 名额已满
default: return 'danger'; // 其他情况
}
};
/** 格式化名额显示文本 */
const formatQuotaText = (type: any) => {
if (!type.hasQuota && type.quotaStatus === 'unlimited') {
return '无名额限制';
}
if (type.hasQuota) {
return `班级名额: ${type.availableQuota}/${type.totalQuota}`;
} else {
return `全校名额: ${type.availableQuota}/${type.totalQuota}`;
}
};
/** 检查奖学金类型是否可选择 */
const isScholarshipTypeSelectable = (type: any) => {
if (!type.hasQuota && type.quotaStatus === 'unlimited') {
return true;
}
return type.availableQuota > 0;
};
3. 界面显示优化
批次信息区域:
- 奖学金类型标签增加名额信息显示
- 根据名额状态显示不同颜色的标签
<el-tag
v-for="type in availableScholarshipTypes"
:key="type.id"
class="mr-2 mb-2"
:type="getQuotaStatusType(type)"
>
<div class="flex flex-col">
<span>{{ type.name }} - {{ type.levelType }} (¥{{ type.amount }})</span>
<span class="text-xs mt-1">{{ formatQuotaText(type) }}</span>
</div>
</el-tag>
学生选择区域:
- 奖学金类型选择器显示名额信息
- 名额不足的选项自动禁用
<el-option
v-for="type in availableScholarshipTypes"
:key="type.id"
:label="`${type.name} (¥${type.amount}) - ${formatQuotaText(type)}`"
:value="type"
:disabled="!isScholarshipTypeSelectable(type)"
>
<div class="flex justify-between items-center">
<span>{{ type.name }} (¥{{ type.amount }})</span>
<el-tag
size="small"
:type="getQuotaStatusType(type)"
class="ml-2"
>
{{ formatQuotaText(type) }}
</el-tag>
</div>
</el-option>
4. 名额验证逻辑
提交前验证:
- 检查选择的奖学金类型是否还有名额
- 检查同一类型申请数量是否超过可用名额
- 提供详细的错误提示
// 检查选择的奖学金类型是否还有名额
const quotaExceededTypes = new Map();
selectedStudents.value.forEach((student: any) => {
if (student.selectedScholarshipType && !isScholarshipTypeSelectable(student.selectedScholarshipType)) {
// 收集名额不足的类型和学生
}
});
// 检查同一奖学金类型的申请数量是否超过可用名额
const typeApplicationCount = new Map();
// ... 统计逻辑
for (const [typeId, count] of typeApplicationCount.entries()) {
const scholarshipType = availableScholarshipTypes.value.find(t => t.id === typeId);
if (scholarshipType && count > scholarshipType.availableQuota) {
ElMessage.error(`${scholarshipType.name} 申请人数(${count})超过可用名额(${scholarshipType.availableQuota})`);
return;
}
}
5. 样式优化
新增CSS样式:
/* 名额信息相关样式 */
.flex-col {
flex-direction: column;
}
.text-xs {
font-size: 0.75rem;
}
/* 名额状态颜色 */
.quota-status-available {
color: #67c23a;
}
.quota-status-warning {
color: #e6a23c;
}
.quota-status-full {
color: #f56c6c;
}
.quota-status-unlimited {
color: #909399;
}
📊 数据结构
名额信息数据格式
getScholarshipTypesWithQuota 接口返回的数据结构:
{
"id": 1,
"name": "国家奖学金",
"amount": 8000,
"levelType": "国家级",
"typeCategory": "奖学金",
"hasQuota": true,
"totalQuota": 10,
"usedQuota": 3,
"availableQuota": 7,
"quotaStatus": "available"
}
名额状态说明
available: 有可用名额 - 绿色标签full: 名额已满 - 橙色标签unlimited: 无名额限制 - 蓝色标签- 其他状态: 红色标签
🎨 用户体验优化
1. 视觉反馈
- 绿色标签: 有可用名额,可以申请
- 橙色标签: 名额已满,不建议申请
- 蓝色标签: 无名额限制,可以申请
- 红色标签: 异常状态
2. 交互优化
- 名额不足的选项自动禁用
- 选择名额不足类型时显示警告提示
- 提交前进行完整的名额验证
3. 信息展示
- 批次信息区域:简洁的名额概览
- 学生选择区域:详细的名额信息和状态
🔍 测试要点
1. 功能测试
- ✅ 批次选择后正确显示名额信息
- ✅ 名额状态颜色正确显示
- ✅ 名额不足时选项正确禁用
- ✅ 提交时名额验证正确执行
2. 边界测试
- ✅ 无班级ID时降级使用普通接口
- ✅ API调用失败时的错误处理
- ✅ 名额为0时的显示和禁用
- ✅ 无名额限制时的正确显示
3. 用户体验测试
- ✅ 名额信息显示清晰易懂
- ✅ 颜色区分明显有效
- ✅ 错误提示信息准确详细
📝 注意事项
1. API依赖
- 依赖后端
getScholarshipTypesWithQuota接口正常工作 - 需要传入正确的批次ID和班级ID
2. 数据一致性
- 名额信息实时性依赖后端数据更新
- 并发申请时可能存在名额竞争问题
3. 权限控制
- 确保班主任只能看到自己班级的名额信息
- 接口需要进行适当的权限验证
✅ 完成状态
- API调用优化
- 名额显示逻辑实现
- 界面显示优化
- 名额验证逻辑
- 样式优化
- 用户体验优化
- 变更记录文档
🔄 方案一优化实施 (2025-01-27 16:00:00)
📋 已完成的优化
1. 数据结构优化
- ✅ 支持
classQuota和schoolQuota双重名额结构 - ✅ 优先显示班级名额,同时显示全校名额作为参考
- ✅ 保持向后兼容性,支持旧数据格式
2. 显示逻辑优化
<!-- 批次信息区域 - 分层显示名额信息 -->
<div class="text-xs mt-1">
<!-- 优先显示班级名额 -->
<div v-if="type.classQuota && type.classQuota.hasQuota"
class="text-primary font-medium">
班级名额: {{ type.classQuota.availableQuota }}/{{ type.classQuota.totalQuota }}
<span v-if="type.classQuota.availableQuota === 0" class="text-warning ml-1">(已满)</span>
</div>
<!-- 显示全校名额 -->
<div v-if="type.schoolQuota" class="text-gray-500">
全校名额: {{ type.schoolQuota.availableQuota }}/{{ type.schoolQuota.totalQuota }}
</div>
</div>
3. 选择器优化
<!-- 学生选择区域 - 详细名额信息 -->
<div class="flex-1">
<div>{{ type.name }} (¥{{ type.amount }})</div>
<div class="text-xs text-gray-500 mt-1">
<div v-if="type.classQuota && type.classQuota.hasQuota" class="text-primary">
班级: {{ type.classQuota.availableQuota }}/{{ type.classQuota.totalQuota }}
</div>
<div v-if="type.schoolQuota">
全校: {{ type.schoolQuota.availableQuota }}/{{ type.schoolQuota.totalQuota }}
</div>
</div>
</div>
4. 验证逻辑优化
// 优先基于班级名额验证
if (scholarshipType.classQuota && scholarshipType.classQuota.hasQuota) {
if (count > scholarshipType.classQuota.availableQuota) {
ElMessage.error(`申请人数(${count})超过班级可用名额(${scholarshipType.classQuota.availableQuota})`);
return;
}
}
📊 新数据格式要求
后端API需要返回的数据结构:
{
"id": 1,
"name": "国家奖学金",
"amount": 8000,
"levelType": "国家级",
"classQuota": {
"hasQuota": true,
"totalQuota": 5,
"usedQuota": 2,
"availableQuota": 3,
"quotaStatus": "available"
},
"schoolQuota": {
"hasQuota": true,
"totalQuota": 100,
"usedQuota": 30,
"availableQuota": 70,
"quotaStatus": "available"
}
}
🎨 视觉效果
显示效果预览:
┌─────────────────────────────────────────┐
│ 国家奖学金 - 国家级 (¥8000) │
│ 班级名额: 3/5 │ <- 蓝色,优先显示
│ 全校名额: 70/100 │ <- 灰色,参考信息
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ 省政府奖学金 - 省级 (¥6000) │
│ 班级名额: 0/2 (已满) │ <- 橙色警告
│ 全校名额: 15/50 │ <- 灰色,参考信息
└─────────────────────────────────────────┘
📝 文档创建
- ✅ 创建
docs/开发文档/API/后端API数据格式示例-班级名额显示.md - ✅ 包含完整的数据结构说明和后端实现建议
- ✅ 提供SQL查询示例和Java实体类模板
🚨 需要后端支持
⚠️ 重要提醒
前端代码已完成适配,但需要后端实现以下内容:
-
修改
getScholarshipTypesWithQuota接口- 返回包含
classQuota和schoolQuota的数据结构 - 计算班级维度的名额分配情况
- 保持与全校名额的数据一致性
- 返回包含
-
数据库设计
- 可能需要添加班级名额分配表
- 建立班级与奖学金类型的名额关联
-
权限验证
- 确保班主任只能看到自己班级的名额信息
- 验证
classId参数的合法性
📋 部署步骤
- 前端部署: 当前修改可以直接部署,会自动兼容现有数据格式
- 后端开发: 根据文档中的数据格式要求实现API
- 测试验证: 确保新旧数据格式都能正确显示
- 生产部署: 先部署后端,再更新前端
🔄 后续优化建议
- 实时名额更新: 考虑添加名额信息的实时刷新机制
- 名额预警: 当名额即将用完时提供预警提示
- 历史名额统计: 显示历史批次的名额使用情况
- 名额分配可视化: 用图表形式展示名额分配情况
变更完成时间: 2025-01-27 16:15:00
前端状态: ✅ 已完成适配
后端状态: ⏳ 待实现新数据格式
部署状态: 🔄 需要后端配合完成