Files
hzdyjs/docs/需求文档/奖惩补贴需求/奖学金申请管理模块需求设计v2.0.md
T
2025-08-07 18:40:25 +08:00

23 KiB
Raw Blame History

奖学金申请管理模块需求设计 v2.0

版本: v2.0
更新时间: 2025-01-01
文档说明: 基于班主任代学生申请模式的重新设计


📋 1. 需求概述

1.1 背景说明

基于实际业务需求调研,奖学金申请流程需要调整为:

  • 班主任代申请模式:不再是学生自主申请,而是由班主任从班级学生中选择推荐
  • 材料上传管理:班主任可以为每个推荐学生上传申请材料(非必填)
  • 名额控制机制:严格按照班级或学院分配的名额进行申请限制
  • 时间窗口控制:只能在批次开放的时间段内进行申请操作

1.2 核心变更点

变更点 原设计 新设计
申请主体 学生自主申请 班主任代学生申请
申请方式 学生在线填写申请表 班主任从班级学生中选择
材料上传 学生自行上传 班主任统一管理上传
条件过滤 系统自动过滤 暂时不做申请条件过滤
名额控制 按院系统计控制 按班级→学院层级控制

👥 2. 角色权限设计

2.1 角色定义

角色 申请管理权限 主要操作
班主任 本班级学生申请管理 选择学生、上传材料、提交申请
学院管理员 本学院申请审核管理 查看申请、审核、统计
学生处管理员 全校申请统计管理 全局统计、结果确认
学生 查看自己申请状态 查看申请进度、结果

2.2 权限矩阵

功能模块 班主任 学院管理员 学生处管理员 学生
学生选择推荐 ✏️ 🔍 🔍 ❌
材料上传管理 ✏️ 🔍 🔍 ❌
申请提交 ✏️ ❌ ❌ ❌
申请审核 🔍 ✏️ ✏️ ❌
申请状态查看 ✅ ✅ ✅ 🔍
统计报表 🔍 ✏️ ✅ ❌

图例: ✅全部权限 ✏️编辑权限 🔍查看权限 ❌无权限


🔧 3. 功能模块设计

3.1 班主任申请管理

3.1.1 学生选择功能

功能描述: 班主任从本班级学生中选择推荐申请奖学金的学生

核心逻辑:

1. 获取班级学生列表(显示基本信息:学号、姓名、专业)
2. 支持多选学生(暂不做申请条件自动过滤)
3. 实时显示已选择学生数量 vs 可申请名额
4. 名额控制:优先使用班级分配名额,无班级名额时使用学院名额
5. 提供学生基本信息预览(便于班主任选择判断)

界面要求:

  • 学生列表表格:学号、姓名、专业、在校状态
  • 批量选择操作:全选、反选、清空
  • 名额提示:已选择 X 人,可申请名额 Y 人
  • 学生详情弹窗:点击学生姓名显示详细信息

3.1.2 材料上传管理

功能描述: 班主任为每个推荐学生上传申请材料

核心逻辑:

1. 已选择学生的材料管理列表
2. 支持每个学生上传多个材料文件
3. 材料分类管理:成绩单、获奖证书、其他证明
4. 文件格式限制:PDF、JPG、PNG,单文件不超过10MB
5. 材料状态标识:已上传、未上传(材料上传为非必填)

界面要求:

  • 学生材料管理表格:学生信息、材料数量、上传状态、操作
  • 材料上传弹窗:支持拖拽上传、批量上传
  • 材料预览功能:支持在线预览已上传材料
  • 进度提示:X 人已上传材料,Y 人未上传

3.1.3 申请提交控制

功能描述: 班主任统一提交本班级所有推荐学生的申请

核心逻辑:

1. 时间窗口检查:必须在批次申请开放时间内
2. 名额数量检查:推荐学生数不能超过分配名额
3. 名额分配检查:班级有名额优先使用,无班级名额时使用学院名额
4. 批量生成申请记录:每个学生生成一条申请记录
5. 状态更新:申请提交后不能修改,除非撤回

提交前验证:

  • ✅ 批次申请时间有效性
  • ✅ 推荐学生数量 ≤ 可用名额
  • ✅ 学生信息完整性
  • ⚠️ 材料上传完整性(提示但不强制)

3.2 名额控制机制

3.2.1 层级名额分配

全校总名额
├── 学院A名额
│   ├── 班级A1名额 (优先使用)
│   ├── 班级A2名额
│   └── 学院A机动名额 (班级无名额时使用)
└── 学院B名额
    ├── 班级B1名额
    └── 学院B机动名额

3.2.2 名额使用逻辑

申请时名额检查顺序:

  1. 班级名额优先: 如果班级有分配名额,优先使用班级名额
  2. 学院名额兜底: 如果班级无名额,使用学院级别名额
  3. 名额不足提示: 超过可用名额时给出明确提示
  4. 实时名额更新: 申请提交后立即更新已用名额

名额计算公式:

-- 班级可用名额计算
班级可用名额 = 班级总名额 - 班级已用名额 - 班级预留名额

-- 学院可用名额计算(当班级无名额时)
学院可用名额 = 学院总名额 - 学院已用名额 - 学院预留名额

3.3 时间窗口控制

3.3.1 申请时间控制

// 申请时间检查逻辑
public boolean checkApplicationTimeWindow(Long batchId) {
    ScholarshipBatch batch = batchService.getById(batchId);
    Date now = new Date();
    
    // 检查批次状态
    if (!"ACTIVE".equals(batch.getStatus())) {
        return false;
    }
    
    // 检查申请时间窗口
    return now.after(batch.getApplicationStartTime()) 
        && now.before(batch.getApplicationEndTime());
}

3.3.2 操作权限控制

操作 申请开始前 申请期间 申请结束后
选择学生 ❌ ✅ ❌
上传材料 ❌ ✅ 🔍(仅查看)
提交申请 ❌ ✅ ❌
撤回申请 ❌ ✅ ❌
查看状态 ✅ ✅ ✅

📊 4. 数据模型设计

4.1 申请记录表调整

基于新需求,需要调整现有的申请记录表结构:

-- 修改申请记录表
ALTER TABLE jcbt_scholarship_application 
ADD COLUMN `applicant_type` VARCHAR(20) DEFAULT 'TEACHER' COMMENT '申请人类型:STUDENT-学生申请,TEACHER-教师代申请';

ALTER TABLE jcbt_scholarship_application 
ADD COLUMN `applicant_id` BIGINT(20) DEFAULT NULL COMMENT '申请人ID(班主任ID)';

ALTER TABLE jcbt_scholarship_application 
ADD COLUMN `applicant_name` VARCHAR(100) DEFAULT NULL COMMENT '申请人姓名(班主任姓名)';

-- 修改申请类型枚举值
ALTER TABLE jcbt_scholarship_application 
MODIFY COLUMN `application_type` VARCHAR(20) NOT NULL 
COMMENT '申请类型:TEACHER_RECOMMEND-教师推荐,AUTO-自动评定,DIRECT-直接指定';

-- 添加班级信息索引
CREATE INDEX idx_class_batch ON jcbt_scholarship_application(class_id, batch_id);
CREATE INDEX idx_applicant_batch ON jcbt_scholarship_application(applicant_id, batch_id);

4.2 班级名额分配表

新增班级级别的名额分配管理:

-- 班级名额分配表
CREATE TABLE jcbt_scholarship_class_quota (
    id                  BIGINT(20)      NOT NULL            COMMENT '主键ID',
    batch_id           BIGINT(20)      NOT NULL            COMMENT '批次ID',
    scholarship_type_id BIGINT(20)     NOT NULL            COMMENT '奖学金类型ID',
    dept_id            BIGINT(20)      NOT NULL            COMMENT '学院ID',
    class_id           BIGINT(20)      NOT NULL            COMMENT '班级ID',
    class_name         VARCHAR(100)    NOT NULL            COMMENT '班级名称',
    total_quota        INT             DEFAULT 0           COMMENT '总名额',
    used_quota         INT             DEFAULT 0           COMMENT '已用名额',
    reserved_quota     INT             DEFAULT 0           COMMENT '预留名额',
    available_quota    INT             DEFAULT 0           COMMENT '可用名额',
    allocation_method  VARCHAR(20)     DEFAULT 'MANUAL'    COMMENT '分配方式:MANUAL-手动分配,AUTO-自动分配',
    is_locked          TINYINT(1)      DEFAULT 0           COMMENT '是否锁定:0-否,1-是',
    status             VARCHAR(20)     DEFAULT 'ACTIVE'    COMMENT '状态:ACTIVE-有效,INACTIVE-无效',
    remark             VARCHAR(500)    DEFAULT NULL        COMMENT '备注',
    tenant_id          BIGINT(20)      NOT NULL            COMMENT '租户ID',
    create_by          BIGINT(20)      DEFAULT NULL        COMMENT '创建者',
    create_time        DATETIME        DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    update_by          BIGINT(20)      DEFAULT NULL        COMMENT '更新者',
    update_time        DATETIME        DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
    deleted            TINYINT(1)      DEFAULT 0           COMMENT '删除标记:0-正常,1-删除',
    PRIMARY KEY (id),
    UNIQUE KEY uk_batch_type_class (batch_id, scholarship_type_id, class_id, deleted),
    INDEX idx_dept_class (dept_id, class_id),
    INDEX idx_batch_dept (batch_id, dept_id),
    INDEX idx_quota_status (total_quota, status),
    INDEX idx_tenant (tenant_id, deleted)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='班级名额分配表';

4.3 申请材料表调整

调整材料表以支持班主任上传:

-- 添加上传者信息
ALTER TABLE jcbt_scholarship_attachment 
ADD COLUMN `uploader_type` VARCHAR(20) DEFAULT 'TEACHER' COMMENT '上传者类型:STUDENT-学生,TEACHER-教师';

ALTER TABLE jcbt_scholarship_attachment 
ADD COLUMN `uploader_id` BIGINT(20) DEFAULT NULL COMMENT '上传者ID';

ALTER TABLE jcbt_scholarship_attachment 
ADD COLUMN `uploader_name` VARCHAR(100) DEFAULT NULL COMMENT '上传者姓名';

-- 修改必需字段逻辑
ALTER TABLE jcbt_scholarship_attachment 
MODIFY COLUMN `is_required` TINYINT(1) DEFAULT 0 COMMENT '是否必需:0-否,1-是(新需求中材料非必填)';

4.4 名额使用记录表

新增名额使用记录表,用于追踪名额使用情况:

-- 名额使用记录表
CREATE TABLE jcbt_scholarship_quota_usage (
    id                  BIGINT(20)      NOT NULL            COMMENT '主键ID',
    batch_id           BIGINT(20)      NOT NULL            COMMENT '批次ID',
    scholarship_type_id BIGINT(20)     NOT NULL            COMMENT '奖学金类型ID',
    quota_type         VARCHAR(20)     NOT NULL            COMMENT '名额类型:CLASS-班级名额,DEPT-学院名额',
    target_id          BIGINT(20)      NOT NULL            COMMENT '目标ID(班级ID或学院ID)',
    application_id     BIGINT(20)      NOT NULL            COMMENT '申请ID',
    student_id         BIGINT(20)      NOT NULL            COMMENT '学生ID',
    operation_type     VARCHAR(20)     NOT NULL            COMMENT '操作类型:USE-使用,RELEASE-释放',
    operation_time     DATETIME        NOT NULL            COMMENT '操作时间',
    operator_id        BIGINT(20)      NOT NULL            COMMENT '操作人ID',
    operator_name      VARCHAR(100)    NOT NULL            COMMENT '操作人姓名',
    remark             VARCHAR(500)    DEFAULT NULL        COMMENT '备注',
    tenant_id          BIGINT(20)      NOT NULL            COMMENT '租户ID',
    create_by          BIGINT(20)      DEFAULT NULL        COMMENT '创建者',
    create_time        DATETIME        DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    update_by          BIGINT(20)      DEFAULT NULL        COMMENT '更新者',
    update_time        DATETIME        DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
    deleted            TINYINT(1)      DEFAULT 0           COMMENT '删除标记:0-正常,1-删除',
    PRIMARY KEY (id),
    INDEX idx_batch_type_target (batch_id, scholarship_type_id, target_id),
    INDEX idx_application_student (application_id, student_id),
    INDEX idx_operation_time (operation_type, operation_time),
    INDEX idx_tenant (tenant_id, deleted)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='名额使用记录表';

🔄 5. 业务流程设计

5.1 申请提交流程

graph TD
    A[班主任登录] --> B[选择申请批次]
    B --> C[检查申请时间窗口]
    C --> D{时间窗口有效?}
    D -->|否| E[提示申请时间未开放]
    D -->|是| F[获取班级学生列表]
    F --> G[选择推荐学生]
    G --> H[检查名额限制]
    H --> I{名额足够?}
    I -->|否| J[提示名额不足]
    I -->|是| K[上传学生材料]
    K --> L[确认提交申请]
    L --> M[生成申请记录]
    M --> N[更新名额使用]
    N --> O[发送提交通知]

5.2 名额检查流程

graph TD
    A[开始名额检查] --> B[获取班级分配名额]
    B --> C{班级有分配名额?}
    C -->|是| D[计算班级可用名额]
    C -->|否| E[获取学院分配名额]
    D --> F{班级名额足够?}
    F -->|是| G[使用班级名额]
    F -->|否| E
    E --> H[计算学院可用名额]
    H --> I{学院名额足够?}
    I -->|是| J[使用学院名额]
    I -->|否| K[提示名额不足]
    G --> L[允许申请]
    J --> L
    K --> M[拒绝申请]

5.3 材料管理流程

graph TD
    A[进入材料管理] --> B[显示已选学生列表]
    B --> C[选择学生上传材料]
    C --> D[检查文件格式]
    D --> E{格式有效?}
    E -->|否| F[提示格式错误]
    E -->|是| G[上传文件到服务器]
    G --> H[保存材料记录]
    H --> I[更新材料状态]
    I --> J[显示上传成功]
    J --> K{还有其他学生?}
    K -->|是| C
    K -->|否| L[完成材料上传]

📋 6. 接口设计

6.1 学生选择接口

/**
 * 获取班级学生列表(供选择推荐)
 */
@GetMapping("/class-students")
public R<List<StudentSelectVo>> getClassStudents(
    @RequestParam Long classId,
    @RequestParam Long batchId,
    @RequestParam Long scholarshipTypeId) {
    // 返回班级学生列表,包含基本信息和是否已申请状态
}

/**
 * 检查申请名额限制
 */
@PostMapping("/check-quota")
public R<QuotaCheckVo> checkQuota(
    @RequestBody QuotaCheckBo quotaCheckBo) {
    // 检查选择的学生数量是否超过可用名额
}

6.2 申请提交接口

/**
 * 批量提交学生申请
 */
@PostMapping("/batch-submit")
public R<BatchSubmitVo> batchSubmitApplications(
    @RequestBody BatchApplicationBo batchApplicationBo) {
    // 批量创建申请记录,更新名额使用情况
}

/**
 * 撤回班级申请
 */
@PostMapping("/withdraw-batch")
public R<Void> withdrawBatchApplications(
    @RequestParam Long classId,
    @RequestParam Long batchId,
    @RequestParam Long scholarshipTypeId) {
    // 撤回班级所有申请,释放名额
}

6.3 材料管理接口

/**
 * 上传学生申请材料
 */
@PostMapping("/upload-material")
public R<MaterialUploadVo> uploadStudentMaterial(
    @RequestParam Long applicationId,
    @RequestParam MultipartFile file,
    @RequestParam String materialType) {
    // 上传单个学生的申请材料
}

/**
 * 获取学生材料列表
 */
@GetMapping("/student-materials")
public R<List<MaterialVo>> getStudentMaterials(
    @RequestParam Long applicationId) {
    // 获取指定申请的所有材料
}

📊 7. 前端页面设计

7.1 申请管理主页面

页面结构:

[批次选择] [奖学金类型选择]
==========================================
申请状态: [时间窗口状态] [名额统计]
==========================================
学生选择区域:
┌─────────────────────────────────────┐
│ [全选] [反选] [清空] 已选择X人/可申请Y人 │
├─────────────────────────────────────┤
│ ☐ 张三 (2021001) 计算机科学与技术      │
│ ☑ 李四 (2021002) 软件工程             │
│ ☐ 王五 (2021003) 信息安全             │
└─────────────────────────────────────┘
==========================================
[上传材料] [提交申请] [撤回申请]

7.2 材料管理页面

页面结构:

材料上传管理
==========================================
┌─学生─┬─材料数量─┬─上传状态─┬─操作─┐
│ 张三 │   2     │  已完成  │ 查看 │
│ 李四 │   0     │  未上传  │ 上传 │
│ 王五 │   1     │  部分    │ 管理 │
└─────┴────────┴────────┴──────┘
==========================================
进度: 2人已上传材料,1人未上传

7.3 申请状态查看页面

页面结构:

申请状态总览
==========================================
批次: 2024年春季学期 | 类型: 国家奖学金
申请时间: 2024-03-01 ~ 2024-03-31
名额情况: 班级名额 2/3,学院名额 15/20
==========================================
申请学生列表:
┌─学号───┬─姓名─┬─状态───┬─材料─┬─操作─┐
│2021001 │ 张三 │ 待审核  │  2   │ 查看 │
│2021002 │ 李四 │ 已通过  │  0   │ 查看 │
└────────┴─────┴────────┴──────┴──────┘

🔧 8. 技术实现要点

8.1 名额控制实现

@Service
public class QuotaControlService {
    
    /**
     * 检查并分配名额
     */
    public QuotaAllocationResult allocateQuota(QuotaAllocationBo request) {
        // 1. 检查班级名额
        QuotaVo classQuota = getClassQuota(request.getClassId(), 
            request.getBatchId(), request.getScholarshipTypeId());
        
        if (classQuota != null && classQuota.getAvailableQuota() >= request.getStudentCount()) {
            // 使用班级名额
            return allocateClassQuota(request, classQuota);
        }
        
        // 2. 检查学院名额
        QuotaVo deptQuota = getDeptQuota(request.getDeptId(), 
            request.getBatchId(), request.getScholarshipTypeId());
        
        if (deptQuota != null && deptQuota.getAvailableQuota() >= request.getStudentCount()) {
            // 使用学院名额
            return allocateDeptQuota(request, deptQuota);
        }
        
        // 3. 名额不足
        throw new BusinessException("可用名额不足");
    }
}

8.2 时间窗口控制

@Component
public class ApplicationTimeValidator {
    
    @Autowired
    private ScholarshipBatchService batchService;
    
    /**
     * 验证申请时间窗口
     */
    public void validateApplicationTime(Long batchId) {
        ScholarshipBatch batch = batchService.getById(batchId);
        Date now = new Date();
        
        // 检查批次状态
        if (!"ACTIVE".equals(batch.getStatus())) {
            throw new BusinessException("当前批次未开放申请");
        }
        
        // 检查申请开始时间
        if (now.before(batch.getApplicationStartTime())) {
            throw new BusinessException("申请尚未开始,开始时间:" + 
                DateUtils.formatDate(batch.getApplicationStartTime()));
        }
        
        // 检查申请结束时间
        if (now.after(batch.getApplicationEndTime())) {
            throw new BusinessException("申请已结束,结束时间:" + 
                DateUtils.formatDate(batch.getApplicationEndTime()));
        }
    }
}

8.3 批量申请提交

@Service
@Transactional(rollbackFor = Exception.class)
public class BatchApplicationService {
    
    /**
     * 批量提交申请
     */
    public BatchSubmitResult batchSubmitApplications(BatchApplicationBo request) {
        // 1. 验证申请时间
        applicationTimeValidator.validateApplicationTime(request.getBatchId());
        
        // 2. 分配名额
        QuotaAllocationResult quotaResult = quotaControlService.allocateQuota(request);
        
        // 3. 批量创建申请记录
        List<ScholarshipApplication> applications = request.getStudentIds().stream()
            .map(studentId -> buildApplication(request, studentId, quotaResult))
            .collect(Collectors.toList());
        
        scholarshipApplicationService.saveBatch(applications);
        
        // 4. 更新名额使用情况
        updateQuotaUsage(quotaResult);
        
        // 5. 记录操作日志
        logBatchOperation(request, applications);
        
        return BatchSubmitResult.success(applications.size());
    }
}

📝 9. 测试用例设计

9.1 功能测试用例

测试场景 测试步骤 预期结果
正常申请流程 1.选择学生 2.上传材料 3.提交申请 申请成功,名额正确扣减
名额不足 选择学生数量超过可用名额 提示名额不足,禁止提交
时间窗口外申请 在申请时间外进行操作 提示时间窗口错误
材料上传 上传各种格式文件 正确文件上传成功,错误格式拒绝
申请撤回 提交后撤回申请 申请状态更新,名额释放

9.2 性能测试用例

测试场景 并发数 数据量 性能要求
批量申请提交 50 100人/班 响应时间<3秒
学生列表查询 100 10000学生 响应时间<1秒
材料上传 20 10MB文件 上传成功率>99%

📚 10. 部署说明

10.1 数据库升级脚本

  1. 执行申请表结构调整脚本
  2. 创建班级名额分配表
  3. 创建名额使用记录表
  4. 更新相关索引

10.2 配置项调整

# application.yml
scholarship:
  application:
    # 材料上传配置
    material:
      max-file-size: 10MB
      allowed-types: pdf,jpg,jpeg,png
      upload-path: /data/scholarship/materials/
    
    # 名额控制配置
    quota:
      check-enabled: true
      auto-allocation: true
    
    # 时间窗口配置
    time-window:
      strict-check: true
      buffer-minutes: 30

📋 11. 总结

11.1 主要改进点

  1. 申请模式优化: 从学生自申请改为班主任代申请,提高管理效率
  2. 名额控制增强: 实现班级→学院两级名额管理,更精确的控制
  3. 材料管理简化: 班主任统一管理,降低学生操作复杂度
  4. 时间窗口严格控制: 确保申请在规定时间内进行

11.2 技术创新点

  1. 层级名额算法: 智能的班级→学院名额分配算法
  2. 批量操作优化: 高效的批量申请提交和撤回机制
  3. 实时状态同步: 名额使用情况实时更新
  4. 操作日志完整: 完整的操作追踪和审计功能

11.3 下一步计划

  1. Phase 1: 完成核心申请管理功能开发
  2. Phase 2: 增加申请条件自动过滤功能
  3. Phase 3: 完善统计报表和数据导出
  4. Phase 4: 优化用户体验和性能调优

文档维护: 本文档将随着需求变更和系统开发进展持续更新
最后更新: 2025-01-01
文档版本: v2.0