Explorar o código

发票添加批量导出功能

徐滕 hai 4 semanas
pai
achega
83f69ac898

+ 37 - 18
jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/invoice/controller/FinanceInvoiceController.java

@@ -1085,44 +1085,63 @@ public class FinanceInvoiceController {
 
         // 查询发票数据
         List<FinanceInvoiceDTO> invoices = financeInvoiceService.queryByIds(invoiceIds);
+        List<String> failureMessages = new ArrayList<>();
 
         String tempDir = System.getProperty("os.name").toLowerCase().contains("win")
                 ? "D:/attachment-file/batch_invoice_" + System.currentTimeMillis()
                 : "/attachment-file/batch_invoice_" + System.currentTimeMillis();
-        File folder = new File(tempDir);
-        folder.mkdirs();
+        File baseFolder = new File(tempDir);
+        if (!baseFolder.exists()) {
+            baseFolder.mkdirs();
+        }
 
         try {
-            // 下载每个发票的附件
+            // 逐个下载OMS附件到本地临时目录
             for (FinanceInvoiceDTO invoice : invoices) {
-                if (StringUtils.isNotBlank(invoice.getOmsAttachmentUrl())) {
+                if (StringUtils.isBlank(invoice.getOmsAttachmentUrl())) {
+                    failureMessages.add("发票[" + invoice.getNo() + "]无OMS附件");
+                    continue;
+                }
+                try {
+                    String invoicePath = tempDir + "/" + invoice.getNo();
+                    File invoiceFolder = new File(invoicePath);
+                    if (!invoiceFolder.exists()) {
+                        invoiceFolder.mkdirs();
+                    }
+                    // 与单条下载保持一致:去掉前导/,截取到目录路径
                     String fileUrl = invoice.getOmsAttachmentUrl().substring(1);
                     fileUrl = fileUrl.substring(0, fileUrl.lastIndexOf('/') + 1);
-                    String invoiceDir = tempDir + "/" + invoice.getNo();
-                    new File(invoiceDir).mkdirs();
-                    SpringUtil.getBean(IWorkAttachmentApi.class).downloadFolderFromOss(fileUrl, invoiceDir + "/");
+                    SpringUtil.getBean(IWorkAttachmentApi.class).downloadFolderFromOss(fileUrl, invoicePath + "/");
+                } catch (Exception e) {
+                    log.error("批量下载-发票[{}]附件下载失败", invoice.getNo(), e);
+                    failureMessages.add("发票[" + invoice.getNo() + "]下载失败: " + e.getMessage());
                 }
             }
 
-            // 打包成ZIP
+            // 打包为ZIP
             FileUtil.zipFolder(tempDir, tempDir + ".zip");
             File zipFile = new File(tempDir + ".zip");
 
             response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("批量数电票_" + new java.text.SimpleDateFormat("yyyy-MM-dd").format(new Date()) + ".zip", "UTF-8"));
             response.setContentType("application/octet-stream;charset=utf-8");
 
-            OutputStream outputStream = response.getOutputStream();
-            InputStream inputStream = new FileInputStream(zipFile);
-            byte[] bytes = new byte[1024];
-            int i = inputStream.read(bytes);
-            while (i != -1) {
-                outputStream.write(bytes, 0, i);
-                i = inputStream.read(bytes);
+            try (InputStream inputStream = new FileInputStream(zipFile);
+                 BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
+                 OutputStream outputStream = response.getOutputStream()) {
+                byte[] bytes = new byte[1024];
+                int len;
+                while ((len = bufferedInputStream.read(bytes)) != -1) {
+                    outputStream.write(bytes, 0, len);
+                }
+                outputStream.flush();
+            }
+
+            // 将失败信息写入response header
+            if (!failureMessages.isEmpty()) {
+                response.setHeader("X-Download-Failures", URLEncoder.encode(String.join(";", failureMessages), "UTF-8"));
             }
-            inputStream.close();
-            outputStream.flush();
         } catch (Exception e) {
-            e.printStackTrace();
+            log.error("批量下载发票异常", e);
             throw new RuntimeException("批量下载失败:" + e.getMessage());
         } finally {
             // 清理临时文件

+ 13 - 56
jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/invoice/mapper/xml/FinanceInvoiceMapper.xml

@@ -312,15 +312,18 @@
 
     <select id="findList" resultMap="BaseResultMap">
         select
-        <include refid="New_Base_Column_List"></include>,
-        -- 补全原有业务逻辑中缺失的account字段(ResultMap已有该字段映射)
-        CASE WHEN fibs.rn = 1 OR fibs.rn IS NULL THEN fi.account ELSE 0 END AS account,
+        DISTINCT
+        <include refid="Base_Column_List"></include>,
         su.name as operator,
         so.name as operator_office,
-        fibs.report_no,
-        fibs.program_no,
-        -- 保留原有字段返回(ResultMap未映射不影响SQL执行,仅DTO不接收)
-        CASE WHEN fibs.program_id is null THEN concat('其他:', fibs.program_name) ELSE rpr1.name END as programName,
+        -- 项目名称:通过关联子查询获取,避免多行重复
+        (SELECT CASE
+            WHEN fib.program_id IS NULL THEN concat('其他:', fib.program_name)
+            ELSE rpr1.name END
+         FROM finance_invoice_base fib
+         LEFT JOIN program_project_list_info rpr1 ON fib.program_id = rpr1.id
+         WHERE fib.invoice_id = fi.id AND fib.del_flag = '0'
+         LIMIT 1) as programName,
         COALESCE(detail.amount, 0) as amount,
         detail.account as accountDetail,
         detail.number as number,
@@ -328,32 +331,7 @@
         art_invalid.ID_ as task_id_invalid,
         su1.name as reconciliationPeopleName
         from finance_invoice fi
-        left join (
-        -- 优化:MySQL5.7适配 - 先过滤+排序,再生成行号(减少临时表/文件排序)
-        select
-        fib.*,
-        @row_num := if(@prev_invoice_id = fib.invoice_id, @row_num + 1, 1) as rn,
-        @prev_invoice_id := fib.invoice_id
-        from (
-        SELECT * FROM finance_invoice_base WHERE del_flag = '0' ORDER BY invoice_id, id
-        ) fib,
-        (select @row_num := 0, @prev_invoice_id := null) as vars
-        ) fibs on fibs.invoice_id = fi.id
-        left join program_project_list_info rpr1 on fibs.program_id = rpr1.id
-        -- 关联主表(原有逻辑不变)
-        -- left join finance_invoice fi on fibs.invoice_id = fi.id
-        -- 优化明细表行号生成(MySQL5.7适配)
-        left join (
-        select
-        fid.*,
-        @row_num2 := if(@prev_invoice_id2 = fid.invoice_id, @row_num2 + 1, 1) as rn,
-        @prev_invoice_id2 := fid.invoice_id
-        from (
-        SELECT * FROM finance_invoice_detail WHERE del_flag = '0' ORDER BY invoice_id, id
-        ) fid,
-        (select @row_num2 := 0, @prev_invoice_id2 := null) as vars2
-        ) detail on detail.invoice_id = fi.id and (fibs.rn = detail.rn or fibs.rn is null)
-        -- 原有关联表逻辑完全保留
+        left join finance_invoice_detail detail on detail.invoice_id = fi.id and detail.del_flag = '0'
         left join sys_user su on fi.create_by_id = su.id and su.del_flag = '0'
         left join sys_office so on su.office_id = so.id and so.del_flag = '0'
         left join act_ru_task art on fi.proc_ins_id = art.PROC_INST_ID_
@@ -365,30 +343,9 @@
     </select>
 
     <select id="findListCount" resultType="java.lang.Long">
-        select count(1)
+        select count(DISTINCT fi.id)
         from finance_invoice fi
-                 left join (
-            -- 优化:MySQL5.7适配 - 先过滤+排序,再生成行号(减少临时表/文件排序)
-            select
-                fib.*,
-                @row_num := if(@prev_invoice_id = fib.invoice_id, @row_num + 1, 1) as rn,
-    @prev_invoice_id := fib.invoice_id
-            from (
-                SELECT * FROM finance_invoice_base WHERE del_flag = '0' ORDER BY invoice_id, id
-                ) fib,
-                (select @row_num := 0, @prev_invoice_id := null) as vars
-        ) fibs on fibs.invoice_id = fi.id
-                 left join program_project_list_info rpr1 on fibs.program_id = rpr1.id
-                 left join (
-            select
-                fid.*,
-                @row_num2 := if(@prev_invoice_id2 = fid.invoice_id, @row_num2 + 1, 1) as rn,
-    @prev_invoice_id2 := fid.invoice_id
-            from (
-                SELECT * FROM finance_invoice_detail WHERE del_flag = '0' ORDER BY invoice_id, id
-                ) fid,
-                (select @row_num2 := 0, @prev_invoice_id2 := null) as vars2
-        ) detail on detail.invoice_id = fi.id and (fibs.rn = detail.rn or fibs.rn is null)
+                 left join finance_invoice_detail detail on detail.invoice_id = fi.id and detail.del_flag = '0'
                  left join sys_user su on fi.create_by_id = su.id and su.del_flag = '0'
                  left join sys_office so on su.office_id = so.id and so.del_flag = '0'
                  left join act_ru_task art on fi.proc_ins_id = art.PROC_INST_ID_

+ 14 - 16
jeeplus-modules/jeeplus-assess/src/main/java/com/jeeplus/assess/invoice/service/FinanceInvoiceService.java

@@ -109,7 +109,6 @@ public class FinanceInvoiceService extends ServiceImpl<FinanceInvoiceMapper, Fin
         queryWrapper.eq("fi.del_flag","0");
         queryWrapper.orderByDesc("fi.create_time");
         queryWrapper.orderByAsc("fi.id");
-        queryWrapper.orderByAsc("fibs.rn");
         ArrayList<String> searchIdList = new ArrayList<>();
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
         AtomicInteger checkNum = new AtomicInteger();
@@ -322,6 +321,20 @@ public class FinanceInvoiceService extends ServiceImpl<FinanceInvoiceMapper, Fin
                 queryWrapper.eq("fi.is_oms_billing", isOmsBilling);
             }
         }
+        // 下载状态筛选(SQL级别过滤,确保分页和总数准确)
+        if (StringUtils.isNotBlank(financeInvoiceDTO.getDownloadStatusFilter())) {
+            List<String> downloadedIds = SpringUtil.getBean(FinanceInvoiceDownloadService.class).getDownloadedInvoiceIds();
+            if ("1".equals(financeInvoiceDTO.getDownloadStatusFilter())) {
+                if (CollectionUtil.isEmpty(downloadedIds)) {
+                    return new Page<>();
+                }
+                queryWrapper.in("fi.id", downloadedIds);
+            } else if ("0".equals(financeInvoiceDTO.getDownloadStatusFilter())) {
+                if (CollectionUtil.isNotEmpty(downloadedIds)) {
+                    queryWrapper.notIn("fi.id", downloadedIds);
+                }
+            }
+        }
         //关闭自动查询count
         page.setSearchCount(false);
         //自定义count
@@ -372,21 +385,6 @@ public class FinanceInvoiceService extends ServiceImpl<FinanceInvoiceMapper, Fin
             }
         }
 
-        // 下载状态筛选
-        if (StringUtils.isNotBlank(financeInvoiceDTO.getDownloadStatusFilter())) {
-            List<String> downloadedIds = SpringUtil.getBean(FinanceInvoiceDownloadService.class).getDownloadedInvoiceIds();
-            if ("1".equals(financeInvoiceDTO.getDownloadStatusFilter())) {
-                // 筛选已下载
-                if (CollectionUtil.isEmpty(downloadedIds)) {
-                    return new Page<FinanceInvoiceDTO>();
-                }
-                pageList.getRecords().removeIf(item -> !downloadedIds.contains(item.getId()));
-            } else if ("0".equals(financeInvoiceDTO.getDownloadStatusFilter())) {
-                // 筛选未下载
-                pageList.getRecords().removeIf(item -> downloadedIds.contains(item.getId()));
-            }
-        }
-
         return pageList;
     }
 

+ 4 - 1
jeeplus-modules/jeeplus-finance/src/main/java/com/jeeplus/finance/invoice/controller/CwFinanceInvoiceController.java

@@ -1489,7 +1489,10 @@ public class CwFinanceInvoiceController {
                     if (!invoiceFolder.exists()) {
                         invoiceFolder.mkdirs();
                     }
-                    SpringUtil.getBean(IWorkAttachmentApi.class).downloadFolderFromOss(invoice.getOmsAttachmentUrl(), invoicePath + "/");
+                    // 与单条下载保持一致:去掉前导/,截取到目录路径
+                    String fileUrl = invoice.getOmsAttachmentUrl().substring(1);
+                    fileUrl = fileUrl.substring(0, fileUrl.lastIndexOf('/') + 1);
+                    SpringUtil.getBean(IWorkAttachmentApi.class).downloadFolderFromOss(fileUrl, invoicePath + "/");
                 } catch (Exception e) {
                     log.error("批量下载-发票[{}]附件下载失败", invoice.getNo(), e);
                     failureMessages.add("发票[" + invoice.getNo() + "]下载失败: " + e.getMessage());