Просмотр исходного кода

“完成出国申请审批流程11.3”

weizhong 1 год назад
Родитель
Сommit
9af67076a1

+ 73 - 0
backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsOverseasApplicationController.java

@@ -550,6 +550,79 @@ public class RsOverseasApplicationController extends BaseController {
         }
     }
 
+    // ==================== 党籍保留附件上传接口 ====================
+
+    /**
+     * 上传党籍保留附件
+     */
+    @SaCheckPermission("rs:overseas:add")
+    @PostMapping("/uploadPartyRetentionFile")
+    @Log(title = "上传党籍保留附件", businessType = BusinessType.OTHER)
+    public R<Map<String, Object>> uploadPartyRetentionFile(@RequestParam("file") MultipartFile file,
+            @RequestParam("applicationId") Long applicationId) {
+        try {
+            // 验证文件格式
+            String contentType = file.getContentType();
+            if (!isValidFileType(contentType)) {
+                return R.fail("不支持的文件格式,请上传PDF、JPG或PNG文件");
+            }
+
+            // 验证文件大小(10MB)
+            long maxSize = 10 * 1024 * 1024; // 10MB
+            if (file.getSize() > maxSize) {
+                return R.fail("文件大小超过10MB限制");
+            }
+
+            // 使用系统OSS服务上传文件(自动保存到sys_oss表)
+            SysOssVo ossResult = ossService.upload(file);
+
+            // 更新申请记录 - 存储OSS ID和文件路径
+            applicationService.updatePartyRetentionFileInfo(
+                    applicationId,
+                    ossResult.getUrl(), // 文件URL
+                    ossResult.getOriginalName(), // 原始文件名
+                    new Date(), // 上传时间
+                    "1", // 上传状态:已上传
+                    ossResult.getOssId() // OSS文件ID
+            );
+
+            // 返回结果
+            Map<String, Object> result = new HashMap<>();
+            result.put("filePath", ossResult.getUrl());
+            result.put("fileName", ossResult.getOriginalName());
+            result.put("uploadTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
+            result.put("ossId", ossResult.getOssId());
+
+            return R.ok("党籍保留附件上传成功", result);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            return R.fail("系统异常:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 下载党籍保留附件(安全下载)
+     */
+    @SaCheckPermission("rs:overseas:query")
+    @GetMapping("/downloadPartyRetentionFile/{applicationId}")
+    public void downloadPartyRetentionFile(@PathVariable Long applicationId, HttpServletResponse response) {
+        try {
+            RsOverseasApplicationVo application = applicationService.queryById(applicationId);
+            if (application == null || application.getPartyRetentionFileOssId() == null) {
+                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
+                response.setContentType("application/json;charset=UTF-8");
+                response.getWriter().write("{\"code\":404,\"msg\":\"文件不存在\"}");
+                return;
+            }
+
+            // 使用系统OSS服务进行安全下载
+            ossService.secureDownload(application.getPartyRetentionFileOssId(), response);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
     /**
      * 验证文件类型
      */

+ 15 - 0
backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsOverseasRecordController.java

@@ -30,6 +30,7 @@ import org.dromara.rs.domain.bo.RsOverseasRecordBo;
 import org.dromara.rs.domain.vo.RsOverseasRecordVo;
 import org.dromara.rs.domain.query.RsOverseasRecordQuery;
 import org.dromara.rs.service.IRsOverseasRecordService;
+import org.dromara.rs.service.IRegistrationFormService;
 import org.dromara.rs.util.OverseasReceiptPdfUtil;
 
 import java.io.IOException;
@@ -50,6 +51,9 @@ public class RsOverseasRecordController extends BaseController {
     @Autowired
     private IRsOverseasRecordService recordService;
 
+    @Autowired
+    private IRegistrationFormService registrationFormService;
+
     /**
      * 查询出国记录列表
      */
@@ -100,6 +104,17 @@ public class RsOverseasRecordController extends BaseController {
         ExcelUtil.exportExcel(list, "出国记录数据", RsOverseasRecordVo.class, response);
     }
 
+    /**
+     * 下载党籍保留申请PDF模板
+     * 注意:此接口必须放在 /{recordId} 之前,避免路由冲突
+     */
+    @SaCheckPermission("rs:overseas:query")
+    @Log(title = "下载党籍保留申请模板", businessType = BusinessType.EXPORT)
+    @GetMapping("/downloadPartyRetention")
+    public void downloadPartyRetention(HttpServletResponse response) {
+        registrationFormService.downloadPartyMembershipTemplate(response);
+    }
+
     /**
      * 获取出国记录详细信息
      */

+ 6 - 0
backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/domain/RsOverseasApplication.java

@@ -315,6 +315,12 @@ public class RsOverseasApplication extends BaseEntity {
     @ExcelProperty(value = "应急联系人及电话")
     private String emergencyContact;
 
+    /**
+     * 附件OSS ID列表(逗号分隔)
+     */
+    @ExcelProperty(value = "附件ID列表")
+    private String attachmentIds;
+
     /**
      * 手写签字(base64格式)
      */

+ 5 - 0
backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/domain/bo/RsOverseasApplicationBo.java

@@ -251,6 +251,11 @@ public class RsOverseasApplicationBo extends BaseEntity {
      */
     private String emergencyContact;
 
+    /**
+     * 附件OSS ID列表(逗号分隔)
+     */
+    private String attachmentIds;
+
     /**
      * 手写签字(base64格式)
      */

+ 5 - 0
backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/domain/query/RsOverseasApplicationQuery.java

@@ -33,6 +33,11 @@ public class RsOverseasApplicationQuery extends PageQuery {
      */
     private String purpose;
 
+    /**
+     * 出境事由
+     */
+    private String exitReason;
+
     /**
      * 目的地国家
      */

+ 5 - 0
backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/domain/vo/RsOverseasApplicationVo.java

@@ -297,6 +297,11 @@ public class RsOverseasApplicationVo implements Serializable {
      */
     private String emergencyContact;
 
+    /**
+     * 附件OSS ID列表(逗号分隔)
+     */
+    private String attachmentIds;
+
     /**
      * 手写签字(base64格式)
      */

+ 14 - 0
backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/service/IRsOverseasApplicationService.java

@@ -195,6 +195,20 @@ public interface IRsOverseasApplicationService {
         Boolean updateStampedFileInfo(Long applicationId, String filePath, String fileName,
                         java.util.Date uploadTime, String uploadStatus, Long ossId);
 
+        /**
+         * 更新党籍保留附件信息
+         *
+         * @param applicationId 申请ID
+         * @param filePath      文件路径
+         * @param fileName      文件名
+         * @param uploadTime    上传时间
+         * @param uploadStatus  上传状态
+         * @param ossId         OSS文件ID
+         * @return 是否成功
+         */
+        Boolean updatePartyRetentionFileInfo(Long applicationId, String filePath, String fileName,
+                        java.util.Date uploadTime, String uploadStatus, Long ossId);
+
         /**
          * 校验出国登记前置条件
          * 检查近3个月内是否有已通过的出国登记记录

+ 17 - 0
backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/service/impl/RsOverseasApplicationServiceImpl.java

@@ -983,6 +983,23 @@ public class RsOverseasApplicationServiceImpl extends ServiceImpl<RsOverseasAppl
                         .set(RsOverseasApplication::getStampedFileOssId, ossId)) > 0;
     }
 
+    /**
+     * 更新党籍保留附件信息
+     */
+    @Override
+    @Transactional
+    public Boolean updatePartyRetentionFileInfo(Long applicationId, String filePath, String fileName,
+            java.util.Date uploadTime, String uploadStatus, Long ossId) {
+        return baseMapper.update(null,
+                new LambdaUpdateWrapper<RsOverseasApplication>()
+                        .eq(RsOverseasApplication::getApplicationId, applicationId)
+                        .set(RsOverseasApplication::getPartyRetentionFilePath, filePath)
+                        .set(RsOverseasApplication::getPartyRetentionFileName, fileName)
+                        .set(RsOverseasApplication::getPartyRetentionUploadTime, uploadTime)
+                        .set(RsOverseasApplication::getPartyRetentionUploadStatus, uploadStatus)
+                        .set(RsOverseasApplication::getPartyRetentionFileOssId, ossId)) > 0;
+    }
+
     /**
      * 校验出国登记前置条件
      * 检查当前自然年内是否有已通过的出国登记记录

+ 15 - 1
backend/ruoyi-modules/ruoyi-rs/src/main/resources/mapper/rs/RsOverseasApplicationMapper.xml

@@ -52,12 +52,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="adminRemark" column="admin_remark"/>
         <result property="applicantRemark" column="applicant_remark"/>
         <result property="emergencyContact" column="emergency_contact"/>
+        <result property="attachmentIds" column="attachment_ids"/>
         <result property="signature" column="signature"/>
         <result property="stampedRegistrationFilePath" column="stamped_registration_file_path"/>
         <result property="stampedRegistrationFileName" column="stamped_registration_file_name"/>
         <result property="stampedFileOssId" column="stamped_file_oss_id"/>
         <result property="stampedFileUploadTime" column="stamped_file_upload_time"/>
         <result property="stampedFileUploadStatus" column="stamped_file_upload_status"/>
+        <result property="partyRetentionFilePath" column="party_retention_file_path"/>
+        <result property="partyRetentionFileName" column="party_retention_file_name"/>
+        <result property="partyRetentionUploadTime" column="party_retention_upload_time"/>
+        <result property="partyRetentionUploadStatus" column="party_retention_upload_status"/>
+        <result property="partyRetentionFileOssId" column="party_retention_file_oss_id"/>
         <result property="tenantId" column="tenant_id"/>
         <result property="createBy" column="create_by"/>
         <result property="createTime" column="create_time"/>
@@ -89,9 +95,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         oa.start_date, oa.end_date, oa.duration, oa.invitation, oa.itinerary,
         oa.accommodation_plan, oa.transportation_plan, oa.status, oa.approval_status, oa.current_approver, oa.approval_level,
         oa.apply_time, oa.approval_time, oa.admin_remark, oa.applicant_remark, 
-        oa.emergency_contact, oa.signature,
+        oa.emergency_contact, oa.attachment_ids, oa.signature,
         oa.stamped_registration_file_path, oa.stamped_registration_file_name, 
         oa.stamped_file_upload_time, oa.stamped_file_upload_status, oa.stamped_file_oss_id,
+        oa.party_retention_file_path, oa.party_retention_file_name,
+        oa.party_retention_upload_time, oa.party_retention_upload_status, oa.party_retention_file_oss_id,
         oa.tenant_id, oa.create_by, oa.create_time, oa.update_by, oa.update_time, oa.deleted,
         CASE 
             WHEN oa.status IS NULL OR oa.status = '' THEN '草稿'
@@ -199,6 +207,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="purpose != null and purpose != ''">
                 AND oa.purpose = #{purpose}
             </if>
+            <if test="exitReason != null and exitReason != ''">
+                AND oa.exit_reason = #{exitReason}
+            </if>
             <if test="destination != null and destination != ''">
                 AND oa.destination like concat('%', #{destination}, '%')
             </if>
@@ -257,6 +268,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="purpose != null and purpose != ''">
                 AND oa.purpose = #{purpose}
             </if>
+            <if test="exitReason != null and exitReason != ''">
+                AND oa.exit_reason = #{exitReason}
+            </if>
             <if test="destination != null and destination != ''">
                 AND oa.destination like concat('%', #{destination}, '%')
             </if>

+ 5 - 1
web/src/api/rs/overseas.ts

@@ -6,7 +6,7 @@ export interface OverseasApplicationQuery {
   pageSize: number;
   applicantName?: string;
   department?: string;
-  purpose?: string;
+  exitReason?: string;
   destination?: string;
   status?: string;
   approvalLevel?: string;
@@ -96,6 +96,8 @@ export interface OverseasApplicationVO {
   approvalStatus?: string;        // 工作流审批状态:draft/waiting/finish/back/cancel
   approvalStatusText?: string;    // 工作流审批状态文本
   taskId?: string;                // 当前待办任务ID(用于审批跳转)
+  // 附件相关字段
+  attachmentIds?: string;         // 附件OSS ID列表(逗号分隔)
 }
 
 // 出国申请表单类型
@@ -150,6 +152,8 @@ export interface OverseasApplicationForm {
   applicantRemark?: string;
   // 工作流相关字段
   approvalStatus?: string;        // 工作流审批状态
+  // 附件相关字段
+  attachmentIds?: string;         // 附件OSS ID列表(逗号分隔)
 }
 
 // 审批请求类型(支持标准工作流模式)

+ 25 - 48
web/src/views/rs/overseas/approval.vue

@@ -7,39 +7,20 @@
           <el-card shadow="hover">
             <el-form ref="queryForm" :model="queryParams" label-width="100px">
               <el-row :gutter="20">
-                <el-col :span="5">
-                  <el-form-item label="申请人" prop="applicantName">
-                    <el-input
-                      v-model="queryParams.applicantName"
-                      placeholder="请输入申请人姓名"
-                      clearable
-                      @keyup.enter="handleQuery"
-                    />
-                  </el-form-item>
-                </el-col>
-                <el-col :span="5">
-                  <el-form-item label="所属部门" prop="department">
-                    <el-input v-model="queryParams.department" placeholder="请输入所属部门" clearable @keyup.enter="handleQuery" />
-                  </el-form-item>
-                </el-col>
-                <el-col :span="5">
-                  <el-form-item label="目的地" prop="destination">
+                <el-col :span="6">
+                  <el-form-item label="前往国家" prop="destination">
                     <el-input
                       v-model="queryParams.destination"
-                      placeholder="请输入目的地国家"
+                      placeholder="请输入前往国家"
                       clearable
                       @keyup.enter="handleQuery"
                     />
                   </el-form-item>
                 </el-col>
-                <el-col :span="5">
-                  <el-form-item label="申请状态" prop="status">
-                    <el-select v-model="queryParams.status" placeholder="请选择申请状态" clearable style="width: 100%">
-                      <el-option label="待审核" value="0" />
-                      <el-option label="已通过" value="1" />
-                      <el-option label="已拒绝" value="2" />
-                      <el-option label="已取消" value="3" />
-                      <el-option label="已完成" value="4" />
+                <el-col :span="6">
+                  <el-form-item label="出境事由" prop="exitReason">
+                    <el-select v-model="queryParams.exitReason" placeholder="请选择出境事由" clearable style="width: 100%">
+                      <el-option v-for="dict in exitReasonOptions" :key="dict.label" :label="dict.label" :value="dict.label" />
                     </el-select>
                   </el-form-item>
                 </el-col>
@@ -79,8 +60,14 @@
           >
           <el-table-column label="申请人" align="center" prop="applicantName" min-width="100" show-overflow-tooltip />
           <el-table-column label="部门" align="center" prop="department" min-width="140" show-overflow-tooltip />
-          <el-table-column label="目的地" align="center" prop="destination" min-width="120" show-overflow-tooltip />
-          <el-table-column label="出国事由" align="center" prop="purpose" min-width="140" show-overflow-tooltip />
+          <el-table-column label="政治面貌" align="center" prop="politicalStatusText" min-width="100" show-overflow-tooltip />
+          <el-table-column label="前往国家" align="center" prop="destination" min-width="120" show-overflow-tooltip />
+          <el-table-column label="出境事由" align="center" prop="exitReason" min-width="140" show-overflow-tooltip />
+          <el-table-column label="出国天数" align="center" prop="duration" min-width="100">
+            <template #default="scope">
+              <span>{{ scope.row.duration || 0 }}天</span>
+            </template>
+          </el-table-column>
           <el-table-column label="申请时间" align="center" prop="applyTime" min-width="170">
             <template #default="scope">
               <span>{{ scope.row.applyTime ? new Date(scope.row.applyTime).toLocaleString() : '-' }}</span>
@@ -392,12 +379,15 @@ const state = reactive({
   queryParams: {
     pageNum: 1,
     pageSize: 10,
-    applicantName: '',
-    department: '',
     destination: '',
-    status: ''
+    exitReason: ''
   } as OverseasApplicationQuery,
 
+  // 出境事由选项
+  exitReasonOptions: [
+    { label: '旅游', value: 'tourism' },
+    { label: '探亲', value: 'visiting_relatives' }
+  ],
 
   // 查看详情
   viewDialog: {
@@ -427,6 +417,7 @@ const {
   total,
   showSearch,
   queryParams,
+  exitReasonOptions,
   viewDialog,
   viewData,
   approvalDialog,
@@ -469,27 +460,15 @@ const applyFilterAndPagination = () => {
   let filteredList = [...state.allApplicationList];
   
   // 🔴 应用搜索过滤
-  if (state.queryParams.applicantName) {
-    filteredList = filteredList.filter(item => 
-      item.applicantName?.includes(state.queryParams.applicantName || '')
-    );
-  }
-  
-  if (state.queryParams.department) {
-    filteredList = filteredList.filter(item => 
-      item.department?.includes(state.queryParams.department || '')
-    );
-  }
-  
   if (state.queryParams.destination) {
     filteredList = filteredList.filter(item => 
       item.destination?.includes(state.queryParams.destination || '')
     );
   }
   
-  if (state.queryParams.status) {
+  if (state.queryParams.exitReason) {
     filteredList = filteredList.filter(item => 
-      item.status === state.queryParams.status
+      item.exitReason === state.queryParams.exitReason
     );
   }
   
@@ -518,10 +497,8 @@ const resetQuery = () => {
     Object.assign(state.queryParams, {
       pageNum: 1,
       pageSize: 10,
-      applicantName: '',
-      department: '',
       destination: '',
-      status: ''
+      exitReason: ''
     });
     const form = proxy.$refs.queryForm;
     if (form && typeof form.resetFields === 'function') {

Разница между файлами не показана из-за своего большого размера
+ 540 - 430
web/src/views/rs/overseas/index.vue


Некоторые файлы не были показаны из-за большого количества измененных файлов