Files
hzdyjs/docs/开发文档/API/出国申请管理API.md
T

48 KiB
Raw Blame History

出国申请管理 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级:学院党委书记审批权限
  • 权限使用说明:

    • 审批接口采用 OR模式,用户拥有以上任一权限即可调用接口
    • 具体审批权限在业务层验证,必须匹配申请的 approval_level
    • 部门负责人通过 rs:overseas:approve1 权限识别,自动应用部门数据过滤

🔐 数据权限控制

权限分级说明

出国申请系统采用基于角色和部门的多级数据权限控制,确保用户只能访问其权限范围内的数据。

角色权限矩阵

角色 角色标识 数据访问范围 可见申请范围 备注
超级管理员 admin 全局数据 所有申请 不受任何限制
人事管理员 rs-admin 全局数据 所有申请 仅当不是部门负责人时
申请人 rs-Applicant 个人数据 仅自己的申请 只能查看和管理自己的申请
部门负责人 具有rs:overseas:approve1权限 本部门数据 本部门所有申请 优先级最高
普通审批人 其他审批权限 分配数据 分配给自己的审批 只能看到分配的审批任务

部门权限过滤规则(🆕 2025-01-28)

核心原则:部门负责人只能看到本部门成员提交的申请,不能看到其他部门的申请。

实现逻辑:

  1. 判断用户是否为部门负责人(三种方式任选其一):

    • 具有 rs:overseas:approve1 权限
    • 具有 dept_head_role 角色
    • 具有 overseas:application:dept_head:approve 权限(兼容旧版)
  2. 应用部门过滤:

    • 查询条件:申请人的dept_id = 当前用户的dept_id
    • SQL实现:通过 sys_user 表关联,筛选申请人所属部门
    • 重要:不限制审批人(approverId),只限制申请人部门(deptId)
  3. 权限优先级(从高到低):

    超级管理员 > 申请人(自己的数据)> 部门负责人(本部门)> 人事管理员(全局)> 普通审批人(分配数据)
    

示例场景:

假设有以下用户和部门:

  • 张三: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;            // 审批状态文本
}

🔧 核心接口详细说明

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级:学院党委书记审批权限

权限验证机制:

  1. 接口层验证:Controller使用 @SaCheckPermission(value={...}, mode=SaMode.OR),满足任一权限即可调用接口
  2. 业务层验证:Service层根据申请的 approval_level 字段验证用户是否拥有对应级别的审批权限
  3. 权限不匹配处理:如果用户审批级别与申请要求不符,返回业务异常"您没有第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

功能说明

修复已审批通过但由于系统异常未自动创建出国记录的申请。该接口会:

  1. 查询所有状态为"已通过"的申请
  2. 检查是否存在对应的出国记录
  3. 为缺失记录的申请自动创建出国记录

请求参数

无需参数,直接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'),因为只有通过审批的申请才会出现在记录中

🔄 业务流程说明

申请流程

  1. 提交申请:用户填写申请信息并提交,状态为"待审核",审批级别为"部门主管"
  2. 部门主管审批:部门主管审批通过后,审批级别自动流转到"分管领导"
  3. 分管领导审批:分管领导审批通过后,审批级别自动流转到"校领导"
  4. 校领导审批:校领导审批通过后,申请状态变为"已通过",自动创建出国记录
  5. 完成出国:申请人完成出国活动后,更新记录状态为"已完成",申请状态同步更新

状态流转

草稿状态 → 待审核 → 已通过/已拒绝
              ↓
           已取消
              ↓
           已完成

权限控制

  • 申请人:可以查看自己的申请,编辑草稿状态的申请,提交/取消申请
  • 审批人:可以查看待审批的申请,进行审批操作
  • 管理员:拥有所有权限,可以管理所有申请和记录

🧪 测试说明

测试环境

  • 基础URL:http://localhost:8080
  • 认证方式:Bearer Token
  • 必需Header:
    Authorization: Bearer {token}
    Content-Type: application/json
    clientid: ruoyi-web
    referer: http://localhost
    

测试用例

  1. 申请管理测试:创建申请→提交申请→审批流程→状态验证
  2. 权限测试:不同角色的权限边界测试
  3. 业务流程测试:完整的申请到完成流程测试
  4. 数据校验测试:参数验证、业务规则验证

注意事项

  • 测试前确保数据库表结构已创建
  • 测试用户需要有相应的权限
  • 审批测试需要使用不同级别的审批人账号
  • 时间字段格式为: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模板包含以下空白填写区域(完全手工填写):

  1. 标题:关于因私赴 ______________ __________保留党籍的申请
  2. 支部信息:______________________ 支部:
  3. 申请人信息:
    • 本人 (_____),现任 _______________
    • 计划于 ____________________
  4. 出国信息:
    • 至 ____________________ 偕配偶 _______________
    • 因私赴 _______________(国家 或地区)探望 在
    • _________________________ 的工作(留学、定居)的 __________
    • 在外停留 __________ 天(含路、抵返国境当
  5. 申请内容:日)。现申请保留期间暂缓籍。
  6. 结束语:特此申请,望予批准。
  7. 签名区域:
    • 申请人:_______________
    • 申请日期: ____________________

使用流程

方式一:申请表单中下载

  1. 用户在新增/编辑申请时,系统检测到是党员且出国天数>30天
  2. 系统显示党籍保留附件上传区域
  3. 用户点击"下载党籍保留申请PDF模板"按钮
  4. 系统生成并下载空白PDF模板
  5. 用户线下手工填写所有内容、打印、盖章
  6. 扫描成PDF后上传到系统

方式二:申请详情中下载

  1. 用户查看申请详情(党员且出国天数>30天)
  2. 详情弹窗底部显示"下载党籍保留申请"按钮
  3. 点击按钮下载空白PDF模板
  4. 线下手工填写、打印、盖章后上传

技术实现

  • 使用 iText 5.5.13 PDF生成库
  • 支持中文字体(STSong-Light)
  • A4纸张大小,标准页边距
  • 所有内容区域使用下划线标识,无预填充数据
  • 标准模板格式,适用于所有党籍保留申请场景

注意事项

  • 模板为完全空白,所有内容需线下手工填写
  • 不需要申请ID或记录ID,任何时候都可以下载
  • 下载后需打印、手写填写、盖章后扫描上传
  • 适用于中共党员且出国天数>30天的情况
  • 按钮显示位置:
    • 申请表单:党员且出国天数>30天时自动显示
    • 申请详情:符合条件时在弹窗底部显示绿色按钮
  • 前端实现:必须使用 request 工具而不是 fetch API,以确保包含所有必要的认证请求头

错误处理

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

✅ 实时性

  • 前端每次查询都获取最新审批人
  • 支持工作流引擎的高级功能(并行审批、会签等)

✅ 扩展性

  • 审批流程调整时,前端无需修改
  • 支持更复杂的审批场景(多人会签、或签等)

实施步骤

  1. ✅ 后端改造:移除所有 current_approver_id 字段的赋值代码
  2. ✅ 前端改造:实现基于工作流API的动态查询
  3. ⏳ 测试验证:确保列表、详情页面正确显示审批人
  4. ⏳ 文档更新:同步更新API文档和技术文档

注意事项

  • 历史数据中的 current_approver_id 字段可能存在脏数据,前端应忽略
  • 工作流API调用失败时,前端应显示友好提示(如 "-" 或 "查询失败")
  • 性能优化:列表页建议使用批量查询,避免N+1查询问题
  • 缓存策略:同一个流程实例的审批人信息可短时间缓存(如30秒)

更新时间:2025-10-28
维护人员:开发团队
变更记录:新增工作流动态审批人方案说明