50 KiB
出国申请管理 API 接口文档
📋 文档说明
适用场景
- 出国申请业务流程管理
- 出国申请审批流程控制
- 出国记录管理和跟踪
- 为 Cursor AI 提供完整的接口开发上下文
模块特色
- 完整审批流程:三级审批(部门主管→分管领导→校领导)
- 状态自动流转:申请提交→审批通过→自动创建记录
- 权限细分控制:申请、审批、记录管理分离
- 数据完整追踪:审批记录、状态变更历史完整保存
🔌 出国申请管理 API 接口文档
模块概述
模块名称:overseas / 出国申请管理
基础路径:/api/rs/overseas
版本:v1.1
负责人:weizzzz
更新时间:2025-10-28
🆕 最近更新
v1.1 (2025-10-28) - 分级审批权限升级
- ✅ 审批权限升级为五级审批制度
- 新增
rs:overseas:approve1-5五个分级审批权限 - 保留
rs:overseas:approve作为通用审批权限
- 新增
- ✅ Controller层采用OR模式权限验证
- 用户拥有任一审批权限即可访问审批接口
- 解决部门负责人403权限错误问题
- ✅ Service层增加审批级别验证
- 新增
validateApproverLevel()方法 - 精确验证用户权限是否匹配申请的审批级别
- 防止越级审批
- 新增
- ✅ 前端按钮权限优化
- 审批按钮支持多级权限显示
- 改善用户体验,按钮显示逻辑更合理
模块功能
出国申请管理模块提供完整的出国申请业务流程管理功能,包括申请提交、多级审批、记录管理等核心功能。支持学术交流、培训学习、合作项目等多种出国目的,提供完整的审批流程控制和状态追踪。
权限说明
出国申请权限
- 权限前缀:
rs:overseas:application: - 权限列表:
rs:overseas:application:list- 查询申请列表权限rs:overseas:application:query- 查询申请详情权限rs:overseas:application:add- 新增申请权限rs:overseas:application:edit- 编辑申请权限rs:overseas:application:remove- 删除申请权限rs:overseas:application:export- 导出申请权限rs:overseas:application:submit- 提交申请权限rs:overseas:application:cancel- 取消申请权限rs:overseas:application:approve- 审批申请权限
出国记录权限
- 权限前缀:
rs:overseas:record: - 权限列表:
rs:overseas:record:list- 查询记录列表权限rs:overseas:record:query- 查询记录详情权限rs:overseas:record:add- 新增记录权限rs:overseas:record:edit- 编辑记录权限rs:overseas:record:remove- 删除记录权限rs:overseas:record:export- 导出记录权限rs:overseas:record:create- 创建记录权限rs:overseas:record:complete- 完成记录权限
出国审批权限(🆕 2025-10-28 更新为五级审批)
-
权限前缀:
rs:overseas: -
审批记录查看权限:
rs:overseas:approval:list- 查询审批记录列表权限rs:overseas:approval:query- 查询审批记录详情权限rs:overseas:approval:export- 导出审批记录权限
-
分级审批权限(五级审批制度):
rs:overseas:approve- 通用审批权限(超级管理员/高级审批者,可审批任意级别)rs:overseas:approve1- 第1级:部门负责人审批权限rs:overseas:approve2- 第2级:人事处审批权限rs:overseas:approve3- 第3级:纪委审批权限rs:overseas:approve4- 第4级:学院分管领导审批权限rs:overseas:approve5- 第5级:学院党委书记审批权限
-
数据返回顺序:审批人下拉接口(
/system/user/list-by-permission)默认按用户名(user_name)升序排序,确保审批人选择器顺序一致(2025-11-13) -
权限使用说明:
- 审批接口采用 OR模式,用户拥有以上任一权限即可调用接口
- 具体审批权限在业务层验证,必须匹配申请的
approval_level - 部门负责人通过
rs:overseas:approve1权限识别,自动应用部门数据过滤
🔐 数据权限控制
权限分级说明
出国申请系统采用基于角色和部门的多级数据权限控制,确保用户只能访问其权限范围内的数据。
角色权限矩阵
| 角色 | 角色标识 | 数据访问范围 | 可见申请范围 | 备注 |
|---|---|---|---|---|
| 超级管理员 | admin |
全局数据 | 所有申请 | 不受任何限制 |
| 人事管理员 | rs-admin |
全局数据 | 所有申请 | 仅当不是部门负责人时 |
| 申请人 | rs-Applicant |
个人数据 | 仅自己的申请 | 只能查看和管理自己的申请 |
| 部门负责人 | 具有rs:overseas:approve1权限 |
本部门数据 | 本部门所有申请 | 优先级最高 |
| 普通审批人 | 其他审批权限 | 分配数据 | 分配给自己的审批 | 只能看到分配的审批任务 |
部门权限过滤规则(🆕 2025-01-28)
核心原则:部门负责人只能看到本部门成员提交的申请,不能看到其他部门的申请。
实现逻辑:
-
判断用户是否为部门负责人(三种方式任选其一):
- 具有
rs:overseas:approve1权限 - 具有
dept_head_role角色 - 具有
overseas:application:dept_head:approve权限(兼容旧版)
- 具有
-
应用部门过滤:
- 查询条件:
申请人的dept_id = 当前用户的dept_id - SQL实现:通过
sys_user表关联,筛选申请人所属部门 - 重要:不限制审批人(approverId),只限制申请人部门(deptId)
- 查询条件:
-
权限优先级(从高到低):
超级管理员 > 申请人(自己的数据)> 部门负责人(本部门)> 人事管理员(全局)> 普通审批人(分配数据)
示例场景:
假设有以下用户和部门:
- 张三:
dept_id = 001(测试部门A),角色:申请人 - 李四:
dept_id = 001(测试部门A),角色:部门负责人 - 王五:
dept_id = 002(测试部门B),角色:部门负责人 - 赵六:
dept_id = 003(测试部门C),角色:部门负责人
张三提交申请后:
- ✅ 李四(同部门):可以看到张三的申请
- ❌ 王五(不同部门):不能看到张三的申请
- ❌ 赵六(不同部门):不能看到张三的申请
技术实现:
// Service层权限过滤逻辑
private void applyDeptPermissionFilter(RsOverseasApprovalQuery query) {
// 1. 判断是否为部门负责人
boolean isDeptApprover = isDeptApprover(currentUserId);
// 2. 如果是部门负责人,只设置部门过滤
if (isDeptApprover) {
query.setDeptId(currentDeptId); // 只应用部门过滤
return; // 不设置approverId,避免过度限制
}
}
<!-- Mapper XML中的部门权限过滤SQL -->
<if test="deptId != null">
AND EXISTS (
SELECT 1 FROM sys_user u
WHERE u.user_id = app.applicant_id
AND u.dept_id = #{deptId}
)
</if>
相关文档:
- 测试指南:
docs/测试文档/出国申请部门权限过滤测试指南.md - 验证脚本:
部门权限过滤验证脚本.sql - 代码实现:
RsOverseasApprovalServiceImpl.java
📊 接口概览
接口分类
出国申请基础 CRUD 接口
| 接口名称 | HTTP 方法 | 路径 | 权限要求 | 功能描述 |
|---|---|---|---|---|
| 查询申请列表 | GET | /rs/overseas/application/list |
rs:overseas:application:list |
分页查询出国申请列表 |
| 查询申请详情 | GET | /rs/overseas/application/{id} |
rs:overseas:application:query |
根据ID查询出国申请详情 |
| 新增申请 | POST | /rs/overseas/application |
rs:overseas:application:add |
创建新的出国申请 |
| 修改申请 | PUT | /rs/overseas/application |
rs:overseas:application:edit |
更新出国申请信息 |
| 删除申请 | DELETE | /rs/overseas/application/{ids} |
rs:overseas:application:remove |
批量删除出国申请 |
| 导出申请 | POST | /rs/overseas/application/export |
rs:overseas:application:export |
导出出国申请数据 |
出国申请业务逻辑接口
| 接口名称 | HTTP 方法 | 路径 | 权限要求 | 功能描述 |
|---|---|---|---|---|
| 查询我的申请列表 | GET | /rs/overseas/application/my/list |
rs:overseas:application:list |
查询当前用户的申请列表(排除已通过的申请) |
| 查询待审批申请 | GET | /rs/overseas/application/pending/list |
rs:overseas:application:approve |
查询待当前用户审批的申请 |
| 按状态查询申请 | GET | /rs/overseas/application/status/{status} |
rs:overseas:application:list |
根据状态查询申请列表 |
| 提交申请 | PUT | /rs/overseas/application/submit/{id} |
rs:overseas:application:submit |
提交出国申请进入审批流程 |
| 重新提交申请 | PUT | /rs/overseas/application/resubmit/{id} |
rs:overseas:application:edit |
重新提交已拒绝的出国申请 |
| 取消申请 | PUT | /rs/overseas/application/cancel/{id} |
rs:overseas:application:cancel |
取消出国申请 |
| 审批申请 | POST | /rs/overseas/application/approve |
rs:overseas:application:approve |
审批出国申请(通过/拒绝) |
| 修复记录 | POST | /rs/overseas/application/fix/records |
rs:overseas:application:approve |
修复已审批通过但未创建记录的申请 |
| 下载党籍保留PDF模板 | GET | /rs/overseas/record/downloadPartyRetention |
rs:overseas:query |
新增:下载党籍保留申请PDF空白模板(线下手工填写)(2025-10-17) |
出国记录管理接口
| 接口名称 | HTTP 方法 | 路径 | 权限要求 | 功能描述 |
|---|---|---|---|---|
| 查询记录列表 | GET | /rs/overseas/record/list |
rs:overseas:record:list |
分页查询出国记录列表 |
| 查询我的记录列表 | GET | /rs/overseas/record/my/list |
rs:overseas:record:list |
查询当前用户的记录列表 |
| 根据申请查询记录 | GET | /rs/overseas/record/application/{id} |
rs:overseas:record:query |
根据申请ID查询出国记录 |
| 查询记录详情 | GET | /rs/overseas/record/{id} |
rs:overseas:record:query |
根据ID查询出国记录详情 |
| 新增记录 | POST | /rs/overseas/record |
rs:overseas:record:add |
创建新的出国记录 |
| 修改记录 | PUT | /rs/overseas/record |
rs:overseas:record:edit |
更新出国记录信息 |
| 删除记录 | DELETE | /rs/overseas/record/{ids} |
rs:overseas:record:remove |
批量删除出国记录 |
| 导出记录 | POST | /rs/overseas/record/export |
rs:overseas:record:export |
导出出国记录数据 |
| 创建记录 | POST | /rs/overseas/record/create/{id} |
rs:overseas:record:create |
基于申请创建出国记录 |
| 更新完成状态 | PUT | /rs/overseas/record/complete |
rs:overseas:record:complete |
更新出国记录完成状态 |
出国审批记录接口
| 接口名称 | HTTP 方法 | 路径 | 权限要求 | 功能描述 |
|---|---|---|---|---|
| 查询审批记录列表 | GET | /rs/overseas/approval/list |
rs:overseas:approval:list |
分页查询审批记录列表 |
| 查询我的审批记录 | GET | /rs/overseas/approval/my/list |
rs:overseas:approval:list |
查询当前用户的审批记录 |
| 根据申请查询审批记录 | GET | /rs/overseas/approval/application/{id} |
rs:overseas:approval:query |
根据申请ID查询审批记录 |
| 查询审批记录详情 | GET | /rs/overseas/approval/{id} |
rs:overseas:approval:query |
根据ID查询审批记录详情 |
| 查询申请审批历史 | GET | /rs/overseas/application/approval/history/{id} |
rs:overseas:application:query |
查询指定申请的完整审批历史 |
| 导出审批记录 | POST | /rs/overseas/approval/export |
rs:overseas:approval:export |
导出审批记录数据 |
📄 数据结构定义
出国申请对象 (OverseasApplication)
interface OverseasApplicationVO {
applicationId: number | string; // 申请ID
applicantId: number; // 申请人ID
applicantName: string; // 申请人姓名
department: string; // 所属部门
position: string; // 职位
contactPhone: string; // 联系电话
contactEmail: string; // 联系邮箱
purpose: string; // 出国目的编码
purposeDetail: string; // 目的详细说明
destination: string; // 目的地国家
destinationCity: string; // 目的地城市
startDate: string; // 开始日期
endDate: string; // 结束日期
duration: number; // 出国天数
budget: number; // 预算金额
budgetSource: string; // 经费来源编码
invitation: string; // 邀请函信息
itinerary: string; // 行程安排
accommodationPlan: string; // 住宿安排
transportationPlan: string; // 交通安排
status: string; // 申请状态编码
approvalStatus: string; // 工作流状态编码
currentApprover: string; // 当前审批人
approvalLevel: string; // 审批级别
applyTime: string; // 申请时间
approvalTime: string; // 审批完成时间
adminRemark: string; // 管理员备注
applicantRemark: string; // 申请人备注
createTime: string; // 创建时间
updateTime: string; // 更新时间
// 显示字段
statusText: string; // 状态文本
approvalStatusText: string; // 工作流状态文本
purposeText: string; // 目的文本
budgetSourceText: string; // 经费来源文本
approvalLevelText: string; // 审批级别文本
}
出国记录对象 (OverseasRecord)
interface OverseasRecordVO {
recordId: number | string; // 记录ID
applicationId: number; // 关联申请ID
applicantId: number; // 申请人ID
applicantName: string; // 申请人姓名
department: string; // 所属部门
purpose: string; // 出国目的
destination: string; // 目的地国家
actualStartDate: string; // 实际开始日期
actualEndDate: string; // 实际结束日期
actualDuration: number; // 实际出国天数
actualBudget: number; // 实际花费金额
completionStatus: string; // 完成状态编码
achievement: string; // 出国成果
reportContent: string; // 总结报告内容
certificatePath: string; // 证书文件路径
createTime: string; // 创建时间
updateTime: string; // 更新时间
// 显示字段
purposeText: string; // 目的文本
completionStatusText: string; // 完成状态文本
}
出国审批记录对象 (OverseasApproval)
interface OverseasApprovalVO {
approvalId: number | string; // 审批ID
applicationId: number; // 关联申请ID
approverId: number; // 审批人ID
approverName: string; // 审批人姓名(优先返回昵称,缺省时回退账号)
approvalLevel: string; // 审批级别编码
approvalStatus: string; // 审批状态编码
approvalOpinion: string; // 审批意见
approvalTime: string; // 审批时间
createTime: string; // 创建时间
updateTime: string; // 更新时间
// 显示字段
approvalLevelText: string; // 审批级别文本
approvalStatusText: string; // 审批状态文本
}
🆕 2025-11-28 更新:
approverName字段统一返回审批人的昵称,若用户未设置昵称则自动回退到账号,确保审批记录界面展示真实姓名。
🔧 核心接口详细说明
1. 查询出国申请列表
接口地址:GET /rs/overseas/application/list
权限要求:rs:overseas:application:list
请求参数
interface OverseasApplicationQuery {
pageNum: number; // 页码(必须)
pageSize: number; // 每页大小(必须)
applicantName?: string; // 申请人姓名
department?: string; // 所属部门
purpose?: string; // 出国目的
destination?: string; // 目的地
status?: string; // 申请状态
approvalLevel?: string; // 审批级别
currentApprover?: string; // 当前审批人
applicantId?: number; // 申请人ID
budgetMin?: number; // 预算最小值
budgetMax?: number; // 预算最大值
applyTimeBegin?: string; // 申请开始时间
applyTimeEnd?: string; // 申请结束时间
startDateBegin?: string; // 出国开始日期范围
startDateEnd?: string; // 出国结束日期范围
}
响应示例
{
"code": 200,
"msg": "查询成功",
"rows": [
{
"applicationId": 1,
"applicantId": 1,
"applicantName": "张三",
"department": "计算机学院",
"position": "副教授",
"contactPhone": "13800138001",
"contactEmail": "zhangsan@example.com",
"purpose": "academic_exchange",
"purposeDetail": "参加国际人工智能学术交流会议,发表研究论文并进行学术交流",
"destination": "美国",
"destinationCity": "纽约",
"startDate": "2025-03-15",
"endDate": "2025-03-25",
"duration": 11,
"budget": 25000.00,
"budgetSource": "school",
"invitation": "已收到会议邀请函",
"itinerary": "3月15日飞往纽约,参加为期5天的会议,会后进行实验室访问",
"status": "1",
"currentApprover": "admin",
"approvalLevel": "2",
"applyTime": "2025-01-28 10:00:00",
"approvalTime": "2025-01-28 15:30:00",
"applicantRemark": "期待能够带回先进的研究成果",
"createTime": "2025-01-28 10:00:00",
"updateTime": "2025-01-28 15:30:00",
"statusText": "已通过",
"purposeText": "学术交流",
"budgetSourceText": "学校经费",
"approvalLevelText": "分管领导"
}
],
"total": 1
}
2. 新增出国申请
接口地址:POST /rs/overseas/application
权限要求:rs:overseas:application:add
请求参数
interface OverseasApplicationForm {
department: string; // 所属部门(必须)
position?: string; // 职位
contactPhone: string; // 联系电话(必须)
contactEmail: string; // 联系邮箱(必须)
purpose: string; // 出国目的(必须)
purposeDetail: string; // 目的详细说明(必须)
destination: string; // 目的地国家(必须)
destinationCity?: string; // 目的地城市
startDate: string; // 开始日期(必须)
endDate: string; // 结束日期(必须)
budget: number; // 预算金额(必须)
budgetSource: string; // 经费来源(必须)
invitation?: string; // 邀请函信息
itinerary: string; // 行程安排(必须)
accommodationPlan?: string; // 住宿安排
transportationPlan?: string; // 交通安排
applicantRemark?: string; // 申请人备注
}
请求示例
{
"department": "计算机学院",
"position": "副教授",
"contactPhone": "13800138001",
"contactEmail": "zhangsan@example.com",
"purpose": "academic_exchange",
"purposeDetail": "参加国际人工智能学术交流会议,发表研究论文并进行学术交流",
"destination": "美国",
"destinationCity": "纽约",
"startDate": "2025-03-15",
"endDate": "2025-03-25",
"budget": 25000.00,
"budgetSource": "school",
"invitation": "已收到会议邀请函",
"itinerary": "3月15日飞往纽约,参加为期5天的会议,会后进行实验室访问",
"accommodationPlan": "入住会议指定酒店",
"transportationPlan": "往返机票+当地交通",
"applicantRemark": "期待能够带回先进的研究成果"
}
响应示例
{
"code": 200,
"msg": "新增成功",
"data": null
}
3. 重新提交被拒绝的出国申请
接口地址: PUT /rs/overseas/application/resubmit/{id}
权限要求: rs:overseas:application:edit
功能说明: 允许用户重新提交已被拒绝的出国申请,支持修改申请内容后重新进入审批流程。
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | Long | 是 | 申请ID |
请求体:
{
"destination": "美国",
"purpose": "1",
"purposeDetail": "参加学术会议",
"destinationCity": "纽约",
"startDate": "2025-02-01",
"endDate": "2025-02-10",
"budget": 15000,
"budgetSource": "科研经费",
"itinerary": "详细行程安排",
"applicantRemark": "申请备注"
}
响应数据:
{
"code": 200,
"msg": "操作成功",
"data": null
}
业务逻辑:
- 只有状态为"已拒绝"(status=2)的申请才能重新提交
- 重新提交后状态重置为"待审核"(status=0)
- 自动重置审批级别和当前审批人信息
- 自动重新计算出国天数
- 更新申请时间为当前时间
4. 审批出国申请
接口地址:POST /rs/overseas/application/approve
权限要求:rs:overseas:approve (通用) 或 rs:overseas:approve1-5 (分级) - 支持多级审批权限(2025-10-28更新)
🔴 权限说明(重要更新)
分级审批权限体系(OR模式,满足任一权限即可访问接口):
rs:overseas:approve- 通用审批权限(超级管理员/高级审批者)rs:overseas:approve1- 第1级:部门负责人审批权限rs:overseas:approve2- 第2级:人事处审批权限rs:overseas:approve3- 第3级:纪委审批权限rs:overseas:approve4- 第4级:学院分管领导审批权限rs:overseas:approve5- 第5级:学院党委书记审批权限
权限验证机制:
- 接口层验证:Controller使用
@SaCheckPermission(value={...}, mode=SaMode.OR),满足任一权限即可调用接口 - 业务层验证:Service层根据申请的
approval_level字段验证用户是否拥有对应级别的审批权限 - 权限不匹配处理:如果用户审批级别与申请要求不符,返回业务异常"您没有第X级审批权限"
示例场景:
- 部门负责人(拥有
approve1)只能审批approval_level=1的申请 - 尝试审批
approval_level=2的申请将被拒绝 - 拥有
rs:overseas:approve通用权限的用户可以审批任意级别
请求参数
interface ApprovalRequest {
applicationId: number | string; // 申请ID(必须)
approvalStatus: string; // 审批状态:1-通过,2-拒绝(必须)
approvalOpinion?: string; // 审批意见
taskId?: string; // 🔴 工作流任务ID(可选,支持标准工作流模式)
}
请求示例
{
"applicationId": 1,
"approvalStatus": "1",
"approvalOpinion": "同意申请,项目具有重要学术价值,注意安全"
}
响应示例
{
"code": 200,
"msg": "审批成功",
"data": null
}
4. 修复已审批通过但未创建记录的申请
接口地址:POST /rs/overseas/application/fix/records
权限要求:rs:overseas:application:approve
功能说明
修复已审批通过但由于系统异常未自动创建出国记录的申请。该接口会:
- 查询所有状态为"已通过"的申请
- 检查是否存在对应的出国记录
- 为缺失记录的申请自动创建出国记录
请求参数
无需参数,直接POST请求即可。
请求示例
POST /rs/overseas/application/fix/records
Authorization: Bearer {token}
Content-Type: application/json
clientid: ruoyi-web
referer: http://localhost
响应示例
{
"code": 200,
"msg": "修复完成,共修复 3 条记录",
"data": "修复完成,共修复 3 条记录"
}
使用场景
- 系统升级后的数据修复
- 审批流程异常导致的记录缺失修复
- 管理员手动数据修复
5. 查询申请审批历史
接口地址:GET /rs/overseas/application/approval/history/{applicationId}
权限要求:rs:overseas:application:query
功能说明
查询指定出国申请的完整审批历史记录,按审批级别升序、审批时间降序排列。主要用于审批历史追溯和流程透明化。
路径参数
| 参数名 | 类型 | 必须 | 说明 |
|---|---|---|---|
| applicationId | number | 是 | 申请ID |
请求示例
GET /rs/overseas/application/approval/history/1
Authorization: Bearer {token}
Content-Type: application/json
clientid: ruoyi-web
referer: http://localhost
响应示例
{
"code": 200,
"msg": "查询成功",
"data": [
{
"approvalId": 1,
"applicationId": 1,
"approverId": 2,
"approverName": "李部长",
"approvalLevel": "1",
"approvalStatus": "1",
"approvalOpinion": "同意申请,项目具有重要学术价值",
"approvalTime": "2025-01-28 14:30:00",
"createTime": "2025-01-28 14:30:00",
"updateTime": "2025-01-28 14:30:00",
"approvalLevelText": "部门主管",
"approvalStatusText": "通过"
},
{
"approvalId": 2,
"applicationId": 1,
"approverId": 3,
"approverName": "王副校长",
"approvalLevel": "2",
"approvalStatus": "1",
"approvalOpinion": "项目符合学校发展战略,建议通过",
"approvalTime": "2025-01-28 16:15:00",
"createTime": "2025-01-28 16:15:00",
"updateTime": "2025-01-28 16:15:00",
"approvalLevelText": "分管领导",
"approvalStatusText": "通过"
},
{
"approvalId": 3,
"applicationId": 1,
"approverId": 4,
"approverName": "张校长",
"approvalLevel": "3",
"approvalStatus": "1",
"approvalOpinion": "同意出国,注意安全,及时汇报进展",
"approvalTime": "2025-01-28 17:45:00",
"createTime": "2025-01-28 17:45:00",
"updateTime": "2025-01-28 17:45:00",
"approvalLevelText": "校领导",
"approvalStatusText": "通过"
}
]
}
响应字段说明
| 字段名 | 类型 | 说明 |
|---|---|---|
| approvalId | number | 审批记录ID |
| applicationId | number | 关联的申请ID |
| approverId | number | 审批人用户ID |
| approverName | string | 审批人姓名 |
| approvalLevel | string | 审批级别编码(1-部门主管,2-分管领导,3-校领导) |
| approvalStatus | string | 审批状态编码(0-待审核,1-通过,2-拒绝) |
| approvalOpinion | string | 审批意见 |
| approvalTime | string | 审批时间 |
| approvalLevelText | string | 审批级别中文描述 |
| approvalStatusText | string | 审批状态中文描述 |
特殊说明
- 返回数据按
approvalLevel升序、approvalTime降序排列 - 如果申请还未产生任何审批记录,返回空数组
- 只返回与指定申请ID相关的审批历史
- 审批历史记录一旦创建不可删除,确保流程可追溯
错误响应
{
"code": 500,
"msg": "申请ID不存在"
}
📝 字典码值说明
申请状态 (status)
| 编码 | 含义 | 描述 |
|---|---|---|
| 0 | 待审核 | 申请已提交,等待审批 |
| 1 | 已通过 | 申请审批通过 |
| 2 | 已拒绝 | 申请审批被拒绝 |
| 3 | 已取消 | 申请被申请人主动取消 |
| 4 | 已完成 | 出国活动已完成 |
工作流状态 (approvalStatus)
| 编码 | 含义 | 描述 |
|---|---|---|
| cancel | 已撤销 | 申请人主动撤销申请 |
| draft | 草稿 | 申请尚未提交,处于编辑状态 |
| waiting | 待审核 | 申请已提交,正在审批流程中 |
| finish | 已完成 | 所有审批节点都已通过,流程结束 |
| invalid | 已作废 | 申请因某种原因被标记为无效 |
| back | 已退回 | 审批被拒绝,退回给申请人修改 |
| termination | 已终止 | 流程被管理员或系统强制终止 |
📝 说明:工作流状态由 Warm-Flow 工作流引擎自动管理,用于总体流程监听和状态跟踪。
出国目的 (purpose)
| 编码 | 含义 | 描述 |
|---|---|---|
| academic_exchange | 学术交流 | 参加学术交流活动 |
| conference | 学术会议 | 参加学术会议 |
| training | 培训学习 | 参加培训课程 |
| cooperation | 合作项目 | 开展合作研究项目 |
| research | 科研访问 | 科研访问学者 |
| other | 其他 | 其他出国目的 |
经费来源 (budgetSource)
| 编码 | 含义 | 描述 |
|---|---|---|
| school | 学校经费 | 学校提供经费支持 |
| government | 政府资助 | 政府资助项目 |
| project | 项目经费 | 科研项目经费 |
| self | 个人承担 | 个人承担费用 |
| cooperation | 合作单位 | 合作单位提供经费 |
| other | 其他 | 其他经费来源 |
审批级别 (approvalLevel)
| 编码 | 含义 | 描述 |
|---|---|---|
| 1 | 部门主管 | 第一级审批:部门主管 |
| 2 | 分管领导 | 第二级审批:分管领导 |
| 3 | 校领导 | 第三级审批:校领导 |
审批记录状态 (审批记录表中的 approvalStatus)
| 编码 | 含义 | 描述 |
|---|---|---|
| 0 | 待审核 | 等待审批 |
| 1 | 通过 | 审批通过 |
| 2 | 拒绝 | 审批拒绝 |
⚠️ 注意:此状态是审批记录表中的状态,与申请表中的工作流状态(approvalStatus)是不同的字段。
完成状态 (completionStatus)
⚠️ 重要说明:完成状态(completionStatus)与申请状态(status)是两个不同的概念!
- 申请状态(status):表示审批流程的状态(待审核/已通过/已拒绝)
- 完成状态(completionStatus):表示出国任务执行的状态(未完成/进行中/已完成/已取消)
| 编码 | 含义 | 描述 | 使用场景 |
|---|---|---|---|
| 0 | 未完成 | 出国活动尚未开始 | 已通过审批但尚未出发 |
| 1 | 进行中 | 出国活动正在进行 | 已出发但未返回(默认值) |
| 2 | 已完成 | 出国活动已完成 | 已返回并完成回执 |
| 3 | 已取消 | 出国活动取消 | 计划取消 |
字段关系示例:
- 出国记录中的申请若已通过审批(
status='1'),默认完成状态为"进行中"(completionStatus='1') - 出国记录列表显示"完成状态"字段,详情弹窗显示"申请状态"字段
- 所有出国记录的申请状态都应该是"已通过"(
status='1'),因为只有通过审批的申请才会出现在记录中
🔄 业务流程说明
申请流程
- 提交申请:用户填写申请信息并提交,状态为"待审核",审批级别为"部门主管"
- 部门主管审批:部门主管审批通过后,审批级别自动流转到"分管领导"
- 分管领导审批:分管领导审批通过后,审批级别自动流转到"校领导"
- 校领导审批:校领导审批通过后,申请状态变为"已通过",自动创建出国记录
- 完成出国:申请人完成出国活动后,更新记录状态为"已完成",申请状态同步更新
状态流转
草稿状态 → 待审核 → 已通过/已拒绝
↓
已取消
↓
已完成
权限控制
- 申请人:可以查看自己的申请,编辑草稿状态的申请,提交/取消申请
- 审批人:可以查看待审批的申请,进行审批操作
- 管理员:拥有所有权限,可以管理所有申请和记录
🧪 测试说明
测试环境
- 基础URL:
http://localhost:8080 - 认证方式:Bearer Token
- 必需Header:
Authorization: Bearer {token} Content-Type: application/json clientid: ruoyi-web referer: http://localhost
测试用例
- 申请管理测试:创建申请→提交申请→审批流程→状态验证
- 权限测试:不同角色的权限边界测试
- 业务流程测试:完整的申请到完成流程测试
- 数据校验测试:参数验证、业务规则验证
注意事项
- 测试前确保数据库表结构已创建
- 测试用户需要有相应的权限
- 审批测试需要使用不同级别的审批人账号
- 时间字段格式为:
YYYY-MM-DD HH:mm:ss
📝 更新记录
| 版本 | 更新时间 | 更新内容 | 更新人 |
|---|---|---|---|
| v1.0 | 2025-01-28 | 初始版本,包含完整的API接口文档 | weizzzz |
| v1.1 | 2025-08-03 | 新增查询申请审批历史接口,完善审批流程追溯功能 | weizzzz |
| v1.2 | 2025-01-09 | 新增修复记录接口,修复审批通过后记录创建问题 | weizzzz |
| v1.3 | 2025-01-08 | 调整我的申请列表接口,显示完整申请历史(包括已通过申请) | weizzzz |
| v1.4 | 2025-01-08 | 修正我的申请列表接口,排除已通过申请(已通过申请显示在出国记录中) | weizzzz |
| v1.5 | 2025-01-28 | 新增盖章文件上传功能,用户需上传盖章文件后才能提交申请 | weizzzz |
8. 上传登记备案表盖章文件
接口地址:POST /rs/overseas/application/uploadStampedFile
权限要求:rs:overseas:add
功能说明
用于上传填写并加盖公章后的登记备案表文件。支持PDF、JPG、PNG格式,文件大小不超过10MB。上传成功后,用户才能提交出国申请。
请求参数
Content-Type: multipart/form-data
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| file | File | 是 | 盖章文件,支持PDF、JPG、PNG格式 |
| applicationId | Long | 是 | 申请ID |
请求示例
POST /rs/overseas/application/uploadStampedFile
Content-Type: multipart/form-data
Authorization: Bearer {token}
clientid: ruoyi-web
referer: http://localhost
form-data:
file: [选择的盖章文件]
applicationId: 1
响应示例
成功响应:
{
"code": 200,
"msg": "盖章文件上传成功",
"data": {
"filePath": "overseas/stamped/stamped_1_1704076800000.pdf",
"fileName": "出国境登记表_张三.pdf",
"uploadTime": "2025-01-28 14:30:00"
}
}
失败响应:
{
"code": 500,
"msg": "不支持的文件格式,请上传PDF、JPG或PNG文件"
}
业务规则
- 文件格式:只支持PDF、JPG、PNG格式
- 文件大小:不超过10MB
- 数量限制:每个申请只能上传一个盖章文件
- 上传成功后,系统自动更新申请记录的盖章文件信息
- 必须先上传盖章文件,才能提交出国申请
数据库更新
上传成功后,系统会自动更新以下字段:
stamped_registration_file_path: 文件存储路径stamped_registration_file_name: 原始文件名stamped_file_upload_time: 上传时间stamped_file_upload_status: 上传状态(设为'1')
21. 下载党籍保留申请PDF空白模板
接口路径:GET /rs/overseas/record/downloadPartyRetention
功能说明
生成标准的党籍保留申请PDF空白模板,用户下载后完全通过线下手工填写所有内容。
权限要求
- 权限标识:
rs:overseas:query - 权限说明:需要有查询出国记录的权限
请求参数
无需参数:接口不需要任何参数,直接下载空白模板。
请求示例
GET /api/rs/overseas/record/downloadPartyRetention
Authorization: Bearer {token}
clientid: {clientid}
referer: {referer}
响应说明
成功响应:
- Content-Type:
application/pdf - Content-Disposition:
attachment; filename="党籍保留申请_yyyyMMdd.pdf" - Body: PDF文件二进制流
失败响应:
{
"code": 500,
"msg": "PDF生成失败: 错误信息"
}
PDF模板内容
PDF模板包含以下空白填写区域(完全手工填写):
- 标题:关于因私赴 ______________ __________保留党籍的申请
- 支部信息:______________________ 支部:
- 申请人信息:
- 本人 (_____),现任 _______________
- 计划于 ____________________
- 出国信息:
- 至 ____________________ 偕配偶 _______________
- 因私赴 _______________(国家 或地区)探望 在
- _________________________ 的工作(留学、定居)的 __________
- 在外停留 __________ 天(含路、抵返国境当
- 申请内容:日)。现申请保留期间暂缓籍。
- 结束语:特此申请,望予批准。
- 签名区域:
- 申请人:_______________
- 申请日期: ____________________
使用流程
方式一:申请表单中下载
- 用户在新增/编辑申请时,系统检测到是党员且出国天数>30天
- 系统显示党籍保留附件上传区域
- 用户点击"下载党籍保留申请PDF模板"按钮
- 系统生成并下载空白PDF模板
- 用户线下手工填写所有内容、打印、盖章
- 扫描成PDF后上传到系统
方式二:申请详情中下载
- 用户查看申请详情(党员且出国天数>30天)
- 详情弹窗底部显示"下载党籍保留申请"按钮
- 点击按钮下载空白PDF模板
- 线下手工填写、打印、盖章后上传
技术实现
- 使用 iText 5.5.13 PDF生成库
- 支持中文字体(STSong-Light)
- A4纸张大小,标准页边距
- 所有内容区域使用下划线标识,无预填充数据
- 标准模板格式,适用于所有党籍保留申请场景
注意事项
- 模板为完全空白,所有内容需线下手工填写
- 不需要申请ID或记录ID,任何时候都可以下载
- 下载后需打印、手写填写、盖章后扫描上传
- 适用于中共党员且出国天数>30天的情况
- 按钮显示位置:
- 申请表单:党员且出国天数>30天时自动显示
- 申请详情:符合条件时在弹窗底部显示绿色按钮
- 前端实现:必须使用
request工具而不是fetchAPI,以确保包含所有必要的认证请求头 - 附件格式:自 2025-11-27 起,党籍保留附件支持任意文件类型上传,仅保留 10MB 单文件大小限制
错误处理
| HTTP状态码 | 错误信息 | 处理建议 |
|---|---|---|
| 500 | PDF生成失败 | 检查服务器日志,联系技术支持 |
📞 技术支持:如有疑问请联系开发团队
📚 相关文档:参考项目API文档基础规范和开发规范
🆕 更新日志:
- 2025-10-17 新增党籍保留PDF空白模板下载功能(线下手工填写)
- 接口路径调整:从
/application/downloadPartyRetentionTemplate/{id}改为/record/downloadPartyRetention - 模板类型变更:从预填充模板改为完全空白模板
附录:工作流集成说明
动态审批人方案
背景
出国申请业务集成了Warm-Flow工作流引擎,审批流程为:发起人 → 部门领导 → 校领导。审批人根据申请人所属部门动态确定,系统需要实时查询当前待审批人信息。
方案设计
1. 数据库字段说明
rs_overseas_application 表中的 current_approver_id 字段:
- 字段类型:
bigint(20) - 字段作用:冗余展示字段(非核心业务字段)
- 维护方式:不再由后端业务代码维护
- 数据来源:前端通过工作流API实时查询获取
- 设计原因:
- 审批人由工作流引擎动态确定,工作流表
flow_node_user是唯一数据源 - 避免数据冗余和不一致问题
- 简化后端业务逻辑,降低维护成本
- 审批人由工作流引擎动态确定,工作流表
2. 后端实现
核心原则:后端不维护 current_approver_id 字段
// OverseasApplicationServiceImpl.java
// ✅ 新增申请:不设置 current_approver_id
public Long addOverseasApplication(OverseasApplicationBo bo) {
// ... 业务逻辑
// 不再包含:application.setCurrentApproverId(xxx);
}
// ✅ 提交审批:不设置 current_approver_id
public R<Void> submitApplication(Long id) {
// ... 提交工作流
// 不再包含:application.setCurrentApproverId(xxx);
}
// ✅ 审批通过:不设置 current_approver_id
public R<Void> approve(Long id, String remark) {
// ... 审批逻辑
// 不再包含:application.setCurrentApproverId(xxx);
}
代码清理:
- 所有
setCurrentApproverId()调用已移除 - 相关查询逻辑已删除
- 字段仅作为数据库表结构保留(历史兼容)
3. 前端实现
核心方案:通过工作流API实时查询当前审批人
// overseasApplication/index.vue
// 方案一:列表查询时批量获取审批人(推荐)
const getList = async () => {
const response = await listOverseasApplication(queryParams.value);
dataList.value = response.rows;
total.value = response.total;
// 批量查询审批人信息
await batchGetCurrentApproverNames();
};
// 批量获取审批人姓名
const batchGetCurrentApproverNames = async () => {
const promises = dataList.value
.filter(item => item.status === 'processing')
.map(async item => {
try {
// 调用工作流API查询当前审批人
const approvers = await getCurrentApproversForTask(item.flowProcessId);
item.currentApproverName = approvers.map(u => u.name).join('、');
} catch (error) {
item.currentApproverName = '-';
}
});
await Promise.all(promises);
};
// 方案二:详情查询时单独获取审批人
const handleViewDetail = async (row: OverseasApplicationVo) => {
currentRow.value = row;
// 如果流程进行中,查询当前审批人
if (row.flowProcessId && row.status === 'processing') {
try {
const approvers = await getCurrentApproversForTask(row.flowProcessId);
currentRow.value.currentApproverName = approvers.map(u => u.name).join('、');
} catch (error) {
currentRow.value.currentApproverName = '查询失败';
}
}
detailDialogVisible.value = true;
};
工作流API调用:
// 查询当前审批人(从工作流引擎获取)
import { getCurrentApproversForTask } from '@/api/workflow/common';
// API 路径:/api/workflow/instance/{processId}/current-approvers
// 返回格式:
{
"code": 200,
"msg": "操作成功",
"data": [
{
"userId": 1001,
"userName": "张三",
"nodeId": 2,
"nodeName": "部门领导审批"
}
]
}
4. 接口改造
相关API接口响应中的 current_approver_id 字段说明:
| 接口 | 字段说明 | 使用建议 |
|---|---|---|
| 查询列表 | 返回null或历史值 | 忽略,通过工作流API获取 |
| 查询详情 | 返回null或历史值 | 忽略,通过工作流API获取 |
| 新增/修改 | 不处理该字段 | 前端不传递 |
| 提交审批 | 不处理该字段 | 前端不传递 |
5. 优势分析
✅ 数据一致性
- 工作流表是唯一数据源,避免双写不一致
- 审批人变更(如转办、委派)自动生效
✅ 降低维护成本
- 后端无需在多个业务方法中同步更新
- 减少代码复杂度和潜在Bug
✅ 实时性
- 前端每次查询都获取最新审批人
- 支持工作流引擎的高级功能(并行审批、会签等)
✅ 扩展性
- 审批流程调整时,前端无需修改
- 支持更复杂的审批场景(多人会签、或签等)
实施步骤
- ✅ 后端改造:移除所有
current_approver_id字段的赋值代码 - ✅ 前端改造:实现基于工作流API的动态查询
- ⏳ 测试验证:确保列表、详情页面正确显示审批人
- ⏳ 文档更新:同步更新API文档和技术文档
注意事项
- 历史数据中的
current_approver_id字段可能存在脏数据,前端应忽略 - 工作流API调用失败时,前端应显示友好提示(如 "-" 或 "查询失败")
- 性能优化:列表页建议使用批量查询,避免N+1查询问题
- 缓存策略:同一个流程实例的审批人信息可短时间缓存(如30秒)
更新时间:2025-10-28
维护人员:开发团队
变更记录:新增工作流动态审批人方案说明
2025-11-28 更新:出国记录回执下载
- 前端:
web/src/views/rs/overseas/index.vue中的 “下载因私出国(境)情况回执” 按钮改为直接基于 Word 模板生成文件,摆脱后端 PDF 下载接口依赖。 - 模板:
web/public/chuguoqingkuanghuizhi.docx,占位符{{applicantName}}、{{startYear}}、{{startMonth}}、{{startDay}}、{{endYear}}、{{endMonth}}、{{endDay}}、{{destinationText}}、{{exitReasonText}}、{{durationDays}}、{{expenseType}}。 - 数据映射:优先使用记录中的实际出行信息(
actualStartDate、actualEndDate、destinationCountry、exitReason等),缺省时回落到申请单数据,行程天数自动根据起止日期计算,默认费用说明为“费用自理”。 - 交互提示:增加起止日期缺失时的前端校验,模板生成失败会提示用户检查模板或稍后再试。
2025-11-28 更新:审批监控页面审批表导出
- 前端:
web/src/views/rs/overseas/monitor/index.vue的 “下载审批表” 按钮从 PDF 调整为 Word 导出,保持统一的 docxtemplater + image module 生成逻辑。 - 模板:
web/public/chuguojingshenpibiao.docx,覆盖个人信息、行程信息、申请人签名及五级审批节点(部门负责人、人事处、纪委、学院分管领导、学院党委书记)的签名、意见、日期占位符,支持{{%signature}}形式的图片变量。 - 数据来源:优先取
currentDetail详情接口返回值;审批节点数据由approvalHistory根据approvalLevel映射,若无签名/日期则留空。详情接口新增signature字段(申请人手写签名 base64),供模板直接使用。 - 交互提示:仅在审批完成(状态为
1)时显示导出按钮,生成失败时给出友好提示并引导检查模板。