wuzhen update

This commit is contained in:
wuzhen committed 2025-08-10 00:24:31 +08:00
1 parent bab7b53074
commit a2222f63cb
284 files changed
+48629 -3473

No files matched your search

+1
View File
@@ -0,0 +1 @@
ALTER TABLE jcbt_scholarship_type ADD COLUMN create_dept BIGINT(20) COMMENT '创建部门' AFTER is_system;
+6
View File
@@ -0,0 +1,6 @@
-- 为 jcbt_scholarship_application 表添加 create_dept 字段
-- 解决 MyBatis-Plus 插入数据时的字段缺失问题
ALTER TABLE jcbt_scholarship_application
ADD COLUMN create_dept bigint(20) DEFAULT NULL COMMENT '创建部门'
AFTER submit_time;
+30
View File
@@ -0,0 +1,30 @@
-- 调试compatibility_type字段问题
-- 检查表结构
DESCRIBE jcbt_scholarship_type;
-- 检查字段是否存在
SHOW COLUMNS FROM jcbt_scholarship_type LIKE 'compatibility_type';
-- 查看具体数据
SELECT id, type_name, compatibility_type,
CASE
WHEN compatibility_type IS NULL THEN 'NULL值'
WHEN compatibility_type = '' THEN '空字符串'
ELSE CONCAT('有值:', compatibility_type)
END as value_status
FROM jcbt_scholarship_type
WHERE deleted = 0
LIMIT 10;
-- 统计各种值的分布
SELECT
compatibility_type,
COUNT(*) as count,
CASE
WHEN compatibility_type IS NULL THEN 'NULL值'
WHEN compatibility_type = '' THEN '空字符串'
ELSE '有效值'
END as value_type
FROM jcbt_scholarship_type
WHERE deleted = 0
GROUP BY compatibility_type;
+36
View File
@@ -0,0 +1,36 @@
-- =====================================================
-- 奖学金兼得关系表 - create_dept字段修复脚本
-- 版本: v1.0
-- 创建时间: 2025-01-27
-- 问题描述: 实体类继承BaseEntity包含create_dept字段,但数据库表缺少该字段
-- 解决方案: 为jcbt_scholarship_compatibility表添加create_dept字段
-- =====================================================
USE `ruoyi-vue-pro`;
-- 为奖学金兼得关系表添加create_dept字段
ALTER TABLE `jcbt_scholarship_compatibility`
ADD COLUMN IF NOT EXISTS `create_dept` BIGINT(20) COMMENT '创建部门'
AFTER `description`;
-- 验证字段添加结果
SELECT
COLUMN_NAME,
DATA_TYPE,
IS_NULLABLE,
COLUMN_DEFAULT,
COLUMN_COMMENT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'ruoyi-vue-pro'
AND TABLE_NAME = 'jcbt_scholarship_compatibility'
AND COLUMN_NAME = 'create_dept';
-- 显示表结构确认修复结果
DESCRIBE `jcbt_scholarship_compatibility`;
-- =====================================================
-- 修复说明:
-- 1. 该字段是BaseEntity的标准字段,用于记录创建部门
-- 2. 字段类型为BIGINT(20),允许NULL,与其他表保持一致
-- 3. 字段位置放在description字段之后,符合标准字段顺序
-- =====================================================
@@ -0,0 +1,33 @@
-- 修复奖学金申请表缺失的create_dept字段
-- 问题: MyBatis-Plus插入数据时报错 Unknown column 'create_dept' in 'field list'
-- 原因: 数据库表缺少BaseEntity中的create_dept字段
-- 解决方案: 为jcbt_scholarship_application表添加create_dept字段
-- 检查字段是否存在,不存在则添加
SET @sql = '';
SELECT COUNT(*) INTO @col_exists
FROM information_schema.columns
WHERE table_schema = 'hzdyjs_xg'
AND table_name = 'jcbt_scholarship_application'
AND column_name = 'create_dept';
-- 如果字段不存在,则添加
SET @sql = IF(@col_exists = 0,
'ALTER TABLE jcbt_scholarship_application ADD COLUMN create_dept bigint(20) DEFAULT NULL COMMENT ''创建部门'' AFTER submit_time;',
'SELECT ''字段 create_dept 已存在,跳过添加'' AS message;');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 验证字段是否添加成功
SELECT
COLUMN_NAME as '字段名',
DATA_TYPE as '数据类型',
IS_NULLABLE as '允许空值',
COLUMN_DEFAULT as '默认值',
COLUMN_COMMENT as '注释'
FROM information_schema.columns
WHERE table_schema = 'hzdyjs_xg'
AND table_name = 'jcbt_scholarship_application'
AND column_name = 'create_dept';
+37
View File
@@ -0,0 +1,37 @@
mysql: [Warning] Using a password on the command line interface can be insecure.
info
=== 1. 班主任和班级信息检查 ===
info
=== 2. 奖学金批次信息检查 ===
batch_id batch_name batch_status start_time end_time create_time
1952730449122004993 2025-2026??????????????? ACTIVE 2025-08-05 00:00:00 2025-08-29 00:00:00 2025-08-05 21:56:34
1 2024-2025??????????? ACTIVE 2024-09-01 00:00:00 2024-12-31 23:59:59 2025-08-05 09:04:39
info
=== 3. 奖学金类型信息检查 ===
type_id type_name level_type type_status batch_id batch_name
1 ??????? FIRST 1 1953330495479644161 2025-2026?????????????
1 ??????? FIRST 1 1952730449122004993 2025-2026???????????????
5 ????????? FIRST 1 1952730449122004993 2025-2026???????????????
1953004971846852609 ??????? FIRST 1 1952730449122004993 2025-2026???????????????
6 ????????? FIRST 1 NULL NULL
2 ??????? SECOND 1 1953330495479644161 2025-2026?????????????
2 ??????? SECOND 1 1952730449122004993 2025-2026???????????????
1953005237862195202 ??????? SECOND 1 1952730449122004993 2025-2026???????????????
7 ????????? SECOND 1 NULL NULL
1953004602014097409 ??????? SPECIAL 1 1952730449122004993 2025-2026???????????????
4 ????????? SPECIAL 1 1952730449122004993 2025-2026???????????????
8 ??????? SPECIAL 1 NULL NULL
1952634577994387457 ????? SPECIAL 1 1952730449122004993 2025-2026???????????????
1953004324552499202 ?????? SPECIAL 1 1952730449122004993 2025-2026???????????????
3 ??????? THIRD 1 1952730449122004993 2025-2026???????????????
1953005415696490497 ??????? THIRD 1 1952730449122004993 2025-2026???????????????
info
=== 4. 班级名额分配情况检查 ===
quota_id batch_id batch_name scholarship_type_id type_name class_id class_name total_quota used_quota available_quota allocation_method status create_time
2001 1 2024-2025??????????? 1 ??????? 1001 NULL 2 0 2 MANUAL ACTIVE 2025-08-06 11:00:49
2003 1 2024-2025??????????? 2 ??????? 1001 NULL 3 0 2 MANUAL ACTIVE 2025-08-06 11:00:49
2002 1 2024-2025??????????? 1 ??????? 1002 NULL 1 0 1 MANUAL ACTIVE 2025-08-06 11:00:49
2004 1 2024-2025??????????? 2 ??????? 1002 NULL 2 0 2 MANUAL ACTIVE 2025-08-06 11:00:49
info
=== 5. 已使用名额情况检查 ===
ERROR 1054 (42S22) at line 87: Unknown column 'sa.applicant_class_id' in 'field list'
+7
View File
@@ -135,6 +135,13 @@
<version>${revision}</version>
</dependency>
<!-- 奖惩补贴管理模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-jcbt</artifactId>
<version>${revision}</version>
</dependency>
<!-- 社团管理模块 -->
<!-- <dependency>
<groupId>org.dromara</groupId>
@@ -341,3 +341,33 @@ system:
# - 对于频繁访问的小文件,可以增加 max-cache-size
# - 对于大文件较多的环境,可以调整 max-single-file-size
# - 对于访问频率较低的环境,可以适当减少 expire-time-ms
--- # SQL日志配置(用于调试班级名额查询问题)
logging:
level:
# 开启 MyBatis SQL 日志
org.dromara.jcbt.mapper: DEBUG
org.dromara.jcbt.service: DEBUG
# 开启 MyBatis-Plus SQL 日志
com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor: DEBUG
# 开启 HikariCP 连接池日志(可选)
com.zaxxer.hikari: DEBUG
# 开启 P6Spy SQL 日志(更详细的SQL执行日志)
p6spy: INFO
pattern:
# 控制台日志格式,增加线程名和方法名
console: "%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wEx"
# MyBatis 配置
mybatis-plus:
configuration:
# 开启 SQL 日志打印
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 开启驼峰命名转换
map-underscore-to-camel-case: true
# 开启缓存
cache-enabled: true
# 开启懒加载
lazy-loading-enabled: true
# 开启积极懒加载
aggressive-lazy-loading: false
@@ -312,4 +312,4 @@ system:
# - 对于内存充足的环境,可以适当增加 max-cache-size-bytes
# - 对于频繁访问的小文件,可以增加 max-cache-size
# - 对于大文件较多的环境,可以调整 max-single-file-size
# - 对于访问频率较低的环境,可以适当减少 expire-time-ms
# - 对于访问频率较低的环境,可以适当减少 expire-time-ms
+1
View File
@@ -22,6 +22,7 @@
<module>ruoyi-cw</module>
<module>ruoyi-rs</module>
<module>ruoyi-xljk</module>
<module>ruoyi-jcbt</module>
<!-- <module>ruoyi-stgl</module> -->
</modules>
@@ -36,6 +36,8 @@ import org.dromara.system.domain.bo.SysDeptBo;
import java.util.*;
import java.util.stream.Collectors;
import org.dromara.common.core.utils.SpringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* 审批记录Service业务层处理
@@ -54,6 +56,9 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
private final ISysUserService sysUserService;
private final ISysDeptService sysDeptService;
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 根据主键查询审批记录
*/
@@ -1119,51 +1124,91 @@ public class CwApprovalRecordServiceImpl implements ICwApprovalRecordService {
return checkApprovalPermission(applicationId, "dept_approve");
}
/**
/**
* 获取可选审批人列表(院领导)
* 修改为基于权限角色查找:查找具有cw:approval:leader权限的用户
*/
@Override
public List<Map<String, Object>> getAvailableApprovers(Long applicationId) {
log.info("开始查询院领导审批人列表,applicationId: {}", applicationId);
log.info("开始查询院领导审批人列表(基于权限角色),applicationId: {}", applicationId);
List<Map<String, Object>> approvers = new ArrayList<>();
try {
// 1. 查询部门名称包含"院领导"的部门
SysDeptBo deptBo = new SysDeptBo();
deptBo.setDeptName("院领导"); // 设置查询条件
List<SysDeptVo> leaderDepts = sysDeptService.selectDeptList(deptBo);
// 使用原生SQL查询具有cw:approval:leader权限的用户
String sql = """
SELECT DISTINCT
u.user_id,
u.user_name,
u.nick_name,
COALESCE(d.dept_name, '未分配部门') as dept_name,
COALESCE(d.dept_id, 0) as dept_id
FROM sys_user u
LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
INNER JOIN sys_user_role ur ON u.user_id = ur.user_id
INNER JOIN sys_role r ON ur.role_id = r.role_id
INNER JOIN sys_role_menu rm ON r.role_id = rm.role_id
INNER JOIN sys_menu m ON rm.menu_id = m.menu_id
WHERE m.perms = 'cw:approval:leader'
AND u.status = '0'
AND u.del_flag = '0'
AND r.status = '0'
ORDER BY u.user_name
""";
log.info("找到院领导部门数量: {}", leaderDepts.size());
for (SysDeptVo dept : leaderDepts) {
log.info("院领导部门: ID={}, 名称={}", dept.getDeptId(), dept.getDeptName());
log.info("执行权限查询SQL查找具有cw:approval:leader权限的用户");
// 执行SQL查询
List<Map<String, Object>> results = jdbcTemplate.queryForList(sql);
log.info("SQL查询结果:找到 {} 个具有院领导审批权限的用户", results.size());
// 转换查询结果为返回格式
for (Map<String, Object> row : results) {
Map<String, Object> approver = new HashMap<>();
approver.put("userId", row.get("user_id"));
approver.put("userName", row.get("user_name"));
approver.put("nickName", row.get("nick_name"));
approver.put("deptName", row.get("dept_name"));
approver.put("deptId", row.get("dept_id"));
approvers.add(approver);
log.info("添加院领导审批人: userId={}, userName={}, nickName={}, deptName={}",
row.get("user_id"), row.get("user_name"), row.get("nick_name"), row.get("dept_name"));
}
// 2. 查询院领导部门下的所有用户
for (SysDeptVo dept : leaderDepts) {
List<SysUserVo> users = sysUserService.selectUserListByDept(dept.getDeptId());
// 如果基于权限查询没有找到用户,使用原有的部门查询作为备选方案
if (approvers.isEmpty()) {
log.warn("基于权限查询未找到院领导,尝试使用部门查询作为备选方案");
log.info("部门[{}]下的用户数量: {}", dept.getDeptName(), users.size());
SysDeptBo deptBo = new SysDeptBo();
deptBo.setDeptName("院领导");
List<SysDeptVo> leaderDepts = sysDeptService.selectDeptList(deptBo);
// 3. 将用户信息转换为Map格式
for (SysUserVo user : users) {
// 只返回状态正常的用户
if ("0".equals(user.getStatus())) {
Map<String, Object> approver = new HashMap<>();
approver.put("userId", user.getUserId());
approver.put("userName", user.getUserName());
approver.put("nickName", user.getNickName());
approver.put("deptName", dept.getDeptName());
approver.put("deptId", dept.getDeptId());
approvers.add(approver);
log.info("备选方案:找到院领导部门数量: {}", leaderDepts.size());
log.info("添加院领导审批人: userId={}, userName={}, nickName={}",
user.getUserId(), user.getUserName(), user.getNickName());
for (SysDeptVo dept : leaderDepts) {
List<SysUserVo> users = sysUserService.selectUserListByDept(dept.getDeptId());
log.info("备选方案:部门[{}]下的用户数量: {}", dept.getDeptName(), users.size());
for (SysUserVo user : users) {
if ("0".equals(user.getStatus())) {
Map<String, Object> approver = new HashMap<>();
approver.put("userId", user.getUserId());
approver.put("userName", user.getUserName());
approver.put("nickName", user.getNickName());
approver.put("deptName", dept.getDeptName());
approver.put("deptId", dept.getDeptId());
approvers.add(approver);
log.info("备选方案:添加院领导审批人: userId={}, userName={}, nickName={}",
user.getUserId(), user.getUserName(), user.getNickName());
}
}
}
}
log.info("查询院领导审批人完成,共找到 {} 个院领导", approvers.size());
log.info("查询院领导审批人完成,共找到 {} 个院领导(权限验证+部门备选)", approvers.size());
} catch (Exception e) {
log.error("查询院领导审批人失败:{}", e.getMessage(), e);
@@ -86,13 +86,29 @@ public class CwProjectApplicationServiceImpl implements ICwProjectApplicationSer
log.info("✅ [统计页面-项目清单] 查询完成");
log.info("📊 [统计页面-项目清单] 查询结果: 总数={}, 当前页记录数={}", result.getTotal(), result.getRecords().size());
// 🔧 为每个项目补充绩效指标数据(修复统计页面详情缺少绩效指标的问题)
if (!result.getRecords().isEmpty()) {
log.info("🔄 [统计页面-项目清单] 开始补充绩效指标数据...");
for (CwProjectApplicationVo record : result.getRecords()) {
try {
List<CwPerformanceIndicatorVo> performanceIndicators = performanceIndicatorService.queryByApplicationId(record.getId());
record.setPerformanceIndicators(performanceIndicators);
log.debug(" ✅ 项目ID: {} 绩效指标数量: {}", record.getId(), performanceIndicators.size());
} catch (Exception e) {
log.error(" ❌ 获取项目ID: {} 的绩效指标数据失败: {}", record.getId(), e.getMessage());
// 设置空列表,避免前端报错
record.setPerformanceIndicators(new ArrayList<>());
}
}
log.info("✅ [统计页面-项目清单] 绩效指标数据补充完成");
log.info("📝 [统计页面-项目清单] 前3条数据示例:");
for (int i = 0; i < Math.min(result.getRecords().size(), 3); i++) {
CwProjectApplicationVo record = result.getRecords().get(i);
log.info(" {}. ID: {}, 申报编号: {}, 项目名称: {}, 状态: {}, 申报人: {}, 部门: {}",
int indicatorCount = record.getPerformanceIndicators() != null ? record.getPerformanceIndicators().size() : 0;
log.info(" {}. ID: {}, 申报编号: {}, 项目名称: {}, 状态: {}, 申报人: {}, 部门: {}, 绩效指标数: {}",
i + 1, record.getId(), record.getApplicationNo(), record.getProjectName(),
record.getApprovalStatus(), record.getApplicantName(), record.getDepartmentName());
record.getApprovalStatus(), record.getApplicantName(), record.getDepartmentName(), indicatorCount);
}
} else {
log.warn("⚠️ [统计页面-项目清单] 查询结果为空!");
+115
View File
@@ -0,0 +1,115 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ruoyi-modules</artifactId>
<groupId>org.dromara</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-jcbt</artifactId>
<description>
奖惩补贴管理模块
</description>
<dependencies>
<!-- 通用工具 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-core</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-doc</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-mybatis</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-log</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-security</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-web</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-excel</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-idempotent</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-tenant</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-social</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-ratelimiter</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-mail</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-system</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-job</artifactId>
</dependency>
<!-- 代码生成-->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-generator</artifactId>
</dependency>
<!-- demo模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-demo</artifactId>
</dependency>
<!-- 工作流模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-workflow</artifactId>
</dependency>
<!-- 学工管理模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-xg</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,19 @@
package org.dromara.jcbt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 奖惩补贴管理模块启动程序
*
* @author ruoyi
*/
@SpringBootApplication
public class RuoyiJcbtApplication {
public static void main(String[] args) {
SpringApplication.run(RuoyiJcbtApplication.class, args);
System.out.println("(♥◠‿◠)ノ゙ 奖惩补贴管理模块启动成功 ლ(´ڡ`ლ)゙");
}
}
@@ -0,0 +1,317 @@
package org.dromara.jcbt.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.web.core.BaseController;
import org.dromara.jcbt.domain.bo.AuditRequestBo;
import org.dromara.jcbt.domain.bo.JcbtPovertyApplicationBo;
import org.dromara.jcbt.domain.vo.JcbtPovertyApplicationVo;
import org.dromara.jcbt.service.IJcbtPovertyApplicationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
/**
* 贫困生认定申请管理
*
* @author ruoyi
* @date 2025-08-09
*/
@Slf4j
@Validated
@Tag(name = "贫困生认定申请管理", description = "贫困生认定申请管理Controller")
@RestController
@RequestMapping("/jcbt/povertyApplication")
public class JcbtPovertyApplicationController extends BaseController {
@Autowired
private IJcbtPovertyApplicationService povertyApplicationService;
// ========== 基础管理接口(6个) ==========
/**
* 查询贫困生认定申请列表
*/
@SaCheckPermission("jcbt:povertyApplication:list")
@GetMapping("/list")
@Operation(summary = "查询贫困生认定申请列表")
public TableDataInfo<JcbtPovertyApplicationVo> list(JcbtPovertyApplicationBo bo, PageQuery pageQuery) {
return povertyApplicationService.queryPageList(bo, pageQuery);
}
/**
* 获取贫困生认定申请详细信息
*/
@SaCheckPermission("jcbt:povertyApplication:query")
@GetMapping("/{id}")
@Operation(summary = "获取贫困生认定申请详细信息")
public R<JcbtPovertyApplicationVo> getInfo(@Parameter(description = "主键") @PathVariable Long id) {
return R.ok(povertyApplicationService.queryById(id));
}
/**
* 新增贫困生认定申请
*/
@SaCheckPermission("jcbt:povertyApplication:add")
@Log(title = "贫困生认定申请", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping
@Operation(summary = "新增贫困生认定申请")
public R<Void> add(@Parameter(description = "贫困生认定申请") @Validated(AddGroup.class) @RequestBody JcbtPovertyApplicationBo bo) {
return toAjax(povertyApplicationService.insertByBo(bo));
}
/**
* 修改贫困生认定申请
*/
@SaCheckPermission("jcbt:povertyApplication:edit")
@Log(title = "贫困生认定申请", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping
@Operation(summary = "修改贫困生认定申请")
public R<Void> edit(@Parameter(description = "贫困生认定申请") @Validated(EditGroup.class) @RequestBody JcbtPovertyApplicationBo bo) {
return toAjax(povertyApplicationService.updateByBo(bo));
}
/**
* 删除贫困生认定申请
*/
@SaCheckPermission("jcbt:povertyApplication:remove")
@Log(title = "删除贫困生认定申请", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
@Operation(summary = "删除贫困生认定申请")
public R<Void> remove(@Parameter(description = "主键集合") @NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
return toAjax(povertyApplicationService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 导出贫困生认定申请列表
*/
@SaCheckPermission("jcbt:povertyApplication:export")
@Log(title = "导出贫困生认定申请", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@Operation(summary = "导出贫困生认定申请列表")
public void export(JcbtPovertyApplicationBo bo, HttpServletResponse response) {
List<JcbtPovertyApplicationVo> list = povertyApplicationService.queryList(bo);
ExcelUtil.exportExcel(list, "贫困生认定申请", JcbtPovertyApplicationVo.class, response);
}
// ========== 业务功能接口(4个) ==========
/**
* 查询我的申请列表(班主任查看自己提交的申请)
*/
@SaCheckPermission("jcbt:povertyApplication:myList")
@GetMapping("/myList")
@Operation(summary = "查询我的申请列表")
public TableDataInfo<JcbtPovertyApplicationVo> myList(JcbtPovertyApplicationBo bo, PageQuery pageQuery) {
Long teacherId = LoginHelper.getUserId();
return povertyApplicationService.queryPageListByTeacher(teacherId, bo, pageQuery);
}
/**
* 查询待审核申请列表(审核人员使用)
*/
@SaCheckPermission("jcbt:povertyApplication:pendingList")
@GetMapping("/pendingList")
@Operation(summary = "查询待审核申请列表")
public TableDataInfo<JcbtPovertyApplicationVo> pendingList(JcbtPovertyApplicationBo bo, PageQuery pageQuery) {
return povertyApplicationService.queryPendingPageList(bo, pageQuery);
}
/**
* 提交申请
*/
@SaCheckPermission("jcbt:povertyApplication:submit")
@Log(title = "提交贫困生认定申请", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/submit/{id}")
@Operation(summary = "提交申请")
public R<Void> submit(@Parameter(description = "申请ID") @PathVariable Long id) {
return toAjax(povertyApplicationService.submitApplication(id));
}
/**
* 撤销申请
*/
@SaCheckPermission("jcbt:povertyApplication:cancel")
@Log(title = "撤销贫困生认定申请", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/cancel/{id}")
@Operation(summary = "撤销申请")
public R<Void> cancel(@Parameter(description = "申请ID") @PathVariable Long id) {
return toAjax(povertyApplicationService.cancelApplication(id));
}
// ========== 辅助功能接口(6个) ==========
/**
* 根据申请编号获取申请信息
*/
@SaCheckPermission("jcbt:povertyApplication:query")
@GetMapping("/byApplicationNo/{applicationNo}")
@Operation(summary = "根据申请编号获取申请信息")
public R<JcbtPovertyApplicationVo> getInfoByApplicationNo(@Parameter(description = "申请编号") @PathVariable String applicationNo) {
return R.ok(povertyApplicationService.queryByApplicationNo(applicationNo));
}
/**
* 保存草稿
*/
@SaCheckPermission("jcbt:povertyApplication:saveDraft")
@Log(title = "保存贫困生认定申请草稿", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PostMapping("/saveDraft")
@Operation(summary = "保存草稿")
public R<Void> saveDraft(@Parameter(description = "贫困生认定申请") @RequestBody JcbtPovertyApplicationBo bo) {
return toAjax(povertyApplicationService.saveDraft(bo));
}
/**
* 审核通过
*/
@SaCheckPermission("jcbt:povertyApplication:approve")
@Log(title = "审核通过贫困生认定申请", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/approve")
@Operation(summary = "审核通过")
public R<Void> approve(@Parameter(description = "审核请求") @Validated @RequestBody AuditRequestBo auditRequest) {
return toAjax(povertyApplicationService.approveApplication(auditRequest.getId(), auditRequest.getAuditOpinion()));
}
/**
* 审核驳回
*/
@SaCheckPermission("jcbt:povertyApplication:reject")
@Log(title = "审核驳回贫困生认定申请", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping("/reject")
@Operation(summary = "审核驳回")
public R<Void> reject(@Parameter(description = "审核请求") @Validated @RequestBody AuditRequestBo auditRequest) {
return toAjax(povertyApplicationService.rejectApplication(auditRequest.getId(), auditRequest.getAuditOpinion()));
}
/**
* 生成申请编号
*/
@SaCheckPermission("jcbt:povertyApplication:add")
@GetMapping("/generateApplicationNo")
@Operation(summary = "生成申请编号")
public R<String> generateApplicationNo() {
return R.ok(povertyApplicationService.generateApplicationNo());
}
/**
* 检查学生申请是否重复
*/
@SaCheckPermission("jcbt:povertyApplication:add")
@GetMapping("/checkDuplicate")
@Operation(summary = "检查学生申请是否重复")
public R<Boolean> checkDuplicate(@Parameter(description = "学生ID") @RequestParam Long studentId,
@Parameter(description = "学年") @RequestParam String academicYear,
@Parameter(description = "认定类型ID") @RequestParam Long recognitionTypeId,
@Parameter(description = "排除的申请ID") @RequestParam(required = false) Long excludeId) {
boolean exists = povertyApplicationService.checkStudentApplicationExists(studentId, academicYear, recognitionTypeId, excludeId);
return R.ok(exists);
}
// ========== 统计分析接口(2个) ==========
/**
* 获取申请统计信息
*/
@SaCheckPermission("jcbt:povertyApplication:statistics")
@GetMapping("/statistics")
@Operation(summary = "获取申请统计信息")
public R<Map<String, Object>> statistics(@Parameter(description = "班主任ID") @RequestParam(required = false) Long teacherId) {
List<JcbtPovertyApplicationVo> statisticsList = povertyApplicationService.getApplicationStatistics(teacherId);
// 转换为前端需要的格式
Map<String, Object> result = new HashMap<>();
Map<String, Integer> statusCount = new HashMap<>();
int totalCount = 0;
for (JcbtPovertyApplicationVo stat : statisticsList) {
String status = stat.getStatus();
Integer count = stat.getId().intValue(); // 统计查询中,id字段存储的是count值
statusCount.put(status, count);
totalCount += count;
}
result.put("statusCount", statusCount);
result.put("totalCount", totalCount);
return R.ok(result);
}
/**
* 获取我的申请统计信息(班主任使用)
*/
@SaCheckPermission("jcbt:povertyApplication:myList")
@GetMapping("/myStatistics")
@Operation(summary = "获取我的申请统计信息")
public R<Map<String, Object>> myStatistics() {
Long teacherId = LoginHelper.getUserId();
List<JcbtPovertyApplicationVo> statisticsList = povertyApplicationService.getApplicationStatistics(teacherId);
// 转换为前端需要的格式
Map<String, Object> result = new HashMap<>();
Map<String, Integer> statusCount = new HashMap<>();
int totalCount = 0;
for (JcbtPovertyApplicationVo stat : statisticsList) {
String status = stat.getStatus();
Integer count = stat.getId().intValue(); // 统计查询中,id字段存储的是count值
statusCount.put(status, count);
totalCount += count;
}
result.put("statusCount", statusCount);
result.put("totalCount", totalCount);
return R.ok(result);
}
/**
* 获取当前用户班级信息
*/
@Operation(summary = "获取当前用户班级信息")
@SaCheckPermission("jcbt:povertyApplication:list")
@GetMapping("/user/classes")
public R<List<Map<String, Object>>> getCurrentUserClasses() {
Long currentUserId = LoginHelper.getLoginUser().getUserId();
List<Map<String, Object>> classes = povertyApplicationService.getCurrentUserClasses(currentUserId);
return R.ok(classes);
}
/**
* 获取班级学生列表
*/
@Operation(summary = "获取班级学生列表")
@Parameter(name = "classId", description = "班级ID", required = true)
@SaCheckPermission("jcbt:povertyApplication:list")
@GetMapping("/class/{classId}/students")
public R<List<Map<String, Object>>> getClassStudents(@PathVariable Long classId) {
List<Map<String, Object>> students = povertyApplicationService.getClassStudents(classId);
return R.ok(students);
}
}
@@ -0,0 +1,417 @@
package org.dromara.jcbt.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.jcbt.domain.bo.JcbtScholarshipApplicationBo;
import org.dromara.jcbt.domain.vo.JcbtScholarshipApplicationVo;
import org.dromara.jcbt.service.IJcbtScholarshipApplicationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
/**
* 奖学金申请记录管理
*
* @author ruoyi
* @date 2025-01-01
*/
@Slf4j
@Validated
@Tag(name = "奖学金申请记录管理", description = "奖学金申请记录管理Controller")
@RestController
@RequestMapping("/jcbt/scholarshipApplication")
public class JcbtScholarshipApplicationController extends BaseController {
@Autowired
private IJcbtScholarshipApplicationService applicationService;
// ========== 基础管理接口(6个) ==========
/**
* 查询奖学金申请记录列表
*/
@SaCheckPermission("jcbt:scholarshipApplication:list")
@GetMapping("/list")
@Operation(summary = "查询奖学金申请记录列表")
public TableDataInfo<JcbtScholarshipApplicationVo> list(JcbtScholarshipApplicationBo bo, PageQuery pageQuery) {
return applicationService.queryPageList(bo, pageQuery);
}
/**
* 获取奖学金申请记录详细信息
*/
@SaCheckPermission("jcbt:scholarshipApplication:query")
@GetMapping("/{id}")
@Operation(summary = "获取奖学金申请记录详细信息")
public R<JcbtScholarshipApplicationVo> getInfo(@Parameter(description = "主键") @PathVariable Long id) {
return R.ok(applicationService.queryById(id));
}
/**
* 新增奖学金申请记录
*/
@SaCheckPermission("jcbt:scholarshipApplication:add")
@Log(title = "奖学金申请记录", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping
@Operation(summary = "新增奖学金申请记录")
public R<Void> add(@Parameter(description = "奖学金申请记录") @Validated(AddGroup.class) @RequestBody JcbtScholarshipApplicationBo bo) {
return toAjax(applicationService.insertByBo(bo));
}
/**
* 修改奖学金申请记录
*/
@SaCheckPermission("jcbt:scholarshipApplication:edit")
@Log(title = "奖学金申请记录", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping
@Operation(summary = "修改奖学金申请记录")
public R<Void> edit(@Parameter(description = "奖学金申请记录") @Validated(EditGroup.class) @RequestBody JcbtScholarshipApplicationBo bo) {
log.info("🔍 [DEBUG] Controller.edit 开始执行");
log.info("🔍 [DEBUG] 接收到的BO对象: {}", bo);
log.info("🔍 [DEBUG] 关键字段检查:");
log.info(" - id: {}", bo.getId());
log.info(" - studentNo: {}", bo.getStudentNo());
log.info(" - studentName: {}", bo.getStudentName());
log.info(" - status: {}", bo.getStatus());
log.info(" - currentStatus: {}", bo.getCurrentStatus());
log.info(" - reviewComment: {}", bo.getReviewComment());
try {
boolean result = applicationService.updateByBo(bo);
log.info("🔍 [DEBUG] Service.updateByBo 执行结果: {}", result);
return toAjax(result);
} catch (Exception e) {
log.error("❌ [ERROR] Controller.edit 执行异常", e);
log.error("❌ [ERROR] 异常类型: {}", e.getClass().getSimpleName());
log.error("❌ [ERROR] 异常消息: {}", e.getMessage());
throw e;
}
}
/**
* 删除奖学金申请记录
*/
@SaCheckPermission("jcbt:scholarshipApplication:remove")
@Log(title = "奖学金申请记录", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
@Operation(summary = "删除奖学金申请记录")
public R<Void> remove(@Parameter(description = "主键串") @PathVariable Long[] ids) {
return toAjax(applicationService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 获取可申请的奖学金类型列表
*/
@SaCheckPermission("jcbt:scholarshipApplication:available")
@GetMapping("/available")
@Operation(summary = "获取可申请的奖学金类型列表")
public R<List<Map<String, Object>>> getAvailableScholarshipTypes(@Parameter(description = "班级ID") @RequestParam Long classId,
@Parameter(description = "批次ID") @RequestParam Long batchId) {
return R.ok(applicationService.queryAvailableScholarshipTypes(classId, batchId));
}
// ========== 业务功能接口(4个) ==========
/**
* 查询我的申请记录(班主任)
*/
@SaCheckPermission("jcbt:scholarshipApplication:my")
@GetMapping("/my")
@Operation(summary = "查询我的申请记录")
public R<List<JcbtScholarshipApplicationVo>> getMyApplications(@Parameter(description = "申请人ID") @RequestParam Long applicantId,
@Parameter(description = "批次ID") @RequestParam(required = false) Long batchId) {
return R.ok(applicationService.queryApplicationsByApplicant(applicantId, batchId));
}
/**
* 查询待审核申请
*/
@SaCheckPermission("jcbt:scholarshipApplication:pending")
@GetMapping("/pending")
@Operation(summary = "查询待审核申请")
public R<List<JcbtScholarshipApplicationVo>> getPendingApplications(@Parameter(description = "审核人ID") @RequestParam(required = false) Long reviewerId,
@Parameter(description = "申请状态") @RequestParam(required = false) String status) {
return R.ok(applicationService.queryPendingApplications(reviewerId, status));
}
/**
* 检查学生申请资格
*/
@SaCheckPermission("jcbt:scholarshipApplication:check")
@GetMapping("/check")
@Operation(summary = "检查学生申请资格")
public R<Map<String, Object>> checkStudentEligibility(@Parameter(description = "学生ID") @RequestParam Long studentId,
@Parameter(description = "批次ID") @RequestParam Long batchId,
@Parameter(description = "奖学金类型ID") @RequestParam Long scholarshipTypeId) {
return R.ok(applicationService.checkStudentEligibility(studentId, batchId, scholarshipTypeId));
}
/**
* 批量审核申请
*/
@SaCheckPermission("jcbt:scholarshipApplication:approve")
@Log(title = "批量审核奖学金申请", businessType = BusinessType.UPDATE)
@PostMapping("/approve")
@Operation(summary = "批量审核申请")
public R<Void> batchApprove(@Parameter(description = "申请ID列表") @RequestBody @NotEmpty List<Long> applicationIds,
@Parameter(description = "审核状态") @RequestParam String status,
@Parameter(description = "审核人ID") @RequestParam Long reviewerId,
@Parameter(description = "审核人姓名") @RequestParam String reviewerName,
@Parameter(description = "审核意见") @RequestParam(required = false) String reviewComment) {
return toAjax(applicationService.batchReviewApplications(applicationIds, status, reviewerId, reviewerName, reviewComment));
}
// ========== 辅助功能接口(6个) ==========
/**
* 导出奖学金申请记录列表
*/
@SaCheckPermission("jcbt:schotlarshipApplication:expor")
@Log(title = "奖学金申请记录", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@Operation(summary = "导出奖学金申请记录列表")
public void export(JcbtScholarshipApplicationBo bo, HttpServletResponse response) {
List<JcbtScholarshipApplicationVo> list = applicationService.queryList(bo);
ExcelUtil.exportExcel(list, "奖学金申请记录", JcbtScholarshipApplicationVo.class, response);
}
/**
* 导入奖学金申请记录
*/
@SaCheckPermission("jcbt:scholarshipApplication:import")
@Log(title = "奖学金申请记录", businessType = BusinessType.IMPORT)
@PostMapping(value = "/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation(summary = "导入奖学金申请记录")
public R<Void> importData(@Parameter(description = "Excel文件") @RequestPart("file") MultipartFile file) throws Exception {
List<JcbtScholarshipApplicationVo> list = ExcelUtil.importExcel(file.getInputStream(), JcbtScholarshipApplicationVo.class);
// 导入逻辑处理
for (JcbtScholarshipApplicationVo vo : list) {
JcbtScholarshipApplicationBo bo = new JcbtScholarshipApplicationBo();
// 这里需要实现VO到BO的转换逻辑
// BeanUtils.copyProperties(vo, bo);
applicationService.insertByBo(bo);
}
return R.ok();
}
/**
* 获取申请统计数据
*/
@SaCheckPermission("jcbt:scholarshipApplication:statistics")
@GetMapping("/statistics")
@Operation(summary = "获取申请统计数据")
public R<Map<String, Object>> getStatistics(@Parameter(description = "批次ID") @RequestParam(required = false) Long batchId,
@Parameter(description = "学院ID") @RequestParam(required = false) Long deptId) {
return R.ok(applicationService.getApplicationStatistics(batchId, deptId));
}
/**
* 班主任批量申请提交
*/
@SaCheckPermission("jcbt:scholarshipApplication:batch")
@Log(title = "班主任批量申请提交", businessType = BusinessType.INSERT)
@PostMapping("/batch")
@Operation(summary = "班主任批量申请提交")
public R<Void> batchSubmitByTeacher(@Parameter(description = "批次ID") @RequestParam Long batchId,
@Parameter(description = "奖学金类型ID") @RequestParam Long scholarshipTypeId,
@Parameter(description = "班级ID") @RequestParam Long classId,
@Parameter(description = "学生申请列表") @RequestBody @NotEmpty List<JcbtScholarshipApplicationBo> studentApplications) {
return toAjax(applicationService.batchSubmitApplicationsByTeacher(batchId, scholarshipTypeId, classId, studentApplications));
}
/**
* 提交申请
*/
@SaCheckPermission("jcbt:scholarshipApplication:submit")
@Log(title = "提交奖学金申请", businessType = BusinessType.UPDATE)
@PostMapping("/{id}/submit")
@Operation(summary = "提交申请")
public R<Void> submitApplication(@Parameter(description = "申请ID") @PathVariable @NotNull Long id) {
return toAjax(applicationService.submitApplication(id));
}
/**
* 撤回申请
*/
@SaCheckPermission("jcbt:scholarshipApplication:withdraw")
@Log(title = "撤回奖学金申请", businessType = BusinessType.UPDATE)
@PostMapping("/{id}/withdraw")
@Operation(summary = "撤回申请")
public R<Void> withdrawApplication(@Parameter(description = "申请ID") @PathVariable @NotNull Long id,
@Parameter(description = "撤回原因") @RequestParam(required = false) String reason) {
return toAjax(applicationService.withdrawApplication(id, reason));
}
// ========== 班级名额相关接口 ==========
/**
* 获取班级名额使用情况
*/
@SaCheckPermission("jcbt:scholarshipApplication:quota")
@GetMapping("/quota")
@Operation(summary = "获取班级名额使用情况")
public R<Map<String, Object>> getClassQuotaUsage(@Parameter(description = "班级ID") @RequestParam Long classId,
@Parameter(description = "批次ID") @RequestParam Long batchId) {
return R.ok(applicationService.getClassQuotaUsage(classId, batchId));
}
// ========== 班主任申请专用接口 ==========
/**
* 获取班主任所带班级信息
*/
@SaCheckPermission("jcbt:scholarshipApplication:classInfo")
@GetMapping("/classInfo")
@Operation(summary = "获取班主任所带班级信息")
public R<Map<String, Object>> getClassInfoByTeacher(@Parameter(description = "班主任ID") @RequestParam Long teacherId) {
return R.ok(applicationService.getClassInfoByTeacher(teacherId));
}
/**
* 获取班级学生列表(用于勾选)
*/
@SaCheckPermission("jcbt:scholarshipApplication:students")
@GetMapping("/students")
@Operation(summary = "获取班级学生列表")
public R<List<Map<String, Object>>> getClassStudents(@Parameter(description = "班级ID") @RequestParam Long classId) {
return R.ok(applicationService.getClassStudents(classId));
}
/**
* 根据批次获取可申请的奖学金类型
*/
@SaCheckPermission("jcbt:scholarshipApplication:scholarshipTypes")
@GetMapping("/scholarshipTypes")
@Operation(summary = "根据批次获取可申请的奖学金类型")
public R<List<Map<String, Object>>> getScholarshipTypesByBatch(@Parameter(description = "批次ID") @RequestParam Long batchId) {
return R.ok(applicationService.getScholarshipTypesByBatch(batchId));
}
/**
* 根据批次和班级获取带名额信息的奖学金类型(班主任专用)
*/
@SaCheckPermission("jcbt:scholarshipApplication:scholarshipTypes")
@GetMapping("/scholarshipTypesWithQuota")
@Operation(summary = "根据批次和班级获取带名额信息的奖学金类型")
public R<List<Map<String, Object>>> getScholarshipTypesWithQuota(
@Parameter(description = "批次ID") @RequestParam Long batchId,
@Parameter(description = "班级ID") @RequestParam Long classId) {
return R.ok(applicationService.getScholarshipTypesWithQuota(batchId, classId));
}
/**
* 确认选择班级(多班级时用户选择后调用)
*/
@SaCheckPermission("jcbt:scholarshipApplication:classInfo")
@PostMapping("/confirmClass")
@Operation(summary = "确认选择班级")
public R<Map<String, Object>> confirmClassSelection(@Parameter(description = "班主任ID") @RequestParam Long teacherId,
@Parameter(description = "班级ID") @RequestParam Long classId) {
return R.ok(applicationService.confirmClassSelection(teacherId, classId));
}
/**
* 测试接口:获取奖学金类型数据结构
*/
@SaCheckPermission("jcbt:scholarshipApplication:scholarshipTypes")
@GetMapping("/test/scholarshipTypesStructure")
@Operation(summary = "测试接口:获取奖学金类型数据结构")
public R<Map<String, Object>> testScholarshipTypesStructure(@Parameter(description = "批次ID") @RequestParam Long batchId,
@Parameter(description = "班级ID") @RequestParam(required = false) Long classId) {
Map<String, Object> result = new HashMap<>();
try {
if (classId != null) {
result.put("withQuota", applicationService.getScholarshipTypesWithQuota(batchId, classId));
}
result.put("withoutQuota", applicationService.getScholarshipTypesByBatch(batchId));
result.put("batchId", batchId);
result.put("classId", classId);
result.put("timestamp", System.currentTimeMillis());
} catch (Exception e) {
result.put("error", e.getMessage());
}
return R.ok(result);
}
/**
* 调试接口:详细SQL日志输出测试
*/
@SaCheckPermission("jcbt:scholarshipApplication:scholarshipTypes")
@GetMapping("/debug/sqlLogs")
@Operation(summary = "调试接口:详细SQL日志输出测试")
public R<Map<String, Object>> debugSqlLogs(@Parameter(description = "批次ID") @RequestParam Long batchId,
@Parameter(description = "班级ID") @RequestParam Long classId,
@Parameter(description = "奖学金类型ID(可选,测试单个类型)") @RequestParam(required = false) Long scholarshipTypeId) {
Map<String, Object> result = new HashMap<>();
try {
log.info("🚀 === SQL调试接口开始 ===");
log.info("📥 接收参数: batchId={}, classId={}, scholarshipTypeId={}", batchId, classId, scholarshipTypeId);
result.put("requestParams", Map.of(
"batchId", batchId,
"classId", classId,
"scholarshipTypeId", scholarshipTypeId
));
// 如果指定了奖学金类型ID,则只测试该类型
if (scholarshipTypeId != null) {
log.info("🎯 单个奖学金类型测试模式");
// 测试班级名额查询
log.info("📊 开始测试班级名额查询");
var classQuota = applicationService.testClassQuotaQuery(classId, scholarshipTypeId, batchId);
result.put("classQuotaTest", classQuota);
// 测试全校名额查询
log.info("🏫 开始测试全校名额查询");
var schoolQuota = applicationService.testSchoolQuotaQuery(batchId, scholarshipTypeId);
result.put("schoolQuotaTest", schoolQuota);
} else {
log.info("📋 完整流程测试模式");
// 完整流程测试
var quotaResult = applicationService.getScholarshipTypesWithQuota(batchId, classId);
result.put("fullProcessTest", quotaResult);
}
result.put("status", "success");
result.put("timestamp", System.currentTimeMillis());
log.info("✅ === SQL调试接口完成 ===");
} catch (Exception e) {
log.error("❌ === SQL调试接口异常 ===", e);
result.put("status", "error");
result.put("error", e.getMessage());
result.put("stackTrace", e.getStackTrace());
}
return R.ok(result);
}
}
@@ -0,0 +1,180 @@
package org.dromara.jcbt.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.jcbt.domain.vo.JcbtScholarshipBatchVo;
import org.dromara.jcbt.domain.bo.JcbtScholarshipBatchBo;
import org.dromara.jcbt.service.IJcbtScholarshipBatchService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.log.enums.BusinessType;
/**
* 奖学金评定批次
*
* @author ruoyi
* @date 2025-01-27
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/jcbt/scholarshipBatch")
@Slf4j
public class JcbtScholarshipBatchController extends BaseController {
private final IJcbtScholarshipBatchService scholarshipBatchService;
/**
* 查询奖学金评定批次列表
*/
@SaCheckPermission("jcbt:scholarshipBatch:list")
@GetMapping("/list")
public TableDataInfo<JcbtScholarshipBatchVo> list(JcbtScholarshipBatchBo bo, PageQuery pageQuery) {
return scholarshipBatchService.queryPageList(bo, pageQuery);
}
/**
* 导出奖学金评定批次列表
*/
@SaCheckPermission("jcbt:scholarshipBatch:export")
@Log(title = "奖学金评定批次", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(JcbtScholarshipBatchBo bo, HttpServletResponse response) {
List<JcbtScholarshipBatchVo> list = scholarshipBatchService.queryExportList(bo);
ExcelUtil.exportExcel(list, "奖学金评定批次", JcbtScholarshipBatchVo.class, response);
}
/**
* 获取奖学金评定批次详细信息
*/
@SaCheckPermission("jcbt:scholarshipBatch:query")
@GetMapping("/{id}")
public R<JcbtScholarshipBatchVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(scholarshipBatchService.queryById(id));
}
/**
* 新增奖学金评定批次
*/
@SaCheckPermission("jcbt:scholarshipBatch:add")
@Log(title = "奖学金评定批次", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody JcbtScholarshipBatchBo bo) {
return toAjax(scholarshipBatchService.insertByBo(bo));
}
/**
* 修改奖学金评定批次
*/
@SaCheckPermission("jcbt:scholarshipBatch:edit")
@Log(title = "奖学金评定批次", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody JcbtScholarshipBatchBo bo) {
return toAjax(scholarshipBatchService.updateByBo(bo));
}
/**
* 删除奖学金评定批次
*/
@SaCheckPermission("jcbt:scholarshipBatch:remove")
@Log(title = "奖学金评定批次", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(scholarshipBatchService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 根据批次编码查询批次信息
*/
@SaCheckPermission("jcbt:scholarshipBatch:query")
@GetMapping("/getByCode/{batchCode}")
public R<JcbtScholarshipBatchVo> getByBatchCode(@PathVariable String batchCode) {
return R.ok(scholarshipBatchService.queryByBatchCode(batchCode));
}
/**
* 根据学年和学期查询批次列表
*/
@SaCheckPermission("jcbt:scholarshipBatch:query")
@GetMapping("/getByAcademicYear")
public R<List<JcbtScholarshipBatchVo>> getByAcademicYearAndSemester(
@RequestParam String academicYear,
@RequestParam(required = false) Integer semester) {
return R.ok(scholarshipBatchService.queryByAcademicYearAndSemester(academicYear, semester));
}
/**
* 查询启用状态的批次列表
*/
@SaCheckPermission("jcbt:scholarshipBatch:query")
@GetMapping("/getActiveBatches")
public R<List<JcbtScholarshipBatchVo>> getActiveBatches() {
return R.ok(scholarshipBatchService.queryActiveBatches());
}
/**
* 检查批次编码是否唯一
*/
@SaCheckPermission("jcbt:scholarshipBatch:query")
@GetMapping("/checkBatchCodeUnique")
public R<Boolean> checkBatchCodeUnique(@RequestParam String batchCode,
@RequestParam(required = false) Long id) {
return R.ok(scholarshipBatchService.checkBatchCodeUnique(batchCode, id));
}
/**
* 更改批次状态
*/
@SaCheckPermission("jcbt:scholarshipBatch:edit")
@Log(title = "奖学金评定批次", businessType = BusinessType.UPDATE)
@PutMapping("/changeStatus")
public R<Void> changeStatus(@RequestParam Long id, @RequestParam String status) {
return toAjax(scholarshipBatchService.changeStatus(id, status));
}
/**
* 查询当前进行中的批次
*/
@SaCheckPermission("jcbt:scholarshipBatch:query")
@GetMapping("/getCurrentActiveBatches")
public R<List<JcbtScholarshipBatchVo>> getCurrentActiveBatches() {
return R.ok(scholarshipBatchService.queryCurrentActiveBatches());
}
/**
* 根据状态查询批次列表
*/
@SaCheckPermission("jcbt:scholarshipBatch:query")
@GetMapping("/getByStatus/{status}")
public R<List<JcbtScholarshipBatchVo>> getByStatus(@PathVariable String status) {
return R.ok(scholarshipBatchService.queryByStatus(status));
}
/**
* 检查批次时间是否有冲突
*/
@SaCheckPermission("jcbt:scholarshipBatch:query")
@PostMapping("/checkTimeConflict")
public R<Boolean> checkTimeConflict(@RequestBody JcbtScholarshipBatchBo bo) {
return R.ok(scholarshipBatchService.checkTimeConflict(bo));
}
}
@@ -0,0 +1,248 @@
package org.dromara.jcbt.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.jcbt.domain.bo.JcbtScholarshipQuotaBo;
import org.dromara.jcbt.domain.vo.JcbtScholarshipQuotaVo;
import org.dromara.jcbt.service.IJcbtScholarshipQuotaService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* 奖学金名额分配
*
* @author ruoyi
* @date 2025-01-27
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/jcbt/scholarshipQuota")
public class JcbtScholarshipQuotaController extends BaseController {
private final IJcbtScholarshipQuotaService scholarshipQuotaService;
/**
* 查询奖学金名额分配列表
*/
@SaCheckPermission("jcbt:scholarshipQuota:list")
@GetMapping("/list")
public TableDataInfo<JcbtScholarshipQuotaVo> list(JcbtScholarshipQuotaBo bo, PageQuery pageQuery) {
return scholarshipQuotaService.queryPageList(bo, pageQuery);
}
/**
* 查询指定批次的名额分配列表
*/
@SaCheckPermission("jcbt:scholarshipQuota:list")
@GetMapping("/listByBatch/{batchId}")
public R<List<JcbtScholarshipQuotaVo>> listByBatch(@PathVariable Long batchId) {
List<JcbtScholarshipQuotaVo> list = scholarshipQuotaService.queryListByBatchId(batchId);
return R.ok(list);
}
/**
* 查询指定批次和奖学金类型的名额分配
*/
@SaCheckPermission("jcbt:scholarshipQuota:list")
@GetMapping("/listByBatchAndType")
public R<List<JcbtScholarshipQuotaVo>> listByBatchAndType(@RequestParam Long batchId,
@RequestParam Long scholarshipTypeId) {
List<JcbtScholarshipQuotaVo> list = scholarshipQuotaService.queryListByBatchAndType(batchId, scholarshipTypeId);
return R.ok(list);
}
/**
* 查询名额分配树形结构
*/
@SaCheckPermission("jcbt:scholarshipQuota:list")
@GetMapping("/tree")
public R<List<JcbtScholarshipQuotaVo>> tree(@RequestParam Long batchId,
@RequestParam Long scholarshipTypeId) {
List<JcbtScholarshipQuotaVo> tree = scholarshipQuotaService.queryQuotaTree(batchId, scholarshipTypeId);
return R.ok(tree);
}
/**
* 查询名额使用统计
*/
@SaCheckPermission("jcbt:scholarshipQuota:list")
@GetMapping("/statistics/{batchId}")
public R<Map<String, Object>> statistics(@PathVariable Long batchId) {
Map<String, Object> statistics = scholarshipQuotaService.queryQuotaUsageStatistics(batchId);
return R.ok(statistics);
}
/**
* 导出奖学金名额分配列表
*/
@SaCheckPermission("jcbt:scholarshipQuota:export")
@Log(title = "导出奖学金名额分配", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(JcbtScholarshipQuotaBo bo, HttpServletResponse response) {
List<JcbtScholarshipQuotaVo> list = scholarshipQuotaService.queryList(bo);
ExcelUtil.exportExcel(list, "奖学金名额分配", JcbtScholarshipQuotaVo.class, response);
}
/**
* 获取奖学金名额分配详细信息
*/
@SaCheckPermission("jcbt:scholarshipQuota:query")
@GetMapping("/{id}")
public R<JcbtScholarshipQuotaVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
return R.ok(scholarshipQuotaService.queryById(id));
}
/**
* 新增奖学金名额分配
*/
@SaCheckPermission("jcbt:scholarshipQuota:add")
@Log(title = "新增奖学金名额分配", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody JcbtScholarshipQuotaBo bo) {
return toAjax(scholarshipQuotaService.insertByBo(bo));
}
/**
* 修改奖学金名额分配
*/
@SaCheckPermission("jcbt:scholarshipQuota:edit")
@Log(title = "修改奖学金名额分配", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody JcbtScholarshipQuotaBo bo) {
return toAjax(scholarshipQuotaService.updateByBo(bo));
}
/**
* 删除奖学金名额分配
*/
@SaCheckPermission("jcbt:scholarshipQuota:remove")
@Log(title = "删除奖学金名额分配", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
return toAjax(scholarshipQuotaService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 批量删除奖学金名额分配
*/
@SaCheckPermission("jcbt:scholarshipQuota:remove")
@Log(title = "批量删除奖学金名额分配", businessType = BusinessType.DELETE)
@DeleteMapping("/batch")
public R<Void> batchRemove(@RequestBody @NotEmpty(message = "主键不能为空") List<Long> ids) {
return toAjax(scholarshipQuotaService.deleteWithValidByIds(ids, true));
}
/**
* 清空指定批次和奖学金类型的名额分配
*/
@SaCheckPermission("jcbt:scholarshipQuota:remove")
@Log(title = "清空奖学金名额分配", businessType = BusinessType.DELETE)
@DeleteMapping("/clear")
public R<Void> clearQuotaByBatchAndType(@RequestParam Long batchId,
@RequestParam(required = false) Long scholarshipTypeId) {
return toAjax(scholarshipQuotaService.clearQuotaByBatchAndType(batchId, scholarshipTypeId));
}
/**
* 批量分配名额
*/
@SaCheckPermission("jcbt:scholarshipQuota:add")
@Log(title = "批量分配奖学金名额", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/batchAllocate")
public R<Void> batchAllocate(@RequestParam Long batchId,
@RequestParam Long scholarshipTypeId,
@RequestBody List<JcbtScholarshipQuotaBo> quotaAllocations) {
return toAjax(scholarshipQuotaService.batchAllocateQuota(batchId, scholarshipTypeId, quotaAllocations));
}
/**
* 调整名额分配
*/
@SaCheckPermission("jcbt:scholarshipQuota:edit")
@Log(title = "调整奖学金名额分配", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PostMapping("/adjust")
public R<Void> adjustQuota(@RequestParam Long fromQuotaId,
@RequestParam Long toQuotaId,
@RequestParam Integer adjustAmount,
@RequestParam String reason) {
return toAjax(scholarshipQuotaService.adjustQuotaAllocation(fromQuotaId, toQuotaId, adjustAmount, reason));
}
/**
* 锁定/解锁名额分配
*/
@SaCheckPermission("jcbt:scholarshipQuota:edit")
@Log(title = "锁定/解锁奖学金名额分配", businessType = BusinessType.UPDATE)
@PutMapping("/lock/{id}")
public R<Void> lockQuota(@PathVariable Long id, @RequestParam Integer isLocked) {
return toAjax(scholarshipQuotaService.lockQuotaAllocation(id, isLocked));
}
/**
* 自动分配名额
*/
@SaCheckPermission("jcbt:scholarshipQuota:edit")
@Log(title = "自动分配奖学金名额", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PostMapping("/autoAllocate")
public R<Void> autoAllocate(@RequestParam Long batchId,
@RequestParam Long scholarshipTypeId,
@RequestParam String allocationRule) {
return toAjax(scholarshipQuotaService.autoAllocateQuota(batchId, scholarshipTypeId, allocationRule));
}
/**
* 复制名额分配
*/
@SaCheckPermission("jcbt:scholarshipQuota:add")
@Log(title = "复制奖学金名额分配", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/copy")
public R<Void> copyQuota(@RequestParam Long sourceBatchId,
@RequestParam Long targetBatchId,
@RequestBody List<Long> scholarshipTypeIds) {
return toAjax(scholarshipQuotaService.copyQuotaFromBatch(sourceBatchId, targetBatchId, scholarshipTypeIds));
}
/**
* 更新名额使用情况
*/
@SaCheckPermission("jcbt:scholarshipQuota:edit")
@Log(title = "更新奖学金名额使用情况", businessType = BusinessType.UPDATE)
@PutMapping("/updateUsage/{id}")
public R<Void> updateUsage(@PathVariable Long id, @RequestParam Integer usedChange) {
return toAjax(scholarshipQuotaService.updateQuotaUsage(id, usedChange));
}
/**
* 验证名额分配
*/
@SaCheckPermission("jcbt:scholarshipQuota:query")
@PostMapping("/validate")
public R<String> validate(@RequestBody JcbtScholarshipQuotaBo bo) {
String validationMsg = scholarshipQuotaService.validateQuotaAllocation(bo);
return R.ok("验证结果", validationMsg);
}
}
@@ -0,0 +1,263 @@
package org.dromara.jcbt.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.jcbt.domain.bo.JcbtScholarshipReviewBo;
import org.dromara.jcbt.domain.vo.JcbtScholarshipReviewVo;
import org.dromara.jcbt.service.IJcbtScholarshipReviewService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* 奖学金审核记录
*
* @author ruoyi
* @date 2025-08-05
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/jcbt/review")
public class JcbtScholarshipReviewController extends BaseController {
private final IJcbtScholarshipReviewService reviewService;
/**
* 查询奖学金审核记录列表
*/
@SaCheckPermission("jcbt:review:list")
@GetMapping("/list")
public TableDataInfo<JcbtScholarshipReviewVo> list(JcbtScholarshipReviewBo bo, PageQuery pageQuery) {
return reviewService.queryPageList(bo, pageQuery);
}
/**
* 导出奖学金审核记录列表
*/
@SaCheckPermission("jcbt:review:export")
@Log(title = "奖学金审核记录", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(JcbtScholarshipReviewBo bo, HttpServletResponse response) {
List<JcbtScholarshipReviewVo> list = reviewService.queryList(bo);
ExcelUtil.exportExcel(list, "奖学金审核记录", JcbtScholarshipReviewVo.class, response);
}
/**
* 获取奖学金审核记录详细信息
*/
@SaCheckPermission("jcbt:review:query")
@GetMapping("/{id}")
public R<JcbtScholarshipReviewVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(reviewService.queryById(id));
}
// 注意:审核记录不允许手动新增、修改、删除
// 审核记录应由系统在申请提交时自动创建
// 仅保留查询和审核操作功能
/**
* 根据申请ID查询审核记录
*/
@SaCheckPermission("jcbt:review:query")
@GetMapping("/application/{applicationId}")
public R<List<JcbtScholarshipReviewVo>> getReviewsByApplicationId(
@NotNull(message = "申请ID不能为空") @PathVariable Long applicationId) {
return R.ok(reviewService.queryReviewsByApplicationId(applicationId));
}
/**
* 查询当前用户待审核的记录
*/
@SaCheckPermission("jcbt:review:pending")
@GetMapping("/pending")
public TableDataInfo<JcbtScholarshipReviewVo> getPendingReviews(
@RequestParam(required = false) Long reviewerId,
@RequestParam(required = false) String reviewLevel,
@RequestParam(required = false) String applicationNo,
@RequestParam(required = false) String studentName,
PageQuery pageQuery) {
return reviewService.queryPendingReviews(reviewerId, reviewLevel, applicationNo, studentName, pageQuery);
}
/**
* 查询审核历史记录
*/
@SaCheckPermission("jcbt:review:history")
@GetMapping("/history")
public TableDataInfo<JcbtScholarshipReviewVo> getReviewHistory(
@RequestParam(required = false) Long reviewerId,
@RequestParam(required = false) String reviewResult,
@RequestParam(required = false) Long batchId,
@RequestParam(required = false) String startTime,
@RequestParam(required = false) String endTime,
PageQuery pageQuery) {
return reviewService.queryReviewHistory(reviewerId, reviewResult, batchId, startTime, endTime, pageQuery);
}
/**
* 提交审核结果
*/
@SaCheckPermission("jcbt:review:approve")
@Log(title = "提交审核结果", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PostMapping("/submit")
public R<Void> submitReview(
@NotNull(message = "审核记录ID不能为空") @RequestParam Long reviewId,
@NotEmpty(message = "审核结果不能为空") @RequestParam String reviewResult,
@RequestParam(required = false) String reviewOpinion,
@RequestParam(required = false) Double reviewScore,
@RequestParam(required = false) Long nextReviewerId) {
return toAjax(reviewService.submitReview(reviewId, reviewResult, reviewOpinion, reviewScore, nextReviewerId));
}
/**
* 批量审核
*/
@SaCheckPermission("jcbt:review:batchApprove")
@Log(title = "批量审核", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PostMapping("/batch")
public R<Void> batchReview(
@NotEmpty(message = "审核记录ID列表不能为空") @RequestParam List<Long> reviewIds,
@NotEmpty(message = "审核结果不能为空") @RequestParam String reviewResult,
@RequestParam(required = false) String reviewOpinion,
@NotNull(message = "审核人ID不能为空") @RequestParam Long reviewerId,
@NotEmpty(message = "审核人姓名不能为空") @RequestParam String reviewerName) {
return toAjax(reviewService.batchReview(reviewIds, reviewResult, reviewOpinion, reviewerId, reviewerName));
}
// 注意:审核任务创建通常在申请提交时自动触发
// 此接口保留作为补偿性操作,用于特殊情况下手动创建审核任务
/**
* 转移审核任务
*/
@SaCheckPermission("jcbt:review:transfer")
@Log(title = "转移审核任务", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PostMapping("/transfer")
public R<Void> transferReview(
@NotNull(message = "审核记录ID不能为空") @RequestParam Long reviewId,
@NotNull(message = "新审核人ID不能为空") @RequestParam Long newReviewerId,
@NotEmpty(message = "新审核人姓名不能为空") @RequestParam String newReviewerName,
@RequestParam(required = false) String reason) {
return toAjax(reviewService.transferReview(reviewId, newReviewerId, newReviewerName, reason));
}
/**
* 撤回审核结果
*/
@SaCheckPermission("jcbt:review:revoke")
@Log(title = "撤回审核结果", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PostMapping("/withdraw")
public R<Void> withdrawReview(
@NotNull(message = "审核记录ID不能为空") @RequestParam Long reviewId,
@RequestParam(required = false) String reason) {
return toAjax(reviewService.withdrawReview(reviewId, reason));
}
/**
* 查询某个申请的最新审核记录
*/
@SaCheckPermission("jcbt:review:query")
@GetMapping("/latest/{applicationId}")
public R<JcbtScholarshipReviewVo> getLatestReview(
@NotNull(message = "申请ID不能为空") @PathVariable Long applicationId) {
return R.ok(reviewService.queryLatestReviewByApplicationId(applicationId));
}
/**
* 查询某个申请的指定级别审核记录
*/
@SaCheckPermission("jcbt:review:query")
@GetMapping("/level/{applicationId}/{reviewLevel}")
public R<JcbtScholarshipReviewVo> getReviewByLevel(
@NotNull(message = "申请ID不能为空") @PathVariable Long applicationId,
@NotEmpty(message = "审核级别不能为空") @PathVariable String reviewLevel) {
return R.ok(reviewService.queryReviewByApplicationAndLevel(applicationId, reviewLevel));
}
/**
* 统计审核数量
*/
@SaCheckPermission("jcbt:review:statistics")
@GetMapping("/statistics/count")
public R<Map<String, Long>> getReviewCount(
@RequestParam(required = false) Long reviewerId,
@RequestParam(required = false) String reviewLevel,
@RequestParam(required = false) String reviewResult,
@RequestParam(required = false) Long batchId) {
return R.ok(reviewService.countReviewsByCondition(reviewerId, reviewLevel, reviewResult, batchId));
}
/**
* 获取下一级审核人员列表
*/
@SaCheckPermission("jcbt:review:query")
@GetMapping("/next-reviewers/{applicationId}/{currentLevel}")
public R<List<Long>> getNextReviewers(
@NotNull(message = "申请ID不能为空") @PathVariable Long applicationId,
@NotEmpty(message = "当前审核级别不能为空") @PathVariable String currentLevel) {
return R.ok(reviewService.getNextReviewers(applicationId, currentLevel));
}
/**
* 审核流程推进
*/
@SaCheckPermission("jcbt:review:approve")
@Log(title = "审核流程推进", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PostMapping("/advance")
public R<Void> advanceReviewProcess(
@NotNull(message = "申请ID不能为空") @RequestParam Long applicationId,
@NotEmpty(message = "当前审核级别不能为空") @RequestParam String currentLevel,
@NotEmpty(message = "审核结果不能为空") @RequestParam String reviewResult,
@RequestParam(required = false) String reviewOpinion,
@RequestParam(required = false) Double reviewScore) {
return toAjax(reviewService.advanceReviewProcess(applicationId, currentLevel, reviewResult, reviewOpinion, reviewScore));
}
/**
* 检查用户审核权限
*/
@SaCheckPermission("jcbt:review:query")
@GetMapping("/permission")
public R<Boolean> checkReviewPermission(
@NotNull(message = "审核人ID不能为空") @RequestParam Long reviewerId,
@NotEmpty(message = "审核级别不能为空") @RequestParam String reviewLevel,
@NotNull(message = "申请ID不能为空") @RequestParam Long applicationId) {
return R.ok(reviewService.checkReviewPermission(reviewerId, reviewLevel, applicationId));
}
/**
* 获取审核统计信息
*/
@SaCheckPermission("jcbt:review:statistics")
@GetMapping("/statistics")
public R<Map<String, Object>> getReviewStatistics(
@RequestParam(required = false) Long reviewerId,
@RequestParam(required = false) String reviewLevel,
@RequestParam(required = false) Long batchId) {
return R.ok(reviewService.getReviewStatistics(reviewerId, reviewLevel, batchId));
}
}
@@ -0,0 +1,298 @@
package org.dromara.jcbt.controller;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.jcbt.domain.vo.JcbtScholarshipTypeVo;
import org.dromara.jcbt.domain.bo.JcbtScholarshipTypeBo;
import org.dromara.jcbt.service.IJcbtScholarshipTypeService;
import org.dromara.jcbt.service.IJcbtScholarshipCompatibilityService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.log.enums.BusinessType;
/**
* 奖学金类型
*
* @author ruoyi
* @date 2025-01-27
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/jcbt/scholarshipType")
@Slf4j
public class JcbtScholarshipTypeController extends BaseController {
private final IJcbtScholarshipTypeService scholarshipTypeService;
private final IJcbtScholarshipCompatibilityService compatibilityService;
/**
* 查询奖学金类型列表
*/
@SaCheckPermission("jcbt:scholarshipType:list")
@GetMapping("/list")
public TableDataInfo<JcbtScholarshipTypeVo> list(JcbtScholarshipTypeBo bo, PageQuery pageQuery) {
return scholarshipTypeService.queryPageList(bo, pageQuery);
}
/**
* 导出奖学金类型列表
*/
@SaCheckPermission("jcbt:scholarshipType:export")
@Log(title = "奖学金类型", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(JcbtScholarshipTypeBo bo, HttpServletResponse response) {
List<JcbtScholarshipTypeVo> list = scholarshipTypeService.queryExportList(bo);
ExcelUtil.exportExcel(list, "奖学金类型", JcbtScholarshipTypeVo.class, response);
}
/**
* 获取奖学金类型详细信息
*/
@SaCheckPermission("jcbt:scholarshipType:query")
@GetMapping("/{id}")
public R<JcbtScholarshipTypeVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(scholarshipTypeService.queryById(id));
}
/**
* 新增奖学金类型
*/
@SaCheckPermission("jcbt:scholarshipType:add")
@Log(title = "奖学金类型", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody JcbtScholarshipTypeBo bo) {
return toAjax(scholarshipTypeService.insertByBo(bo));
}
/**
* 修改奖学金类型
*/
@SaCheckPermission("jcbt:scholarshipType:edit")
@Log(title = "奖学金类型", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody JcbtScholarshipTypeBo bo) {
return toAjax(scholarshipTypeService.updateByBo(bo));
}
/**
* 删除奖学金类型
*/
@SaCheckPermission("jcbt:scholarshipType:remove")
@Log(title = "奖学金类型", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(scholarshipTypeService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 根据类型名称查询奖学金类型
*/
@SaCheckPermission("jcbt:scholarshipType:query")
@GetMapping("/getByName/{typeName}")
public R<JcbtScholarshipTypeVo> getByTypeName(@PathVariable String typeName) {
return R.ok(scholarshipTypeService.queryByTypeName(typeName));
}
/**
* 根据类别查询奖学金类型列表
*/
@SaCheckPermission("jcbt:scholarshipType:query")
@GetMapping("/getByCategory/{typeCategory}")
public R<List<JcbtScholarshipTypeVo>> getByCategory(@PathVariable String typeCategory) {
return R.ok(scholarshipTypeService.queryByCategory(typeCategory));
}
/**
* 查询启用状态的奖学金类型列表
*/
@SaCheckPermission("jcbt:scholarshipType:query")
@GetMapping("/getActiveTypes")
public R<List<JcbtScholarshipTypeVo>> getActiveTypes() {
return R.ok(scholarshipTypeService.queryActiveTypes());
}
/**
* 检查奖学金名称是否重复
*/
@SaCheckPermission("jcbt:scholarshipType:query")
@GetMapping("/checkTypeNameUnique")
public R<Boolean> checkTypeNameUnique(@RequestParam String typeName,
@RequestParam(required = false) Long id) {
return R.ok(scholarshipTypeService.checkTypeNameUnique(typeName, id));
}
/**
* 批量更新排序号
*/
@SaCheckPermission("jcbt:scholarshipType:edit")
@Log(title = "奖学金类型", businessType = BusinessType.UPDATE)
@PutMapping("/batchUpdateSort")
public R<Void> batchUpdateSortOrder(@RequestBody List<JcbtScholarshipTypeBo> scholarshipTypes) {
return toAjax(scholarshipTypeService.batchUpdateSortOrder(scholarshipTypes));
}
/**
* 根据兼得类型查询相关奖学金类型
*/
@SaCheckPermission("jcbt:scholarshipType:query")
@GetMapping("/getByCompatibilityType/{compatibilityType}")
public R<List<JcbtScholarshipTypeVo>> getByCompatibilityType(@PathVariable String compatibilityType) {
return R.ok(scholarshipTypeService.queryByCompatibilityType(compatibilityType));
}
/**
* 启用/停用奖学金类型
*/
@SaCheckPermission("jcbt:scholarshipType:edit")
@Log(title = "奖学金类型", businessType = BusinessType.UPDATE)
@PutMapping("/changeStatus")
public R<Void> changeStatus(@RequestParam Long id, @RequestParam Integer status) {
return toAjax(scholarshipTypeService.changeStatus(id, status));
}
/**
* 获取奖学金类型选项列表
*/
@SaCheckPermission("jcbt:scholarshipType:query")
@GetMapping("/options")
public R<List<JcbtScholarshipTypeVo>> getOptions() {
return R.ok(scholarshipTypeService.queryOptions());
}
/**
* 获取奖学金类型的兼得关系配置
*/
@SaCheckPermission("jcbt:scholarshipType:compatibility")
@GetMapping("/{id}/compatibility")
public R<Map<String, Object>> getCompatibilityConfig(@NotNull(message = "主键不能为空") @PathVariable Long id) {
// 获取所有启用的奖学金类型(除了当前奖学金)
List<JcbtScholarshipTypeVo> allTypes = scholarshipTypeService.queryActiveTypes()
.stream()
.filter(type -> !type.getId().equals(id))
.toList();
// 获取当前奖学金的互斥关系ID列表
List<Long> exclusiveTypeIds = compatibilityService.getExclusiveTypeIds(id);
// 获取当前奖学金的兼容关系ID列表
List<Long> compatibleTypeIds = compatibilityService.getCompatibleTypeIds(id);
// 获取互斥奖学金的详细信息(包含名称)
List<JcbtScholarshipTypeVo> exclusiveTypes = allTypes.stream()
.filter(type -> exclusiveTypeIds.contains(type.getId()))
.toList();
// 获取兼容奖学金的详细信息(包含名称)
List<JcbtScholarshipTypeVo> compatibleTypes = allTypes.stream()
.filter(type -> compatibleTypeIds.contains(type.getId()))
.toList();
Map<String, Object> result = new HashMap<>();
result.put("allTypes", allTypes);
result.put("exclusiveTypeIds", exclusiveTypeIds);
result.put("compatibleTypeIds", compatibleTypeIds);
// 新增:返回详细的兼容性信息
result.put("exclusiveTypes", exclusiveTypes);
result.put("compatibleTypes", compatibleTypes);
return R.ok(result);
}
/**
* 保存奖学金类型的兼得关系配置
*/
@SaCheckPermission("jcbt:scholarshipType:compatibility")
@Log(title = "奖学金兼得关系配置", businessType = BusinessType.UPDATE)
@PostMapping("/{id}/compatibility")
public R<Void> saveCompatibilityConfig(@NotNull(message = "主键不能为空") @PathVariable Long id,
@RequestBody Map<String, Object> config) {
// 安全地转换互斥类型ID列表,支持前端传递的字符串或数字类型
@SuppressWarnings("unchecked")
List<Object> exclusiveTypeIdsObj = (List<Object>) config.get("exclusiveTypeIds");
List<Long> exclusiveTypeIds = exclusiveTypeIdsObj != null ?
exclusiveTypeIdsObj.stream()
.map(obj -> {
if (obj instanceof String) {
return Long.parseLong((String) obj);
} else if (obj instanceof Number) {
return ((Number) obj).longValue();
} else {
throw new IllegalArgumentException("Invalid exclusiveTypeId type: " + obj.getClass());
}
})
.collect(Collectors.toList()) :
null;
// 安全地转换兼容类型ID列表,支持前端传递的字符串或数字类型
@SuppressWarnings("unchecked")
List<Object> compatibleTypeIdsObj = (List<Object>) config.get("compatibleTypeIds");
List<Long> compatibleTypeIds = compatibleTypeIdsObj != null ?
compatibleTypeIdsObj.stream()
.map(obj -> {
if (obj instanceof String) {
return Long.parseLong((String) obj);
} else if (obj instanceof Number) {
return ((Number) obj).longValue();
} else {
throw new IllegalArgumentException("Invalid compatibleTypeId type: " + obj.getClass());
}
})
.collect(Collectors.toList()) :
null;
boolean result = compatibilityService.saveCompatibilityConfig(id, exclusiveTypeIds, compatibleTypeIds);
return toAjax(result);
}
/**
* 检查两个奖学金类型是否兼容
*/
@SaCheckPermission("jcbt:scholarshipType:query")
@GetMapping("/checkCompatibility")
public R<Boolean> checkCompatibility(@RequestParam Long typeId1, @RequestParam Long typeId2) {
return R.ok(compatibilityService.checkCompatibility(typeId1, typeId2));
}
/**
* 获取可与指定奖学金兼得的奖学金类型列表
*/
@SaCheckPermission("jcbt:scholarshipType:query")
@GetMapping("/{id}/compatibleTypes")
public R<List<JcbtScholarshipTypeVo>> getCompatibleTypes(@NotNull(message = "主键不能为空") @PathVariable Long id) {
List<Long> compatibleTypeIds = compatibilityService.getCompatibleTypeIds(id);
List<JcbtScholarshipTypeVo> compatibleTypes = new ArrayList<>();
for (Long typeId : compatibleTypeIds) {
JcbtScholarshipTypeVo type = scholarshipTypeService.queryById(typeId);
if (type != null && type.getStatus() == 1) { // 只返回启用状态的
compatibleTypes.add(type);
}
}
return R.ok(compatibleTypes);
}
}
@@ -0,0 +1,66 @@
package org.dromara.jcbt.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
/**
* 申请自助类型对象 jcbt_assistance_type
*
* @author ruoyi
* @date 2025-08-09
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("jcbt_assistance_type")
public class JcbtAssistanceType extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 自助类型编码
*/
private String assistanceCode;
/**
* 自助类型名称
*/
private String assistanceName;
/**
* 自助类型描述
*/
private String assistanceDescription;
/**
* 是否支持多选(0单选 1多选)
*/
private Integer isMultiSelect;
/**
* 排序号
*/
private Integer sortOrder;
/**
* 状态(0正常 1停用)
*/
private String status;
/**
* 逻辑删除标记
*/
@TableLogic
private Long deleted;
}
@@ -0,0 +1,201 @@
package org.dromara.jcbt.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
/**
* 贫困生认定申请对象 jcbt_poverty_application
*
* @author ruoyi
* @date 2025-08-09
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("jcbt_poverty_application")
public class JcbtPovertyApplication extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 申请编号
*/
private String applicationNo;
/**
* 学年
*/
private String academicYear;
/**
* 学期
*/
private Integer term;
/**
* 学生ID
*/
private Long studentId;
/**
* 学号
*/
private String studentNo;
/**
* 学生姓名
*/
private String studentName;
/**
* 性别
*/
private String gender;
/**
* 学院ID
*/
private Long collegeId;
/**
* 学院名称
*/
private String collegeName;
/**
* 专业ID
*/
private Long majorId;
/**
* 专业名称
*/
private String majorName;
/**
* 班级ID
*/
private Long classId;
/**
* 班级名称
*/
private String className;
/**
* 认定群体(特殊群体/其他群体)
*/
private String recognitionGroup;
/**
* 认定类型ID
*/
private Long recognitionTypeId;
/**
* 认定类型编码
*/
private String recognitionTypeCode;
/**
* 认定类型名称
*/
private String recognitionTypeName;
/**
* 申请自助类型ID数组(多选)
*/
private String assistanceTypeIds;
/**
* 申请自助类型名称(多个用逗号分隔)
*/
private String assistanceTypeNames;
/**
* 家庭经济情况摘要
*/
private String familyEconomySummary;
/**
* 申请表附件URL
*/
private String attachApplicationFormUrl;
/**
* 申请表附件ID
*/
private Long attachApplicationFormId;
/**
* 调查表附件URL
*/
private String attachSurveyFormUrl;
/**
* 调查表附件ID
*/
private Long attachSurveyFormId;
/**
* 申请状态
*/
private String status;
/**
* 提交人ID
*/
private Long submitterId;
/**
* 提交人姓名
*/
private String submitterName;
/**
* 提交时间
*/
private java.util.Date submitTime;
/**
* 审核人ID
*/
private Long auditorId;
/**
* 审核人姓名
*/
private String auditorName;
/**
* 审核时间
*/
private java.util.Date auditTime;
/**
* 审核意见
*/
private String auditOpinion;
/**
* 备注
*/
private String remark;
/**
* 逻辑删除标记
*/
@TableLogic
private Long deleted;
}
@@ -0,0 +1,71 @@
package org.dromara.jcbt.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
/**
* 认定类型对象 jcbt_recognition_type
*
* @author ruoyi
* @date 2025-08-09
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("jcbt_recognition_type")
public class JcbtRecognitionType extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 类型分组(special特殊群体/other其他群体)
*/
private String typeGroup;
/**
* 类型编码
*/
private String typeCode;
/**
* 类型名称
*/
private String typeName;
/**
* 类型描述
*/
private String typeDescription;
/**
* 证明材料要求
*/
private String certificateRequirement;
/**
* 排序号
*/
private Integer sortOrder;
/**
* 状态(0正常 1停用)
*/
private String status;
/**
* 逻辑删除标记
*/
@TableLogic
private Long deleted;
}
@@ -0,0 +1,160 @@
package org.dromara.jcbt.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
import java.util.Date;
/**
* 奖学金申请记录对象 jcbt_scholarship_application
*
* @author ruoyi
* @date 2025-01-01
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("jcbt_scholarship_application")
public class JcbtScholarshipApplication extends BaseEntity {
/**
* 重写父类的createDept字段,排除此字段因为数据库表中不存在create_dept列
* 通过重新声明字段并标记为不存在来避免MyBatis-Plus自动处理
*/
@TableField(exist = false)
private Long createDept;
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 申请编号
*/
@TableField("application_no")
private String applicationNo;
/**
* 批次ID
*/
private Long batchId;
/**
* 奖学金类型ID
*/
private Long scholarshipTypeId;
/**
* 学生学号
*/
@TableField("student_no")
private String studentNo;
/**
* 学生姓名
*/
private String studentName;
/**
* 学生ID
*/
private Long studentId;
/**
* 学院ID
*/
private Long deptId;
/**
* 专业ID
*/
private Long majorId;
/**
* 班级ID
*/
private Long classId;
/**
* 申请类型:RECOMMEND-教师推荐,AUTO-自动评定,DIRECT-直接指定
*/
@TableField("application_type")
private String applicationType;
/**
* 申请原因
*/
@TableField("apply_reason")
private String applyReason;
/**
* 自我评价
*/
@TableField("self_evaluation")
private String selfEvaluation;
/**
* 系统计算分数
*/
@TableField("calculated_score")
private Double calculatedScore;
/**
* 最终评定分数
*/
@TableField("final_score")
private Double finalScore;
/**
* 在院系的排名
*/
@TableField("ranking_in_dept")
private Integer rankingInDept;
/**
* 在专业的排名
*/
@TableField("ranking_in_major")
private Integer rankingInMajor;
/**
* 当前状态:DRAFT-草稿,SUBMITTED-已提交,REVIEWING-审核中,APPROVED-已通过,REJECTED-已拒绝,WITHDRAWN-已撤回
*/
@TableField("current_status")
private String currentStatus;
/**
* 提交时间
*/
private Date submitTime;
/**
* 租户ID
*/
private String tenantId;
/**
* 删除标志
*/
@TableLogic
private Integer deleted;
}
@@ -0,0 +1,131 @@
package org.dromara.jcbt.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
/**
* 奖学金申请材料对象 jcbt_scholarship_attachment
*
* @author ruoyi
* @date 2025-01-01
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("jcbt_scholarship_attachment")
public class JcbtScholarshipAttachment extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 申请记录ID
*/
private Long applicationId;
/**
* 批次ID
*/
private Long batchId;
/**
* 奖学金类型ID
*/
private Long scholarshipTypeId;
/**
* 材料类型:TRANSCRIPT-成绩单,CERTIFICATE-获奖证书,RECOMMENDATION-推荐信,FAMILY_PROOF-家庭经济证明,OTHER-其他材料
*/
private String materialType;
/**
* 材料名称
*/
private String materialName;
/**
* 材料描述
*/
private String materialDescription;
/**
* 文件名称
*/
private String fileName;
/**
* 文件路径
*/
private String filePath;
/**
* 文件大小(字节)
*/
private Long fileSize;
/**
* 文件类型
*/
private String fileType;
/**
* 上传者类型:STUDENT-学生,TEACHER-教师
*/
private String uploaderType;
/**
* 上传者ID
*/
private Long uploaderId;
/**
* 上传者姓名
*/
private String uploaderName;
/**
* 审核状态:PENDING-待审核,APPROVED-已通过,REJECTED-已拒绝
*/
private String auditStatus;
/**
* 审核意见
*/
private String auditComment;
/**
* 是否必须:0-否,1-是
*/
private Integer isRequired;
/**
* 排序号
*/
private Integer sortOrder;
/**
* 备注
*/
private String remark;
/**
* 租户ID
*/
private String tenantId;
/**
* 删除标志
*/
@TableLogic
private Integer deleted;
}
@@ -0,0 +1,118 @@
package org.dromara.jcbt.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.util.Date;
import java.util.List;
/**
* 奖学金评定批次对象 jcbt_scholarship_batch
*
* @author ruoyi
* @date 2025-01-27
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("jcbt_scholarship_batch")
public class JcbtScholarshipBatch extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 批次编码
*/
private String batchCode;
/**
* 批次名称
*/
private String batchName;
/**
* 学年
*/
private String academicYear;
/**
* 学期:1-第一学期,2-第二学期,3-全年
*/
private Integer semester;
/**
* 批次类型:REGULAR-常规批次,SPECIAL-专项批次,SUPPLEMENTARY-补充批次
*/
private String batchType;
/**
* 开始时间
*/
private Date startTime;
/**
* 结束时间
*/
private Date endTime;
/**
* 申请开始时间
*/
private Date applyStartTime;
/**
* 申请结束时间
*/
private Date applyEndTime;
/**
* 审核开始时间
*/
private Date reviewStartTime;
/**
* 审核结束时间
*/
private Date reviewEndTime;
/**
* 状态:DRAFT-草稿,ACTIVE-进行中,COMPLETED-已完成,CANCELLED-已取消
*/
private String status;
/**
* 批次描述
*/
private String description;
/**
* 通知内容
*/
private String noticeContent;
/**
* 租户ID
*/
@TableField("tenant_id")
private Long tenantId;
/**
* 删除标记
*/
@TableLogic
private Integer deleted;
/**
* 关联的奖学金类型ID列表(非数据库字段)
*/
@TableField(exist = false)
private List<Long> scholarshipTypeIds;
}
@@ -0,0 +1,58 @@
package org.dromara.jcbt.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
/**
* 奖学金批次类型关联对象 jcbt_scholarship_batch_type
*
* @author ruoyi
* @date 2025-01-27
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("jcbt_scholarship_batch_type")
public class JcbtScholarshipBatchType extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 批次ID
*/
private Long batchId;
/**
* 奖学金类型ID
*/
private Long scholarshipTypeId;
/**
* 是否启用:0-禁用,1-启用
*/
private Integer isActive;
/**
* 排序号
*/
private Integer sortOrder;
/**
* 租户ID
*/
private String tenantId;
/**
* 删除标志
*/
@TableLogic
private Integer deleted;
}
@@ -0,0 +1,111 @@
package org.dromara.jcbt.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
/**
* 奖学金班级名额分配对象 jcbt_scholarship_class_quota
*
* @author ruoyi
* @date 2025-01-01
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("jcbt_scholarship_class_quota")
public class JcbtScholarshipClassQuota extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 批次ID
*/
private Long batchId;
/**
* 奖学金类型ID
*/
private Long scholarshipTypeId;
/**
* 学院ID
*/
private Long deptId;
/**
* 班级ID
*/
private Long classId;
/**
* 班级名称
*/
private String className;
/**
* 总名额
*/
private Integer totalQuota;
/**
* 已使用名额
*/
private Integer usedQuota;
/**
* 预留名额
*/
private Integer reservedQuota;
/**
* 可用名额
*/
private Integer availableQuota;
/**
* 分配方式:MANUAL-手动分配,AUTO-自动分配,PROPORTIONAL-按比例分配
*/
private String allocationMethod;
/**
* 分配依据说明
*/
private String allocationBasis;
/**
* 是否锁定:0-否,1-是
*/
private Integer isLocked;
/**
* 状态:ACTIVE-生效,INACTIVE-失效,SUSPENDED-暂停
*/
private String status;
/**
* 备注
*/
private String remark;
/**
* 租户ID
*/
private String tenantId;
/**
* 删除标志
*/
@TableLogic
private Integer deleted;
}
@@ -0,0 +1,68 @@
package org.dromara.jcbt.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
/**
* 奖学金兼得关系对象 jcbt_scholarship_compatibility
*
* @author ruoyi
* @date 2025-01-27
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("jcbt_scholarship_compatibility")
public class JcbtScholarshipCompatibility extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 奖学金类型1
*/
@TableField("type_id_1")
private Long typeId1;
/**
* 奖学金类型2
*/
@TableField("type_id_2")
private Long typeId2;
/**
* 关系类型:COMPATIBLE-兼容,EXCLUSIVE-互斥,PRIORITY-优先级关系
*/
@TableField("relation_type")
private String relationType;
/**
* 优先级(relation_type为PRIORITY时有效)
*/
@TableField("priority_level")
private Integer priorityLevel;
/**
* 关系描述
*/
private String description;
/**
* 租户ID
*/
@TableField("tenant_id")
private Long tenantId;
/**
* 删除标记
*/
@TableLogic
private Integer deleted;
}
@@ -0,0 +1,125 @@
package org.dromara.jcbt.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.tenant.core.TenantEntity;
import java.io.Serial;
/**
* 奖学金名额分配对象 jcbt_scholarship_quota
*
* @author ruoyi
* @date 2025-01-27
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("jcbt_scholarship_quota")
public class JcbtScholarshipQuota extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 批次ID
*/
private Long batchId;
/**
* 奖学金类型ID
*/
private Long scholarshipTypeId;
/**
* 分配级别:UNIVERSITY-全校,COLLEGE-学院,MAJOR-专业,CLASS-班级
*/
private String allocationLevel;
/**
* 目标部门ID(学院/专业/班级)
*/
private Long targetDeptId;
/**
* 上级名额ID(层级分配)
*/
private Long parentQuotaId;
/**
* 总名额
*/
private Integer totalQuota;
/**
* 已使用名额
*/
private Integer usedQuota;
/**
* 预留名额
*/
private Integer reservedQuota;
/**
* 可用名额
*/
private Integer availableQuota;
/**
* 分配规则(JSON格式)
*/
private String allocationRule;
/**
* 分配依据说明
*/
private String allocationBasis;
/**
* 分配方式:MANUAL-手动分配,AUTO-自动分配,PROPORTIONAL-按比例分配
*/
private String allocationMethod;
/**
* 是否可调整:0-否,1-是
*/
private Integer isAdjustable;
/**
* 是否锁定:0-否,1-是
*/
private Integer isLocked;
/**
* 状态:ACTIVE-生效,INACTIVE-失效,PENDING-待审核
*/
private String status;
/**
* 备注
*/
private String remark;
/**
* 租户ID
*/
private Long tenantId;
/**
* 删除标记:0-正常,1-删除
*/
@TableLogic
private Integer deleted;
}
@@ -0,0 +1,107 @@
package org.dromara.jcbt.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
import java.util.Date;
/**
* 奖学金名额使用记录对象 jcbt_scholarship_quota_usage
*
* @author ruoyi
* @date 2025-01-01
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("jcbt_scholarship_quota_usage")
public class JcbtScholarshipQuotaUsage extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 申请记录ID
*/
private Long applicationId;
/**
* 批次ID
*/
private Long batchId;
/**
* 奖学金类型ID
*/
private Long scholarshipTypeId;
/**
* 名额类型:CLASS-班级名额,DEPT-学院名额
*/
private String quotaType;
/**
* 名额来源ID(班级名额分配ID或学院名额分配ID)
*/
private Long quotaSourceId;
/**
* 目标部门ID(学院ID或班级ID)
*/
private Long targetDeptId;
/**
* 操作类型:USE-使用名额,RELEASE-释放名额
*/
private String operationType;
/**
* 名额数量(通常为1)
*/
private Integer quotaCount;
/**
* 操作时间
*/
private Date operationTime;
/**
* 操作人ID
*/
private Long operatorId;
/**
* 操作人姓名
*/
private String operatorName;
/**
* 操作原因
*/
private String operationReason;
/**
* 备注
*/
private String remark;
/**
* 租户ID
*/
private String tenantId;
/**
* 删除标志
*/
@TableLogic
private Integer deleted;
}
@@ -0,0 +1,95 @@
package org.dromara.jcbt.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
import java.math.BigDecimal;
import java.util.Date;
/**
* 奖学金审核记录对象 jcbt_scholarship_review
*
* @author ruoyi
* @date 2025-08-05
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("jcbt_scholarship_review")
public class JcbtScholarshipReview extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 申请记录ID
*/
private Long applicationId;
/**
* 审核级别:DEPARTMENT-院系审核,SCHOOL-学校审核,FINANCE-财务审核,FINAL-终审
*/
private String reviewLevel;
/**
* 审核人ID
*/
private Long reviewerId;
/**
* 审核人姓名
*/
private String reviewerName;
/**
* 审核结果:PENDING-待审核,APPROVED-通过,REJECTED-拒绝,RETURNED-退回
*/
private String reviewResult;
/**
* 审核评分
*/
private BigDecimal reviewScore;
/**
* 审核意见
*/
private String reviewOpinion;
/**
* 审核时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date reviewTime;
/**
* 下一审核人ID
*/
private Long nextReviewerId;
/**
* 是否最终审核:0-否,1-是
*/
private Integer isFinalReview;
/**
* 租户ID
*/
private String tenantId;
/**
* 删除标志
*/
@TableLogic
private Integer deleted;
}
@@ -0,0 +1,110 @@
package org.dromara.jcbt.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.math.BigDecimal;
/**
* 奖学金类型对象 jcbt_scholarship_type
*
* @author ruoyi
* @date 2025-01-27
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("jcbt_scholarship_type")
public class JcbtScholarshipType extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id")
private Long id;
/**
* 奖学金类型编码
*/
private String typeCode;
/**
* 奖学金名称
*/
private String typeName;
/**
* 奖学金类别
*/
private String typeCategory;
/**
* 奖学金等级
*/
private String levelType;
/**
* 奖金金额
*/
private BigDecimal awardAmount;
/**
* 奖学金描述
*/
private String description;
/**
* 申请指南
*/
private String applicationGuide;
/**
* 申请条件
*/
private String applicationConditions;
/**
* 评定标准
*/
private String evaluationCriteria;
/**
* 备注
*/
private String remark;
/**
* 排序号
*/
private Integer sortOrder;
/**
* 状态:0-禁用,1-启用
*/
private Integer status;
/**
* 是否系统内置:0-否,1-是
*/
private Integer isSystem;
/**
* 兼得类型:EXCLUSIVE-完全互斥,COMPATIBLE-完全兼容,CUSTOM-自定义配置
*/
private String compatibilityType;
/**
* 租户ID
*/
private String tenantId;
/**
* 删除标志
*/
@TableLogic
private Integer deleted;
}
@@ -0,0 +1,28 @@
package org.dromara.jcbt.domain.bo;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* 审核请求业务对象
*
* @author ruoyi
* @date 2025-08-09
*/
@Data
public class AuditRequestBo {
/**
* 申请ID
*/
@NotNull(message = "申请ID不能为空")
private Long id;
/**
* 审核意见
*/
@NotBlank(message = "审核意见不能为空")
private String auditOpinion;
}
@@ -0,0 +1,238 @@
package org.dromara.jcbt.domain.bo;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.jcbt.domain.JcbtPovertyApplication;
import java.util.Date;
/**
* 贫困生认定申请业务对象 jcbt_poverty_application
*
* @author ruoyi
* @date 2025-08-09
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = JcbtPovertyApplication.class, reverseConvertGenerate = false)
public class JcbtPovertyApplicationBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 申请编号
*/
private String applicationNo;
/**
* 学年
*/
@NotBlank(message = "学年不能为空", groups = { AddGroup.class, EditGroup.class })
private String academicYear;
/**
* 学期
*/
private Integer term;
/**
* 学生ID
*/
@NotNull(message = "学生ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long studentId;
/**
* 学号
*/
@NotBlank(message = "学号不能为空", groups = { AddGroup.class, EditGroup.class })
private String studentNo;
/**
* 学生姓名
*/
@NotBlank(message = "学生姓名不能为空", groups = { AddGroup.class, EditGroup.class })
private String studentName;
/**
* 性别
*/
private String gender;
/**
* 学院ID
*/
@NotNull(message = "学院ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long collegeId;
/**
* 学院名称
*/
@NotBlank(message = "学院名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String collegeName;
/**
* 专业ID
*/
@NotNull(message = "专业ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long majorId;
/**
* 专业名称
*/
@NotBlank(message = "专业名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String majorName;
/**
* 班级ID
*/
@NotNull(message = "班级ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long classId;
/**
* 班级名称
*/
@NotBlank(message = "班级名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String className;
/**
* 认定群体(特殊群体/其他群体)
*/
@NotBlank(message = "认定群体不能为空", groups = { AddGroup.class, EditGroup.class })
private String recognitionGroup;
/**
* 认定类型ID
*/
@NotNull(message = "认定类型ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long recognitionTypeId;
/**
* 认定类型编码
*/
@NotBlank(message = "认定类型编码不能为空", groups = { AddGroup.class, EditGroup.class })
private String recognitionTypeCode;
/**
* 认定类型名称
*/
@NotBlank(message = "认定类型名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String recognitionTypeName;
/**
* 申请自助类型ID数组(多选)
*/
@NotBlank(message = "申请自助类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String assistanceTypeIds;
/**
* 申请自助类型名称(多个用逗号分隔)
*/
@NotBlank(message = "申请自助类型名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String assistanceTypeNames;
/**
* 家庭经济情况摘要
*/
@NotBlank(message = "家庭经济情况摘要不能为空", groups = { AddGroup.class, EditGroup.class })
private String familyEconomySummary;
/**
* 申请表附件URL
*/
@NotBlank(message = "申请表附件不能为空", groups = { AddGroup.class, EditGroup.class })
private String attachApplicationFormUrl;
/**
* 申请表附件ID
*/
@NotNull(message = "申请表附件ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long attachApplicationFormId;
/**
* 调查表附件URL
*/
@NotBlank(message = "调查表附件不能为空", groups = { AddGroup.class, EditGroup.class })
private String attachSurveyFormUrl;
/**
* 调查表附件ID
*/
@NotNull(message = "调查表附件ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long attachSurveyFormId;
/**
* 申请状态
*/
private String status;
/**
* 提交人ID
*/
private Long submitterId;
/**
* 提交人姓名
*/
private String submitterName;
/**
* 提交时间
*/
private Date submitTime;
/**
* 审核人ID
*/
private Long auditorId;
/**
* 审核人姓名
*/
private String auditorName;
/**
* 审核时间
*/
private Date auditTime;
/**
* 审核意见
*/
private String auditOpinion;
/**
* 备注
*/
private String remark;
/**
* 创建者
*/
private Long createBy;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新者
*/
private Long updateBy;
/**
* 更新时间
*/
private Date updateTime;
}
@@ -0,0 +1,232 @@
package org.dromara.jcbt.domain.bo;
import org.dromara.jcbt.domain.JcbtScholarshipApplication;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.util.Date;
/**
* 奖学金申请记录业务对象 jcbt_scholarship_application
*
* @author ruoyi
* @date 2025-01-01
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = JcbtScholarshipApplication.class, reverseConvertGenerate = false)
public class JcbtScholarshipApplicationBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 批次ID
*/
@NotNull(message = "批次ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long batchId;
/**
* 奖学金类型ID
*/
@NotNull(message = "奖学金类型ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long scholarshipTypeId;
/**
* 学生学号
*/
@NotBlank(message = "学生学号不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 50, message = "学生学号长度不能超过50个字符")
private String studentNo;
/**
* 学生姓名
*/
@NotBlank(message = "学生姓名不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 100, message = "学生姓名长度不能超过100个字符")
private String studentName;
/**
* 学生ID
*/
private Long studentId;
/**
* 学院ID
*/
@NotNull(message = "学院ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long deptId;
/**
* 学院名称
*/
@Size(max = 100, message = "学院名称长度不能超过100个字符")
private String deptName;
/**
* 班级ID
*/
@NotNull(message = "班级ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long classId;
/**
* 班级名称
*/
@Size(max = 100, message = "班级名称长度不能超过100个字符")
private String className;
// 已删除 applicantType 和 applicantId 字段
/**
* 申请人姓名(班主任姓名)
*/
@Size(max = 100, message = "申请人姓名长度不能超过100个字符")
private String applicantName;
/**
* 申请类型:RECOMMEND-教师推荐,AUTO-自动评定,DIRECT-直接指定
*/
private String applicationType;
/**
* 申请原因
*/
@Size(max = 1000, message = "申请原因长度不能超过1000个字符")
private String applicationReason;
/**
* 申请说明
*/
@Size(max = 2000, message = "申请说明长度不能超过2000个字符")
private String applicationDescription;
/**
* 综合测评成绩
*/
@DecimalMin(value = "0", message = "综合测评成绩不能为负数")
@DecimalMax(value = "100", message = "综合测评成绩不能超过100分")
private Double comprehensiveScore;
/**
* 学习成绩
*/
@DecimalMin(value = "0", message = "学习成绩不能为负数")
@DecimalMax(value = "100", message = "学习成绩不能超过100分")
private Double academicScore;
/**
* 德育成绩
*/
@DecimalMin(value = "0", message = "德育成绩不能为负数")
@DecimalMax(value = "100", message = "德育成绩不能超过100分")
private Double moralScore;
/**
* 体育成绩
*/
@DecimalMin(value = "0", message = "体育成绩不能为负数")
@DecimalMax(value = "100", message = "体育成绩不能超过100分")
private Double physicalScore;
/**
* 美育成绩
*/
@DecimalMin(value = "0", message = "美育成绩不能为负数")
@DecimalMax(value = "100", message = "美育成绩不能超过100分")
private Double aestheticScore;
/**
* 劳动成绩
*/
@DecimalMin(value = "0", message = "劳动成绩不能为负数")
@DecimalMax(value = "100", message = "劳动成绩不能超过100分")
private Double laborScore;
/**
* 系统计算分数
*/
@DecimalMin(value = "0", message = "系统计算分数不能为负数")
@DecimalMax(value = "100", message = "系统计算分数不能超过100分")
private Double calculatedScore;
/**
* 最终评定分数
*/
@DecimalMin(value = "0", message = "最终评定分数不能为负数")
@DecimalMax(value = "100", message = "最终评定分数不能超过100分")
private Double finalScore;
/**
* 在院系的排名
*/
@Min(value = 1, message = "在院系的排名至少为1")
private Integer rankingInDept;
/**
* 在专业的排名
*/
@Min(value = 1, message = "在专业的排名至少为1")
private Integer rankingInMajor;
/**
* 当前状态
*/
private String currentStatus;
/**
* 状态字段(前端使用,映射到currentStatus)
*/
private String status;
/**
* 提交时间
*/
private Date submitTime;
/**
* 审核评语
*/
@Size(max = 1000, message = "审核评语长度不能超过1000个字符")
private String reviewComment;
// Getter和Setter方法,确保status和currentStatus保持同步
public String getStatus() {
return this.currentStatus;
}
public void setStatus(String status) {
this.status = status;
this.currentStatus = status;
}
public String getCurrentStatus() {
return this.currentStatus;
}
public void setCurrentStatus(String currentStatus) {
this.currentStatus = currentStatus;
this.status = currentStatus;
}
/**
* 获取申请状态(兼容旧版本,返回currentStatus)
*/
public String getApplicationStatus() {
return currentStatus;
}
/**
* 设置申请状态(兼容旧版本,设置currentStatus)
*/
public void setApplicationStatus(String applicationStatus) {
this.currentStatus = applicationStatus;
}
}
@@ -0,0 +1,126 @@
package org.dromara.jcbt.domain.bo;
import org.dromara.jcbt.domain.JcbtScholarshipBatch;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.util.Date;
import java.util.List;
/**
* 奖学金评定批次业务对象 jcbt_scholarship_batch
*
* @author ruoyi
* @date 2025-01-27
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = JcbtScholarshipBatch.class, reverseConvertGenerate = false)
public class JcbtScholarshipBatchBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 批次编码
*/
@NotBlank(message = "批次编码不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 50, message = "批次编码不能超过50个字符")
private String batchCode;
/**
* 批次名称
*/
@NotBlank(message = "批次名称不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 100, message = "批次名称不能超过100个字符")
private String batchName;
/**
* 学年
*/
@NotBlank(message = "学年不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 20, message = "学年不能超过20个字符")
private String academicYear;
/**
* 学期:1-第一学期,2-第二学期,3-全年
*/
@NotNull(message = "学期不能为空", groups = { AddGroup.class, EditGroup.class })
@Min(value = 1, message = "学期值必须在1-3之间")
@Max(value = 3, message = "学期值必须在1-3之间")
private Integer semester;
/**
* 批次类型:REGULAR-常规批次,SPECIAL-专项批次,SUPPLEMENTARY-补充批次
*/
@NotBlank(message = "批次类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String batchType;
/**
* 开始时间
*/
@NotNull(message = "开始时间不能为空", groups = { AddGroup.class, EditGroup.class })
private Date startTime;
/**
* 结束时间
*/
@NotNull(message = "结束时间不能为空", groups = { AddGroup.class, EditGroup.class })
private Date endTime;
/**
* 申请开始时间
*/
private Date applyStartTime;
/**
* 申请结束时间
*/
private Date applyEndTime;
/**
* 审核开始时间
*/
private Date reviewStartTime;
/**
* 审核结束时间
*/
private Date reviewEndTime;
/**
* 状态:DRAFT-草稿,ACTIVE-进行中,COMPLETED-已完成,CANCELLED-已取消
*/
@NotBlank(message = "状态不能为空", groups = { AddGroup.class, EditGroup.class })
private String status;
/**
* 批次描述
*/
@Size(max = 1000, message = "批次描述不能超过1000个字符")
private String description;
/**
* 通知内容
*/
private String noticeContent;
/**
* 关联的奖学金类型ID列表
*/
private List<Long> scholarshipTypeIds;
/**
* 租户ID
*/
private Long tenantId;
}
@@ -0,0 +1,112 @@
package org.dromara.jcbt.domain.bo;
import org.dromara.jcbt.domain.JcbtScholarshipClassQuota;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
* 奖学金班级名额分配业务对象 jcbt_scholarship_class_quota
*
* @author ruoyi
* @date 2025-01-01
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = JcbtScholarshipClassQuota.class, reverseConvertGenerate = false)
public class JcbtScholarshipClassQuotaBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 批次ID
*/
@NotNull(message = "批次ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long batchId;
/**
* 奖学金类型ID
*/
@NotNull(message = "奖学金类型ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long scholarshipTypeId;
/**
* 学院ID
*/
@NotNull(message = "学院ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long deptId;
/**
* 班级ID
*/
@NotNull(message = "班级ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long classId;
/**
* 班级名称
*/
@NotBlank(message = "班级名称不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 100, message = "班级名称长度不能超过100个字符")
private String className;
/**
* 总名额
*/
@NotNull(message = "总名额不能为空", groups = { AddGroup.class, EditGroup.class })
@Min(value = 0, message = "总名额不能小于0")
private Integer totalQuota;
/**
* 已使用名额
*/
@Min(value = 0, message = "已使用名额不能小于0")
private Integer usedQuota;
/**
* 预留名额
*/
@Min(value = 0, message = "预留名额不能小于0")
private Integer reservedQuota;
/**
* 可用名额
*/
@Min(value = 0, message = "可用名额不能小于0")
private Integer availableQuota;
/**
* 分配方式:MANUAL-手动分配,AUTO-自动分配,PROPORTIONAL-按比例分配
*/
private String allocationMethod;
/**
* 分配依据说明
*/
@Size(max = 500, message = "分配依据说明长度不能超过500个字符")
private String allocationBasis;
/**
* 是否锁定:0-否,1-是
*/
private Integer isLocked;
/**
* 状态:ACTIVE-生效,INACTIVE-失效,SUSPENDED-暂停
*/
private String status;
/**
* 备注
*/
@Size(max = 500, message = "备注长度不能超过500个字符")
private String remark;
}
@@ -0,0 +1,68 @@
package org.dromara.jcbt.domain.bo;
import org.dromara.jcbt.domain.JcbtScholarshipCompatibility;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import com.baomidou.mybatisplus.annotation.TableField;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
* 奖学金兼得关系业务对象 jcbt_scholarship_compatibility
*
* @author ruoyi
* @date 2025-01-27
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = JcbtScholarshipCompatibility.class, reverseConvertGenerate = false)
public class JcbtScholarshipCompatibilityBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 奖学金类型1
*/
@NotNull(message = "奖学金类型1不能为空", groups = { AddGroup.class, EditGroup.class })
@TableField("type_id_1")
private Long typeId1;
/**
* 奖学金类型2
*/
@NotNull(message = "奖学金类型2不能为空", groups = { AddGroup.class, EditGroup.class })
@TableField("type_id_2")
private Long typeId2;
/**
* 关系类型:COMPATIBLE-兼容,EXCLUSIVE-互斥,PRIORITY-优先级关系
*/
@NotBlank(message = "关系类型不能为空", groups = { AddGroup.class, EditGroup.class })
@TableField("relation_type")
private String relationType;
/**
* 优先级(relation_type为PRIORITY时有效)
*/
@TableField("priority_level")
private Integer priorityLevel;
/**
* 关系描述
*/
@Size(max = 500, message = "关系描述长度不能超过500个字符")
private String description;
/**
* 租户ID
*/
private Long tenantId;
}
@@ -0,0 +1,123 @@
package org.dromara.jcbt.domain.bo;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.jcbt.domain.JcbtScholarshipQuota;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
* 奖学金名额分配业务对象 JcbtScholarshipQuotaBo
*
* @author ruoyi
* @date 2025-01-27
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = JcbtScholarshipQuota.class, reverseConvertGenerate = false)
public class JcbtScholarshipQuotaBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 批次ID
*/
@NotNull(message = "批次ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long batchId;
/**
* 奖学金类型ID
*/
@NotNull(message = "奖学金类型ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long scholarshipTypeId;
/**
* 分配级别:UNIVERSITY-全校,COLLEGE-学院,MAJOR-专业,CLASS-班级
*/
@NotBlank(message = "分配级别不能为空", groups = { AddGroup.class, EditGroup.class })
private String allocationLevel;
/**
* 目标部门ID(学院/专业/班级)
*/
private Long targetDeptId;
/**
* 上级名额ID(层级分配)
*/
private Long parentQuotaId;
/**
* 总名额
*/
@NotNull(message = "总名额不能为空", groups = { AddGroup.class, EditGroup.class })
@Min(value = 0, message = "总名额不能小于0")
private Integer totalQuota;
/**
* 已使用名额
*/
@Min(value = 0, message = "已使用名额不能小于0")
private Integer usedQuota;
/**
* 预留名额
*/
@Min(value = 0, message = "预留名额不能小于0")
private Integer reservedQuota;
/**
* 可用名额
*/
@Min(value = 0, message = "可用名额不能小于0")
private Integer availableQuota;
/**
* 分配规则(JSON格式)
*/
private String allocationRule;
/**
* 分配依据说明
*/
private String allocationBasis;
/**
* 分配方式:MANUAL-手动分配,AUTO-自动分配,PROPORTIONAL-按比例分配
*/
private String allocationMethod;
/**
* 是否可调整:0-否,1-是
*/
private Integer isAdjustable;
/**
* 是否锁定:0-否,1-是
*/
private Integer isLocked;
/**
* 状态:ACTIVE-生效,INACTIVE-失效,PENDING-待审核
*/
private String status;
/**
* 备注
*/
private String remark;
/**
* 租户ID
*/
private Long tenantId;
}
@@ -0,0 +1,101 @@
package org.dromara.jcbt.domain.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.jcbt.domain.JcbtScholarshipReview;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
import java.util.Date;
/**
* 奖学金审核记录业务对象 jcbt_scholarship_review
*
* @author ruoyi
* @date 2025-08-05
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = JcbtScholarshipReview.class, reverseConvertGenerate = false)
public class JcbtScholarshipReviewBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 申请记录ID
*/
@NotNull(message = "申请记录ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long applicationId;
/**
* 审核级别:DEPARTMENT-院系审核,SCHOOL-学校审核,FINANCE-财务审核,FINAL-终审
*/
@NotBlank(message = "审核级别不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 20, message = "审核级别长度不能超过20个字符")
private String reviewLevel;
/**
* 审核人ID
*/
@NotNull(message = "审核人ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long reviewerId;
/**
* 审核人姓名
*/
@NotBlank(message = "审核人姓名不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 100, message = "审核人姓名长度不能超过100个字符")
private String reviewerName;
/**
* 审核结果:PENDING-待审核,APPROVED-通过,REJECTED-拒绝,RETURNED-退回
*/
@NotBlank(message = "审核结果不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 20, message = "审核结果长度不能超过20个字符")
private String reviewResult;
/**
* 审核评分
*/
@DecimalMin(value = "0.00", message = "审核评分不能小于0")
@DecimalMax(value = "999999.99", message = "审核评分不能大于999999.99")
private BigDecimal reviewScore;
/**
* 审核意见
*/
@Size(max = 1000, message = "审核意见长度不能超过1000个字符")
private String reviewOpinion;
/**
* 审核时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@NotNull(message = "审核时间不能为空", groups = { AddGroup.class, EditGroup.class })
private Date reviewTime;
/**
* 下一审核人ID
*/
private Long nextReviewerId;
/**
* 是否最终审核:0-否,1-是
*/
private Integer isFinalReview;
/**
* 租户ID
*/
private String tenantId;
}
@@ -0,0 +1,113 @@
package org.dromara.jcbt.domain.bo;
import org.dromara.jcbt.domain.JcbtScholarshipType;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
/**
* 奖学金类型业务对象 jcbt_scholarship_type
*
* @author ruoyi
* @date 2025-01-27
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = JcbtScholarshipType.class, reverseConvertGenerate = false)
public class JcbtScholarshipTypeBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long id;
/**
* 奖学金类型编码
*/
@NotBlank(message = "奖学金类型编码不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 50, message = "奖学金类型编码不能超过50个字符")
private String typeCode;
/**
* 奖学金名称
*/
@NotBlank(message = "奖学金名称不能为空", groups = { AddGroup.class, EditGroup.class })
@Size(max = 100, message = "奖学金名称不能超过100个字符")
private String typeName;
/**
* 奖学金类别
*/
@NotBlank(message = "奖学金类别不能为空", groups = { AddGroup.class, EditGroup.class })
private String typeCategory;
/**
* 奖学金等级
*/
private String levelType;
/**
* 奖金金额
*/
@DecimalMin(value = "0", message = "奖金金额不能为负数")
@Digits(integer = 8, fraction = 2, message = "奖金金额格式不正确")
private BigDecimal awardAmount;
/**
* 奖学金描述
*/
private String description;
/**
* 申请指南
*/
private String applicationGuide;
/**
* 申请条件
*/
@Size(max = 2000, message = "申请条件不能超过2000个字符")
private String applicationConditions;
/**
* 评定标准
*/
@Size(max = 2000, message = "评定标准不能超过2000个字符")
private String evaluationCriteria;
/**
* 备注
*/
@Size(max = 500, message = "备注不能超过500个字符")
private String remark;
/**
* 排序号
*/
@Min(value = 0, message = "排序号不能为负数")
private Integer sortOrder;
/**
* 状态:0-停用 1-启用
*/
@NotNull(message = "状态不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer status;
/**
* 是否系统内置:0-否,1-是
*/
private Integer isSystem;
/**
* 兼得类型:EXCLUSIVE-完全互斥,COMPATIBLE-完全兼容,CUSTOM-自定义配置
*/
private String compatibilityType;
}
@@ -0,0 +1,245 @@
package org.dromara.jcbt.domain.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.jcbt.domain.JcbtPovertyApplication;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 贫困生认定申请视图对象 jcbt_poverty_application
*
* @author ruoyi
* @date 2025-08-09
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = JcbtPovertyApplication.class)
public class JcbtPovertyApplicationVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long id;
/**
* 申请编号
*/
@ExcelProperty(value = "申请编号")
private String applicationNo;
/**
* 学年
*/
@ExcelProperty(value = "学年")
private String academicYear;
/**
* 学期
*/
@ExcelProperty(value = "学期")
private Integer term;
/**
* 学生ID
*/
private Long studentId;
/**
* 学号
*/
@ExcelProperty(value = "学号")
private String studentNo;
/**
* 学生姓名
*/
@ExcelProperty(value = "学生姓名")
private String studentName;
/**
* 性别
*/
@ExcelProperty(value = "性别")
private String gender;
/**
* 学院ID
*/
private Long collegeId;
/**
* 学院名称
*/
@ExcelProperty(value = "学院名称")
private String collegeName;
/**
* 专业ID
*/
private Long majorId;
/**
* 专业名称
*/
@ExcelProperty(value = "专业名称")
private String majorName;
/**
* 班级ID
*/
private Long classId;
/**
* 班级名称
*/
@ExcelProperty(value = "班级名称")
private String className;
/**
* 认定群体(特殊群体/其他群体)
*/
@ExcelProperty(value = "认定群体")
private String recognitionGroup;
/**
* 认定类型ID
*/
private Long recognitionTypeId;
/**
* 认定类型编码
*/
private String recognitionTypeCode;
/**
* 认定类型名称
*/
@ExcelProperty(value = "认定类型")
private String recognitionTypeName;
/**
* 申请自助类型ID数组(多选)
*/
private String assistanceTypeIds;
/**
* 申请自助类型名称(多个用逗号分隔)
*/
@ExcelProperty(value = "申请自助类型")
private String assistanceTypeNames;
/**
* 家庭经济情况摘要
*/
@ExcelProperty(value = "家庭经济情况")
private String familyEconomySummary;
/**
* 申请表附件URL
*/
private String attachApplicationFormUrl;
/**
* 申请表附件ID
*/
private Long attachApplicationFormId;
/**
* 调查表附件URL
*/
private String attachSurveyFormUrl;
/**
* 调查表附件ID
*/
private Long attachSurveyFormId;
/**
* 申请状态
*/
@ExcelProperty(value = "申请状态")
private String status;
/**
* 提交人ID
*/
private Long submitterId;
/**
* 提交人姓名
*/
@ExcelProperty(value = "提交人")
private String submitterName;
/**
* 提交时间
*/
@ExcelProperty(value = "提交时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date submitTime;
/**
* 审核人ID
*/
private Long auditorId;
/**
* 审核人姓名
*/
@ExcelProperty(value = "审核人")
private String auditorName;
/**
* 审核时间
*/
@ExcelProperty(value = "审核时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date auditTime;
/**
* 审核意见
*/
@ExcelProperty(value = "审核意见")
private String auditOpinion;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 创建者
*/
private Long createBy;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 更新者
*/
private Long updateBy;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}
@@ -0,0 +1,192 @@
package org.dromara.jcbt.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.dromara.jcbt.domain.JcbtScholarshipApplication;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 奖学金申请记录视图对象 jcbt_scholarship_application
*
* @author ruoyi
* @date 2025-01-01
*/
@Data
@AutoMapper(target = JcbtScholarshipApplication.class)
public class JcbtScholarshipApplicationVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
private Long id;
/**
* 批次ID
*/
private Long batchId;
/**
* 批次名称
*/
private String batchName;
/**
* 奖学金类型ID
*/
private Long scholarshipTypeId;
/**
* 奖学金名称
*/
private String scholarshipTypeName;
/**
* 申请编号
*/
private String applicationNo;
/**
* 学生学号
*/
private String studentNo;
/**
* 学生姓名
*/
private String studentName;
/**
* 学生ID
*/
private Long studentId;
/**
* 学院ID
*/
private Long deptId;
/**
* 学院名称
*/
private String deptName;
/**
* 专业ID
*/
private Long majorId;
/**
* 班级ID
*/
private Long classId;
/**
* 班级名称
*/
private String className;
// 已删除 applicantType 和 applicantId 字段
/**
* 申请人姓名
*/
private String applicantName;
/**
* 申请类型
*/
private String applicationType;
/**
* 当前状态
*/
private String currentStatus;
/**
* 状态(前端兼容字段,与currentStatus保持一致)
*/
public String getStatus() {
return currentStatus;
}
public void setStatus(String status) {
this.currentStatus = status;
}
/**
* 申请原因
*/
private String applyReason;
/**
* 自我评价
*/
private String selfEvaluation;
/**
* 系统计算分数
*/
private Double calculatedScore;
/**
* 最终评定分数
*/
private Double finalScore;
/**
* 在院系的排名
*/
private Integer rankingInDept;
/**
* 在专业的排名
*/
private Integer rankingInMajor;
/**
* 提交时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date submitTime;
/**
* 租户编号
*/
private String tenantId;
/**
* 备注
*/
private String remark;
/**
* 创建者
*/
private Long createBy;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 更新者
*/
private Long updateBy;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}
@@ -0,0 +1,123 @@
package org.dromara.jcbt.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.dromara.jcbt.domain.JcbtScholarshipAttachment;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 奖学金申请材料视图对象 jcbt_scholarship_attachment
*
* @author ruoyi
* @date 2025-01-01
*/
@Data
@AutoMapper(target = JcbtScholarshipAttachment.class)
public class JcbtScholarshipAttachmentVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
private Long id;
/**
* 申请记录ID
*/
private Long applicationId;
/**
* 材料类型
*/
private String materialType;
/**
* 材料名称
*/
private String materialName;
/**
* 文件名称
*/
private String fileName;
/**
* 文件路径
*/
private String filePath;
/**
* 文件大小
*/
private Long fileSize;
/**
* 上传者类型
*/
private String uploaderType;
/**
* 上传者ID
*/
private Long uploaderId;
/**
* 上传者姓名
*/
private String uploaderName;
/**
* 上传时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date uploadTime;
/**
* 审核状态
*/
private String auditStatus;
/**
* 审核意见
*/
private String auditComment;
/**
* 是否必需
*/
private Integer isRequired;
/**
* 备注
*/
private String remark;
/**
* 创建者
*/
private Long createBy;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 更新者
*/
private Long updateBy;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}
@@ -0,0 +1,162 @@
package org.dromara.jcbt.domain.vo;
import org.dromara.jcbt.domain.JcbtScholarshipBatch;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* 奖学金评定批次视图对象 jcbt_scholarship_batch
*
* @author ruoyi
* @date 2025-01-27
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = JcbtScholarshipBatch.class)
public class JcbtScholarshipBatchVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long id;
/**
* 批次编码
*/
@ExcelProperty(value = "批次编码")
private String batchCode;
/**
* 批次名称
*/
@ExcelProperty(value = "批次名称")
private String batchName;
/**
* 学年
*/
@ExcelProperty(value = "学年")
private String academicYear;
/**
* 学期:1-第一学期,2-第二学期,3-全年
*/
@ExcelProperty(value = "学期", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "jcbt_semester_type")
private Integer semester;
/**
* 批次类型:REGULAR-常规批次,SPECIAL-专项批次,SUPPLEMENTARY-补充批次
*/
@ExcelProperty(value = "批次类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "jcbt_batch_type")
private String batchType;
/**
* 开始时间
*/
@ExcelProperty(value = "开始时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
/**
* 结束时间
*/
@ExcelProperty(value = "结束时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
/**
* 申请开始时间
*/
@ExcelProperty(value = "申请开始时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date applyStartTime;
/**
* 申请结束时间
*/
@ExcelProperty(value = "申请结束时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date applyEndTime;
/**
* 审核开始时间
*/
@ExcelProperty(value = "审核开始时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date reviewStartTime;
/**
* 审核结束时间
*/
@ExcelProperty(value = "审核结束时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date reviewEndTime;
/**
* 状态:DRAFT-草稿,ACTIVE-进行中,COMPLETED-已完成,CANCELLED-已取消
*/
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "jcbt_batch_status")
private String status;
/**
* 批次描述
*/
@ExcelProperty(value = "批次描述")
private String description;
/**
* 通知内容
*/
@ExcelProperty(value = "通知内容")
private String noticeContent;
/**
* 创建者
*/
private Long createBy;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 更新者
*/
private Long updateBy;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
/**
* 关联的奖学金类型ID列表
*/
private List<Long> scholarshipTypeIds;
/**
* 租户ID
*/
private Long tenantId;
}
@@ -0,0 +1,117 @@
package org.dromara.jcbt.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.dromara.jcbt.domain.JcbtScholarshipClassQuota;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 班级奖学金名额分配视图对象 jcbt_scholarship_class_quota
*
* @author ruoyi
* @date 2025-01-01
*/
@Data
@AutoMapper(target = JcbtScholarshipClassQuota.class)
public class JcbtScholarshipClassQuotaVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
private Long id;
/**
* 批次ID
*/
private Long batchId;
/**
* 批次名称
*/
private String batchName;
/**
* 奖学金类型ID
*/
private Long scholarshipTypeId;
/**
* 奖学金类型名称
*/
private String scholarshipTypeName;
/**
* 班级ID
*/
private Long classId;
/**
* 班级名称
*/
private String className;
/**
* 总名额
*/
private Integer totalQuota;
/**
* 已使用名额
*/
private Integer usedQuota;
/**
* 可用名额
*/
private Integer availableQuota;
/**
* 分配方式
*/
private String allocationMethod;
/**
* 分配级别
*/
private String allocationLevel;
/**
* 名额状态
*/
private String status;
/**
* 备注
*/
private String remark;
/**
* 创建者
*/
private Long createBy;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 更新者
*/
private Long updateBy;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}
@@ -0,0 +1,99 @@
package org.dromara.jcbt.domain.vo;
import org.dromara.jcbt.domain.JcbtScholarshipCompatibility;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.TableField;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 奖学金兼得关系视图对象 jcbt_scholarship_compatibility
*
* @author ruoyi
* @date 2025-01-27
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = JcbtScholarshipCompatibility.class)
public class JcbtScholarshipCompatibilityVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long id;
/**
* 奖学金类型1
*/
@ExcelProperty(value = "奖学金类型1")
@TableField("type_id_1")
private Long typeId1;
/**
* 奖学金类型2
*/
@ExcelProperty(value = "奖学金类型2")
@TableField("type_id_2")
private Long typeId2;
/**
* 关系类型:COMPATIBLE-兼容,EXCLUSIVE-互斥,PRIORITY-优先级关系
*/
@ExcelProperty(value = "关系类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "jcbt_relation_type")
@TableField("relation_type")
private String relationType;
/**
* 优先级(relation_type为PRIORITY时有效)
*/
@ExcelProperty(value = "优先级")
@TableField("priority_level")
private Integer priorityLevel;
/**
* 关系描述
*/
@ExcelProperty(value = "关系描述")
private String description;
/**
* 创建者
*/
private Long createBy;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 更新者
*/
private Long updateBy;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
/**
* 租户ID
*/
private Long tenantId;
}
@@ -0,0 +1,224 @@
package org.dromara.jcbt.domain.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.jcbt.domain.JcbtScholarshipQuota;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 奖学金名额分配视图对象 JcbtScholarshipQuotaVo
*
* @author ruoyi
* @date 2025-01-27
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = JcbtScholarshipQuota.class)
public class JcbtScholarshipQuotaVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long id;
/**
* 批次ID
*/
@ExcelProperty(value = "批次ID")
private Long batchId;
/**
* 批次名称
*/
@ExcelProperty(value = "批次名称")
private String batchName;
/**
* 批次编码
*/
@ExcelProperty(value = "批次编码")
private String batchCode;
/**
* 学年
*/
@ExcelProperty(value = "学年")
private String academicYear;
/**
* 学期
*/
@ExcelProperty(value = "学期")
private Integer semester;
/**
* 奖学金类型ID
*/
@ExcelProperty(value = "奖学金类型ID")
private Long scholarshipTypeId;
/**
* 奖学金类型名称
*/
@ExcelProperty(value = "奖学金类型名称")
private String scholarshipTypeName;
/**
* 奖学金等级
*/
@ExcelProperty(value = "奖学金等级")
private String scholarshipLevel;
/**
* 分配级别:UNIVERSITY-全校,COLLEGE-学院,MAJOR-专业,CLASS-班级
*/
@ExcelProperty(value = "分配级别")
private String allocationLevel;
/**
* 分配级别名称
*/
@ExcelProperty(value = "分配级别名称")
private String allocationLevelName;
/**
* 目标部门ID(学院/专业/班级)
*/
@ExcelProperty(value = "目标部门ID")
private Long targetDeptId;
/**
* 目标部门名称
*/
@ExcelProperty(value = "目标部门名称")
private String targetDeptName;
/**
* 上级名额ID(层级分配)
*/
@ExcelProperty(value = "上级名额ID")
private Long parentQuotaId;
/**
* 上级部门名称
*/
@ExcelProperty(value = "上级部门名称")
private String parentDeptName;
/**
* 总名额
*/
@ExcelProperty(value = "总名额")
private Integer totalQuota;
/**
* 已使用名额
*/
@ExcelProperty(value = "已使用名额")
private Integer usedQuota;
/**
* 预留名额
*/
@ExcelProperty(value = "预留名额")
private Integer reservedQuota;
/**
* 可用名额
*/
@ExcelProperty(value = "可用名额")
private Integer availableQuota;
/**
* 分配规则(JSON格式)
*/
@ExcelProperty(value = "分配规则")
private String allocationRule;
/**
* 分配依据说明
*/
@ExcelProperty(value = "分配依据说明")
private String allocationBasis;
/**
* 分配方式:MANUAL-手动分配,AUTO-自动分配,PROPORTIONAL-按比例分配
*/
@ExcelProperty(value = "分配方式")
private String allocationMethod;
/**
* 分配方式名称
*/
@ExcelProperty(value = "分配方式名称")
private String allocationMethodName;
/**
* 是否可调整:0-否,1-是
*/
@ExcelProperty(value = "是否可调整")
private Integer isAdjustable;
/**
* 是否锁定:0-否,1-是
*/
@ExcelProperty(value = "是否锁定")
private Integer isLocked;
/**
* 状态:ACTIVE-生效,INACTIVE-失效,PENDING-待审核
*/
@ExcelProperty(value = "状态")
private String status;
/**
* 状态名称
*/
@ExcelProperty(value = "状态名称")
private String statusName;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 租户ID
*/
private Long tenantId;
/**
* 创建者
*/
private Long createBy;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ExcelProperty(value = "创建时间")
private Date createTime;
/**
* 更新者
*/
private Long updateBy;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}
@@ -0,0 +1,162 @@
package org.dromara.jcbt.domain.vo;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.jcbt.domain.JcbtScholarshipReview;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 奖学金审核记录视图对象 jcbt_scholarship_review
*
* @author ruoyi
* @date 2025-08-05
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = JcbtScholarshipReview.class)
public class JcbtScholarshipReviewVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long id;
/**
* 申请记录ID
*/
@ExcelProperty(value = "申请记录ID")
private Long applicationId;
/**
* 审核级别:DEPARTMENT-院系审核,SCHOOL-学校审核,FINANCE-财务审核,FINAL-终审
*/
@ExcelProperty(value = "审核级别")
private String reviewLevel;
/**
* 审核人ID
*/
@ExcelProperty(value = "审核人ID")
private Long reviewerId;
/**
* 审核人姓名
*/
@ExcelProperty(value = "审核人姓名")
private String reviewerName;
/**
* 审核结果:PENDING-待审核,APPROVED-通过,REJECTED-拒绝,RETURNED-退回
*/
@ExcelProperty(value = "审核结果")
private String reviewResult;
/**
* 审核评分
*/
@ExcelProperty(value = "审核评分")
private BigDecimal reviewScore;
/**
* 审核意见
*/
@ExcelProperty(value = "审核意见")
private String reviewOpinion;
/**
* 审核时间
*/
@ExcelProperty(value = "审核时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date reviewTime;
/**
* 下一审核人ID
*/
@ExcelProperty(value = "下一审核人ID")
private Long nextReviewerId;
/**
* 是否最终审核:0-否,1-是
*/
@ExcelProperty(value = "是否最终审核")
private Integer isFinalReview;
/**
* 租户ID
*/
@ExcelProperty(value = "租户ID")
private String tenantId;
/**
* 创建者(基础字段)
*/
private Long createBy;
/**
* 创建时间(基础字段)
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 更新者(基础字段)
*/
private Long updateBy;
/**
* 更新时间(基础字段)
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
// 扩展字段:申请信息
/**
* 申请编号
*/
@ExcelProperty(value = "申请编号")
private String applicationNo;
/**
* 学生学号
*/
@ExcelProperty(value = "学生学号")
private String studentNo;
/**
* 学生姓名
*/
@ExcelProperty(value = "学生姓名")
private String studentName;
/**
* 奖学金类型名称
*/
@ExcelProperty(value = "奖学金类型")
private String scholarshipTypeName;
/**
* 批次名称
*/
@ExcelProperty(value = "批次名称")
private String batchName;
/**
* 申请状态
*/
@ExcelProperty(value = "申请状态")
private String applicationStatus;
}
@@ -0,0 +1,147 @@
package org.dromara.jcbt.domain.vo;
import org.dromara.jcbt.domain.JcbtScholarshipType;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 奖学金类型视图对象 jcbt_scholarship_type
*
* @author ruoyi
* @date 2025-01-27
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = JcbtScholarshipType.class)
public class JcbtScholarshipTypeVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long id;
/**
* 奖学金类型编码
*/
@ExcelProperty(value = "奖学金类型编码")
private String typeCode;
/**
* 奖学金名称
*/
@ExcelProperty(value = "奖学金名称")
private String typeName;
/**
* 奖学金类别
*/
@ExcelProperty(value = "奖学金类别", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "jcbt_scholarship_category")
private String typeCategory;
/**
* 奖学金等级
*/
@ExcelProperty(value = "奖学金等级", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "jcbt_scholarship_level")
private String levelType;
/**
* 奖金金额
*/
@ExcelProperty(value = "奖金金额")
private BigDecimal awardAmount;
/**
* 奖学金描述
*/
@ExcelProperty(value = "奖学金描述")
private String description;
/**
* 申请指南
*/
@ExcelProperty(value = "申请指南")
private String applicationGuide;
/**
* 申请条件
*/
@ExcelProperty(value = "申请条件")
private String applicationConditions;
/**
* 评定标准
*/
@ExcelProperty(value = "评定标准")
private String evaluationCriteria;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 排序号
*/
@ExcelProperty(value = "排序号")
private Integer sortOrder;
/**
* 状态:0-停用 1-启用
*/
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "sys_normal_disable")
private Integer status;
/**
* 是否系统内置:0-否,1-是
*/
@ExcelProperty(value = "是否系统内置", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "sys_yes_no")
private Integer isSystem;
/**
* 兼得类型:EXCLUSIVE-完全互斥,COMPATIBLE-完全兼容,CUSTOM-自定义配置
*/
@ExcelProperty(value = "兼得类型")
private String compatibilityType;
/**
* 创建者
*/
private Long createBy;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 更新者
*/
private Long updateBy;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}
@@ -0,0 +1,111 @@
package org.dromara.jcbt.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 申请状态枚举
*
* @author ruoyi
* @date 2025-08-09
*/
@Getter
@AllArgsConstructor
public enum ApplicationStatusEnum {
/**
* 草稿
*/
DRAFT("draft", "草稿"),
/**
* 已提交
*/
SUBMITTED("submitted", "已提交"),
/**
* 待审核
*/
WAITING("waiting", "待审核"),
/**
* 已驳回
*/
REJECTED("rejected", "已驳回"),
/**
* 已通过
*/
COMPLETE("complete", "已通过"),
/**
* 已撤销
*/
CANCELED("canceled", "已撤销");
/**
* 状态编码
*/
private final String code;
/**
* 状态名称
*/
private final String name;
/**
* 根据编码获取枚举
*
* @param code 状态编码
* @return 枚举对象
*/
public static ApplicationStatusEnum getByCode(String code) {
for (ApplicationStatusEnum status : values()) {
if (status.getCode().equals(code)) {
return status;
}
}
return null;
}
/**
* 判断是否为有效状态
*
* @param code 状态编码
* @return 是否有效
*/
public static boolean isValidStatus(String code) {
return getByCode(code) != null;
}
/**
* 判断是否可以编辑
*
* @param code 状态编码
* @return 是否可以编辑
*/
public static boolean canEdit(String code) {
return DRAFT.getCode().equals(code) || REJECTED.getCode().equals(code);
}
/**
* 判断是否可以撤销
*
* @param code 状态编码
* @return 是否可以撤销
*/
public static boolean canCancel(String code) {
return WAITING.getCode().equals(code);
}
/**
* 判断是否可以审核
*
* @param code 状态编码
* @return 是否可以审核
*/
public static boolean canAudit(String code) {
return WAITING.getCode().equals(code);
}
}
@@ -0,0 +1,91 @@
package org.dromara.jcbt.mapper;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.jcbt.domain.JcbtPovertyApplication;
import org.dromara.jcbt.domain.vo.JcbtPovertyApplicationVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* 贫困生认定申请Mapper接口
*
* @author ruoyi
* @date 2025-08-09
*/
public interface JcbtPovertyApplicationMapper extends BaseMapperPlus<JcbtPovertyApplication, JcbtPovertyApplicationVo> {
/**
* 查询贫困生认定申请列表
*
* @param application 贫困生认定申请
* @return 贫困生认定申请集合
*/
List<JcbtPovertyApplicationVo> selectApplicationList(JcbtPovertyApplication application);
/**
* 根据申请编号查询申请信息
*
* @param applicationNo 申请编号
* @return 申请信息
*/
JcbtPovertyApplicationVo selectByApplicationNo(@Param("applicationNo") String applicationNo);
/**
* 检查学生在指定学年是否已有认定申请
*
* @param studentId 学生ID
* @param academicYear 学年
* @param recognitionTypeId 认定类型ID
* @param excludeId 排除的申请ID(用于修改时排除自己)
* @return 申请数量
*/
int checkStudentApplicationExists(@Param("studentId") Long studentId,
@Param("academicYear") String academicYear,
@Param("recognitionTypeId") Long recognitionTypeId,
@Param("excludeId") Long excludeId);
/**
* 根据班主任ID查询其负责班级的申请列表
*
* @param teacherId 班主任ID
* @param application 查询条件
* @return 申请列表
*/
List<JcbtPovertyApplicationVo> selectApplicationListByTeacher(@Param("teacherId") Long teacherId,
@Param("application") JcbtPovertyApplication application);
/**
* 查询待审核的申请列表
*
* @param application 查询条件
* @return 申请列表
*/
List<JcbtPovertyApplicationVo> selectPendingApplicationList(JcbtPovertyApplication application);
/**
* 统计各种状态的申请数量
*
* @param teacherId 班主任ID(可选,为空则统计全部)
* @return 统计结果
*/
List<JcbtPovertyApplicationVo> selectApplicationStatistics(@Param("teacherId") Long teacherId);
/**
* 获取当前用户班级信息
*
* @param userId 用户ID
* @return 班级信息列表
*/
List<Map<String, Object>> selectCurrentUserClasses(@Param("userId") Long userId);
/**
* 获取班级学生列表
*
* @param classId 班级ID
* @return 学生信息列表
*/
List<Map<String, Object>> selectClassStudents(@Param("classId") Long classId);
}
@@ -0,0 +1,99 @@
package org.dromara.jcbt.mapper;
import org.dromara.jcbt.domain.JcbtScholarshipApplication;
import org.dromara.jcbt.domain.vo.JcbtScholarshipApplicationVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import java.util.List;
/**
* 奖学金申请记录Mapper接口
*
* @author ruoyi
* @date 2025-01-01
*/
public interface JcbtScholarshipApplicationMapper extends BaseMapperPlus<JcbtScholarshipApplication, JcbtScholarshipApplicationVo> {
/**
* 自定义分页查询(包含关联表信息)
*
* @param page 分页对象
* @param ew 查询条件包装器
* @return 分页结果
*/
Page<JcbtScholarshipApplicationVo> selectJcbtScholarshipApplicationPage(@Param("page") Page<JcbtScholarshipApplicationVo> page, @Param("ew") Wrapper<JcbtScholarshipApplication> ew);
/**
* 查询班主任负责班级的申请记录列表(已删除applicantId字段,需重新设计)
*
* @param applicantId 申请人ID(班主任ID)
* @param batchId 批次ID
* @return 申请记录列表
*/
// List<JcbtScholarshipApplicationVo> selectApplicationsByApplicant(@Param("applicantId") Long applicantId, @Param("batchId") Long batchId);
/**
* 查询班级的申请记录列表
*
* @param classId 班级ID
* @param batchId 批次ID
* @return 申请记录列表
*/
List<JcbtScholarshipApplicationVo> selectApplicationsByClass(@Param("classId") Long classId, @Param("batchId") Long batchId);
/**
* 查询待审核的申请记录列表
*
* @param reviewerId 审核人ID
* @param status 申请状态
* @return 申请记录列表
*/
List<JcbtScholarshipApplicationVo> selectPendingApplications(@Param("reviewerId") Long reviewerId, @Param("status") String status);
/**
* 根据ID查询申请记录详情(包含关联信息)
*
* @param id 主键ID
* @return 申请记录详情
*/
JcbtScholarshipApplicationVo selectByIdWithRelations(@Param("id") Long id);
/**
* 检查学生在指定批次中是否已有申请记录
*
* @param studentId 学生ID
* @param batchId 批次ID
* @param scholarshipTypeId 奖学金类型ID
* @return 申请记录数量
*/
int checkStudentApplication(@Param("studentId") Long studentId, @Param("batchId") Long batchId, @Param("scholarshipTypeId") Long scholarshipTypeId);
/**
* 获取申请统计数据
*
* @param batchId 批次ID
* @param deptId 学院ID
* @return 统计数据
*/
List<JcbtScholarshipApplicationVo> selectApplicationStatistics(@Param("batchId") Long batchId, @Param("deptId") Long deptId);
/**
* 批量更新申请状态
*
* @param applicationIds 申请记录ID列表
* @param status 新状态
* @param reviewerId 审核人ID
* @param reviewerName 审核人姓名
* @param reviewComment 审核意见
* @return 更新记录数
*/
int batchUpdateStatus(@Param("applicationIds") List<Long> applicationIds,
@Param("status") String status,
@Param("reviewerId") Long reviewerId,
@Param("reviewerName") String reviewerName,
@Param("reviewComment") String reviewComment);
}
@@ -0,0 +1,15 @@
package org.dromara.jcbt.mapper;
import org.dromara.jcbt.domain.JcbtScholarshipBatch;
import org.dromara.jcbt.domain.vo.JcbtScholarshipBatchVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 奖学金评定批次Mapper接口
*
* @author ruoyi
* @date 2025-01-27
*/
public interface JcbtScholarshipBatchMapper extends BaseMapperPlus<JcbtScholarshipBatch, JcbtScholarshipBatchVo> {
}
@@ -0,0 +1,14 @@
package org.dromara.jcbt.mapper;
import org.dromara.jcbt.domain.JcbtScholarshipBatchType;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 奖学金批次类型关联Mapper接口
*
* @author ruoyi
* @date 2025-01-27
*/
public interface JcbtScholarshipBatchTypeMapper extends BaseMapperPlus<JcbtScholarshipBatchType, JcbtScholarshipBatchType> {
}
@@ -0,0 +1,66 @@
package org.dromara.jcbt.mapper;
import org.dromara.jcbt.domain.JcbtScholarshipClassQuota;
import org.dromara.jcbt.domain.vo.JcbtScholarshipClassQuotaVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 奖学金班级名额分配Mapper接口
*
* @author ruoyi
* @date 2025-01-01
*/
public interface JcbtScholarshipClassQuotaMapper extends BaseMapperPlus<JcbtScholarshipClassQuota, JcbtScholarshipClassQuotaVo> {
/**
* 查询班级可用名额
*
* @param classId 班级ID
* @param scholarshipTypeId 奖学金类型ID
* @param batchId 批次ID
* @return 名额分配信息
*/
JcbtScholarshipClassQuotaVo selectAvailableQuota(@Param("classId") Long classId,
@Param("scholarshipTypeId") Long scholarshipTypeId,
@Param("batchId") Long batchId);
/**
* 查询学院下所有班级的名额分配
*
* @param deptId 学院ID
* @param batchId 批次ID
* @return 名额分配列表
*/
List<JcbtScholarshipClassQuotaVo> selectQuotasByDept(@Param("deptId") Long deptId, @Param("batchId") Long batchId);
/**
* 更新名额使用情况
*
* @param id 名额分配ID
* @param usedQuota 已使用名额
* @param availableQuota 可用名额
* @return 更新记录数
*/
int updateQuotaUsage(@Param("id") Long id, @Param("usedQuota") Integer usedQuota, @Param("availableQuota") Integer availableQuota);
/**
* 批量更新名额分配
*
* @param quotaList 名额分配列表
* @return 更新记录数
*/
int batchUpdateQuota(@Param("quotaList") List<JcbtScholarshipClassQuota> quotaList);
/**
* 查询名额统计信息
*
* @param batchId 批次ID
* @param scholarshipTypeId 奖学金类型ID
* @return 统计信息
*/
List<JcbtScholarshipClassQuotaVo> selectQuotaStatistics(@Param("batchId") Long batchId, @Param("scholarshipTypeId") Long scholarshipTypeId);
}
@@ -0,0 +1,42 @@
package org.dromara.jcbt.mapper;
import org.dromara.jcbt.domain.JcbtScholarshipCompatibility;
import org.dromara.jcbt.domain.vo.JcbtScholarshipCompatibilityVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import java.util.List;
/**
* 奖学金兼得关系Mapper接口
*
* @author ruoyi
* @date 2025-01-27
*/
public interface JcbtScholarshipCompatibilityMapper extends BaseMapperPlus<JcbtScholarshipCompatibility, JcbtScholarshipCompatibilityVo> {
/**
* 查询与指定奖学金类型的兼得关系
*
* @param scholarshipTypeId 奖学金类型ID
* @return 兼得关系列表
*/
List<JcbtScholarshipCompatibilityVo> selectCompatibilityByTypeId(Long scholarshipTypeId);
/**
* 检查两个奖学金类型的兼得关系
*
* @param typeId1 奖学金类型1
* @param typeId2 奖学金类型2
* @return 兼得关系记录
*/
JcbtScholarshipCompatibilityVo selectCompatibilityByTwoTypes(Long typeId1, Long typeId2);
/**
* 批量删除指定奖学金类型的兼得关系
*
* @param scholarshipTypeId 奖学金类型ID
* @return 删除记录数
*/
int deleteByScholarshipTypeId(Long scholarshipTypeId);
}
@@ -0,0 +1,118 @@
package org.dromara.jcbt.mapper;
import org.dromara.jcbt.domain.JcbtScholarshipQuota;
import org.dromara.jcbt.domain.vo.JcbtScholarshipQuotaVo;
import org.dromara.jcbt.domain.bo.JcbtScholarshipQuotaBo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import java.util.List;
/**
* 奖学金名额分配Mapper接口
*
* @author ruoyi
* @date 2025-01-27
*/
public interface JcbtScholarshipQuotaMapper extends BaseMapperPlus<JcbtScholarshipQuota, JcbtScholarshipQuotaVo> {
/**
* 分页查询奖学金名额分配列表(带关联查询)
*
* @param page 分页参数
* @param bo 查询条件
* @return 分页结果
*/
IPage<JcbtScholarshipQuotaVo> selectQuotaPageList(IPage<JcbtScholarshipQuotaVo> page, @Param("bo") JcbtScholarshipQuotaBo bo);
/**
* 查询奖学金名额分配列表(带关联查询)
*
* @param bo 查询条件
* @return 名额分配列表
*/
List<JcbtScholarshipQuotaVo> selectQuotaList(@Param("bo") JcbtScholarshipQuotaBo bo);
/**
* 查询指定批次的名额分配列表
*
* @param batchId 批次ID
* @return 名额分配列表
*/
List<JcbtScholarshipQuotaVo> selectQuotaListByBatchId(@Param("batchId") Long batchId);
/**
* 查询指定批次和奖学金类型的名额分配
*
* @param batchId 批次ID
* @param scholarshipTypeId 奖学金类型ID
* @return 名额分配列表
*/
List<JcbtScholarshipQuotaVo> selectQuotaListByBatchAndType(@Param("batchId") Long batchId,
@Param("scholarshipTypeId") Long scholarshipTypeId);
/**
* 查询指定部门的名额分配统计
*
* @param targetDeptId 目标部门ID
* @param batchId 批次ID
* @return 名额统计信息
*/
JcbtScholarshipQuotaVo selectQuotaSummaryByDept(@Param("targetDeptId") Long targetDeptId,
@Param("batchId") Long batchId);
/**
* 查询子级名额分配列表
*
* @param parentQuotaId 父级名额ID
* @return 子级名额分配列表
*/
List<JcbtScholarshipQuotaVo> selectQuotaListByParentId(@Param("parentQuotaId") Long parentQuotaId);
/**
* 批量更新名额使用情况
*
* @param quotaList 名额分配列表
* @return 更新数量
*/
int batchUpdateQuotaUsage(@Param("quotaList") List<JcbtScholarshipQuota> quotaList);
/**
* 检查名额分配是否存在冲突
*
* @param batchId 批次ID
* @param scholarshipTypeId 奖学金类型ID
* @param targetDeptId 目标部门ID
* @param excludeId 排除的ID(修改时使用)
* @return 冲突记录数
*/
int checkQuotaConflict(@Param("batchId") Long batchId,
@Param("scholarshipTypeId") Long scholarshipTypeId,
@Param("targetDeptId") Long targetDeptId,
@Param("excludeId") Long excludeId);
/**
* 查询名额分配树形结构
*
* @param batchId 批次ID
* @param scholarshipTypeId 奖学金类型ID
* @return 树形结构数据
*/
List<JcbtScholarshipQuotaVo> selectQuotaTreeByBatchAndType(@Param("batchId") Long batchId,
@Param("scholarshipTypeId") Long scholarshipTypeId);
/**
* 查询班级级别的名额分配
*
* @param classId 班级ID
* @param scholarshipTypeId 奖学金类型ID
* @param batchId 批次ID
* @return 班级名额分配信息
*/
JcbtScholarshipQuotaVo selectClassQuota(@Param("classId") Long classId,
@Param("scholarshipTypeId") Long scholarshipTypeId,
@Param("batchId") Long batchId);
}
@@ -0,0 +1,85 @@
package org.dromara.jcbt.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.jcbt.domain.JcbtScholarshipReview;
import org.dromara.jcbt.domain.vo.JcbtScholarshipReviewVo;
import java.util.List;
/**
* 奖学金审核记录Mapper接口
*
* @author ruoyi
* @date 2025-08-05
*/
public interface JcbtScholarshipReviewMapper extends BaseMapperPlus<JcbtScholarshipReview, JcbtScholarshipReviewVo> {
/**
* 查询奖学金审核记录列表
*/
List<JcbtScholarshipReviewVo> selectVoList(@Param(Constants.WRAPPER) Wrapper<JcbtScholarshipReview> queryWrapper);
/**
* 根据申请ID查询审核记录
*/
List<JcbtScholarshipReviewVo> selectReviewsByApplicationId(@Param("applicationId") Long applicationId);
/**
* 查询当前用户待审核的记录
*/
Page<JcbtScholarshipReviewVo> selectPendingReviews(Page<JcbtScholarshipReviewVo> page,
@Param("reviewerId") Long reviewerId,
@Param("reviewLevel") String reviewLevel,
@Param("applicationNo") String applicationNo,
@Param("studentName") String studentName);
/**
* 查询审核历史记录
*/
Page<JcbtScholarshipReviewVo> selectReviewHistory(Page<JcbtScholarshipReviewVo> page,
@Param("reviewerId") Long reviewerId,
@Param("reviewResult") String reviewResult,
@Param("batchId") Long batchId,
@Param("startTime") String startTime,
@Param("endTime") String endTime);
/**
* 查询某个申请的最新审核记录
*/
JcbtScholarshipReviewVo selectLatestReviewByApplicationId(@Param("applicationId") Long applicationId);
/**
* 查询某个申请的指定级别审核记录
*/
JcbtScholarshipReviewVo selectReviewByApplicationAndLevel(@Param("applicationId") Long applicationId,
@Param("reviewLevel") String reviewLevel);
/**
* 批量更新审核结果
*/
int batchUpdateReviewResult(@Param("reviewIds") List<Long> reviewIds,
@Param("reviewResult") String reviewResult,
@Param("reviewOpinion") String reviewOpinion,
@Param("reviewerId") Long reviewerId,
@Param("reviewerName") String reviewerName);
/**
* 统计审核数量
*/
Long countReviewsByCondition(@Param("reviewerId") Long reviewerId,
@Param("reviewLevel") String reviewLevel,
@Param("reviewResult") String reviewResult,
@Param("batchId") Long batchId);
/**
* 查询下一级审核人员
*/
List<Long> selectNextReviewers(@Param("applicationId") Long applicationId,
@Param("currentLevel") String currentLevel);
}
@@ -0,0 +1,73 @@
package org.dromara.jcbt.mapper;
import org.dromara.jcbt.domain.JcbtScholarshipType;
import org.dromara.jcbt.domain.vo.JcbtScholarshipTypeVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 奖学金类型Mapper接口
*
* @author ruoyi
* @date 2025-01-27
*/
public interface JcbtScholarshipTypeMapper extends BaseMapperPlus<JcbtScholarshipType, JcbtScholarshipTypeVo> {
/**
* 查询奖学金类型列表
*
* @param scholarshipType 奖学金类型
* @return 奖学金类型集合
*/
List<JcbtScholarshipTypeVo> selectScholarshipTypeList(JcbtScholarshipType scholarshipType);
/**
* 根据类型名称查询奖学金类型
*
* @param typeName 类型名称
* @return 奖学金类型
*/
JcbtScholarshipTypeVo selectByTypeName(@Param("typeName") String typeName);
/**
* 根据类别查询奖学金类型列表
*
* @param typeCategory 奖学金类别
* @return 奖学金类型集合
*/
List<JcbtScholarshipTypeVo> selectByCategory(@Param("typeCategory") String typeCategory);
/**
* 查询启用状态的奖学金类型列表
*
* @return 奖学金类型集合
*/
List<JcbtScholarshipTypeVo> selectActiveTypes();
/**
* 检查是否存在重复的奖学金名称
*
* @param typeName 奖学金名称
* @param id 排除的ID
* @return 是否存在重复
*/
boolean checkTypeNameExists(@Param("typeName") String typeName, @Param("id") Long id);
/**
* 批量更新排序号
*
* @param scholarshipTypes 奖学金类型列表
*/
void batchUpdateSortOrder(@Param("list") List<JcbtScholarshipType> scholarshipTypes);
/**
* 根据兼得类型查询相关奖学金类型
*
* @param compatibilityType 兼得限制类型
* @return 奖学金类型集合
*/
List<JcbtScholarshipTypeVo> selectByCompatibilityType(@Param("compatibilityType") String compatibilityType);
}
@@ -0,0 +1,181 @@
package org.dromara.jcbt.service;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.jcbt.domain.bo.JcbtPovertyApplicationBo;
import org.dromara.jcbt.domain.vo.JcbtPovertyApplicationVo;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 贫困生认定申请Service接口
*
* @author ruoyi
* @date 2025-08-09
*/
public interface IJcbtPovertyApplicationService {
/**
* 查询贫困生认定申请
*
* @param id 贫困生认定申请主键
* @return 贫困生认定申请
*/
JcbtPovertyApplicationVo queryById(Long id);
/**
* 根据申请编号查询申请信息
*
* @param applicationNo 申请编号
* @return 申请信息
*/
JcbtPovertyApplicationVo queryByApplicationNo(String applicationNo);
/**
* 查询贫困生认定申请列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 贫困生认定申请分页列表
*/
TableDataInfo<JcbtPovertyApplicationVo> queryPageList(JcbtPovertyApplicationBo bo, PageQuery pageQuery);
/**
* 查询贫困生认定申请列表
*
* @param bo 查询条件
* @return 贫困生认定申请列表
*/
List<JcbtPovertyApplicationVo> queryList(JcbtPovertyApplicationBo bo);
/**
* 根据班主任ID查询申请列表(班主任查看自己班级的申请)
*
* @param teacherId 班主任ID
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 申请分页列表
*/
TableDataInfo<JcbtPovertyApplicationVo> queryPageListByTeacher(Long teacherId, JcbtPovertyApplicationBo bo, PageQuery pageQuery);
/**
* 查询待审核的申请列表(审核人员使用)
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 申请分页列表
*/
TableDataInfo<JcbtPovertyApplicationVo> queryPendingPageList(JcbtPovertyApplicationBo bo, PageQuery pageQuery);
/**
* 新增贫困生认定申请
*
* @param bo 贫困生认定申请
* @return 结果
*/
Boolean insertByBo(JcbtPovertyApplicationBo bo);
/**
* 修改贫困生认定申请
*
* @param bo 贫困生认定申请
* @return 结果
*/
Boolean updateByBo(JcbtPovertyApplicationBo bo);
/**
* 保存草稿
*
* @param bo 贫困生认定申请
* @return 结果
*/
Boolean saveDraft(JcbtPovertyApplicationBo bo);
/**
* 提交申请
*
* @param id 申请ID
* @return 结果
*/
Boolean submitApplication(Long id);
/**
* 撤销申请
*
* @param id 申请ID
* @return 结果
*/
Boolean cancelApplication(Long id);
/**
* 审核通过
*
* @param id 申请ID
* @param auditOpinion 审核意见
* @return 结果
*/
Boolean approveApplication(Long id, String auditOpinion);
/**
* 审核驳回
*
* @param id 申请ID
* @param auditOpinion 审核意见
* @return 结果
*/
Boolean rejectApplication(Long id, String auditOpinion);
/**
* 校验删除数据
*
* @param ids 主键集合
* @param isValid 是否校验,true-删除前校验,false-不校验
* @return 结果
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 生成申请编号
*
* @return 申请编号
*/
String generateApplicationNo();
/**
* 检查学生是否已有相同类型的认定申请
*
* @param studentId 学生ID
* @param academicYear 学年
* @param recognitionTypeId 认定类型ID
* @param excludeId 排除的申请ID(修改时使用)
* @return 是否存在
*/
boolean checkStudentApplicationExists(Long studentId, String academicYear, Long recognitionTypeId, Long excludeId);
/**
* 统计申请数据
*
* @param teacherId 班主任ID(可选)
* @return 统计结果
*/
List<JcbtPovertyApplicationVo> getApplicationStatistics(Long teacherId);
/**
* 获取当前用户班级信息
*
* @param userId 用户ID
* @return 班级信息列表
*/
List<Map<String, Object>> getCurrentUserClasses(Long userId);
/**
* 获取班级学生列表
*
* @param classId 班级ID
* @return 学生信息列表
*/
List<Map<String, Object>> getClassStudents(Long classId);
}
@@ -0,0 +1,239 @@
package org.dromara.jcbt.service;
import org.dromara.jcbt.domain.bo.JcbtScholarshipApplicationBo;
import org.dromara.jcbt.domain.vo.JcbtScholarshipApplicationVo;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 奖学金申请记录Service接口
*
* @author ruoyi
* @date 2025-01-01
*/
public interface IJcbtScholarshipApplicationService {
/**
* 查询奖学金申请记录详情
*
* @param id 主键
* @return 奖学金申请记录
*/
JcbtScholarshipApplicationVo queryById(Long id);
/**
* 查询奖学金申请记录列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 奖学金申请记录分页列表
*/
TableDataInfo<JcbtScholarshipApplicationVo> queryPageList(JcbtScholarshipApplicationBo bo, PageQuery pageQuery);
/**
* 查询奖学金申请记录列表
*
* @param bo 查询条件
* @return 奖学金申请记录列表
*/
List<JcbtScholarshipApplicationVo> queryList(JcbtScholarshipApplicationBo bo);
/**
* 新增奖学金申请记录
*
* @param bo 奖学金申请记录
* @return 是否新增成功
*/
Boolean insertByBo(JcbtScholarshipApplicationBo bo);
/**
* 修改奖学金申请记录
*
* @param bo 奖学金申请记录
* @return 是否修改成功
*/
Boolean updateByBo(JcbtScholarshipApplicationBo bo);
/**
* 校验并批量删除奖学金申请记录信息
*
* @param ids 需要删除的奖学金申请记录主键集合
* @param isValid 是否校验,true-删除前校验,false-不校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 班主任代申请功能 - 批量提交学生申请
*
* @param batchId 批次ID
* @param scholarshipTypeId 奖学金类型ID
* @param classId 班级ID
* @param studentApplications 学生申请信息列表
* @return 提交结果
*/
Boolean batchSubmitApplicationsByTeacher(Long batchId, Long scholarshipTypeId, Long classId,
List<JcbtScholarshipApplicationBo> studentApplications);
/**
* 查询班主任负责班级的申请记录
*
* @param applicantId 申请人ID(班主任ID)
* @param batchId 批次ID
* @return 申请记录列表
*/
List<JcbtScholarshipApplicationVo> queryApplicationsByApplicant(Long applicantId, Long batchId);
/**
* 查询班级的申请记录
*
* @param classId 班级ID
* @param batchId 批次ID
* @return 申请记录列表
*/
List<JcbtScholarshipApplicationVo> queryApplicationsByClass(Long classId, Long batchId);
/**
* 查询待审核的申请记录
*
* @param reviewerId 审核人ID
* @param status 申请状态
* @return 申请记录列表
*/
List<JcbtScholarshipApplicationVo> queryPendingApplications(Long reviewerId, String status);
/**
* 检查学生申请资格和限制
*
* @param studentId 学生ID
* @param batchId 批次ID
* @param scholarshipTypeId 奖学金类型ID
* @return 检查结果
*/
Map<String, Object> checkStudentEligibility(Long studentId, Long batchId, Long scholarshipTypeId);
/**
* 批量审核申请
*
* @param applicationIds 申请ID列表
* @param status 审核状态
* @param reviewerId 审核人ID
* @param reviewerName 审核人姓名
* @param reviewComment 审核意见
* @return 是否审核成功
*/
Boolean batchReviewApplications(List<Long> applicationIds, String status, Long reviewerId,
String reviewerName, String reviewComment);
/**
* 提交申请(草稿状态改为提交状态)
*
* @param id 申请ID
* @return 是否提交成功
*/
Boolean submitApplication(Long id);
/**
* 撤回申请
*
* @param id 申请ID
* @param reason 撤回原因
* @return 是否撤回成功
*/
Boolean withdrawApplication(Long id, String reason);
/**
* 获取申请统计数据
*
* @param batchId 批次ID
* @param deptId 学院ID
* @return 统计数据
*/
Map<String, Object> getApplicationStatistics(Long batchId, Long deptId);
/**
* 查询可申请的奖学金类型列表(根据班级名额)
*
* @param classId 班级ID
* @param batchId 批次ID
* @return 奖学金类型列表
*/
List<Map<String, Object>> queryAvailableScholarshipTypes(Long classId, Long batchId);
/**
* 获取班级名额使用情况
*
* @param classId 班级ID
* @param batchId 批次ID
* @return 名额使用情况
*/
Map<String, Object> getClassQuotaUsage(Long classId, Long batchId);
// ========== 班主任申请专用接口 ==========
/**
* 获取班主任所带班级信息
*
* @param teacherId 班主任ID
* @return 班级信息
*/
Map<String, Object> getClassInfoByTeacher(Long teacherId);
/**
* 获取班级学生列表(用于勾选)
*
* @param classId 班级ID
* @return 学生列表
*/
List<Map<String, Object>> getClassStudents(Long classId);
/**
* 根据批次获取可申请的奖学金类型
*
* @param batchId 批次ID
* @return 奖学金类型列表
*/
List<Map<String, Object>> getScholarshipTypesByBatch(Long batchId);
/**
* 根据批次和班级获取带名额信息的奖学金类型(班主任专用)
*
* @param batchId 批次ID
* @param classId 班级ID
* @return 奖学金类型列表(包含名额信息)
*/
List<Map<String, Object>> getScholarshipTypesWithQuota(Long batchId, Long classId);
/**
* 测试班级名额查询(用于SQL日志调试)
*
* @param classId 班级ID
* @param scholarshipTypeId 奖学金类型ID
* @param batchId 批次ID
* @return 班级名额信息
*/
Map<String, Object> testClassQuotaQuery(Long classId, Long scholarshipTypeId, Long batchId);
/**
* 测试全校名额查询(用于SQL日志调试)
*
* @param batchId 批次ID
* @param scholarshipTypeId 奖学金类型ID
* @return 全校名额信息
*/
Map<String, Object> testSchoolQuotaQuery(Long batchId, Long scholarshipTypeId);
/**
* 确认选择班级(当用户从多个班级中选择一个时调用)
*
* @param teacherId 班主任ID
* @param classId 班级ID
* @return 班级信息
*/
Map<String, Object> confirmClassSelection(Long teacherId, Long classId);
}
@@ -0,0 +1,89 @@
package org.dromara.jcbt.service;
import org.dromara.jcbt.domain.bo.JcbtScholarshipBatchBo;
import org.dromara.jcbt.domain.vo.JcbtScholarshipBatchVo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 奖学金评定批次Service接口
*
* @author ruoyi
* @date 2025-01-27
*/
public interface IJcbtScholarshipBatchService {
/**
* 查询奖学金评定批次分页列表
*/
TableDataInfo<JcbtScholarshipBatchVo> queryPageList(JcbtScholarshipBatchBo bo, PageQuery pageQuery);
/**
* 查询奖学金评定批次列表(用于导出)
*/
List<JcbtScholarshipBatchVo> queryExportList(JcbtScholarshipBatchBo bo);
/**
* 根据id查询奖学金评定批次
*/
JcbtScholarshipBatchVo queryById(Long id);
/**
* 新增奖学金评定批次
*/
Boolean insertByBo(JcbtScholarshipBatchBo bo);
/**
* 修改奖学金评定批次
*/
Boolean updateByBo(JcbtScholarshipBatchBo bo);
/**
* 校验并批量删除奖学金评定批次信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 根据批次编码查询批次信息
*/
JcbtScholarshipBatchVo queryByBatchCode(String batchCode);
/**
* 根据学年和学期查询批次列表
*/
List<JcbtScholarshipBatchVo> queryByAcademicYearAndSemester(String academicYear, Integer semester);
/**
* 查询启用状态的批次列表
*/
List<JcbtScholarshipBatchVo> queryActiveBatches();
/**
* 检查批次编码是否唯一
*/
Boolean checkBatchCodeUnique(String batchCode, Long id);
/**
* 更改批次状态
*/
Boolean changeStatus(Long id, String status);
/**
* 查询当前进行中的批次
*/
List<JcbtScholarshipBatchVo> queryCurrentActiveBatches();
/**
* 根据状态查询批次列表
*/
List<JcbtScholarshipBatchVo> queryByStatus(String status);
/**
* 检查批次时间是否有冲突
*/
Boolean checkTimeConflict(JcbtScholarshipBatchBo bo);
}
@@ -0,0 +1,41 @@
package org.dromara.jcbt.service;
import org.dromara.jcbt.domain.JcbtScholarshipBatchType;
import java.util.List;
/**
* 奖学金批次类型关联Service接口
*
* @author ruoyi
* @date 2025-01-27
*/
public interface IJcbtScholarshipBatchTypeService {
/**
* 根据批次ID获取关联的奖学金类型ID列表
*
* @param batchId 批次ID
* @return 奖学金类型ID列表
*/
List<Long> getScholarshipTypeIdsByBatchId(Long batchId);
/**
* 批量保存批次类型关联关系
*
* @param batchId 批次ID
* @param scholarshipTypeIds 奖学金类型ID列表
* @param tenantId 租户ID
* @return 保存结果
*/
Boolean saveBatchTypes(Long batchId, List<Long> scholarshipTypeIds, String tenantId);
/**
* 根据批次ID删除关联关系
*
* @param batchId 批次ID
* @return 删除结果
*/
Boolean deleteByBatchId(Long batchId);
}
@@ -0,0 +1,116 @@
package org.dromara.jcbt.service;
import org.dromara.jcbt.domain.bo.JcbtScholarshipClassQuotaBo;
import org.dromara.jcbt.domain.vo.JcbtScholarshipClassQuotaVo;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import java.util.Collection;
import java.util.List;
/**
* 奖学金班级名额分配Service接口
*
* @author ruoyi
* @date 2025-01-01
*/
public interface IJcbtScholarshipClassQuotaService {
/**
* 查询奖学金班级名额分配详情
*
* @param id 主键
* @return 奖学金班级名额分配
*/
JcbtScholarshipClassQuotaVo queryById(Long id);
/**
* 查询奖学金班级名额分配列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 奖学金班级名额分配分页列表
*/
TableDataInfo<JcbtScholarshipClassQuotaVo> queryPageList(JcbtScholarshipClassQuotaBo bo, PageQuery pageQuery);
/**
* 查询奖学金班级名额分配列表
*
* @param bo 查询条件
* @return 奖学金班级名额分配列表
*/
List<JcbtScholarshipClassQuotaVo> queryList(JcbtScholarshipClassQuotaBo bo);
/**
* 新增奖学金班级名额分配
*
* @param bo 奖学金班级名额分配
* @return 是否新增成功
*/
Boolean insertByBo(JcbtScholarshipClassQuotaBo bo);
/**
* 修改奖学金班级名额分配
*
* @param bo 奖学金班级名额分配
* @return 是否修改成功
*/
Boolean updateByBo(JcbtScholarshipClassQuotaBo bo);
/**
* 校验并批量删除奖学金班级名额分配信息
*
* @param ids 需要删除的奖学金班级名额分配主键集合
* @param isValid 是否校验,true-删除前校验,false-不校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 查询班级可用名额
*
* @param classId 班级ID
* @param scholarshipTypeId 奖学金类型ID
* @param batchId 批次ID
* @return 名额分配信息
*/
JcbtScholarshipClassQuotaVo queryAvailableQuota(Long classId, Long scholarshipTypeId, Long batchId);
/**
* 查询班级的所有名额分配
*
* @param classId 班级ID
* @param batchId 批次ID
* @return 名额分配列表
*/
List<JcbtScholarshipClassQuotaVo> queryQuotasByClass(Long classId, Long batchId);
/**
* 查询学院下所有班级的名额分配
*
* @param deptId 学院ID
* @param batchId 批次ID
* @return 名额分配列表
*/
List<JcbtScholarshipClassQuotaVo> queryQuotasByDept(Long deptId, Long batchId);
/**
* 更新名额使用情况
*
* @param id 名额分配ID
* @param usedQuota 已使用名额
* @param availableQuota 可用名额
* @return 是否更新成功
*/
Boolean updateQuotaUsage(Long id, Integer usedQuota, Integer availableQuota);
/**
* 查询名额统计信息
*
* @param batchId 批次ID
* @param scholarshipTypeId 奖学金类型ID
* @return 统计信息
*/
List<JcbtScholarshipClassQuotaVo> queryQuotaStatistics(Long batchId, Long scholarshipTypeId);
}
@@ -0,0 +1,100 @@
package org.dromara.jcbt.service;
import org.dromara.jcbt.domain.vo.JcbtScholarshipCompatibilityVo;
import org.dromara.jcbt.domain.bo.JcbtScholarshipCompatibilityBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 奖学金兼得关系Service接口
*
* @author ruoyi
* @date 2025-01-27
*/
public interface IJcbtScholarshipCompatibilityService {
/**
* 查询奖学金兼得关系
*/
JcbtScholarshipCompatibilityVo queryById(Long id);
/**
* 查询奖学金兼得关系列表
*/
TableDataInfo<JcbtScholarshipCompatibilityVo> queryPageList(JcbtScholarshipCompatibilityBo bo, PageQuery pageQuery);
/**
* 查询奖学金兼得关系列表
*/
List<JcbtScholarshipCompatibilityVo> queryList(JcbtScholarshipCompatibilityBo bo);
/**
* 新增奖学金兼得关系
*/
Boolean insertByBo(JcbtScholarshipCompatibilityBo bo);
/**
* 修改奖学金兼得关系
*/
Boolean updateByBo(JcbtScholarshipCompatibilityBo bo);
/**
* 校验并批量删除奖学金兼得关系信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 查询与指定奖学金类型的兼得关系
*
* @param scholarshipTypeId 奖学金类型ID
* @return 兼得关系列表
*/
List<JcbtScholarshipCompatibilityVo> queryByScholarshipTypeId(Long scholarshipTypeId);
/**
* 检查两个奖学金类型是否兼容
*
* @param typeId1 奖学金类型1
* @param typeId2 奖学金类型2
* @return true-兼容,false-不兼容
*/
Boolean checkCompatibility(Long typeId1, Long typeId2);
/**
* 保存奖学金类型的兼得关系配置
*
* @param scholarshipTypeId 奖学金类型ID
* @param exclusiveTypeIds 互斥的奖学金类型ID列表
* @param compatibleTypeIds 兼容的奖学金类型ID列表
* @return 保存结果
*/
Boolean saveCompatibilityConfig(Long scholarshipTypeId, List<Long> exclusiveTypeIds, List<Long> compatibleTypeIds);
/**
* 获取与指定奖学金类型互斥的奖学金类型ID列表
*
* @param scholarshipTypeId 奖学金类型ID
* @return 互斥的奖学金类型ID列表
*/
List<Long> getExclusiveTypeIds(Long scholarshipTypeId);
/**
* 获取与指定奖学金类型兼容的奖学金类型ID列表
*
* @param scholarshipTypeId 奖学金类型ID
* @return 兼容的奖学金类型ID列表
*/
List<Long> getCompatibleTypeIds(Long scholarshipTypeId);
/**
* 删除指定奖学金类型的所有兼得关系
*
* @param scholarshipTypeId 奖学金类型ID
* @return 删除结果
*/
Boolean deleteByScholarshipTypeId(Long scholarshipTypeId);
}
@@ -0,0 +1,190 @@
package org.dromara.jcbt.service;
import org.dromara.jcbt.domain.bo.JcbtScholarshipQuotaBo;
import org.dromara.jcbt.domain.vo.JcbtScholarshipQuotaVo;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 奖学金名额分配Service接口
*
* @author ruoyi
* @date 2025-01-27
*/
public interface IJcbtScholarshipQuotaService {
/**
* 查询奖学金名额分配
*
* @param id 主键
* @return 奖学金名额分配
*/
JcbtScholarshipQuotaVo queryById(Long id);
/**
* 分页查询奖学金名额分配列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 奖学金名额分配分页列表
*/
TableDataInfo<JcbtScholarshipQuotaVo> queryPageList(JcbtScholarshipQuotaBo bo, PageQuery pageQuery);
/**
* 查询符合条件的奖学金名额分配列表
*
* @param bo 查询条件
* @return 奖学金名额分配列表
*/
List<JcbtScholarshipQuotaVo> queryList(JcbtScholarshipQuotaBo bo);
/**
* 新增奖学金名额分配
*
* @param bo 奖学金名额分配
* @return 是否新增成功
*/
Boolean insertByBo(JcbtScholarshipQuotaBo bo);
/**
* 修改奖学金名额分配
*
* @param bo 奖学金名额分配
* @return 是否修改成功
*/
Boolean updateByBo(JcbtScholarshipQuotaBo bo);
/**
* 校验并批量删除奖学金名额分配信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 清空指定批次和奖学金类型的名额分配
*
* @param batchId 批次ID
* @param scholarshipTypeId 奖学金类型ID(可选)
* @return 是否清空成功
*/
Boolean clearQuotaByBatchAndType(Long batchId, Long scholarshipTypeId);
/**
* 查询指定批次的名额分配列表
*
* @param batchId 批次ID
* @return 名额分配列表
*/
List<JcbtScholarshipQuotaVo> queryListByBatchId(Long batchId);
/**
* 查询指定批次和奖学金类型的名额分配
*
* @param batchId 批次ID
* @param scholarshipTypeId 奖学金类型ID
* @return 名额分配列表
*/
List<JcbtScholarshipQuotaVo> queryListByBatchAndType(Long batchId, Long scholarshipTypeId);
/**
* 批量分配名额
*
* @param batchId 批次ID
* @param scholarshipTypeId 奖学金类型ID
* @param quotaAllocations 分配配置列表
* @return 是否分配成功
*/
Boolean batchAllocateQuota(Long batchId, Long scholarshipTypeId, List<JcbtScholarshipQuotaBo> quotaAllocations);
/**
* 调整名额分配
*
* @param fromQuotaId 源名额ID
* @param toQuotaId 目标名额ID
* @param adjustAmount 调整数量
* @param reason 调整原因
* @return 是否调整成功
*/
Boolean adjustQuotaAllocation(Long fromQuotaId, Long toQuotaId, Integer adjustAmount, String reason);
/**
* 锁定/解锁名额分配
*
* @param id 名额分配ID
* @param isLocked 是否锁定
* @return 是否操作成功
*/
Boolean lockQuotaAllocation(Long id, Integer isLocked);
/**
* 查询名额分配树形结构
*
* @param batchId 批次ID
* @param scholarshipTypeId 奖学金类型ID
* @return 树形结构数据
*/
List<JcbtScholarshipQuotaVo> queryQuotaTree(Long batchId, Long scholarshipTypeId);
/**
* 查询名额使用统计
*
* @param batchId 批次ID
* @return 统计数据
*/
Map<String, Object> queryQuotaUsageStatistics(Long batchId);
/**
* 自动分配名额(按规则)
*
* @param batchId 批次ID
* @param scholarshipTypeId 奖学金类型ID
* @param allocationRule 分配规则
* @return 是否分配成功
*/
Boolean autoAllocateQuota(Long batchId, Long scholarshipTypeId, String allocationRule);
/**
* 复制名额分配(从其他批次)
*
* @param sourceBatchId 源批次ID
* @param targetBatchId 目标批次ID
* @param scholarshipTypeIds 奖学金类型ID列表
* @return 是否复制成功
*/
Boolean copyQuotaFromBatch(Long sourceBatchId, Long targetBatchId, List<Long> scholarshipTypeIds);
/**
* 更新名额使用情况
*
* @param quotaId 名额分配ID
* @param usedChange 使用数量变化(正数增加,负数减少)
* @return 是否更新成功
*/
Boolean updateQuotaUsage(Long quotaId, Integer usedChange);
/**
* 验证名额分配的有效性
*
* @param bo 名额分配数据
* @return 验证结果消息
*/
String validateQuotaAllocation(JcbtScholarshipQuotaBo bo);
/**
* 查询班级级别的名额分配
*
* @param classId 班级ID
* @param scholarshipTypeId 奖学金类型ID
* @param batchId 批次ID
* @return 班级名额分配信息
*/
JcbtScholarshipQuotaVo selectClassQuota(Long classId, Long scholarshipTypeId, Long batchId);
}
@@ -0,0 +1,135 @@
package org.dromara.jcbt.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.jcbt.domain.bo.JcbtScholarshipReviewBo;
import org.dromara.jcbt.domain.vo.JcbtScholarshipReviewVo;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 奖学金审核记录Service接口
*
* @author ruoyi
* @date 2025-08-05
*/
public interface IJcbtScholarshipReviewService {
/**
* 查询奖学金审核记录
*/
JcbtScholarshipReviewVo queryById(Long id);
/**
* 查询奖学金审核记录列表
*/
TableDataInfo<JcbtScholarshipReviewVo> queryPageList(JcbtScholarshipReviewBo bo, PageQuery pageQuery);
/**
* 查询奖学金审核记录列表
*/
List<JcbtScholarshipReviewVo> queryList(JcbtScholarshipReviewBo bo);
/**
* 新增奖学金审核记录
*/
Boolean insertByBo(JcbtScholarshipReviewBo bo);
/**
* 修改奖学金审核记录
*/
Boolean updateByBo(JcbtScholarshipReviewBo bo);
/**
* 校验并批量删除奖学金审核记录信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 根据申请ID查询审核记录
*/
List<JcbtScholarshipReviewVo> queryReviewsByApplicationId(Long applicationId);
/**
* 查询当前用户待审核的记录
*/
TableDataInfo<JcbtScholarshipReviewVo> queryPendingReviews(Long reviewerId, String reviewLevel,
String applicationNo, String studentName,
PageQuery pageQuery);
/**
* 查询审核历史记录
*/
TableDataInfo<JcbtScholarshipReviewVo> queryReviewHistory(Long reviewerId, String reviewResult,
Long batchId, String startTime, String endTime,
PageQuery pageQuery);
/**
* 提交审核结果
*/
Boolean submitReview(Long reviewId, String reviewResult, String reviewOpinion,
Double reviewScore, Long nextReviewerId);
/**
* 批量审核
*/
Boolean batchReview(List<Long> reviewIds, String reviewResult, String reviewOpinion,
Long reviewerId, String reviewerName);
/**
* 创建审核任务
*/
Boolean createReviewTask(Long applicationId, String reviewLevel, Long reviewerId,
String reviewerName, Long nextReviewerId);
/**
* 转移审核任务
*/
Boolean transferReview(Long reviewId, Long newReviewerId, String newReviewerName, String reason);
/**
* 撤回审核结果
*/
Boolean withdrawReview(Long reviewId, String reason);
/**
* 查询某个申请的最新审核记录
*/
JcbtScholarshipReviewVo queryLatestReviewByApplicationId(Long applicationId);
/**
* 查询某个申请的指定级别审核记录
*/
JcbtScholarshipReviewVo queryReviewByApplicationAndLevel(Long applicationId, String reviewLevel);
/**
* 统计审核数量
*/
Map<String, Long> countReviewsByCondition(Long reviewerId, String reviewLevel,
String reviewResult, Long batchId);
/**
* 获取下一级审核人员列表
*/
List<Long> getNextReviewers(Long applicationId, String currentLevel);
/**
* 审核流程推进
*/
Boolean advanceReviewProcess(Long applicationId, String currentLevel, String reviewResult,
String reviewOpinion, Double reviewScore);
/**
* 检查用户审核权限
*/
Boolean checkReviewPermission(Long reviewerId, String reviewLevel, Long applicationId);
/**
* 获取审核统计信息
*/
Map<String, Object> getReviewStatistics(Long reviewerId, String reviewLevel, Long batchId);
}
@@ -0,0 +1,94 @@
package org.dromara.jcbt.service;
import org.dromara.jcbt.domain.vo.JcbtScholarshipTypeVo;
import org.dromara.jcbt.domain.bo.JcbtScholarshipTypeBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 奖学金类型Service接口
*
* @author ruoyi
* @date 2025-01-27
*/
public interface IJcbtScholarshipTypeService {
/**
* 查询奖学金类型
*/
JcbtScholarshipTypeVo queryById(Long id);
/**
* 查询奖学金类型列表
*/
TableDataInfo<JcbtScholarshipTypeVo> queryPageList(JcbtScholarshipTypeBo bo, PageQuery pageQuery);
/**
* 查询奖学金类型列表
*/
List<JcbtScholarshipTypeVo> queryList(JcbtScholarshipTypeBo bo);
/**
* 新增奖学金类型
*/
Boolean insertByBo(JcbtScholarshipTypeBo bo);
/**
* 修改奖学金类型
*/
Boolean updateByBo(JcbtScholarshipTypeBo bo);
/**
* 校验并批量删除奖学金类型信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 根据类型名称查询奖学金类型
*/
JcbtScholarshipTypeVo queryByTypeName(String typeName);
/**
* 根据类别查询奖学金类型列表
*/
List<JcbtScholarshipTypeVo> queryByCategory(String typeCategory);
/**
* 查询启用状态的奖学金类型列表
*/
List<JcbtScholarshipTypeVo> queryActiveTypes();
/**
* 检查奖学金名称是否重复
*/
boolean checkTypeNameUnique(String typeName, Long id);
/**
* 批量更新排序号
*/
Boolean batchUpdateSortOrder(List<JcbtScholarshipTypeBo> scholarshipTypes);
/**
* 根据兼得类型查询相关奖学金类型
*/
List<JcbtScholarshipTypeVo> queryByCompatibilityType(String compatibilityType);
/**
* 启用/停用奖学金类型
*/
Boolean changeStatus(Long id, Integer status);
/**
* 导出奖学金类型数据
*/
List<JcbtScholarshipTypeVo> queryExportList(JcbtScholarshipTypeBo bo);
/**
* 获取奖学金类型选项列表
*/
List<JcbtScholarshipTypeVo> queryOptions();
}
@@ -0,0 +1,465 @@
package org.dromara.jcbt.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.jcbt.domain.JcbtPovertyApplication;
import org.dromara.jcbt.domain.bo.JcbtPovertyApplicationBo;
import org.dromara.jcbt.domain.vo.JcbtPovertyApplicationVo;
import org.dromara.jcbt.enums.ApplicationStatusEnum;
import org.dromara.jcbt.mapper.JcbtPovertyApplicationMapper;
import org.dromara.jcbt.service.IJcbtPovertyApplicationService;
import org.dromara.xg.domain.vo.XgStudentMsgVo;
import org.dromara.xg.service.IXgStudentMsgService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 贫困生认定申请Service业务层处理
*
* @author ruoyi
* @date 2025-08-09
*/
@RequiredArgsConstructor
@Service
public class JcbtPovertyApplicationServiceImpl implements IJcbtPovertyApplicationService {
private final JcbtPovertyApplicationMapper baseMapper;
@Autowired
private IXgStudentMsgService xgStudentMsgService;
/**
* 查询贫困生认定申请
*/
@Override
public JcbtPovertyApplicationVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 根据申请编号查询申请信息
*/
@Override
public JcbtPovertyApplicationVo queryByApplicationNo(String applicationNo) {
return baseMapper.selectByApplicationNo(applicationNo);
}
/**
* 查询贫困生认定申请分页列表
*/
@Override
public TableDataInfo<JcbtPovertyApplicationVo> queryPageList(JcbtPovertyApplicationBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<JcbtPovertyApplication> lqw = buildQueryWrapper(bo);
Page<JcbtPovertyApplicationVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询贫困生认定申请列表
*/
@Override
public List<JcbtPovertyApplicationVo> queryList(JcbtPovertyApplicationBo bo) {
LambdaQueryWrapper<JcbtPovertyApplication> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
/**
* 根据班主任ID查询申请列表(班主任查看自己班级的申请)
*/
@Override
public TableDataInfo<JcbtPovertyApplicationVo> queryPageListByTeacher(Long teacherId, JcbtPovertyApplicationBo bo, PageQuery pageQuery) {
JcbtPovertyApplication application = BeanUtil.toBean(bo, JcbtPovertyApplication.class);
Page<JcbtPovertyApplicationVo> page = pageQuery.build();
List<JcbtPovertyApplicationVo> list = baseMapper.selectApplicationListByTeacher(teacherId, application);
// 手动分页
int start = (int) ((page.getCurrent() - 1) * page.getSize());
int end = Math.min(start + (int) page.getSize(), list.size());
List<JcbtPovertyApplicationVo> pageList = list.subList(start, end);
page.setRecords(pageList);
page.setTotal(list.size());
return TableDataInfo.build(page);
}
/**
* 查询待审核的申请列表(审核人员使用)
*/
@Override
public TableDataInfo<JcbtPovertyApplicationVo> queryPendingPageList(JcbtPovertyApplicationBo bo, PageQuery pageQuery) {
JcbtPovertyApplication application = BeanUtil.toBean(bo, JcbtPovertyApplication.class);
Page<JcbtPovertyApplicationVo> page = pageQuery.build();
List<JcbtPovertyApplicationVo> list = baseMapper.selectPendingApplicationList(application);
// 手动分页
int start = (int) ((page.getCurrent() - 1) * page.getSize());
int end = Math.min(start + (int) page.getSize(), list.size());
List<JcbtPovertyApplicationVo> pageList = list.subList(start, end);
page.setRecords(pageList);
page.setTotal(list.size());
return TableDataInfo.build(page);
}
private LambdaQueryWrapper<JcbtPovertyApplication> buildQueryWrapper(JcbtPovertyApplicationBo bo) {
LambdaQueryWrapper<JcbtPovertyApplication> lqw = Wrappers.lambdaQuery();
lqw.like(StringUtils.isNotBlank(bo.getApplicationNo()), JcbtPovertyApplication::getApplicationNo, bo.getApplicationNo());
lqw.eq(StringUtils.isNotBlank(bo.getAcademicYear()), JcbtPovertyApplication::getAcademicYear, bo.getAcademicYear());
lqw.eq(ObjectUtil.isNotNull(bo.getTerm()), JcbtPovertyApplication::getTerm, bo.getTerm());
lqw.like(StringUtils.isNotBlank(bo.getStudentNo()), JcbtPovertyApplication::getStudentNo, bo.getStudentNo());
lqw.like(StringUtils.isNotBlank(bo.getStudentName()), JcbtPovertyApplication::getStudentName, bo.getStudentName());
lqw.eq(ObjectUtil.isNotNull(bo.getCollegeId()), JcbtPovertyApplication::getCollegeId, bo.getCollegeId());
lqw.eq(ObjectUtil.isNotNull(bo.getMajorId()), JcbtPovertyApplication::getMajorId, bo.getMajorId());
lqw.eq(ObjectUtil.isNotNull(bo.getClassId()), JcbtPovertyApplication::getClassId, bo.getClassId());
lqw.eq(StringUtils.isNotBlank(bo.getRecognitionGroup()), JcbtPovertyApplication::getRecognitionGroup, bo.getRecognitionGroup());
lqw.eq(ObjectUtil.isNotNull(bo.getRecognitionTypeId()), JcbtPovertyApplication::getRecognitionTypeId, bo.getRecognitionTypeId());
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), JcbtPovertyApplication::getStatus, bo.getStatus());
lqw.eq(ObjectUtil.isNotNull(bo.getSubmitterId()), JcbtPovertyApplication::getSubmitterId, bo.getSubmitterId());
lqw.orderByDesc(JcbtPovertyApplication::getCreateTime);
return lqw;
}
/**
* 新增贫困生认定申请
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByBo(JcbtPovertyApplicationBo bo) {
// 业务校验
validateApplicationData(bo, null);
JcbtPovertyApplication add = BeanUtil.toBean(bo, JcbtPovertyApplication.class);
validEntityBeforeSave(add);
// 设置申请编号
if (StrUtil.isBlank(add.getApplicationNo())) {
add.setApplicationNo(generateApplicationNo());
}
// 设置默认状态为草稿
if (StrUtil.isBlank(add.getStatus())) {
add.setStatus(ApplicationStatusEnum.DRAFT.getCode());
}
// 设置提交人信息
add.setSubmitterId(LoginHelper.getUserId());
add.setSubmitterName(LoginHelper.getUsername());
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改贫困生认定申请
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateByBo(JcbtPovertyApplicationBo bo) {
// 业务校验
validateApplicationData(bo, bo.getId());
JcbtPovertyApplication update = BeanUtil.toBean(bo, JcbtPovertyApplication.class);
validEntityBeforeSave(update);
// 检查是否可以编辑
JcbtPovertyApplication existing = baseMapper.selectById(update.getId());
if (existing == null) {
throw new ServiceException("申请不存在");
}
if (!ApplicationStatusEnum.canEdit(existing.getStatus())) {
throw new ServiceException("当前状态不允许编辑");
}
return baseMapper.updateById(update) > 0;
}
/**
* 保存草稿
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean saveDraft(JcbtPovertyApplicationBo bo) {
bo.setStatus(ApplicationStatusEnum.DRAFT.getCode());
if (ObjectUtil.isNull(bo.getId())) {
return insertByBo(bo);
} else {
return updateByBo(bo);
}
}
/**
* 提交申请
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean submitApplication(Long id) {
JcbtPovertyApplication application = baseMapper.selectById(id);
if (application == null) {
throw new ServiceException("申请不存在");
}
// 检查是否可以提交
if (!ApplicationStatusEnum.DRAFT.getCode().equals(application.getStatus())
&& !ApplicationStatusEnum.REJECTED.getCode().equals(application.getStatus())) {
throw new ServiceException("当前状态不允许提交");
}
// 更新状态为待审核
application.setStatus(ApplicationStatusEnum.WAITING.getCode());
application.setSubmitTime(new Date());
return baseMapper.updateById(application) > 0;
}
/**
* 撤销申请
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean cancelApplication(Long id) {
JcbtPovertyApplication application = baseMapper.selectById(id);
if (application == null) {
throw new ServiceException("申请不存在");
}
// 检查是否可以撤销
if (!ApplicationStatusEnum.canCancel(application.getStatus())) {
throw new ServiceException("当前状态不允许撤销");
}
// 更新状态为已撤销
application.setStatus(ApplicationStatusEnum.CANCELED.getCode());
return baseMapper.updateById(application) > 0;
}
/**
* 审核通过
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean approveApplication(Long id, String auditOpinion) {
JcbtPovertyApplication application = baseMapper.selectById(id);
if (application == null) {
throw new ServiceException("申请不存在");
}
// 检查是否可以审核
if (!ApplicationStatusEnum.canAudit(application.getStatus())) {
throw new ServiceException("当前状态不允许审核");
}
// 更新状态为已通过
application.setStatus(ApplicationStatusEnum.COMPLETE.getCode());
application.setAuditorId(LoginHelper.getUserId());
application.setAuditorName(LoginHelper.getUsername());
application.setAuditTime(new Date());
application.setAuditOpinion(auditOpinion);
return baseMapper.updateById(application) > 0;
}
/**
* 审核驳回
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean rejectApplication(Long id, String auditOpinion) {
JcbtPovertyApplication application = baseMapper.selectById(id);
if (application == null) {
throw new ServiceException("申请不存在");
}
// 检查是否可以审核
if (!ApplicationStatusEnum.canAudit(application.getStatus())) {
throw new ServiceException("当前状态不允许审核");
}
if (StrUtil.isBlank(auditOpinion)) {
throw new ServiceException("驳回意见不能为空");
}
// 更新状态为已驳回
application.setStatus(ApplicationStatusEnum.REJECTED.getCode());
application.setAuditorId(LoginHelper.getUserId());
application.setAuditorName(LoginHelper.getUsername());
application.setAuditTime(new Date());
application.setAuditOpinion(auditOpinion);
return baseMapper.updateById(application) > 0;
}
/**
* 校验删除数据
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// 删除前校验
for (Long id : ids) {
JcbtPovertyApplication application = baseMapper.selectById(id);
if (application != null && !ApplicationStatusEnum.DRAFT.getCode().equals(application.getStatus())) {
throw new ServiceException("只能删除草稿状态的申请");
}
}
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 生成申请编号
*/
@Override
public String generateApplicationNo() {
String dateStr = DateUtil.format(new Date(), "yyyyMMdd");
String randomStr = String.valueOf(System.currentTimeMillis() % 10000);
return "PJRZ" + dateStr + String.format("%04d", Integer.parseInt(randomStr));
}
/**
* 检查学生是否已有相同类型的认定申请
*/
@Override
public boolean checkStudentApplicationExists(Long studentId, String academicYear, Long recognitionTypeId, Long excludeId) {
int count = baseMapper.checkStudentApplicationExists(studentId, academicYear, recognitionTypeId, excludeId);
return count > 0;
}
/**
* 统计申请数据
*/
@Override
public List<JcbtPovertyApplicationVo> getApplicationStatistics(Long teacherId) {
return baseMapper.selectApplicationStatistics(teacherId);
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(JcbtPovertyApplication entity) {
// 校验申请自助类型不能为空
if (StrUtil.isBlank(entity.getAssistanceTypeIds())) {
throw new ServiceException("申请自助类型不能为空");
}
// 校验家庭经济情况摘要长度
if (StrUtil.isNotBlank(entity.getFamilyEconomySummary())
&& entity.getFamilyEconomySummary().length() > 500) {
throw new ServiceException("家庭经济情况摘要不能超过500个字符");
}
// 校验审核意见长度
if (StrUtil.isNotBlank(entity.getAuditOpinion())
&& entity.getAuditOpinion().length() > 1000) {
throw new ServiceException("审核意见不能超过1000个字符");
}
}
/**
* 业务数据校验
*/
private void validateApplicationData(JcbtPovertyApplicationBo bo, Long excludeId) {
// 校验学生在同一学年是否已有相同类型的认定申请
if (checkStudentApplicationExists(bo.getStudentId(), bo.getAcademicYear(), bo.getRecognitionTypeId(), excludeId)) {
throw new ServiceException("该学生在" + bo.getAcademicYear() + "学年已有相同类型的认定申请");
}
// 校验认定群体与认定类型的匹配性
if (StrUtil.isNotBlank(bo.getRecognitionGroup()) && StrUtil.isNotBlank(bo.getRecognitionTypeCode())) {
// 这里可以添加更复杂的业务校验逻辑
// 例如:特殊群体只能选择特定的认定类型等
}
// 校验附件
if (ObjectUtil.isNull(bo.getAttachApplicationFormId()) || ObjectUtil.isNull(bo.getAttachSurveyFormId())) {
throw new ServiceException("申请表和调查表附件都不能为空");
}
}
/**
* 获取当前用户班级信息
*/
@Override
public List<Map<String, Object>> getCurrentUserClasses(Long userId) {
return baseMapper.selectCurrentUserClasses(userId);
}
/**
* 获取班级学生列表
*/
@Override
public List<Map<String, Object>> getClassStudents(Long classId) {
// 调用学生管理模块的服务,获取完整的学生信息(包含学院和专业)
List<XgStudentMsgVo> students = xgStudentMsgService.queryStudentsByClassId(String.valueOf(classId), null);
// 添加调试日志
System.out.println("============ 调试日志 getClassStudents ============");
System.out.println("班级ID: " + classId);
System.out.println("查询到学生数量: " + students.size());
if (!students.isEmpty()) {
XgStudentMsgVo firstStudent = students.get(0);
System.out.println("第一个学生信息:");
System.out.println(" ID: " + firstStudent.getId());
System.out.println(" 姓名: " + firstStudent.getName());
System.out.println(" 学号: " + firstStudent.getStudentNo());
System.out.println(" 学院ID: " + firstStudent.getCollegeId());
System.out.println(" 学院名称: " + firstStudent.getCollegeName());
System.out.println(" 专业ID: " + firstStudent.getMajorId());
System.out.println(" 专业名称: " + firstStudent.getMajorName());
System.out.println(" 班级ID: " + firstStudent.getClassId());
System.out.println(" 班级名称: " + firstStudent.getClassName());
}
// 转换为Map格式返回,保持原有接口兼容性
return students.stream()
.map(student -> {
Map<String, Object> map = new HashMap<>();
map.put("studentId", student.getId());
map.put("id", student.getId()); // 兼容前端可能使用的字段
map.put("studentNo", student.getStudentNo());
map.put("studentName", student.getName());
map.put("name", student.getName()); // 兼容前端可能使用的字段
map.put("gender", student.getGender());
map.put("collegeId", student.getCollegeId());
map.put("collegeName", student.getCollegeName());
map.put("majorId", student.getMajorId());
map.put("majorName", student.getMajorName());
map.put("classId", student.getClassId());
map.put("className", student.getClassName());
map.put("grade", student.getGrade());
// 添加调试日志,打印转换后的Map
System.out.println("转换后的学生Map: " + map);
return map;
})
.toList();
}
}
@@ -0,0 +1,295 @@
package org.dromara.jcbt.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.jcbt.domain.JcbtScholarshipBatch;
import org.dromara.jcbt.domain.bo.JcbtScholarshipBatchBo;
import org.dromara.jcbt.domain.vo.JcbtScholarshipBatchVo;
import org.dromara.jcbt.mapper.JcbtScholarshipBatchMapper;
import org.dromara.jcbt.service.IJcbtScholarshipBatchService;
import org.dromara.jcbt.service.IJcbtScholarshipBatchTypeService;
import org.springframework.transaction.annotation.Transactional;
import org.dromara.common.satoken.utils.LoginHelper;
import java.util.Collection;
import java.util.Date;
import java.util.List;
/**
* 奖学金评定批次Service业务层处理
*
* @author ruoyi
* @date 2025-01-27
*/
@RequiredArgsConstructor
@Service
public class JcbtScholarshipBatchServiceImpl implements IJcbtScholarshipBatchService {
private final JcbtScholarshipBatchMapper baseMapper;
private final IJcbtScholarshipBatchTypeService batchTypeService;
/**
* 查询奖学金评定批次分页列表
*/
@Override
public TableDataInfo<JcbtScholarshipBatchVo> queryPageList(JcbtScholarshipBatchBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<JcbtScholarshipBatch> lqw = buildQueryWrapper(bo);
Page<JcbtScholarshipBatchVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询奖学金评定批次列表(用于导出)
*/
@Override
public List<JcbtScholarshipBatchVo> queryExportList(JcbtScholarshipBatchBo bo) {
LambdaQueryWrapper<JcbtScholarshipBatch> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
/**
* 构建查询条件
*/
private LambdaQueryWrapper<JcbtScholarshipBatch> buildQueryWrapper(JcbtScholarshipBatchBo bo) {
LambdaQueryWrapper<JcbtScholarshipBatch> lqw = Wrappers.lambdaQuery();
lqw.like(StringUtils.isNotBlank(bo.getBatchCode()), JcbtScholarshipBatch::getBatchCode, bo.getBatchCode());
lqw.like(StringUtils.isNotBlank(bo.getBatchName()), JcbtScholarshipBatch::getBatchName, bo.getBatchName());
lqw.eq(StringUtils.isNotBlank(bo.getAcademicYear()), JcbtScholarshipBatch::getAcademicYear, bo.getAcademicYear());
lqw.eq(ObjectUtil.isNotNull(bo.getSemester()), JcbtScholarshipBatch::getSemester, bo.getSemester());
lqw.eq(StringUtils.isNotBlank(bo.getBatchType()), JcbtScholarshipBatch::getBatchType, bo.getBatchType());
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), JcbtScholarshipBatch::getStatus, bo.getStatus());
lqw.orderByDesc(JcbtScholarshipBatch::getCreateTime);
return lqw;
}
/**
* 根据id查询奖学金评定批次
*/
@Override
public JcbtScholarshipBatchVo queryById(Long id){
JcbtScholarshipBatchVo vo = baseMapper.selectVoById(id);
if (vo != null) {
// 查询关联的奖学金类型ID列表
List<Long> scholarshipTypeIds = batchTypeService.getScholarshipTypeIdsByBatchId(id);
vo.setScholarshipTypeIds(scholarshipTypeIds);
}
return vo;
}
/**
* 新增奖学金评定批次
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByBo(JcbtScholarshipBatchBo bo) {
JcbtScholarshipBatch add = MapstructUtils.convert(bo, JcbtScholarshipBatch.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
// 保存批次类型关联关系
if (bo.getScholarshipTypeIds() != null && !bo.getScholarshipTypeIds().isEmpty()) {
String tenantId = LoginHelper.getTenantId();
batchTypeService.saveBatchTypes(add.getId(), bo.getScholarshipTypeIds(), tenantId);
}
}
return flag;
}
/**
* 修改奖学金评定批次
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateByBo(JcbtScholarshipBatchBo bo) {
JcbtScholarshipBatch update = MapstructUtils.convert(bo, JcbtScholarshipBatch.class);
validEntityBeforeSave(update);
boolean flag = baseMapper.updateById(update) > 0;
if (flag) {
// 更新批次类型关联关系
String tenantId = LoginHelper.getTenantId();
batchTypeService.saveBatchTypes(update.getId(), bo.getScholarshipTypeIds(), tenantId);
}
return flag;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(JcbtScholarshipBatch entity){
// 批次编码重复性校验
if (!checkBatchCodeUnique(entity.getBatchCode(), entity.getId())) {
throw new RuntimeException("批次编码已存在");
}
// 时间逻辑校验
if (entity.getStartTime() != null && entity.getEndTime() != null) {
if (entity.getStartTime().after(entity.getEndTime())) {
throw new RuntimeException("开始时间不能晚于结束时间");
}
}
// 申请时间校验
if (entity.getApplyStartTime() != null && entity.getApplyEndTime() != null) {
if (entity.getApplyStartTime().after(entity.getApplyEndTime())) {
throw new RuntimeException("申请开始时间不能晚于申请结束时间");
}
}
// 审核时间校验
if (entity.getReviewStartTime() != null && entity.getReviewEndTime() != null) {
if (entity.getReviewStartTime().after(entity.getReviewEndTime())) {
throw new RuntimeException("审核开始时间不能晚于审核结束时间");
}
}
}
/**
* 批量删除奖学金评定批次
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
// 进行业务校验
for (Long id : ids) {
JcbtScholarshipBatchVo batch = queryById(id);
if (batch != null && "ACTIVE".equals(batch.getStatus())) {
throw new RuntimeException("批次【" + batch.getBatchName() + "】正在进行中,不能删除");
}
}
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 根据批次编码查询批次信息
*/
@Override
public JcbtScholarshipBatchVo queryByBatchCode(String batchCode) {
return baseMapper.selectVoOne(Wrappers.<JcbtScholarshipBatch>lambdaQuery()
.eq(JcbtScholarshipBatch::getBatchCode, batchCode));
}
/**
* 根据学年和学期查询批次列表
*/
@Override
public List<JcbtScholarshipBatchVo> queryByAcademicYearAndSemester(String academicYear, Integer semester) {
return baseMapper.selectVoList(Wrappers.<JcbtScholarshipBatch>lambdaQuery()
.eq(StringUtils.isNotBlank(academicYear), JcbtScholarshipBatch::getAcademicYear, academicYear)
.eq(ObjectUtil.isNotNull(semester), JcbtScholarshipBatch::getSemester, semester)
.orderByDesc(JcbtScholarshipBatch::getCreateTime));
}
/**
* 查询启用状态的批次列表
*/
@Override
public List<JcbtScholarshipBatchVo> queryActiveBatches() {
return baseMapper.selectVoList(Wrappers.<JcbtScholarshipBatch>lambdaQuery()
.in(JcbtScholarshipBatch::getStatus, "DRAFT", "ACTIVE")
.orderByDesc(JcbtScholarshipBatch::getCreateTime));
}
/**
* 检查批次编码是否唯一
*/
@Override
public Boolean checkBatchCodeUnique(String batchCode, Long id) {
boolean exist = baseMapper.exists(Wrappers.<JcbtScholarshipBatch>lambdaQuery()
.eq(JcbtScholarshipBatch::getBatchCode, batchCode)
.ne(ObjectUtil.isNotNull(id), JcbtScholarshipBatch::getId, id));
return !exist;
}
/**
* 更改批次状态
*/
@Override
public Boolean changeStatus(Long id, String status) {
// 状态切换前业务校验
JcbtScholarshipBatchVo batch = queryById(id);
if (batch == null) {
throw new RuntimeException("批次不存在");
}
// 检查状态切换的合理性
validateStatusChange(batch.getStatus(), status);
JcbtScholarshipBatch update = new JcbtScholarshipBatch();
update.setId(id);
update.setStatus(status);
return baseMapper.updateById(update) > 0;
}
/**
* 校验状态切换的合理性
*/
private void validateStatusChange(String currentStatus, String newStatus) {
// 已完成或已取消的批次不能再更改状态
if ("COMPLETED".equals(currentStatus) || "CANCELLED".equals(currentStatus)) {
throw new RuntimeException("批次已完成或已取消,不能更改状态");
}
// 其他业务规则校验可以在此处添加
}
/**
* 查询当前进行中的批次
*/
@Override
public List<JcbtScholarshipBatchVo> queryCurrentActiveBatches() {
Date now = new Date();
return baseMapper.selectVoList(Wrappers.<JcbtScholarshipBatch>lambdaQuery()
.eq(JcbtScholarshipBatch::getStatus, "ACTIVE")
.le(JcbtScholarshipBatch::getStartTime, now)
.ge(JcbtScholarshipBatch::getEndTime, now)
.orderByDesc(JcbtScholarshipBatch::getCreateTime));
}
/**
* 根据状态查询批次列表
*/
@Override
public List<JcbtScholarshipBatchVo> queryByStatus(String status) {
return baseMapper.selectVoList(Wrappers.<JcbtScholarshipBatch>lambdaQuery()
.eq(JcbtScholarshipBatch::getStatus, status)
.orderByDesc(JcbtScholarshipBatch::getCreateTime));
}
/**
* 检查批次时间是否有冲突
*/
@Override
public Boolean checkTimeConflict(JcbtScholarshipBatchBo bo) {
if (bo.getStartTime() == null || bo.getEndTime() == null) {
return false;
}
// 查询同学年同学期同类型的批次,检查时间是否有重叠
boolean exist = baseMapper.exists(Wrappers.<JcbtScholarshipBatch>lambdaQuery()
.eq(JcbtScholarshipBatch::getAcademicYear, bo.getAcademicYear())
.eq(JcbtScholarshipBatch::getSemester, bo.getSemester())
.eq(JcbtScholarshipBatch::getBatchType, bo.getBatchType())
.ne(ObjectUtil.isNotNull(bo.getId()), JcbtScholarshipBatch::getId, bo.getId())
.and(wrapper -> wrapper
.le(JcbtScholarshipBatch::getStartTime, bo.getEndTime())
.ge(JcbtScholarshipBatch::getEndTime, bo.getStartTime())
));
return exist;
}
}
@@ -0,0 +1,89 @@
package org.dromara.jcbt.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.jcbt.domain.JcbtScholarshipBatchType;
import org.dromara.jcbt.mapper.JcbtScholarshipBatchTypeMapper;
import org.dromara.jcbt.service.IJcbtScholarshipBatchTypeService;
import org.springframework.stereotype.Service;
import org.dromara.common.satoken.utils.LoginHelper;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 奖学金批次类型关联Service业务层处理
*
* @author ruoyi
* @date 2025-01-27
*/
@RequiredArgsConstructor
@Service
public class JcbtScholarshipBatchTypeServiceImpl implements IJcbtScholarshipBatchTypeService {
private final JcbtScholarshipBatchTypeMapper baseMapper;
@Override
public List<Long> getScholarshipTypeIdsByBatchId(Long batchId) {
LambdaQueryWrapper<JcbtScholarshipBatchType> lqw = Wrappers.lambdaQuery();
lqw.eq(JcbtScholarshipBatchType::getBatchId, batchId);
lqw.eq(JcbtScholarshipBatchType::getTenantId, LoginHelper.getTenantId());
List<JcbtScholarshipBatchType> list = baseMapper.selectList(lqw);
List<Long> typeIds = new ArrayList<>();
for (JcbtScholarshipBatchType item : list) {
typeIds.add(item.getScholarshipTypeId());
}
return typeIds;
}
@Override
public Boolean saveBatchTypes(Long batchId, List<Long> scholarshipTypeIds, String tenantId) {
if (batchId == null || scholarshipTypeIds == null || scholarshipTypeIds.isEmpty()) {
return true; // 空列表视为成功
}
// 先删除原有关联关系
deleteByBatchId(batchId);
// 批量插入新的关联关系
List<JcbtScholarshipBatchType> batchTypes = new ArrayList<>();
int sortOrder = 1;
for (Long typeId : scholarshipTypeIds) {
JcbtScholarshipBatchType batchType = new JcbtScholarshipBatchType();
batchType.setBatchId(batchId);
batchType.setScholarshipTypeId(typeId);
batchType.setIsActive(1);
batchType.setSortOrder(sortOrder++);
batchType.setTenantId(tenantId);
batchType.setCreateBy(LoginHelper.getUserId());
batchType.setCreateTime(new Date());
batchType.setUpdateBy(LoginHelper.getUserId());
batchType.setUpdateTime(new Date());
batchType.setDeleted(0);
batchTypes.add(batchType);
}
// 批量插入
for (JcbtScholarshipBatchType batchType : batchTypes) {
baseMapper.insert(batchType);
}
return true;
}
@Override
public Boolean deleteByBatchId(Long batchId) {
if (batchId == null) {
return true;
}
LambdaQueryWrapper<JcbtScholarshipBatchType> lqw = Wrappers.lambdaQuery();
lqw.eq(JcbtScholarshipBatchType::getBatchId, batchId);
lqw.eq(JcbtScholarshipBatchType::getTenantId, LoginHelper.getTenantId());
return baseMapper.delete(lqw) >= 0;
}
}
@@ -0,0 +1,159 @@
package org.dromara.jcbt.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.jcbt.domain.JcbtScholarshipClassQuota;
import org.dromara.jcbt.domain.bo.JcbtScholarshipClassQuotaBo;
import org.dromara.jcbt.domain.vo.JcbtScholarshipClassQuotaVo;
import org.dromara.jcbt.mapper.JcbtScholarshipClassQuotaMapper;
import org.dromara.jcbt.service.IJcbtScholarshipClassQuotaService;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
/**
* 奖学金班级名额分配Service业务层处理
*
* @author ruoyi
* @date 2025-01-01
*/
@RequiredArgsConstructor
@Service
public class JcbtScholarshipClassQuotaServiceImpl implements IJcbtScholarshipClassQuotaService {
private final JcbtScholarshipClassQuotaMapper baseMapper;
/**
* 查询奖学金班级名额分配详情
*/
@Override
public JcbtScholarshipClassQuotaVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 查询奖学金班级名额分配列表
*/
@Override
public TableDataInfo<JcbtScholarshipClassQuotaVo> queryPageList(JcbtScholarshipClassQuotaBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<JcbtScholarshipClassQuota> lqw = buildQueryWrapper(bo);
Page<JcbtScholarshipClassQuotaVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询奖学金班级名额分配列表
*/
@Override
public List<JcbtScholarshipClassQuotaVo> queryList(JcbtScholarshipClassQuotaBo bo) {
LambdaQueryWrapper<JcbtScholarshipClassQuota> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<JcbtScholarshipClassQuota> buildQueryWrapper(JcbtScholarshipClassQuotaBo bo) {
LambdaQueryWrapper<JcbtScholarshipClassQuota> lqw = Wrappers.lambdaQuery();
lqw.eq(ObjectUtil.isNotNull(bo.getBatchId()), JcbtScholarshipClassQuota::getBatchId, bo.getBatchId());
lqw.eq(ObjectUtil.isNotNull(bo.getScholarshipTypeId()), JcbtScholarshipClassQuota::getScholarshipTypeId, bo.getScholarshipTypeId());
lqw.eq(ObjectUtil.isNotNull(bo.getDeptId()), JcbtScholarshipClassQuota::getDeptId, bo.getDeptId());
lqw.eq(ObjectUtil.isNotNull(bo.getClassId()), JcbtScholarshipClassQuota::getClassId, bo.getClassId());
lqw.eq(ObjectUtil.isNotNull(bo.getTotalQuota()), JcbtScholarshipClassQuota::getTotalQuota, bo.getTotalQuota());
lqw.eq(ObjectUtil.isNotNull(bo.getUsedQuota()), JcbtScholarshipClassQuota::getUsedQuota, bo.getUsedQuota());
lqw.eq(ObjectUtil.isNotNull(bo.getAvailableQuota()), JcbtScholarshipClassQuota::getAvailableQuota, bo.getAvailableQuota());
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), JcbtScholarshipClassQuota::getStatus, bo.getStatus());
return lqw;
}
/**
* 新增奖学金班级名额分配
*/
@Override
public Boolean insertByBo(JcbtScholarshipClassQuotaBo bo) {
JcbtScholarshipClassQuota add = MapstructUtils.convert(bo, JcbtScholarshipClassQuota.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改奖学金班级名额分配
*/
@Override
public Boolean updateByBo(JcbtScholarshipClassQuotaBo bo) {
JcbtScholarshipClassQuota update = MapstructUtils.convert(bo, JcbtScholarshipClassQuota.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(JcbtScholarshipClassQuota entity) {
// TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除奖学金班级名额分配
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 查询班级可用名额
*/
@Override
public JcbtScholarshipClassQuotaVo queryAvailableQuota(Long classId, Long scholarshipTypeId, Long batchId) {
return baseMapper.selectAvailableQuota(classId, scholarshipTypeId, batchId);
}
/**
* 查询班级的所有名额分配
*/
@Override
public List<JcbtScholarshipClassQuotaVo> queryQuotasByClass(Long classId, Long batchId) {
LambdaQueryWrapper<JcbtScholarshipClassQuota> lqw = Wrappers.lambdaQuery();
lqw.eq(JcbtScholarshipClassQuota::getClassId, classId);
lqw.eq(ObjectUtil.isNotNull(batchId), JcbtScholarshipClassQuota::getBatchId, batchId);
return baseMapper.selectVoList(lqw);
}
/**
* 查询学院下所有班级的名额分配
*/
@Override
public List<JcbtScholarshipClassQuotaVo> queryQuotasByDept(Long deptId, Long batchId) {
return baseMapper.selectQuotasByDept(deptId, batchId);
}
/**
* 更新名额使用情况
*/
@Override
public Boolean updateQuotaUsage(Long id, Integer usedQuota, Integer availableQuota) {
return baseMapper.updateQuotaUsage(id, usedQuota, availableQuota) > 0;
}
/**
* 查询名额统计信息
*/
@Override
public List<JcbtScholarshipClassQuotaVo> queryQuotaStatistics(Long batchId, Long scholarshipTypeId) {
return baseMapper.selectQuotaStatistics(batchId, scholarshipTypeId);
}
}
@@ -0,0 +1,220 @@
package org.dromara.jcbt.service.impl;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.jcbt.domain.JcbtScholarshipCompatibility;
import org.dromara.jcbt.domain.vo.JcbtScholarshipCompatibilityVo;
import org.dromara.jcbt.domain.bo.JcbtScholarshipCompatibilityBo;
import org.dromara.jcbt.mapper.JcbtScholarshipCompatibilityMapper;
import org.dromara.jcbt.service.IJcbtScholarshipCompatibilityService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.ArrayList;
import java.util.stream.Collectors;
/**
* 奖学金兼得关系Service业务层处理
*
* @author ruoyi
* @date 2025-01-27
*/
@RequiredArgsConstructor
@Service
public class JcbtScholarshipCompatibilityServiceImpl implements IJcbtScholarshipCompatibilityService {
private final JcbtScholarshipCompatibilityMapper baseMapper;
/**
* 查询奖学金兼得关系
*/
@Override
public JcbtScholarshipCompatibilityVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 查询奖学金兼得关系列表
*/
@Override
public TableDataInfo<JcbtScholarshipCompatibilityVo> queryPageList(JcbtScholarshipCompatibilityBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<JcbtScholarshipCompatibility> lqw = buildQueryWrapper(bo);
Page<JcbtScholarshipCompatibilityVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询奖学金兼得关系列表
*/
@Override
public List<JcbtScholarshipCompatibilityVo> queryList(JcbtScholarshipCompatibilityBo bo) {
LambdaQueryWrapper<JcbtScholarshipCompatibility> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<JcbtScholarshipCompatibility> buildQueryWrapper(JcbtScholarshipCompatibilityBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<JcbtScholarshipCompatibility> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getTypeId1() != null, JcbtScholarshipCompatibility::getTypeId1, bo.getTypeId1());
lqw.eq(bo.getTypeId2() != null, JcbtScholarshipCompatibility::getTypeId2, bo.getTypeId2());
lqw.eq(StringUtils.isNotBlank(bo.getRelationType()), JcbtScholarshipCompatibility::getRelationType, bo.getRelationType());
lqw.eq(bo.getPriorityLevel() != null, JcbtScholarshipCompatibility::getPriorityLevel, bo.getPriorityLevel());
lqw.like(StringUtils.isNotBlank(bo.getDescription()), JcbtScholarshipCompatibility::getDescription, bo.getDescription());
return lqw;
}
/**
* 新增奖学金兼得关系
*/
@Override
public Boolean insertByBo(JcbtScholarshipCompatibilityBo bo) {
JcbtScholarshipCompatibility add = MapstructUtils.convert(bo, JcbtScholarshipCompatibility.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改奖学金兼得关系
*/
@Override
public Boolean updateByBo(JcbtScholarshipCompatibilityBo bo) {
JcbtScholarshipCompatibility update = MapstructUtils.convert(bo, JcbtScholarshipCompatibility.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(JcbtScholarshipCompatibility entity) {
// 确保 typeId1 < typeId2,避免重复的关系记录
if (entity.getTypeId1() != null && entity.getTypeId2() != null && entity.getTypeId1().compareTo(entity.getTypeId2()) > 0) {
Long temp = entity.getTypeId1();
entity.setTypeId1(entity.getTypeId2());
entity.setTypeId2(temp);
}
}
/**
* 批量删除奖学金兼得关系
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 查询与指定奖学金类型的兼得关系
*/
@Override
public List<JcbtScholarshipCompatibilityVo> queryByScholarshipTypeId(Long scholarshipTypeId) {
return baseMapper.selectCompatibilityByTypeId(scholarshipTypeId);
}
/**
* 检查两个奖学金类型是否兼容
*/
@Override
public Boolean checkCompatibility(Long typeId1, Long typeId2) {
if (typeId1.equals(typeId2)) {
return true; // 同一个奖学金类型,兼容
}
JcbtScholarshipCompatibilityVo compatibility = baseMapper.selectCompatibilityByTwoTypes(typeId1, typeId2);
if (compatibility == null) {
return true; // 没有明确的关系配置,默认兼容
}
// 检查关系类型
return !"EXCLUSIVE".equals(compatibility.getRelationType());
}
/**
* 保存奖学金类型的兼得关系配置
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean saveCompatibilityConfig(Long scholarshipTypeId, List<Long> exclusiveTypeIds, List<Long> compatibleTypeIds) {
// 1. 先删除现有的关系配置
deleteByScholarshipTypeId(scholarshipTypeId);
// 2. 保存互斥关系
if (exclusiveTypeIds != null && !exclusiveTypeIds.isEmpty()) {
for (Long exclusiveTypeId : exclusiveTypeIds) {
if (!exclusiveTypeId.equals(scholarshipTypeId)) {
JcbtScholarshipCompatibilityBo exclusiveBo = new JcbtScholarshipCompatibilityBo();
exclusiveBo.setTypeId1(Math.min(scholarshipTypeId, exclusiveTypeId));
exclusiveBo.setTypeId2(Math.max(scholarshipTypeId, exclusiveTypeId));
exclusiveBo.setRelationType("EXCLUSIVE");
exclusiveBo.setDescription("自定义配置的互斥关系");
insertByBo(exclusiveBo);
}
}
}
// 3. 保存兼容关系
if (compatibleTypeIds != null && !compatibleTypeIds.isEmpty()) {
for (Long compatibleTypeId : compatibleTypeIds) {
if (!compatibleTypeId.equals(scholarshipTypeId)) {
JcbtScholarshipCompatibilityBo compatibleBo = new JcbtScholarshipCompatibilityBo();
compatibleBo.setTypeId1(Math.min(scholarshipTypeId, compatibleTypeId));
compatibleBo.setTypeId2(Math.max(scholarshipTypeId, compatibleTypeId));
compatibleBo.setRelationType("COMPATIBLE");
compatibleBo.setDescription("自定义配置的兼容关系");
insertByBo(compatibleBo);
}
}
}
return true;
}
/**
* 获取与指定奖学金类型互斥的奖学金类型ID列表
*/
@Override
public List<Long> getExclusiveTypeIds(Long scholarshipTypeId) {
List<JcbtScholarshipCompatibilityVo> compatibilities = queryByScholarshipTypeId(scholarshipTypeId);
return compatibilities.stream()
.filter(c -> "EXCLUSIVE".equals(c.getRelationType()))
.map(c -> c.getTypeId1().equals(scholarshipTypeId) ? c.getTypeId2() : c.getTypeId1())
.collect(Collectors.toList());
}
/**
* 获取与指定奖学金类型兼容的奖学金类型ID列表
*/
@Override
public List<Long> getCompatibleTypeIds(Long scholarshipTypeId) {
List<JcbtScholarshipCompatibilityVo> compatibilities = queryByScholarshipTypeId(scholarshipTypeId);
return compatibilities.stream()
.filter(c -> "COMPATIBLE".equals(c.getRelationType()))
.map(c -> c.getTypeId1().equals(scholarshipTypeId) ? c.getTypeId2() : c.getTypeId1())
.collect(Collectors.toList());
}
/**
* 删除指定奖学金类型的所有兼得关系
*/
@Override
public Boolean deleteByScholarshipTypeId(Long scholarshipTypeId) {
return baseMapper.deleteByScholarshipTypeId(scholarshipTypeId) >= 0;
}
}
@@ -0,0 +1,515 @@
package org.dromara.jcbt.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.jcbt.domain.JcbtScholarshipQuota;
import org.dromara.jcbt.domain.bo.JcbtScholarshipQuotaBo;
import org.dromara.jcbt.domain.vo.JcbtScholarshipQuotaVo;
import org.dromara.jcbt.mapper.JcbtScholarshipQuotaMapper;
import org.dromara.jcbt.service.IJcbtScholarshipQuotaService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
/**
* 奖学金名额分配Service业务层处理
*
* @author ruoyi
* @date 2025-01-27
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class JcbtScholarshipQuotaServiceImpl implements IJcbtScholarshipQuotaService {
private final JcbtScholarshipQuotaMapper baseMapper;
/**
* 查询奖学金名额分配
*
* @param id 主键
* @return 奖学金名额分配
*/
@Override
public JcbtScholarshipQuotaVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 分页查询奖学金名额分配列表
*
* @param bo 查询条件
* @param pageQuery 分页参数
* @return 奖学金名额分配分页列表
*/
@Override
public TableDataInfo<JcbtScholarshipQuotaVo> queryPageList(JcbtScholarshipQuotaBo bo, PageQuery pageQuery) {
// 使用自定义的关联查询方法,而不是MyBatis-Plus的自动方法
Page<JcbtScholarshipQuotaVo> page = pageQuery.build();
IPage<JcbtScholarshipQuotaVo> result = baseMapper.selectQuotaPageList(page, bo);
return TableDataInfo.build(result);
}
/**
* 查询符合条件的奖学金名额分配列表
*
* @param bo 查询条件
* @return 奖学金名额分配列表
*/
@Override
public List<JcbtScholarshipQuotaVo> queryList(JcbtScholarshipQuotaBo bo) {
// 使用自定义的关联查询方法
return baseMapper.selectQuotaList(bo);
}
private LambdaQueryWrapper<JcbtScholarshipQuota> buildQueryWrapper(JcbtScholarshipQuotaBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<JcbtScholarshipQuota> lqw = Wrappers.lambdaQuery();
lqw.eq(ObjectUtil.isNotNull(bo.getBatchId()), JcbtScholarshipQuota::getBatchId, bo.getBatchId());
lqw.eq(ObjectUtil.isNotNull(bo.getScholarshipTypeId()), JcbtScholarshipQuota::getScholarshipTypeId, bo.getScholarshipTypeId());
lqw.eq(StringUtils.isNotBlank(bo.getAllocationLevel()), JcbtScholarshipQuota::getAllocationLevel, bo.getAllocationLevel());
lqw.eq(ObjectUtil.isNotNull(bo.getTargetDeptId()), JcbtScholarshipQuota::getTargetDeptId, bo.getTargetDeptId());
lqw.eq(ObjectUtil.isNotNull(bo.getParentQuotaId()), JcbtScholarshipQuota::getParentQuotaId, bo.getParentQuotaId());
lqw.eq(StringUtils.isNotBlank(bo.getAllocationMethod()), JcbtScholarshipQuota::getAllocationMethod, bo.getAllocationMethod());
lqw.eq(ObjectUtil.isNotNull(bo.getIsAdjustable()), JcbtScholarshipQuota::getIsAdjustable, bo.getIsAdjustable());
lqw.eq(ObjectUtil.isNotNull(bo.getIsLocked()), JcbtScholarshipQuota::getIsLocked, bo.getIsLocked());
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), JcbtScholarshipQuota::getStatus, bo.getStatus());
return lqw;
}
/**
* 新增奖学金名额分配
*
* @param bo 奖学金名额分配
* @return 是否新增成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByBo(JcbtScholarshipQuotaBo bo) {
// 数据验证
String validationMsg = validateQuotaAllocation(bo);
if (StringUtils.isNotBlank(validationMsg)) {
throw new RuntimeException(validationMsg);
}
JcbtScholarshipQuota add = MapstructUtils.convert(bo, JcbtScholarshipQuota.class);
// 计算可用名额
Integer availableQuota = calculateAvailableQuota(add.getTotalQuota(), add.getUsedQuota(), add.getReservedQuota());
add.setAvailableQuota(availableQuota);
// 设置默认状态
if (StringUtils.isBlank(add.getStatus())) {
add.setStatus("ACTIVE");
}
if (ObjectUtil.isNull(add.getIsAdjustable())) {
add.setIsAdjustable(1);
}
if (ObjectUtil.isNull(add.getIsLocked())) {
add.setIsLocked(0);
}
if (StringUtils.isBlank(add.getAllocationMethod())) {
add.setAllocationMethod("MANUAL");
}
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改奖学金名额分配
*
* @param bo 奖学金名额分配
* @return 是否修改成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateByBo(JcbtScholarshipQuotaBo bo) {
// 数据验证
String validationMsg = validateQuotaAllocation(bo);
if (StringUtils.isNotBlank(validationMsg)) {
throw new RuntimeException(validationMsg);
}
JcbtScholarshipQuota update = MapstructUtils.convert(bo, JcbtScholarshipQuota.class);
// 重新计算可用名额
Integer availableQuota = calculateAvailableQuota(update.getTotalQuota(), update.getUsedQuota(), update.getReservedQuota());
update.setAvailableQuota(availableQuota);
return baseMapper.updateById(update) > 0;
}
/**
* 校验并批量删除奖学金名额分配信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// 校验删除条件
for (Long id : ids) {
JcbtScholarshipQuotaVo quota = baseMapper.selectVoById(id);
if (ObjectUtil.isNotNull(quota)) {
if (quota.getUsedQuota() > 0) {
throw new RuntimeException("名额分配ID:" + id + " 已有使用记录,不能删除");
}
if (ObjectUtil.equals(quota.getIsLocked(), 1)) {
throw new RuntimeException("名额分配ID:" + id + " 已被锁定,不能删除");
}
}
}
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 清空指定批次和奖学金类型的名额分配
*
* @param batchId 批次ID
* @param scholarshipTypeId 奖学金类型ID(可选)
* @return 是否清空成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean clearQuotaByBatchAndType(Long batchId, Long scholarshipTypeId) {
// 构建查询条件
LambdaQueryWrapper<JcbtScholarshipQuota> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(JcbtScholarshipQuota::getBatchId, batchId);
if (scholarshipTypeId != null) {
queryWrapper.eq(JcbtScholarshipQuota::getScholarshipTypeId, scholarshipTypeId);
}
// 查询要删除的记录
List<JcbtScholarshipQuota> quotaList = baseMapper.selectList(queryWrapper);
if (CollUtil.isEmpty(quotaList)) {
return true; // 没有数据需要删除,返回成功
}
// 校验删除条件
for (JcbtScholarshipQuota quota : quotaList) {
if (quota.getUsedQuota() > 0) {
throw new RuntimeException("批次ID:" + batchId + " 中存在已使用的名额,不能清空");
}
if (ObjectUtil.equals(quota.getIsLocked(), 1)) {
throw new RuntimeException("批次ID:" + batchId + " 中存在已锁定的名额,不能清空");
}
}
// 执行删除
return baseMapper.delete(queryWrapper) > 0;
}
/**
* 查询指定批次的名额分配列表
*
* @param batchId 批次ID
* @return 名额分配列表
*/
@Override
public List<JcbtScholarshipQuotaVo> queryListByBatchId(Long batchId) {
return baseMapper.selectQuotaListByBatchId(batchId);
}
/**
* 查询指定批次和奖学金类型的名额分配
*
* @param batchId 批次ID
* @param scholarshipTypeId 奖学金类型ID
* @return 名额分配列表
*/
@Override
public List<JcbtScholarshipQuotaVo> queryListByBatchAndType(Long batchId, Long scholarshipTypeId) {
return baseMapper.selectQuotaListByBatchAndType(batchId, scholarshipTypeId);
}
/**
* 批量分配名额
*
* @param batchId 批次ID
* @param scholarshipTypeId 奖学金类型ID
* @param quotaAllocations 分配配置列表
* @return 是否分配成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean batchAllocateQuota(Long batchId, Long scholarshipTypeId, List<JcbtScholarshipQuotaBo> quotaAllocations) {
if (CollUtil.isEmpty(quotaAllocations)) {
return false;
}
try {
for (JcbtScholarshipQuotaBo allocation : quotaAllocations) {
allocation.setBatchId(batchId);
allocation.setScholarshipTypeId(scholarshipTypeId);
insertByBo(allocation);
}
return true;
} catch (Exception e) {
log.error("批量分配名额失败", e);
throw new RuntimeException("批量分配名额失败: " + e.getMessage());
}
}
/**
* 调整名额分配
*
* @param fromQuotaId 源名额ID
* @param toQuotaId 目标名额ID
* @param adjustAmount 调整数量
* @param reason 调整原因
* @return 是否调整成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean adjustQuotaAllocation(Long fromQuotaId, Long toQuotaId, Integer adjustAmount, String reason) {
if (adjustAmount <= 0) {
throw new RuntimeException("调整数量必须大于0");
}
JcbtScholarshipQuota fromQuota = baseMapper.selectById(fromQuotaId);
JcbtScholarshipQuota toQuota = baseMapper.selectById(toQuotaId);
if (fromQuota == null || toQuota == null) {
throw new RuntimeException("名额分配不存在");
}
if (fromQuota.getAvailableQuota() < adjustAmount) {
throw new RuntimeException("源名额可用数量不足");
}
// 调整源名额
fromQuota.setTotalQuota(fromQuota.getTotalQuota() - adjustAmount);
fromQuota.setAvailableQuota(fromQuota.getAvailableQuota() - adjustAmount);
// 调整目标名额
toQuota.setTotalQuota(toQuota.getTotalQuota() + adjustAmount);
toQuota.setAvailableQuota(toQuota.getAvailableQuota() + adjustAmount);
// 更新数据库
return baseMapper.updateById(fromQuota) > 0 && baseMapper.updateById(toQuota) > 0;
}
/**
* 锁定/解锁名额分配
*
* @param id 名额分配ID
* @param isLocked 是否锁定
* @return 是否操作成功
*/
@Override
public Boolean lockQuotaAllocation(Long id, Integer isLocked) {
JcbtScholarshipQuota quota = new JcbtScholarshipQuota();
quota.setId(id);
quota.setIsLocked(isLocked);
return baseMapper.updateById(quota) > 0;
}
/**
* 查询名额分配树形结构
*
* @param batchId 批次ID
* @param scholarshipTypeId 奖学金类型ID
* @return 树形结构数据
*/
@Override
public List<JcbtScholarshipQuotaVo> queryQuotaTree(Long batchId, Long scholarshipTypeId) {
return baseMapper.selectQuotaTreeByBatchAndType(batchId, scholarshipTypeId);
}
/**
* 查询名额使用统计
*
* @param batchId 批次ID
* @return 统计数据
*/
@Override
public Map<String, Object> queryQuotaUsageStatistics(Long batchId) {
log.info("查询批次 {} 的名额统计数据", batchId);
List<JcbtScholarshipQuotaVo> quotaList = queryListByBatchId(batchId);
log.info("查询到 {} 条名额分配数据", quotaList.size());
Map<String, Object> statistics = new HashMap<>();
int totalQuota = quotaList.stream().mapToInt(q -> ObjectUtil.defaultIfNull(q.getTotalQuota(), 0)).sum();
int usedQuota = quotaList.stream().mapToInt(q -> ObjectUtil.defaultIfNull(q.getUsedQuota(), 0)).sum();
// 计算可用名额:总名额 - 已用名额 - 预留名额
int reservedQuota = quotaList.stream().mapToInt(q -> ObjectUtil.defaultIfNull(q.getReservedQuota(), 0)).sum();
int availableQuota = totalQuota - usedQuota - reservedQuota;
log.info("统计结果 - 总名额: {}, 已用: {}, 预留: {}, 可用: {}", totalQuota, usedQuota, reservedQuota, availableQuota);
statistics.put("totalQuota", totalQuota);
statistics.put("usedQuota", usedQuota);
statistics.put("reservedQuota", reservedQuota);
statistics.put("availableQuota", Math.max(0, availableQuota)); // 确保不为负数
statistics.put("usageRate", totalQuota > 0 ? (double) usedQuota / totalQuota : 0.0);
statistics.put("allocationCount", quotaList.size());
return statistics;
}
/**
* 自动分配名额(按规则)
*
* @param batchId 批次ID
* @param scholarshipTypeId 奖学金类型ID
* @param allocationRule 分配规则
* @return 是否分配成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean autoAllocateQuota(Long batchId, Long scholarshipTypeId, String allocationRule) {
// 这里实现自动分配逻辑
// 根据分配规则(JSON格式)进行自动分配
log.info("执行自动分配名额: batchId={}, scholarshipTypeId={}, rule={}", batchId, scholarshipTypeId, allocationRule);
// TODO: 实现具体的自动分配算法
return true;
}
/**
* 复制名额分配(从其他批次)
*
* @param sourceBatchId 源批次ID
* @param targetBatchId 目标批次ID
* @param scholarshipTypeIds 奖学金类型ID列表
* @return 是否复制成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean copyQuotaFromBatch(Long sourceBatchId, Long targetBatchId, List<Long> scholarshipTypeIds) {
for (Long scholarshipTypeId : scholarshipTypeIds) {
List<JcbtScholarshipQuotaVo> sourceQuotas = queryListByBatchAndType(sourceBatchId, scholarshipTypeId);
for (JcbtScholarshipQuotaVo sourceQuota : sourceQuotas) {
JcbtScholarshipQuotaBo newQuota = new JcbtScholarshipQuotaBo();
BeanUtil.copyProperties(sourceQuota, newQuota);
newQuota.setId(null);
newQuota.setBatchId(targetBatchId);
newQuota.setUsedQuota(0);
newQuota.setAvailableQuota(newQuota.getTotalQuota());
insertByBo(newQuota);
}
}
return true;
}
/**
* 更新名额使用情况
*
* @param quotaId 名额分配ID
* @param usedChange 使用数量变化(正数增加,负数减少)
* @return 是否更新成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateQuotaUsage(Long quotaId, Integer usedChange) {
JcbtScholarshipQuota quota = baseMapper.selectById(quotaId);
if (quota == null) {
return false;
}
int newUsedQuota = quota.getUsedQuota() + usedChange;
if (newUsedQuota < 0) {
throw new RuntimeException("使用名额不能小于0");
}
if (newUsedQuota > quota.getTotalQuota()) {
throw new RuntimeException("使用名额不能超过总名额");
}
quota.setUsedQuota(newUsedQuota);
quota.setAvailableQuota(calculateAvailableQuota(quota.getTotalQuota(), newUsedQuota, quota.getReservedQuota()));
return baseMapper.updateById(quota) > 0;
}
/**
* 验证名额分配的有效性
*
* @param bo 名额分配数据
* @return 验证结果消息
*/
@Override
public String validateQuotaAllocation(JcbtScholarshipQuotaBo bo) {
// 检查总名额是否合理
if (bo.getTotalQuota() <= 0) {
return "总名额必须大于0";
}
// 检查使用名额不能超过总名额
if (bo.getUsedQuota() != null && bo.getUsedQuota() > bo.getTotalQuota()) {
return "已使用名额不能超过总名额";
}
// 检查预留名额不能超过总名额
if (bo.getReservedQuota() != null && bo.getReservedQuota() > bo.getTotalQuota()) {
return "预留名额不能超过总名额";
}
// 检查是否存在重复分配
int conflictCount = baseMapper.checkQuotaConflict(bo.getBatchId(), bo.getScholarshipTypeId(),
bo.getTargetDeptId(), bo.getId());
if (conflictCount > 0) {
return "该批次和奖学金类型下已存在相同部门的名额分配";
}
return null;
}
/**
* 计算可用名额
*
* @param totalQuota 总名额
* @param usedQuota 已使用名额
* @param reservedQuota 预留名额
* @return 可用名额
*/
private Integer calculateAvailableQuota(Integer totalQuota, Integer usedQuota, Integer reservedQuota) {
int total = ObjectUtil.defaultIfNull(totalQuota, 0);
int used = ObjectUtil.defaultIfNull(usedQuota, 0);
int reserved = ObjectUtil.defaultIfNull(reservedQuota, 0);
return Math.max(0, total - used - reserved);
}
/**
* 查询班级级别的名额分配
*
* @param classId 班级ID
* @param scholarshipTypeId 奖学金类型ID
* @param batchId 批次ID
* @return 班级名额分配信息
*/
@Override
public JcbtScholarshipQuotaVo selectClassQuota(Long classId, Long scholarshipTypeId, Long batchId) {
log.info("查询班级名额分配 - classId: {}, scholarshipTypeId: {}, batchId: {}", classId, scholarshipTypeId, batchId);
JcbtScholarshipQuotaVo result = baseMapper.selectClassQuota(classId, scholarshipTypeId, batchId);
log.info("班级名额查询结果: {}", result != null ?
String.format("ID=%s, 总名额=%s, 已用=%s, 可用=%s, 状态=%s",
result.getId(), result.getTotalQuota(), result.getUsedQuota(),
result.getAvailableQuota(), result.getStatus()) : "null");
return result;
}
}
@@ -0,0 +1,520 @@
package org.dromara.jcbt.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.jcbt.domain.JcbtScholarshipApplication;
import org.dromara.jcbt.domain.JcbtScholarshipReview;
import org.dromara.jcbt.domain.bo.JcbtScholarshipReviewBo;
import org.dromara.jcbt.domain.vo.JcbtScholarshipReviewVo;
import org.dromara.jcbt.mapper.JcbtScholarshipApplicationMapper;
import org.dromara.jcbt.mapper.JcbtScholarshipReviewMapper;
import org.dromara.jcbt.service.IJcbtScholarshipReviewService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.*;
/**
* 奖学金审核记录Service业务层处理
*
* @author ruoyi
* @date 2025-08-05
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class JcbtScholarshipReviewServiceImpl implements IJcbtScholarshipReviewService {
private final JcbtScholarshipReviewMapper baseMapper;
private final JcbtScholarshipApplicationMapper applicationMapper;
/**
* 查询奖学金审核记录
*/
@Override
public JcbtScholarshipReviewVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 查询奖学金审核记录列表
*/
@Override
public TableDataInfo<JcbtScholarshipReviewVo> queryPageList(JcbtScholarshipReviewBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<JcbtScholarshipReview> lqw = buildQueryWrapper(bo);
Page<JcbtScholarshipReviewVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询奖学金审核记录列表
*/
@Override
public List<JcbtScholarshipReviewVo> queryList(JcbtScholarshipReviewBo bo) {
LambdaQueryWrapper<JcbtScholarshipReview> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<JcbtScholarshipReview> buildQueryWrapper(JcbtScholarshipReviewBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<JcbtScholarshipReview> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getApplicationId() != null, JcbtScholarshipReview::getApplicationId, bo.getApplicationId());
lqw.eq(StringUtils.isNotBlank(bo.getReviewLevel()), JcbtScholarshipReview::getReviewLevel, bo.getReviewLevel());
lqw.eq(bo.getReviewerId() != null, JcbtScholarshipReview::getReviewerId, bo.getReviewerId());
lqw.like(StringUtils.isNotBlank(bo.getReviewerName()), JcbtScholarshipReview::getReviewerName, bo.getReviewerName());
lqw.eq(StringUtils.isNotBlank(bo.getReviewResult()), JcbtScholarshipReview::getReviewResult, bo.getReviewResult());
lqw.between(params.get("beginReviewTime") != null && params.get("endReviewTime") != null,
JcbtScholarshipReview::getReviewTime, params.get("beginReviewTime"), params.get("endReviewTime"));
lqw.eq(bo.getNextReviewerId() != null, JcbtScholarshipReview::getNextReviewerId, bo.getNextReviewerId());
lqw.eq(bo.getIsFinalReview() != null, JcbtScholarshipReview::getIsFinalReview, bo.getIsFinalReview());
lqw.orderByDesc(JcbtScholarshipReview::getReviewTime);
return lqw;
}
/**
* 新增奖学金审核记录
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByBo(JcbtScholarshipReviewBo bo) {
JcbtScholarshipReview add = MapstructUtils.convert(bo, JcbtScholarshipReview.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改奖学金审核记录
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateByBo(JcbtScholarshipReviewBo bo) {
JcbtScholarshipReview update = MapstructUtils.convert(bo, JcbtScholarshipReview.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(JcbtScholarshipReview entity) {
// 校验申请ID是否存在
if (entity.getApplicationId() != null) {
JcbtScholarshipApplication application = applicationMapper.selectById(entity.getApplicationId());
if (application == null) {
throw new RuntimeException("申请记录不存在,ID: " + entity.getApplicationId());
}
}
// 校验审核级别
if (StringUtils.isNotBlank(entity.getReviewLevel())) {
List<String> validLevels = Arrays.asList("DEPARTMENT", "SCHOOL", "FINANCE", "FINAL");
if (!validLevels.contains(entity.getReviewLevel())) {
throw new RuntimeException("无效的审核级别: " + entity.getReviewLevel());
}
}
// 校验审核结果
if (StringUtils.isNotBlank(entity.getReviewResult())) {
List<String> validResults = Arrays.asList("PENDING", "APPROVED", "REJECTED", "RETURNED");
if (!validResults.contains(entity.getReviewResult())) {
throw new RuntimeException("无效的审核结果: " + entity.getReviewResult());
}
}
}
/**
* 批量删除奖学金审核记录
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// 检查是否存在已完成的审核记录,不允许删除
List<JcbtScholarshipReview> reviews = baseMapper.selectBatchIds(ids);
for (JcbtScholarshipReview review : reviews) {
if (!"PENDING".equals(review.getReviewResult())) {
throw new RuntimeException("审核记录已完成,不允许删除,ID: " + review.getId());
}
}
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 根据申请ID查询审核记录
*/
@Override
public List<JcbtScholarshipReviewVo> queryReviewsByApplicationId(Long applicationId) {
return baseMapper.selectReviewsByApplicationId(applicationId);
}
/**
* 查询当前用户待审核的记录
*/
@Override
public TableDataInfo<JcbtScholarshipReviewVo> queryPendingReviews(Long reviewerId, String reviewLevel,
String applicationNo, String studentName,
PageQuery pageQuery) {
Page<JcbtScholarshipReviewVo> page = baseMapper.selectPendingReviews(
pageQuery.build(), reviewerId, reviewLevel, applicationNo, studentName);
return TableDataInfo.build(page);
}
/**
* 查询审核历史记录
*/
@Override
public TableDataInfo<JcbtScholarshipReviewVo> queryReviewHistory(Long reviewerId, String reviewResult,
Long batchId, String startTime, String endTime,
PageQuery pageQuery) {
Page<JcbtScholarshipReviewVo> page = baseMapper.selectReviewHistory(
pageQuery.build(), reviewerId, reviewResult, batchId, startTime, endTime);
return TableDataInfo.build(page);
}
/**
* 提交审核结果
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean submitReview(Long reviewId, String reviewResult, String reviewOpinion,
Double reviewScore, Long nextReviewerId) {
JcbtScholarshipReview review = baseMapper.selectById(reviewId);
if (review == null) {
throw new RuntimeException("审核记录不存在,ID: " + reviewId);
}
if (!"PENDING".equals(review.getReviewResult())) {
throw new RuntimeException("该审核记录已处理,不能重复提交");
}
// 更新审核记录
review.setReviewResult(reviewResult);
review.setReviewOpinion(reviewOpinion);
if (reviewScore != null) {
review.setReviewScore(BigDecimal.valueOf(reviewScore));
}
review.setReviewTime(new Date());
review.setNextReviewerId(nextReviewerId);
// 判断是否为最终审核
if ("FINAL".equals(review.getReviewLevel()) || nextReviewerId == null) {
review.setIsFinalReview(1);
}
boolean flag = baseMapper.updateById(review) > 0;
// 更新申请状态
if (flag) {
updateApplicationStatus(review.getApplicationId(), reviewResult, review.getReviewLevel());
// 如果审核通过且不是最终审核,创建下一级审核任务
if ("APPROVED".equals(reviewResult) && nextReviewerId != null && review.getIsFinalReview() != 1) {
createNextLevelReview(review.getApplicationId(), review.getReviewLevel(), nextReviewerId);
}
}
return flag;
}
/**
* 批量审核
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean batchReview(List<Long> reviewIds, String reviewResult, String reviewOpinion,
Long reviewerId, String reviewerName) {
if (CollUtil.isEmpty(reviewIds)) {
return false;
}
// 验证所有审核记录都是待审核状态
List<JcbtScholarshipReview> reviews = baseMapper.selectBatchIds(reviewIds);
for (JcbtScholarshipReview review : reviews) {
if (!"PENDING".equals(review.getReviewResult())) {
throw new RuntimeException("审核记录已处理,不能重复提交,ID: " + review.getId());
}
}
// 批量更新审核结果
int count = baseMapper.batchUpdateReviewResult(reviewIds, reviewResult, reviewOpinion, reviewerId, reviewerName);
// 更新对应的申请状态
if (count > 0) {
for (JcbtScholarshipReview review : reviews) {
updateApplicationStatus(review.getApplicationId(), reviewResult, review.getReviewLevel());
}
}
return count > 0;
}
/**
* 创建审核任务
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean createReviewTask(Long applicationId, String reviewLevel, Long reviewerId,
String reviewerName, Long nextReviewerId) {
// 检查是否已存在相同级别的审核记录
JcbtScholarshipReviewVo existingReview = baseMapper.selectReviewByApplicationAndLevel(applicationId, reviewLevel);
if (existingReview != null) {
throw new RuntimeException("该申请在此审核级别已存在审核记录");
}
JcbtScholarshipReview review = new JcbtScholarshipReview();
review.setApplicationId(applicationId);
review.setReviewLevel(reviewLevel);
review.setReviewerId(reviewerId);
review.setReviewerName(reviewerName);
review.setReviewResult("PENDING");
review.setNextReviewerId(nextReviewerId);
review.setIsFinalReview("FINAL".equals(reviewLevel) ? 1 : 0);
return baseMapper.insert(review) > 0;
}
/**
* 转移审核任务
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean transferReview(Long reviewId, Long newReviewerId, String newReviewerName, String reason) {
JcbtScholarshipReview review = baseMapper.selectById(reviewId);
if (review == null) {
throw new RuntimeException("审核记录不存在,ID: " + reviewId);
}
if (!"PENDING".equals(review.getReviewResult())) {
throw new RuntimeException("只有待审核的记录才能转移");
}
review.setReviewerId(newReviewerId);
review.setReviewerName(newReviewerName);
if (StringUtils.isNotBlank(reason)) {
review.setReviewOpinion("转移原因: " + reason);
}
return baseMapper.updateById(review) > 0;
}
/**
* 撤回审核结果
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean withdrawReview(Long reviewId, String reason) {
JcbtScholarshipReview review = baseMapper.selectById(reviewId);
if (review == null) {
throw new RuntimeException("审核记录不存在,ID: " + reviewId);
}
if ("PENDING".equals(review.getReviewResult())) {
throw new RuntimeException("待审核的记录不能撤回");
}
// 重置审核状态
review.setReviewResult("PENDING");
review.setReviewOpinion("撤回原因: " + reason);
review.setReviewTime(null);
review.setReviewScore(null);
boolean flag = baseMapper.updateById(review) > 0;
// 更新申请状态为审核中
if (flag) {
updateApplicationStatus(review.getApplicationId(), "REVIEWING", review.getReviewLevel());
}
return flag;
}
/**
* 查询某个申请的最新审核记录
*/
@Override
public JcbtScholarshipReviewVo queryLatestReviewByApplicationId(Long applicationId) {
return baseMapper.selectLatestReviewByApplicationId(applicationId);
}
/**
* 查询某个申请的指定级别审核记录
*/
@Override
public JcbtScholarshipReviewVo queryReviewByApplicationAndLevel(Long applicationId, String reviewLevel) {
return baseMapper.selectReviewByApplicationAndLevel(applicationId, reviewLevel);
}
/**
* 统计审核数量
*/
@Override
public Map<String, Long> countReviewsByCondition(Long reviewerId, String reviewLevel,
String reviewResult, Long batchId) {
Map<String, Long> result = new HashMap<>();
// 待审核数量
Long pendingCount = baseMapper.countReviewsByCondition(reviewerId, reviewLevel, "PENDING", batchId);
result.put("pending", pendingCount);
// 已通过数量
Long approvedCount = baseMapper.countReviewsByCondition(reviewerId, reviewLevel, "APPROVED", batchId);
result.put("approved", approvedCount);
// 已拒绝数量
Long rejectedCount = baseMapper.countReviewsByCondition(reviewerId, reviewLevel, "REJECTED", batchId);
result.put("rejected", rejectedCount);
// 总数量
Long totalCount = baseMapper.countReviewsByCondition(reviewerId, reviewLevel, null, batchId);
result.put("total", totalCount);
return result;
}
/**
* 获取下一级审核人员列表
*/
@Override
public List<Long> getNextReviewers(Long applicationId, String currentLevel) {
return baseMapper.selectNextReviewers(applicationId, currentLevel);
}
/**
* 审核流程推进
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean advanceReviewProcess(Long applicationId, String currentLevel, String reviewResult,
String reviewOpinion, Double reviewScore) {
// 获取当前级别的审核记录
JcbtScholarshipReviewVo currentReview = queryReviewByApplicationAndLevel(applicationId, currentLevel);
if (currentReview == null) {
throw new RuntimeException("未找到当前级别的审核记录");
}
// 提交当前审核结果
Long nextReviewerId = null;
if ("APPROVED".equals(reviewResult)) {
List<Long> nextReviewers = getNextReviewers(applicationId, currentLevel);
if (CollUtil.isNotEmpty(nextReviewers)) {
nextReviewerId = nextReviewers.get(0); // 选择第一个审核人
}
}
return submitReview(currentReview.getId(), reviewResult, reviewOpinion, reviewScore, nextReviewerId);
}
/**
* 检查用户审核权限
*/
@Override
public Boolean checkReviewPermission(Long reviewerId, String reviewLevel, Long applicationId) {
// 这里可以根据实际业务需求实现权限检查逻辑
// 比如检查用户角色、部门权限等
return true;
}
/**
* 获取审核统计信息
*/
@Override
public Map<String, Object> getReviewStatistics(Long reviewerId, String reviewLevel, Long batchId) {
Map<String, Object> statistics = new HashMap<>();
// 获取审核数量统计
Map<String, Long> counts = countReviewsByCondition(reviewerId, reviewLevel, null, batchId);
statistics.putAll(counts);
// 计算审核效率
Long total = counts.get("total");
Long pending = counts.get("pending");
if (total > 0) {
double efficiency = ((double) (total - pending) / total) * 100;
statistics.put("efficiency", Math.round(efficiency * 100.0) / 100.0);
} else {
statistics.put("efficiency", 0.0);
}
return statistics;
}
/**
* 更新申请状态
*/
private void updateApplicationStatus(Long applicationId, String reviewResult, String reviewLevel) {
JcbtScholarshipApplication application = applicationMapper.selectById(applicationId);
if (application == null) {
return;
}
String newStatus = application.getCurrentStatus();
switch (reviewResult) {
case "APPROVED":
if ("FINAL".equals(reviewLevel)) {
newStatus = "APPROVED";
} else {
newStatus = "REVIEWING";
}
break;
case "REJECTED":
newStatus = "REJECTED";
break;
case "RETURNED":
newStatus = "RETURNED";
break;
default:
newStatus = "REVIEWING";
break;
}
application.setCurrentStatus(newStatus);
applicationMapper.updateById(application);
}
/**
* 创建下一级审核任务
*/
private void createNextLevelReview(Long applicationId, String currentLevel, Long nextReviewerId) {
String nextLevel = getNextReviewLevel(currentLevel);
if (StringUtils.isNotBlank(nextLevel)) {
// 这里可以查询下一级审核人员的姓名
String nextReviewerName = "系统分配"; // 实际应该查询用户表获取姓名
createReviewTask(applicationId, nextLevel, nextReviewerId, nextReviewerName, null);
}
}
/**
* 获取下一个审核级别
*/
private String getNextReviewLevel(String currentLevel) {
switch (currentLevel) {
case "DEPARTMENT":
return "SCHOOL";
case "SCHOOL":
return "FINANCE";
case "FINANCE":
return "FINAL";
default:
return null;
}
}
}
@@ -0,0 +1,234 @@
package org.dromara.jcbt.service.impl;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.dromara.jcbt.domain.bo.JcbtScholarshipTypeBo;
import org.dromara.jcbt.domain.vo.JcbtScholarshipTypeVo;
import org.dromara.jcbt.domain.JcbtScholarshipType;
import org.dromara.jcbt.mapper.JcbtScholarshipTypeMapper;
import org.dromara.jcbt.service.IJcbtScholarshipTypeService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 奖学金类型Service业务层处理
*
* @author ruoyi
* @date 2025-01-27
*/
@RequiredArgsConstructor
@Service
public class JcbtScholarshipTypeServiceImpl implements IJcbtScholarshipTypeService {
private final JcbtScholarshipTypeMapper baseMapper;
/**
* 查询奖学金类型
*/
@Override
public JcbtScholarshipTypeVo queryById(Long id){
JcbtScholarshipTypeVo vo = baseMapper.selectVoById(id);
if (vo != null) {
// 临时设置默认兼得类型,等数据库字段添加后移除此逻辑
if (vo.getCompatibilityType() == null || vo.getCompatibilityType().trim().isEmpty()) {
vo.setCompatibilityType("COMPATIBLE");
}
}
return vo;
}
/**
* 查询奖学金类型列表
*/
@Override
public TableDataInfo<JcbtScholarshipTypeVo> queryPageList(JcbtScholarshipTypeBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<JcbtScholarshipType> lqw = buildQueryWrapper(bo);
Page<JcbtScholarshipTypeVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
// 临时设置默认兼得类型,等数据库字段添加后移除此逻辑
if (result.getRecords() != null) {
result.getRecords().forEach(vo -> {
if (vo.getCompatibilityType() == null || vo.getCompatibilityType().trim().isEmpty()) {
vo.setCompatibilityType("COMPATIBLE");
}
});
}
return TableDataInfo.build(result);
}
/**
* 查询奖学金类型列表
*/
@Override
public List<JcbtScholarshipTypeVo> queryList(JcbtScholarshipTypeBo bo) {
LambdaQueryWrapper<JcbtScholarshipType> lqw = buildQueryWrapper(bo);
List<JcbtScholarshipTypeVo> list = baseMapper.selectVoList(lqw);
// 临时设置默认兼得类型,等数据库字段添加后移除此逻辑
if (list != null) {
list.forEach(vo -> {
if (vo.getCompatibilityType() == null || vo.getCompatibilityType().trim().isEmpty()) {
vo.setCompatibilityType("COMPATIBLE");
}
});
}
return list;
}
private LambdaQueryWrapper<JcbtScholarshipType> buildQueryWrapper(JcbtScholarshipTypeBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<JcbtScholarshipType> lqw = Wrappers.lambdaQuery();
lqw.eq(StringUtils.isNotBlank(bo.getTypeCode()), JcbtScholarshipType::getTypeCode, bo.getTypeCode());
lqw.like(StringUtils.isNotBlank(bo.getTypeName()), JcbtScholarshipType::getTypeName, bo.getTypeName());
lqw.eq(StringUtils.isNotBlank(bo.getTypeCategory()), JcbtScholarshipType::getTypeCategory, bo.getTypeCategory());
lqw.eq(StringUtils.isNotBlank(bo.getLevelType()), JcbtScholarshipType::getLevelType, bo.getLevelType());
lqw.eq(StringUtils.isNotBlank(bo.getCompatibilityType()), JcbtScholarshipType::getCompatibilityType, bo.getCompatibilityType());
lqw.eq(bo.getAwardAmount() != null, JcbtScholarshipType::getAwardAmount, bo.getAwardAmount());
lqw.like(StringUtils.isNotBlank(bo.getDescription()), JcbtScholarshipType::getDescription, bo.getDescription());
lqw.like(StringUtils.isNotBlank(bo.getApplicationGuide()), JcbtScholarshipType::getApplicationGuide, bo.getApplicationGuide());
lqw.eq(bo.getStatus() != null, JcbtScholarshipType::getStatus, bo.getStatus());
lqw.eq(bo.getIsSystem() != null, JcbtScholarshipType::getIsSystem, bo.getIsSystem());
lqw.orderByAsc(JcbtScholarshipType::getSortOrder);
lqw.orderByDesc(JcbtScholarshipType::getCreateTime);
return lqw;
}
/**
* 新增奖学金类型
*/
@Override
public Boolean insertByBo(JcbtScholarshipTypeBo bo) {
JcbtScholarshipType add = MapstructUtils.convert(bo, JcbtScholarshipType.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改奖学金类型
*/
@Override
public Boolean updateByBo(JcbtScholarshipTypeBo bo) {
JcbtScholarshipType update = MapstructUtils.convert(bo, JcbtScholarshipType.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(JcbtScholarshipType entity){
// 校验奖学金名称是否重复
if (!checkTypeNameUnique(entity.getTypeName(), entity.getId())) {
throw new RuntimeException("新增奖学金类型'" + entity.getTypeName() + "'失败,奖学金名称已存在");
}
}
/**
* 批量删除奖学金类型
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
// TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
/**
* 根据类型名称查询奖学金类型
*/
@Override
public JcbtScholarshipTypeVo queryByTypeName(String typeName) {
return baseMapper.selectByTypeName(typeName);
}
/**
* 根据类别查询奖学金类型列表
*/
@Override
public List<JcbtScholarshipTypeVo> queryByCategory(String typeCategory) {
return baseMapper.selectByCategory(typeCategory);
}
/**
* 查询启用状态的奖学金类型列表
*/
@Override
public List<JcbtScholarshipTypeVo> queryActiveTypes() {
return baseMapper.selectActiveTypes();
}
/**
* 检查奖学金名称是否重复
*/
@Override
public boolean checkTypeNameUnique(String typeName, Long id) {
return !baseMapper.checkTypeNameExists(typeName, id);
}
/**
* 批量更新排序号
*/
@Override
public Boolean batchUpdateSortOrder(List<JcbtScholarshipTypeBo> scholarshipTypes) {
List<JcbtScholarshipType> entities = MapstructUtils.convert(scholarshipTypes, JcbtScholarshipType.class);
baseMapper.batchUpdateSortOrder(entities);
return true;
}
/**
* 根据兼得类型查询相关奖学金类型
*/
@Override
public List<JcbtScholarshipTypeVo> queryByCompatibilityType(String compatibilityType) {
return baseMapper.selectByCompatibilityType(compatibilityType);
}
/**
* 启用/停用奖学金类型
*/
@Override
public Boolean changeStatus(Long id, Integer status) {
JcbtScholarshipType scholarshipType = new JcbtScholarshipType();
scholarshipType.setId(id);
scholarshipType.setStatus(status);
return baseMapper.updateById(scholarshipType) > 0;
}
/**
* 导出奖学金类型数据
*/
@Override
public List<JcbtScholarshipTypeVo> queryExportList(JcbtScholarshipTypeBo bo) {
LambdaQueryWrapper<JcbtScholarshipType> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
/**
* 获取奖学金类型选项列表
*/
@Override
public List<JcbtScholarshipTypeVo> queryOptions() {
LambdaQueryWrapper<JcbtScholarshipType> lqw = Wrappers.lambdaQuery();
lqw.eq(JcbtScholarshipType::getStatus, 1);
lqw.orderByAsc(JcbtScholarshipType::getSortOrder);
lqw.select(JcbtScholarshipType::getId, JcbtScholarshipType::getTypeName,
JcbtScholarshipType::getTypeCategory, JcbtScholarshipType::getAwardAmount);
return baseMapper.selectVoList(lqw);
}
}
@@ -0,0 +1,36 @@
# 项目相关配置
ruoyi:
# 名称
name: ruoyi-jcbt
# 版本
version: ${ruoyi-vue-plus.version}
# 版权年份
copyrightYear: 2025
# 实例演示开关
demoEnabled: true
# 获取ip地址开关
addressEnabled: false
# 开发环境配置
server:
# 服务器的HTTP端口,默认为8080
port: 9205
servlet:
# 应用的访问路径
context-path: /
tomcat:
# tomcat的URI编码
uri-encoding: UTF-8
# 连接数满后的排队数,默认为100
accept-count: 1000
threads:
# tomcat最大线程数,默认为200
max: 800
# Tomcat启动初始化的线程数,默认值10
min-spare: 100
# 日志配置
logging:
level:
org.dromara.jcbt: debug
org.springframework: warn
Whitespace-only changes.
@@ -0,0 +1,316 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.jcbt.mapper.JcbtScholarshipQuotaMapper">
<resultMap type="org.dromara.jcbt.domain.vo.JcbtScholarshipQuotaVo" id="JcbtScholarshipQuotaResult">
<result property="id" column="id" />
<result property="batchId" column="batch_id" />
<result property="batchName" column="batch_name" />
<result property="batchCode" column="batch_code" />
<result property="academicYear" column="academic_year" />
<result property="semester" column="semester" />
<result property="scholarshipTypeId" column="scholarship_type_id" />
<result property="scholarshipTypeName" column="scholarship_type_name" />
<result property="scholarshipLevel" column="scholarship_level" />
<result property="allocationLevel" column="allocation_level" />
<result property="allocationLevelName" column="allocation_level_name" />
<result property="targetDeptId" column="target_dept_id" />
<result property="targetDeptName" column="target_dept_name" />
<result property="parentQuotaId" column="parent_quota_id" />
<result property="parentDeptName" column="parent_dept_name" />
<result property="totalQuota" column="total_quota" />
<result property="usedQuota" column="used_quota" />
<result property="reservedQuota" column="reserved_quota" />
<result property="availableQuota" column="available_quota" />
<result property="allocationRule" column="allocation_rule" />
<result property="allocationBasis" column="allocation_basis" />
<result property="allocationMethod" column="allocation_method" />
<result property="allocationMethodName" column="allocation_method_name"/>
<result property="isAdjustable" column="is_adjustable" />
<result property="isLocked" column="is_locked" />
<result property="status" column="status" />
<result property="statusName" column="status_name" />
<result property="remark" column="remark" />
<result property="tenantId" column="tenant_id" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectJcbtScholarshipQuotaVo">
select q.id,
q.batch_id,
b.batch_name,
b.batch_code,
b.academic_year,
b.semester,
q.scholarship_type_id,
st.type_name as scholarship_type_name,
st.level_type as scholarship_level,
q.allocation_level,
CASE q.allocation_level
WHEN 'UNIVERSITY' THEN '全校'
WHEN 'COLLEGE' THEN '学院'
WHEN 'MAJOR' THEN '专业'
WHEN 'CLASS' THEN '班级'
ELSE q.allocation_level
END as allocation_level_name,
q.target_dept_id,
d.dept_name as target_dept_name,
q.parent_quota_id,
pd.dept_name as parent_dept_name,
q.total_quota,
q.used_quota,
q.reserved_quota,
q.available_quota,
q.allocation_rule,
q.allocation_basis,
q.allocation_method,
CASE q.allocation_method
WHEN 'MANUAL' THEN '手动分配'
WHEN 'AUTO' THEN '自动分配'
WHEN 'PROPORTIONAL' THEN '按比例分配'
ELSE q.allocation_method
END as allocation_method_name,
q.is_adjustable,
q.is_locked,
q.status,
CASE q.status
WHEN 'ACTIVE' THEN '生效'
WHEN 'INACTIVE' THEN '失效'
WHEN 'PENDING' THEN '待审核'
ELSE q.status
END as status_name,
q.remark,
q.tenant_id,
q.create_by,
q.create_time,
q.update_by,
q.update_time
from jcbt_scholarship_quota q
left join jcbt_scholarship_batch b on q.batch_id = b.id
left join jcbt_scholarship_type st on q.scholarship_type_id = st.id
left join sys_dept d on q.target_dept_id = d.dept_id
left join jcbt_scholarship_quota pq on q.parent_quota_id = pq.id
left join sys_dept pd on pq.target_dept_id = pd.dept_id
where q.deleted = 0
</sql>
<!-- 分页查询奖学金名额分配列表 -->
<select id="selectQuotaPageList" parameterType="org.dromara.jcbt.domain.bo.JcbtScholarshipQuotaBo" resultMap="JcbtScholarshipQuotaResult">
<include refid="selectJcbtScholarshipQuotaVo"/>
<if test="bo.batchId != null">
and q.batch_id = #{bo.batchId}
</if>
<if test="bo.scholarshipTypeId != null">
and q.scholarship_type_id = #{bo.scholarshipTypeId}
</if>
<if test="bo.allocationLevel != null and bo.allocationLevel != ''">
and q.allocation_level = #{bo.allocationLevel}
</if>
<if test="bo.targetDeptId != null">
and q.target_dept_id = #{bo.targetDeptId}
</if>
<if test="bo.parentQuotaId != null">
and q.parent_quota_id = #{bo.parentQuotaId}
</if>
<if test="bo.allocationMethod != null and bo.allocationMethod != ''">
and q.allocation_method = #{bo.allocationMethod}
</if>
<if test="bo.isAdjustable != null">
and q.is_adjustable = #{bo.isAdjustable}
</if>
<if test="bo.isLocked != null">
and q.is_locked = #{bo.isLocked}
</if>
<if test="bo.status != null and bo.status != ''">
and q.status = #{bo.status}
</if>
order by q.allocation_level, q.target_dept_id, q.scholarship_type_id
</select>
<!-- 查询奖学金名额分配列表 -->
<select id="selectQuotaList" parameterType="org.dromara.jcbt.domain.bo.JcbtScholarshipQuotaBo" resultMap="JcbtScholarshipQuotaResult">
<include refid="selectJcbtScholarshipQuotaVo"/>
<if test="bo.batchId != null">
and q.batch_id = #{bo.batchId}
</if>
<if test="bo.scholarshipTypeId != null">
and q.scholarship_type_id = #{bo.scholarshipTypeId}
</if>
<if test="bo.allocationLevel != null and bo.allocationLevel != ''">
and q.allocation_level = #{bo.allocationLevel}
</if>
<if test="bo.targetDeptId != null">
and q.target_dept_id = #{bo.targetDeptId}
</if>
<if test="bo.parentQuotaId != null">
and q.parent_quota_id = #{bo.parentQuotaId}
</if>
<if test="bo.allocationMethod != null and bo.allocationMethod != ''">
and q.allocation_method = #{bo.allocationMethod}
</if>
<if test="bo.isAdjustable != null">
and q.is_adjustable = #{bo.isAdjustable}
</if>
<if test="bo.isLocked != null">
and q.is_locked = #{bo.isLocked}
</if>
<if test="bo.status != null and bo.status != ''">
and q.status = #{bo.status}
</if>
order by q.allocation_level, q.target_dept_id, q.scholarship_type_id
</select>
<!-- 查询指定批次的名额分配列表 -->
<select id="selectQuotaListByBatchId" parameterType="Long" resultMap="JcbtScholarshipQuotaResult">
<include refid="selectJcbtScholarshipQuotaVo"/>
and q.batch_id = #{batchId}
order by q.allocation_level, q.target_dept_id, q.scholarship_type_id
</select>
<!-- 查询指定批次和奖学金类型的名额分配 -->
<select id="selectQuotaListByBatchAndType" resultMap="JcbtScholarshipQuotaResult">
<include refid="selectJcbtScholarshipQuotaVo"/>
and q.batch_id = #{batchId}
and q.scholarship_type_id = #{scholarshipTypeId}
order by q.allocation_level, q.target_dept_id
</select>
<!-- 查询指定部门的名额分配统计 -->
<select id="selectQuotaSummaryByDept" resultMap="JcbtScholarshipQuotaResult">
select
sum(q.total_quota) as total_quota,
sum(q.used_quota) as used_quota,
sum(q.reserved_quota) as reserved_quota,
sum(q.available_quota) as available_quota,
count(*) as allocation_count
from jcbt_scholarship_quota q
where q.deleted = 0
and q.target_dept_id = #{targetDeptId}
and q.batch_id = #{batchId}
</select>
<!-- 查询子级名额分配列表 -->
<select id="selectQuotaListByParentId" parameterType="Long" resultMap="JcbtScholarshipQuotaResult">
<include refid="selectJcbtScholarshipQuotaVo"/>
and q.parent_quota_id = #{parentQuotaId}
order by q.target_dept_id
</select>
<!-- 批量更新名额使用情况 -->
<update id="batchUpdateQuotaUsage" parameterType="java.util.List">
<foreach collection="quotaList" item="quota" separator=";">
update jcbt_scholarship_quota
set used_quota = #{quota.usedQuota},
available_quota = #{quota.availableQuota},
update_time = now()
where id = #{quota.id}
</foreach>
</update>
<!-- 检查名额分配是否存在冲突 -->
<select id="checkQuotaConflict" resultType="int">
select count(*)
from jcbt_scholarship_quota
where deleted = 0
and batch_id = #{batchId}
and scholarship_type_id = #{scholarshipTypeId}
and target_dept_id = #{targetDeptId}
<if test="excludeId != null">
and id != #{excludeId}
</if>
</select>
<!-- 查询名额分配树形结构 -->
<select id="selectQuotaTreeByBatchAndType" resultMap="JcbtScholarshipQuotaResult">
WITH RECURSIVE quota_tree AS (
-- 查询顶级节点(没有父级的名额分配)
SELECT q.*, 0 as level
FROM jcbt_scholarship_quota q
WHERE q.deleted = 0
AND q.batch_id = #{batchId}
AND q.scholarship_type_id = #{scholarshipTypeId}
AND q.parent_quota_id IS NULL
UNION ALL
-- 递归查询子节点
SELECT q.*, qt.level + 1
FROM jcbt_scholarship_quota q
INNER JOIN quota_tree qt ON q.parent_quota_id = qt.id
WHERE q.deleted = 0
)
SELECT qt.id,
qt.batch_id,
b.batch_name,
b.batch_code,
b.academic_year,
b.semester,
qt.scholarship_type_id,
st.type_name as scholarship_type_name,
st.level_type as scholarship_level,
qt.allocation_level,
CASE qt.allocation_level
WHEN 'UNIVERSITY' THEN '全校'
WHEN 'COLLEGE' THEN '学院'
WHEN 'MAJOR' THEN '专业'
WHEN 'CLASS' THEN '班级'
ELSE qt.allocation_level
END as allocation_level_name,
qt.target_dept_id,
d.dept_name as target_dept_name,
qt.parent_quota_id,
pd.dept_name as parent_dept_name,
qt.total_quota,
qt.used_quota,
qt.reserved_quota,
qt.available_quota,
qt.allocation_rule,
qt.allocation_basis,
qt.allocation_method,
CASE qt.allocation_method
WHEN 'MANUAL' THEN '手动分配'
WHEN 'AUTO' THEN '自动分配'
WHEN 'PROPORTIONAL' THEN '按比例分配'
ELSE qt.allocation_method
END as allocation_method_name,
qt.is_adjustable,
qt.is_locked,
qt.status,
CASE qt.status
WHEN 'ACTIVE' THEN '生效'
WHEN 'INACTIVE' THEN '失效'
WHEN 'PENDING' THEN '待审核'
ELSE qt.status
END as status_name,
qt.remark,
qt.tenant_id,
qt.create_by,
qt.create_time,
qt.update_by,
qt.update_time,
qt.level
FROM quota_tree qt
LEFT JOIN jcbt_scholarship_batch b ON qt.batch_id = b.id
LEFT JOIN jcbt_scholarship_type st ON qt.scholarship_type_id = st.id
LEFT JOIN sys_dept d ON qt.target_dept_id = d.dept_id
LEFT JOIN jcbt_scholarship_quota pq ON qt.parent_quota_id = pq.id
LEFT JOIN sys_dept pd ON pq.target_dept_id = pd.dept_id
ORDER BY qt.level, qt.target_dept_id
</select>
<!-- 查询班级级别的名额分配 -->
<select id="selectClassQuota" resultMap="JcbtScholarshipQuotaResult">
<include refid="selectJcbtScholarshipQuotaVo"/>
and q.allocation_level = 'CLASS'
and q.target_dept_id = #{classId}
and q.scholarship_type_id = #{scholarshipTypeId}
and q.batch_id = #{batchId}
and q.status = 'ACTIVE'
</select>
</mapper>
@@ -0,0 +1,246 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.jcbt.mapper.JcbtPovertyApplicationMapper">
<resultMap type="org.dromara.jcbt.domain.vo.JcbtPovertyApplicationVo" id="JcbtPovertyApplicationResult">
<result property="id" column="id"/>
<result property="applicationNo" column="application_no"/>
<result property="academicYear" column="academic_year"/>
<result property="term" column="term"/>
<result property="studentId" column="student_id"/>
<result property="studentNo" column="student_no"/>
<result property="studentName" column="student_name"/>
<result property="gender" column="gender"/>
<result property="collegeId" column="college_id"/>
<result property="collegeName" column="college_name"/>
<result property="majorId" column="major_id"/>
<result property="majorName" column="major_name"/>
<result property="classId" column="class_id"/>
<result property="className" column="class_name"/>
<result property="recognitionGroup" column="recognition_group"/>
<result property="recognitionTypeId" column="recognition_type_id"/>
<result property="recognitionTypeCode" column="recognition_type_code"/>
<result property="recognitionTypeName" column="recognition_type_name"/>
<result property="assistanceTypeIds" column="assistance_type_ids"/>
<result property="assistanceTypeNames" column="assistance_type_names"/>
<result property="familyEconomySummary" column="family_economy_summary"/>
<result property="attachApplicationFormUrl" column="attach_application_form_url"/>
<result property="attachApplicationFormId" column="attach_application_form_id"/>
<result property="attachSurveyFormUrl" column="attach_survey_form_url"/>
<result property="attachSurveyFormId" column="attach_survey_form_id"/>
<result property="status" column="status"/>
<result property="submitterId" column="submitter_id"/>
<result property="submitterName" column="submitter_name"/>
<result property="submitTime" column="submit_time"/>
<result property="auditorId" column="auditor_id"/>
<result property="auditorName" column="auditor_name"/>
<result property="auditTime" column="audit_time"/>
<result property="auditOpinion" column="audit_opinion"/>
<result property="remark" column="remark"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
</resultMap>
<sql id="selectJcbtPovertyApplicationVo">
select id, application_no, academic_year, term, student_id, student_no, student_name, gender,
college_id, college_name, major_id, major_name, class_id, class_name, recognition_group,
recognition_type_id, recognition_type_code, recognition_type_name, assistance_type_ids,
assistance_type_names, family_economy_summary, attach_application_form_url, attach_application_form_id,
attach_survey_form_url, attach_survey_form_id, status, submitter_id, submitter_name, submit_time,
auditor_id, auditor_name, audit_time, audit_opinion, remark, create_by, create_time, update_by, update_time
from jcbt_poverty_application
</sql>
<select id="selectApplicationList" parameterType="org.dromara.jcbt.domain.JcbtPovertyApplication" resultMap="JcbtPovertyApplicationResult">
<include refid="selectJcbtPovertyApplicationVo"/>
<where>
and deleted = 0
<if test="applicationNo != null and applicationNo != ''">
and application_no like concat('%', #{applicationNo}, '%')
</if>
<if test="academicYear != null and academicYear != ''">
and academic_year = #{academicYear}
</if>
<if test="term != null">
and term = #{term}
</if>
<if test="studentNo != null and studentNo != ''">
and student_no like concat('%', #{studentNo}, '%')
</if>
<if test="studentName != null and studentName != ''">
and student_name like concat('%', #{studentName}, '%')
</if>
<if test="collegeId != null">
and college_id = #{collegeId}
</if>
<if test="majorId != null">
and major_id = #{majorId}
</if>
<if test="classId != null">
and class_id = #{classId}
</if>
<if test="recognitionGroup != null and recognitionGroup != ''">
and recognition_group = #{recognitionGroup}
</if>
<if test="recognitionTypeId != null">
and recognition_type_id = #{recognitionTypeId}
</if>
<if test="status != null and status != ''">
and status = #{status}
</if>
<if test="submitterId != null">
and submitter_id = #{submitterId}
</if>
<if test="params.beginTime != null and params.beginTime != ''">
and create_time &gt;= #{params.beginTime}
</if>
<if test="params.endTime != null and params.endTime != ''">
and create_time &lt;= #{params.endTime}
</if>
</where>
order by create_time desc
</select>
<select id="selectByApplicationNo" resultMap="JcbtPovertyApplicationResult">
<include refid="selectJcbtPovertyApplicationVo"/>
where application_no = #{applicationNo} and deleted = 0
</select>
<select id="checkStudentApplicationExists" resultType="int">
select count(*)
from jcbt_poverty_application
where student_id = #{studentId}
and academic_year = #{academicYear}
and recognition_type_id = #{recognitionTypeId}
and deleted = 0
<if test="excludeId != null">
and id != #{excludeId}
</if>
</select>
<select id="selectApplicationListByTeacher" resultMap="JcbtPovertyApplicationResult">
<include refid="selectJcbtPovertyApplicationVo"/>
<where>
and deleted = 0
and submitter_id = #{teacherId}
<if test="application.applicationNo != null and application.applicationNo != ''">
and application_no like concat('%', #{application.applicationNo}, '%')
</if>
<if test="application.academicYear != null and application.academicYear != ''">
and academic_year = #{application.academicYear}
</if>
<if test="application.term != null">
and term = #{application.term}
</if>
<if test="application.studentNo != null and application.studentNo != ''">
and student_no like concat('%', #{application.studentNo}, '%')
</if>
<if test="application.studentName != null and application.studentName != ''">
and student_name like concat('%', #{application.studentName}, '%')
</if>
<if test="application.classId != null">
and class_id = #{application.classId}
</if>
<if test="application.recognitionGroup != null and application.recognitionGroup != ''">
and recognition_group = #{application.recognitionGroup}
</if>
<if test="application.status != null and application.status != ''">
and status = #{application.status}
</if>
</where>
order by create_time desc
</select>
<select id="selectPendingApplicationList" parameterType="org.dromara.jcbt.domain.JcbtPovertyApplication" resultMap="JcbtPovertyApplicationResult">
<include refid="selectJcbtPovertyApplicationVo"/>
<where>
and deleted = 0
and status = 'waiting'
<if test="applicationNo != null and applicationNo != ''">
and application_no like concat('%', #{applicationNo}, '%')
</if>
<if test="academicYear != null and academicYear != ''">
and academic_year = #{academicYear}
</if>
<if test="studentNo != null and studentNo != ''">
and student_no like concat('%', #{studentNo}, '%')
</if>
<if test="studentName != null and studentName != ''">
and student_name like concat('%', #{studentName}, '%')
</if>
<if test="collegeId != null">
and college_id = #{collegeId}
</if>
<if test="majorId != null">
and major_id = #{majorId}
</if>
<if test="classId != null">
and class_id = #{classId}
</if>
<if test="recognitionGroup != null and recognitionGroup != ''">
and recognition_group = #{recognitionGroup}
</if>
<if test="recognitionTypeId != null">
and recognition_type_id = #{recognitionTypeId}
</if>
</where>
order by submit_time asc
</select>
<select id="selectApplicationStatistics" resultMap="JcbtPovertyApplicationResult">
select status, count(*) as id
from jcbt_poverty_application
<where>
and deleted = 0
<if test="teacherId != null">
and submitter_id = #{teacherId}
</if>
</where>
group by status
</select>
<!-- 获取当前用户班级信息 -->
<select id="selectCurrentUserClasses" resultType="java.util.Map">
select
c.id as classId,
c.class_name as className,
c.grade,
c.major_name as majorName,
c.college_name as collegeName
from xg_class_msg c
inner join xg_class_teacher_counselor_rel tcr on c.id = tcr.class_id
where tcr.teacher_id = #{userId}
and c.deleted = 0
and tcr.deleted = 0
and tcr.teacher_type in ('class_teacher', 'counselor')
and (tcr.end_date is null or tcr.end_date > now())
order by c.grade desc, c.class_name asc
</select>
<!-- 获取班级学生列表 -->
<select id="selectClassStudents" resultType="java.util.Map">
select
s.id as studentId,
s.student_no as studentNo,
s.name as studentName,
s.gender,
s.phone as phoneNumber,
c.college_id as collegeId,
c.college_name as collegeName,
c.major_id as majorId,
c.major_name as majorName,
c.class_name as className,
c.grade
from xg_student_msg s
left join xg_class_msg c on s.class_id = c.id
where s.class_id = #{classId}
and s.deleted = 0
and s.student_status = '1'
and (c.deleted is null or c.deleted = 0)
order by s.student_no asc
</select>
</mapper>
@@ -0,0 +1,167 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.jcbt.mapper.JcbtScholarshipApplicationMapper">
<!-- 结果映射(包含基础字段) -->
<resultMap type="org.dromara.jcbt.domain.vo.JcbtScholarshipApplicationVo" id="JcbtScholarshipApplicationResult">
<result property="id" column="id"/>
<result property="batchId" column="batch_id"/>
<result property="batchName" column="batch_name"/>
<result property="scholarshipTypeId" column="scholarship_type_id"/>
<result property="scholarshipTypeName" column="scholarship_type_name"/>
<result property="applicationNo" column="application_no"/>
<result property="studentNo" column="student_no"/>
<result property="studentName" column="student_name"/>
<result property="studentId" column="student_id"/>
<result property="deptId" column="dept_id"/>
<result property="deptName" column="dept_name"/>
<result property="majorId" column="major_id"/>
<result property="classId" column="class_id"/>
<result property="className" column="class_name"/>
<result property="applicationType" column="application_type"/>
<result property="applyReason" column="apply_reason"/>
<result property="selfEvaluation" column="self_evaluation"/>
<result property="currentStatus" column="current_status"/>
<result property="status" column="current_status"/>
<result property="submitTime" column="submit_time"/>
<result property="calculatedScore" column="calculated_score"/>
<result property="finalScore" column="final_score"/>
<result property="rankingInDept" column="ranking_in_dept"/>
<result property="rankingInMajor" column="ranking_in_major"/>
<result property="tenantId" column="tenant_id"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
</resultMap>
<!-- 基础查询SQL -->
<sql id="selectJcbtScholarshipApplicationVo">
select a.id, a.application_no, a.batch_id, b.batch_name, a.scholarship_type_id, st.type_name as scholarship_type_name,
a.student_no, a.student_name, a.student_id, a.dept_id, d.dept_name, a.major_id, a.class_id, c.class_name,
a.application_type, a.current_status, a.apply_reason, a.self_evaluation,
a.calculated_score, a.final_score, a.ranking_in_dept, a.ranking_in_major,
a.submit_time, a.tenant_id,
a.create_by, a.create_time, a.update_by, a.update_time
from jcbt_scholarship_application a
left join jcbt_scholarship_batch b on a.batch_id = b.id
left join jcbt_scholarship_type st on a.scholarship_type_id = st.id
left join xg_class_msg c on a.class_id = c.id
left join sys_dept d on a.dept_id = d.dept_id
</sql>
<!-- 分页查询(标准模板) -->
<select id="selectJcbtScholarshipApplicationPage" resultMap="JcbtScholarshipApplicationResult">
<include refid="selectJcbtScholarshipApplicationVo"/>
<where>
a.deleted = 0
<if test="ew != null and ew.sqlSegment != null and ew.sqlSegment != ''">
AND ${ew.sqlSegment}
</if>
</where>
ORDER BY a.create_time DESC
</select>
<!-- 查询班主任负责班级的申请记录列表(已删除applicantId字段,需重新设计) -->
<!--
<select id="selectApplicationsByApplicant" resultMap="JcbtScholarshipApplicationResult">
<include refid="selectJcbtScholarshipApplicationVo"/>
<where>
a.deleted = 0
AND a.applicant_id = #{applicantId}
<if test="batchId != null">
AND a.batch_id = #{batchId}
</if>
</where>
ORDER BY a.create_time DESC
</select>
-->
<!-- 查询班级的申请记录列表 -->
<select id="selectApplicationsByClass" resultMap="JcbtScholarshipApplicationResult">
<include refid="selectJcbtScholarshipApplicationVo"/>
<where>
a.deleted = 0
AND a.class_id = #{classId}
<if test="batchId != null">
AND a.batch_id = #{batchId}
</if>
</where>
ORDER BY a.create_time DESC
</select>
<!-- 查询待审核的申请记录列表 -->
<select id="selectPendingApplications" resultMap="JcbtScholarshipApplicationResult">
<include refid="selectJcbtScholarshipApplicationVo"/>
<where>
a.deleted = 0
<if test="reviewerId != null">
AND a.reviewer_id = #{reviewerId}
</if>
<if test="status != null and status != ''">
AND a.status = #{status}
</if>
</where>
ORDER BY a.submit_time DESC
</select>
<!-- 检查学生在指定批次中是否已有申请记录 -->
<select id="checkStudentApplication" resultType="int">
SELECT COUNT(1)
FROM jcbt_scholarship_application
WHERE deleted = 0
AND student_id = #{studentId}
AND batch_id = #{batchId}
<if test="scholarshipTypeId != null">
AND scholarship_type_id = #{scholarshipTypeId}
</if>
</select>
<!-- 获取申请统计数据 -->
<select id="selectApplicationStatistics" resultMap="JcbtScholarshipApplicationResult">
SELECT
a.scholarship_type_id,
st.type_name as scholarship_type_name,
a.current_status,
COUNT(*) as total_count,
a.dept_id,
d.dept_name
FROM jcbt_scholarship_application a
LEFT JOIN jcbt_scholarship_type st ON a.scholarship_type_id = st.id
LEFT JOIN sys_dept d ON a.dept_id = d.dept_id
<where>
a.deleted = 0
<if test="batchId != null">
AND a.batch_id = #{batchId}
</if>
<if test="deptId != null">
AND a.dept_id = #{deptId}
</if>
</where>
GROUP BY a.scholarship_type_id, a.current_status, a.dept_id
ORDER BY a.scholarship_type_id, a.current_status
</select>
<!-- 批量更新申请状态 -->
<update id="batchUpdateStatus">
UPDATE jcbt_scholarship_application
SET status = #{status},
reviewer_id = #{reviewerId},
reviewer_name = #{reviewerName},
review_comment = #{reviewComment},
review_time = NOW(),
update_time = NOW()
WHERE id IN
<foreach collection="applicationIds" item="id" open="(" separator="," close=")">
#{id}
</foreach>
AND deleted = 0
</update>
<!-- 根据ID查询申请记录详情(包含关联信息) -->
<select id="selectByIdWithRelations" resultMap="JcbtScholarshipApplicationResult">
<include refid="selectJcbtScholarshipApplicationVo"/>
WHERE a.id = #{id} AND a.deleted = 0
</select>
</mapper>
@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.jcbt.mapper.JcbtScholarshipClassQuotaMapper">
<resultMap type="org.dromara.jcbt.domain.vo.JcbtScholarshipClassQuotaVo" id="JcbtScholarshipClassQuotaVoResult">
<result property="id" column="id" />
<result property="batchId" column="batch_id" />
<result property="scholarshipTypeId" column="scholarship_type_id" />
<result property="deptId" column="dept_id" />
<result property="classId" column="class_id" />
<result property="totalQuota" column="total_quota" />
<result property="usedQuota" column="used_quota" />
<result property="availableQuota" column="available_quota" />
<result property="status" column="status" />
<result property="remark" column="remark" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectJcbtScholarshipClassQuotaVo">
select id, batch_id, scholarship_type_id, dept_id, class_id, total_quota, used_quota, available_quota, status, remark, create_by, create_time, update_by, update_time from jcbt_scholarship_class_quota
</sql>
<!-- 查询班级可用名额 -->
<select id="selectAvailableQuota" resultMap="JcbtScholarshipClassQuotaVoResult">
<include refid="selectJcbtScholarshipClassQuotaVo"/>
where class_id = #{classId}
and scholarship_type_id = #{scholarshipTypeId}
and batch_id = #{batchId}
and status = '1'
and deleted = 0
</select>
<!-- 查询学院下所有班级的名额分配 -->
<select id="selectQuotasByDept" resultMap="JcbtScholarshipClassQuotaVoResult">
<include refid="selectJcbtScholarshipClassQuotaVo"/>
where dept_id = #{deptId}
<if test="batchId != null">
and batch_id = #{batchId}
</if>
and deleted = 0
order by class_id, scholarship_type_id
</select>
<!-- 更新名额使用情况 -->
<update id="updateQuotaUsage">
update jcbt_scholarship_class_quota
set used_quota = #{usedQuota},
available_quota = #{availableQuota},
update_time = now()
where id = #{id} and deleted = 0
</update>
<!-- 批量更新名额分配 -->
<update id="batchUpdateQuota">
<foreach collection="quotaList" item="quota" separator=";">
update jcbt_scholarship_class_quota
set total_quota = #{quota.totalQuota},
used_quota = #{quota.usedQuota},
available_quota = #{quota.availableQuota},
update_time = now()
where id = #{quota.id} and deleted = 0
</foreach>
</update>
<!-- 查询名额统计信息 -->
<select id="selectQuotaStatistics" resultMap="JcbtScholarshipClassQuotaVoResult">
select
q.scholarship_type_id,
st.type_name as scholarshipTypeName,
sum(q.total_quota) as totalQuota,
sum(q.used_quota) as usedQuota,
sum(q.available_quota) as availableQuota
from jcbt_scholarship_class_quota q
left join jcbt_scholarship_type st on q.scholarship_type_id = st.id
where q.deleted = 0
<if test="batchId != null">
and q.batch_id = #{batchId}
</if>
<if test="scholarshipTypeId != null">
and q.scholarship_type_id = #{scholarshipTypeId}
</if>
group by q.scholarship_type_id, st.type_name
order by q.scholarship_type_id
</select>
</mapper>
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.jcbt.mapper.JcbtScholarshipCompatibilityMapper">
<resultMap type="org.dromara.jcbt.domain.vo.JcbtScholarshipCompatibilityVo" id="JcbtScholarshipCompatibilityResult">
<result property="id" column="id" />
<result property="typeId1" column="type_id_1" />
<result property="typeId2" column="type_id_2" />
<result property="relationType" column="relation_type" />
<result property="priorityLevel" column="priority_level" />
<result property="description" column="description" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectJcbtScholarshipCompatibilityVo">
select id, type_id_1, type_id_2, relation_type, priority_level, description, tenant_id, create_by, create_time, update_by, update_time, deleted
from jcbt_scholarship_compatibility
</sql>
<!-- 查询与指定奖学金类型的兼得关系 -->
<select id="selectCompatibilityByTypeId" parameterType="Long" resultMap="JcbtScholarshipCompatibilityResult">
<include refid="selectJcbtScholarshipCompatibilityVo"/>
where deleted = 0
and (type_id_1 = #{scholarshipTypeId} or type_id_2 = #{scholarshipTypeId})
order by create_time desc
</select>
<!-- 检查两个奖学金类型的兼得关系 -->
<select id="selectCompatibilityByTwoTypes" resultMap="JcbtScholarshipCompatibilityResult">
<include refid="selectJcbtScholarshipCompatibilityVo"/>
where deleted = 0
and ((type_id_1 = #{typeId1} and type_id_2 = #{typeId2})
or (type_id_1 = #{typeId2} and type_id_2 = #{typeId1}))
limit 1
</select>
<!-- 批量删除指定奖学金类型的兼得关系 -->
<update id="deleteByScholarshipTypeId" parameterType="Long">
update jcbt_scholarship_compatibility
set deleted = 1, update_time = now()
where deleted = 0
and (type_id_1 = #{scholarshipTypeId} or type_id_2 = #{scholarshipTypeId})
</update>
</mapper>
@@ -0,0 +1,191 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.jcbt.mapper.JcbtScholarshipReviewMapper">
<resultMap type="org.dromara.jcbt.domain.vo.JcbtScholarshipReviewVo" id="JcbtScholarshipReviewResult">
<result property="id" column="id"/>
<result property="applicationId" column="application_id"/>
<result property="reviewLevel" column="review_level"/>
<result property="reviewerId" column="reviewer_id"/>
<result property="reviewerName" column="reviewer_name"/>
<result property="reviewResult" column="review_result"/>
<result property="reviewScore" column="review_score"/>
<result property="reviewOpinion" column="review_opinion"/>
<result property="reviewTime" column="review_time"/>
<result property="nextReviewerId" column="next_reviewer_id"/>
<result property="isFinalReview" column="is_final_review"/>
<result property="tenantId" column="tenant_id"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<!-- 扩展字段 -->
<result property="applicationNo" column="application_no"/>
<result property="studentNo" column="student_no"/>
<result property="studentName" column="student_name"/>
<result property="scholarshipTypeName" column="scholarship_type_name"/>
<result property="batchName" column="batch_name"/>
<result property="applicationStatus" column="application_status"/>
</resultMap>
<sql id="selectJcbtScholarshipReviewVo">
select r.id,
r.application_id,
r.review_level,
r.reviewer_id,
r.reviewer_name,
r.review_result,
r.review_score,
r.review_opinion,
r.review_time,
r.next_reviewer_id,
r.is_final_review,
r.tenant_id,
r.create_by,
r.create_time,
r.update_by,
r.update_time,
a.application_no,
a.student_no,
a.student_name,
st.type_name as scholarship_type_name,
b.batch_name,
a.current_status as application_status
from jcbt_scholarship_review r
left join jcbt_scholarship_application a on r.application_id = a.id
left join jcbt_scholarship_type st on a.scholarship_type_id = st.id
left join jcbt_scholarship_batch b on a.batch_id = b.id
where r.deleted = 0
</sql>
<!-- 根据申请ID查询审核记录 -->
<select id="selectReviewsByApplicationId" parameterType="Long" resultMap="JcbtScholarshipReviewResult">
<include refid="selectJcbtScholarshipReviewVo"/>
and r.application_id = #{applicationId}
order by r.review_time desc
</select>
<!-- 查询当前用户待审核的记录 -->
<select id="selectPendingReviews" resultMap="JcbtScholarshipReviewResult">
<include refid="selectJcbtScholarshipReviewVo"/>
and r.review_result = 'PENDING'
<if test="reviewerId != null">
and r.reviewer_id = #{reviewerId}
</if>
<if test="reviewLevel != null and reviewLevel != ''">
and r.review_level = #{reviewLevel}
</if>
<if test="applicationNo != null and applicationNo != ''">
and a.application_no like concat('%', #{applicationNo}, '%')
</if>
<if test="studentName != null and studentName != ''">
and a.student_name like concat('%', #{studentName}, '%')
</if>
order by a.submit_time asc
</select>
<!-- 查询审核历史记录 -->
<select id="selectReviewHistory" resultMap="JcbtScholarshipReviewResult">
<include refid="selectJcbtScholarshipReviewVo"/>
and r.review_result != 'PENDING'
<if test="reviewerId != null">
and r.reviewer_id = #{reviewerId}
</if>
<if test="reviewResult != null and reviewResult != ''">
and r.review_result = #{reviewResult}
</if>
<if test="batchId != null">
and a.batch_id = #{batchId}
</if>
<if test="startTime != null and startTime != ''">
and date_format(r.review_time,'%Y-%m-%d') &gt;= #{startTime}
</if>
<if test="endTime != null and endTime != ''">
and date_format(r.review_time,'%Y-%m-%d') &lt;= #{endTime}
</if>
order by r.review_time desc
</select>
<!-- 查询某个申请的最新审核记录 -->
<select id="selectLatestReviewByApplicationId" parameterType="Long" resultMap="JcbtScholarshipReviewResult">
<include refid="selectJcbtScholarshipReviewVo"/>
and r.application_id = #{applicationId}
order by r.review_time desc, r.id desc
limit 1
</select>
<!-- 查询某个申请的指定级别审核记录 -->
<select id="selectReviewByApplicationAndLevel" resultMap="JcbtScholarshipReviewResult">
<include refid="selectJcbtScholarshipReviewVo"/>
and r.application_id = #{applicationId}
and r.review_level = #{reviewLevel}
order by r.review_time desc
limit 1
</select>
<!-- 批量更新审核结果 -->
<update id="batchUpdateReviewResult">
update jcbt_scholarship_review
set review_result = #{reviewResult},
review_opinion = #{reviewOpinion},
reviewer_id = #{reviewerId},
reviewer_name = #{reviewerName},
review_time = now(),
update_time = now(),
update_by = #{reviewerId}
where id in
<foreach collection="reviewIds" item="id" open="(" separator="," close=")">
#{id}
</foreach>
and deleted = 0
</update>
<!-- 统计审核数量 -->
<select id="countReviewsByCondition" resultType="Long">
select count(1)
from jcbt_scholarship_review r
left join jcbt_scholarship_application a on r.application_id = a.id
where r.deleted = 0
<if test="reviewerId != null">
and r.reviewer_id = #{reviewerId}
</if>
<if test="reviewLevel != null and reviewLevel != ''">
and r.review_level = #{reviewLevel}
</if>
<if test="reviewResult != null and reviewResult != ''">
and r.review_result = #{reviewResult}
</if>
<if test="batchId != null">
and a.batch_id = #{batchId}
</if>
</select>
<!-- 查询下一级审核人员 -->
<select id="selectNextReviewers" resultType="Long">
select distinct u.user_id
from sys_user u
inner join sys_user_role ur on u.user_id = ur.user_id
inner join sys_role r on ur.role_id = r.role_id
where u.status = '0'
and u.del_flag = '0'
and r.status = '0'
and r.del_flag = '0'
<choose>
<when test="currentLevel == 'DEPARTMENT'">
and r.role_key like '%school_admin%'
</when>
<when test="currentLevel == 'SCHOOL'">
and r.role_key like '%finance_admin%'
</when>
<when test="currentLevel == 'FINANCE'">
and r.role_key like '%final_admin%'
</when>
<otherwise>
and 1 = 2
</otherwise>
</choose>
</select>
</mapper>
@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.jcbt.mapper.JcbtScholarshipTypeMapper">
<resultMap type="org.dromara.jcbt.domain.vo.JcbtScholarshipTypeVo" id="JcbtScholarshipTypeResult">
<result property="id" column="id" />
<result property="typeCode" column="type_code" />
<result property="typeName" column="type_name" />
<result property="typeCategory" column="type_category" />
<result property="levelType" column="level_type" />
<result property="awardAmount" column="award_amount" />
<result property="description" column="description" />
<result property="applicationGuide" column="application_guide" />
<result property="applicationConditions" column="application_conditions" />
<result property="evaluationCriteria" column="evaluation_criteria" />
<result property="remark" column="remark" />
<result property="compatibilityType" column="compatibility_type" />
<result property="sortOrder" column="sort_order" />
<result property="status" column="status" />
<result property="isSystem" column="is_system" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectJcbtScholarshipTypeVo">
select id, type_code, type_name, type_category, level_type, award_amount,
description, application_guide, application_conditions, evaluation_criteria, remark,
compatibility_type, sort_order, status, is_system,
create_dept, create_by, create_time, update_by, update_time
from jcbt_scholarship_type
</sql>
<select id="selectScholarshipTypeList" parameterType="org.dromara.jcbt.domain.JcbtScholarshipType" resultMap="JcbtScholarshipTypeResult">
<include refid="selectJcbtScholarshipTypeVo"/>
<where>
<if test="typeName != null and typeName != ''"> and type_name like concat('%', #{typeName}, '%')</if>
<if test="typeCategory != null and typeCategory != ''"> and type_category = #{typeCategory}</if>
<if test="levelType != null and levelType != ''"> and level_type = #{levelType}</if>
<if test="awardAmount != null"> and award_amount = #{awardAmount}</if>
<if test="applicationConditions != null and applicationConditions != ''"> and application_conditions like concat('%', #{applicationConditions}, '%')</if>
<if test="evaluationCriteria != null and evaluationCriteria != ''"> and evaluation_criteria like concat('%', #{evaluationCriteria}, '%')</if>
<if test="compatibilityType != null and compatibilityType != ''"> and compatibility_type = #{compatibilityType}</if>
<if test="status != null"> and status = #{status}</if>
and deleted = 0
</where>
order by sort_order asc, create_time desc
</select>
<select id="selectByTypeName" parameterType="String" resultMap="JcbtScholarshipTypeResult">
<include refid="selectJcbtScholarshipTypeVo"/>
where type_name = #{typeName} and deleted = 0 limit 1
</select>
<select id="selectByCategory" parameterType="String" resultMap="JcbtScholarshipTypeResult">
<include refid="selectJcbtScholarshipTypeVo"/>
where type_category = #{typeCategory} and deleted = 0
order by sort_order asc, create_time desc
</select>
<select id="selectActiveTypes" resultMap="JcbtScholarshipTypeResult">
<include refid="selectJcbtScholarshipTypeVo"/>
where status = 1 and deleted = 0
order by sort_order asc, create_time desc
</select>
<select id="checkTypeNameExists" resultType="boolean">
select count(1) > 0 from jcbt_scholarship_type
where type_name = #{typeName} and deleted = 0
<if test="id != null"> and id != #{id}</if>
</select>
<update id="batchUpdateSortOrder">
<foreach collection="list" item="item" separator=";">
update jcbt_scholarship_type set sort_order = #{item.sortOrder}
where id = #{item.id}
</foreach>
</update>
<select id="selectByCompatibilityType" parameterType="String" resultMap="JcbtScholarshipTypeResult">
<include refid="selectJcbtScholarshipTypeVo"/>
where compatibility_type = #{compatibilityType} and deleted = 0
order by sort_order asc, create_time desc
</select>
</mapper>
@@ -0,0 +1,75 @@
-- 奖学金审核管理菜单和权限配置
-- 专注于审核功能,不包含申请提交功能
-- Date: 2025-01-27
-- Author: system
-- 使用正确的数据库
USE hzdyjs_xg;
-- 设置会话字符集
SET NAMES utf8mb4;
SET CHARACTER_SET_CLIENT = utf8mb4;
SET CHARACTER_SET_CONNECTION = utf8mb4;
SET CHARACTER_SET_RESULTS = utf8mb4;
-- 删除可能存在的旧菜单(从子级开始删除)
DELETE FROM sys_menu WHERE menu_id >= 2100 AND menu_id <= 2120;
-- 1. 奖学金审核管理目录
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES
(2100, '奖学金审核管理', 1, 5, 'scholarshipReview', NULL, 1, 0, 'M', '0', '0', NULL, 'form', 1, NOW(), 1, NOW(), '奖学金审核管理目录');
-- 2. 我的审核任务菜单
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES
(2101, '我的审核任务', 2100, 1, 'myTasks', 'jcbt/scholarship/review/myTasks', 1, 0, 'C', '0', '0', 'jcbt:review:list', 'form', 1, NOW(), 1, NOW(), '我的审核任务菜单');
-- 3. 审核历史菜单
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES
(2102, '审核历史', 2100, 2, 'history', 'jcbt/scholarship/review/history', 1, 0, 'C', '0', '0', 'jcbt:review:history', 'time', 1, NOW(), 1, NOW(), '审核历史记录菜单');
-- 4. 审核记录查询权限
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES
(2103, '审核记录查询', 2101, 1, '', '', 1, 0, 'F', '0', '0', 'jcbt:review:query', '#', 1, NOW(), 1, NOW(), '审核记录查询权限');
-- 5. 审核操作权限(通过/拒绝/退回)
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES
(2104, '审核操作', 2101, 2, '', '', 1, 0, 'F', '0', '0', 'jcbt:review:approve', '#', 1, NOW(), 1, NOW(), '审核通过/拒绝/退回操作权限');
-- 6. 批量审核权限
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES
(2105, '批量审核', 2101, 3, '', '', 1, 0, 'F', '0', '0', 'jcbt:review:batchApprove', '#', 1, NOW(), 1, NOW(), '批量审核操作权限');
-- 7. 审核转移权限
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES
(2106, '审核转移', 2101, 4, '', '', 1, 0, 'F', '0', '0', 'jcbt:review:transfer', '#', 1, NOW(), 1, NOW(), '审核任务转移权限');
-- 8. 审核撤回权限
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES
(2107, '审核撤回', 2101, 5, '', '', 1, 0, 'F', '0', '0', 'jcbt:review:revoke', '#', 1, NOW(), 1, NOW(), '审核结果撤回权限');
-- 9. 待审核列表权限
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES
(2108, '待审核列表', 2101, 6, '', '', 1, 0, 'F', '0', '0', 'jcbt:review:pending', '#', 1, NOW(), 1, NOW(), '查看待审核列表权限');
-- 10. 审核详情权限
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES
(2109, '审核详情', 2101, 7, '', '', 1, 0, 'F', '0', '0', 'jcbt:review:detail', '#', 1, NOW(), 1, NOW(), '查看审核详情权限');
-- 11. 审核统计权限
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES
(2110, '审核统计', 2101, 8, '', '', 1, 0, 'F', '0', '0', 'jcbt:review:statistics', '#', 1, NOW(), 1, NOW(), '审核数据统计权限');
-- 12. 导出权限(审核记录导出)
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES
(2111, '审核记录导出', 2101, 9, '', '', 1, 0, 'F', '0', '0', 'jcbt:review:export', '#', 1, NOW(), 1, NOW(), '审核记录导出权限');
-- 验证插入结果
SELECT COUNT(*) as '插入菜单数量' FROM sys_menu WHERE menu_id >= 2100 AND menu_id <= 2111;
-- 显示插入的菜单
SELECT menu_id, menu_name, parent_id, menu_type, perms, remark
FROM sys_menu
WHERE menu_id >= 2100 AND menu_id <= 2111
ORDER BY menu_id;
COMMIT;
@@ -0,0 +1,28 @@
-- =====================================================
-- 奖学金类型表 - 添加缺失字段
-- 创建时间: 2025-08-04
-- 说明: 添加申请条件、评定标准、备注三个字段
-- =====================================================
-- 添加申请条件字段
ALTER TABLE jcbt_scholarship_type
ADD COLUMN IF NOT EXISTS application_conditions TEXT COMMENT '申请条件'
AFTER application_guide;
-- 添加评定标准字段
ALTER TABLE jcbt_scholarship_type
ADD COLUMN IF NOT EXISTS evaluation_criteria TEXT COMMENT '评定标准'
AFTER application_conditions;
-- 添加备注字段
ALTER TABLE jcbt_scholarship_type
ADD COLUMN IF NOT EXISTS remark VARCHAR(500) COMMENT '备注'
AFTER evaluation_criteria;
-- 验证字段添加
SELECT COLUMN_NAME, DATA_TYPE, COLUMN_COMMENT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'jcbt_scholarship_type'
AND COLUMN_NAME IN ('application_conditions', 'evaluation_criteria', 'remark')
ORDER BY ORDINAL_POSITION;
+134
View File
@@ -0,0 +1,134 @@
-- ========================================
-- 奖学金名额分配删除问题诊断脚本
-- 创建时间: 2025-01-28
-- 说明: 用于排查无法删除的名额分配记录
-- ========================================
USE hzdyjs_xg;
-- 1. 查看所有名额分配记录的状态
SELECT
id,
batch_id,
scholarship_type_id,
allocation_level,
target_dept_id,
total_quota,
used_quota,
reserved_quota,
available_quota,
is_adjustable,
is_locked,
status,
deleted,
create_time,
update_time
FROM jcbt_scholarship_quota
WHERE deleted = 0
ORDER BY create_time DESC;
-- 2. 查找可能有问题的记录(已使用名额大于0或已锁定)
SELECT
'已使用名额大于0' as issue_type,
id,
batch_id,
scholarship_type_id,
total_quota,
used_quota,
reserved_quota,
available_quota,
is_locked,
status
FROM jcbt_scholarship_quota
WHERE deleted = 0 AND used_quota > 0
UNION ALL
SELECT
'已被锁定' as issue_type,
id,
batch_id,
scholarship_type_id,
total_quota,
used_quota,
reserved_quota,
available_quota,
is_locked,
status
FROM jcbt_scholarship_quota
WHERE deleted = 0 AND is_locked = 1
UNION ALL
SELECT
'状态异常' as issue_type,
id,
batch_id,
scholarship_type_id,
total_quota,
used_quota,
reserved_quota,
available_quota,
is_locked,
status
FROM jcbt_scholarship_quota
WHERE deleted = 0 AND status != 'ACTIVE';
-- 3. 检查是否存在外键约束或关联数据
-- 检查是否有申请记录引用了这些名额
SELECT
q.id as quota_id,
q.batch_id,
q.scholarship_type_id,
q.used_quota,
q.is_locked,
COUNT(DISTINCT a.id) as application_count
FROM jcbt_scholarship_quota q
LEFT JOIN jcbt_scholarship_application a ON a.batch_id = q.batch_id
AND a.scholarship_type_id = q.scholarship_type_id
WHERE q.deleted = 0
GROUP BY q.id, q.batch_id, q.scholarship_type_id, q.used_quota, q.is_locked
HAVING application_count > 0 OR q.used_quota > 0 OR q.is_locked = 1;
-- 4. 检查是否有下级名额分配
SELECT
parent.id as parent_quota_id,
parent.allocation_level as parent_level,
parent.used_quota as parent_used_quota,
parent.is_locked as parent_is_locked,
COUNT(child.id) as child_count
FROM jcbt_scholarship_quota parent
LEFT JOIN jcbt_scholarship_quota child ON child.parent_quota_id = parent.id AND child.deleted = 0
WHERE parent.deleted = 0
GROUP BY parent.id, parent.allocation_level, parent.used_quota, parent.is_locked
HAVING child_count > 0;
-- 5. 详细查看有问题的记录(根据实际情况调整ID)
-- 请替换下面的ID为实际无法删除的记录ID
-- SELECT * FROM jcbt_scholarship_quota WHERE id = 替换为实际ID;
-- 6. 查看相关批次信息
SELECT
b.id as batch_id,
b.batch_name,
b.batch_code,
b.status as batch_status,
b.start_time,
b.end_time,
COUNT(q.id) as quota_count
FROM jcbt_scholarship_batch b
LEFT JOIN jcbt_scholarship_quota q ON q.batch_id = b.id AND q.deleted = 0
WHERE b.deleted = 0
GROUP BY b.id, b.batch_name, b.batch_code, b.status, b.start_time, b.end_time;
-- 7. 查看奖学金类型信息
SELECT
st.id as type_id,
st.type_name,
st.type_code,
st.status as type_status,
COUNT(q.id) as quota_count
FROM jcbt_scholarship_type st
LEFT JOIN jcbt_scholarship_quota q ON q.scholarship_type_id = st.id AND q.deleted = 0
WHERE st.deleted = 0
GROUP BY st.id, st.type_name, st.type_code, st.status;
Loaded 100 of 284 files, more files were not shown because too many files have changed in this diff. Show more