变更日期: 2025-01-27 15:30:00
操作人员: AI Assistant
变更类型: 功能增强
影响模块: 奖学金申请管理
在班主任批量申请奖学金页面中新增名额信息显示功能,让班主任能够清楚地看到每个奖学金类型的名额分配情况,包括总名额、已用名额、可用名额等信息。
班主任在进行批量申请奖学金时,需要了解每个奖学金类型的名额情况,以便合理分配和选择,避免申请时才发现名额不足的问题。
文件: 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);
}
新增方法:
/** 获取名额状态对应的标签类型 */
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;
};
批次信息区域:
<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>
提交前验证:
// 检查选择的奖学金类型是否还有名额
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;
}
}
新增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: 无名额限制 - 蓝色标签getScholarshipTypesWithQuota 接口正常工作classQuota 和 schoolQuota 双重名额结构<!-- 批次信息区域 - 分层显示名额信息 -->
<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>
<!-- 学生选择区域 - 详细名额信息 -->
<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>
// 优先基于班级名额验证
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前端代码已完成适配,但需要后端实现以下内容:
修改 getScholarshipTypesWithQuota 接口
classQuota 和 schoolQuota 的数据结构数据库设计
权限验证
classId 参数的合法性变更完成时间: 2025-01-27 16:15:00
前端状态: ✅ 已完成适配
后端状态: ⏳ 待实现新数据格式
部署状态: 🔄 需要后端配合完成