36 changed files with 2091 additions and 45 deletions
@ -0,0 +1,107 @@ |
|||||
|
package org.dromara.productManagement.controller; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import jakarta.servlet.http.HttpServletResponse; |
||||
|
import jakarta.validation.constraints.*; |
||||
|
import cn.dev33.satoken.annotation.SaCheckPermission; |
||||
|
import org.dromara.productManagement.domain.ContractualInfo; |
||||
|
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.log.enums.BusinessType; |
||||
|
import org.dromara.common.excel.utils.ExcelUtil; |
||||
|
import org.dromara.productManagement.domain.vo.ContractualInfoVo; |
||||
|
import org.dromara.productManagement.domain.bo.ContractualInfoBo; |
||||
|
import org.dromara.productManagement.service.IContractualInfoService; |
||||
|
import org.dromara.common.mybatis.core.page.TableDataInfo; |
||||
|
|
||||
|
/** |
||||
|
* 合同信息保存 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
* @date 2025-03-10 |
||||
|
*/ |
||||
|
@Validated |
||||
|
@RequiredArgsConstructor |
||||
|
@RestController |
||||
|
@RequestMapping("/productManagement/ContractualInfo") |
||||
|
public class ContractualInfoController extends BaseController { |
||||
|
|
||||
|
private final IContractualInfoService ContractualInfoService; |
||||
|
|
||||
|
/** |
||||
|
* 查询合同信息保存列表 |
||||
|
*/ |
||||
|
@SaCheckPermission("productManagement:ContractualInfo:list") |
||||
|
@GetMapping("/list") |
||||
|
public TableDataInfo<ContractualInfoVo> list(ContractualInfoBo bo, PageQuery pageQuery) { |
||||
|
return ContractualInfoService.queryPageList(bo, pageQuery); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 导出合同信息保存列表 |
||||
|
*/ |
||||
|
@SaCheckPermission("productManagement:ContractualInfo:export") |
||||
|
@Log(title = "合同信息保存", businessType = BusinessType.EXPORT) |
||||
|
@PostMapping("/export") |
||||
|
public void export(ContractualInfoBo bo, HttpServletResponse response) { |
||||
|
List<ContractualInfoVo> list = ContractualInfoService.queryList(bo); |
||||
|
ExcelUtil.exportExcel(list, "合同信息保存", ContractualInfoVo.class, response); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取合同信息保存详细信息 |
||||
|
* |
||||
|
* @param id 主键 |
||||
|
*/ |
||||
|
@SaCheckPermission("productManagement:ContractualInfo:query") |
||||
|
@GetMapping("/{id}") |
||||
|
public R<ContractualInfoVo> getInfo(@NotNull(message = "主键不能为空") |
||||
|
@PathVariable Long id) { |
||||
|
return R.ok(ContractualInfoService.queryById(id)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 新增合同信息保存 |
||||
|
*/ |
||||
|
@SaCheckPermission("productManagement:ContractualInfo:add") |
||||
|
@Log(title = "合同信息保存", businessType = BusinessType.INSERT) |
||||
|
@RepeatSubmit() |
||||
|
@PostMapping() |
||||
|
public R<Void> add(@Validated(AddGroup.class) @RequestBody ContractualInfoBo bo) { |
||||
|
return toAjax(ContractualInfoService.insertByBo(bo)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 修改合同信息保存 |
||||
|
*/ |
||||
|
@SaCheckPermission("productManagement:ContractualInfo:edit") |
||||
|
@Log(title = "合同信息保存", businessType = BusinessType.UPDATE) |
||||
|
@RepeatSubmit() |
||||
|
@PutMapping() |
||||
|
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ContractualInfoBo bo) { |
||||
|
return toAjax(ContractualInfoService.updateByBo(bo)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 删除合同信息保存 |
||||
|
* |
||||
|
* @param ids 主键串 |
||||
|
*/ |
||||
|
@SaCheckPermission("productManagement:ContractualInfo:remove") |
||||
|
@Log(title = "合同信息保存", businessType = BusinessType.DELETE) |
||||
|
@DeleteMapping("/{ids}") |
||||
|
public R<Void> remove(@NotEmpty(message = "主键不能为空") |
||||
|
@PathVariable Long[] ids) { |
||||
|
return toAjax(ContractualInfoService.deleteWithValidByIds(List.of(ids), true)); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,133 @@ |
|||||
|
package org.dromara.productManagement.controller; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.List; |
||||
|
|
||||
|
import cn.hutool.core.io.resource.InputStreamResource; |
||||
|
import com.fasterxml.jackson.core.JsonProcessingException; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import jakarta.servlet.http.HttpServletResponse; |
||||
|
import jakarta.validation.constraints.*; |
||||
|
import cn.dev33.satoken.annotation.SaCheckPermission; |
||||
|
import org.dromara.productManagement.domain.ContractualRes; |
||||
|
import org.dromara.system.domain.vo.SysOssUploadVo; |
||||
|
import org.dromara.system.domain.vo.SysOssVo; |
||||
|
import org.springframework.http.MediaType; |
||||
|
import org.springframework.http.ResponseEntity; |
||||
|
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.log.enums.BusinessType; |
||||
|
import org.dromara.common.excel.utils.ExcelUtil; |
||||
|
import org.dromara.productManagement.domain.vo.JyjContractualTaskBatchVo; |
||||
|
import org.dromara.productManagement.domain.bo.JyjContractualTaskBatchBo; |
||||
|
import org.dromara.productManagement.service.IJyjContractualTaskBatchService; |
||||
|
import org.dromara.common.mybatis.core.page.TableDataInfo; |
||||
|
import org.springframework.web.multipart.MultipartFile; |
||||
|
|
||||
|
/** |
||||
|
* 合同批处理记录 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
* @date 2025-03-05 |
||||
|
*/ |
||||
|
@Validated |
||||
|
@RequiredArgsConstructor |
||||
|
@RestController |
||||
|
@RequestMapping("/productManagement/JyjcontractualTaskBatch") |
||||
|
public class JyjContractualTaskBatchController extends BaseController { |
||||
|
|
||||
|
private final IJyjContractualTaskBatchService jyjContractualTaskBatchService; |
||||
|
|
||||
|
/** |
||||
|
* 查询合同批处理记录列表 |
||||
|
*/ |
||||
|
@SaCheckPermission("productManagement:JyjcontractualTaskBatch:list") |
||||
|
@GetMapping("/list") |
||||
|
public TableDataInfo<JyjContractualTaskBatchVo> list(JyjContractualTaskBatchBo bo, PageQuery pageQuery) { |
||||
|
return jyjContractualTaskBatchService.queryPageList(bo, pageQuery); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 导出合同批处理记录列表 |
||||
|
*/ |
||||
|
@SaCheckPermission("productManagement:JyjcontractualTaskBatch:export") |
||||
|
@Log(title = "合同批处理记录", businessType = BusinessType.EXPORT) |
||||
|
@PostMapping("/export") |
||||
|
public void export(JyjContractualTaskBatchBo bo, HttpServletResponse response) { |
||||
|
List<JyjContractualTaskBatchVo> list = jyjContractualTaskBatchService.queryList(bo); |
||||
|
ExcelUtil.exportExcel(list, "合同批处理记录", JyjContractualTaskBatchVo.class, response); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取合同批处理记录详细信息 |
||||
|
* |
||||
|
* @param id 主键 |
||||
|
*/ |
||||
|
@SaCheckPermission("productManagement:JyjcontractualTaskBatch:query") |
||||
|
@GetMapping("/{id}") |
||||
|
public R<JyjContractualTaskBatchVo> getInfo(@NotNull(message = "主键不能为空") |
||||
|
@PathVariable Long id) { |
||||
|
return R.ok(jyjContractualTaskBatchService.queryById(id)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 新增合同批处理记录 |
||||
|
*/ |
||||
|
@SaCheckPermission("productManagement:JyjcontractualTaskBatch:add") |
||||
|
@Log(title = "合同批处理记录", businessType = BusinessType.INSERT) |
||||
|
@RepeatSubmit() |
||||
|
@PostMapping() |
||||
|
public R<Void> add(@Validated(AddGroup.class) @RequestBody JyjContractualTaskBatchBo bo) { |
||||
|
return toAjax(jyjContractualTaskBatchService.insertByBo(bo)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 修改合同批处理记录 |
||||
|
*/ |
||||
|
@SaCheckPermission("productManagement:JyjcontractualTaskBatch:edit") |
||||
|
@Log(title = "合同批处理记录", businessType = BusinessType.UPDATE) |
||||
|
@RepeatSubmit() |
||||
|
@PutMapping() |
||||
|
public R<Void> edit(@Validated(EditGroup.class) @RequestBody JyjContractualTaskBatchBo bo) { |
||||
|
return toAjax(jyjContractualTaskBatchService.updateByBo(bo)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 删除合同批处理记录 |
||||
|
* |
||||
|
* @param ids 主键串 |
||||
|
*/ |
||||
|
@SaCheckPermission("productManagement:JyjcontractualTaskBatch:remove") |
||||
|
@Log(title = "合同批处理记录", businessType = BusinessType.DELETE) |
||||
|
@DeleteMapping("/{ids}") |
||||
|
public R<Void> remove(@NotEmpty(message = "主键不能为空") |
||||
|
@PathVariable Long[] ids) { |
||||
|
return toAjax(jyjContractualTaskBatchService.deleteWithValidByIds(List.of(ids), true)); |
||||
|
} |
||||
|
@PostMapping(value = "/back/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) |
||||
|
public R<HashMap<String,String>> uploadFile(@RequestPart(name = "file") MultipartFile file) throws IOException, InterruptedException { |
||||
|
HashMap<String,String> uploadVo = jyjContractualTaskBatchService.uploadFile(file); |
||||
|
return R.ok(uploadVo); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据id获取合同的审查结果 |
||||
|
*/ |
||||
|
@GetMapping("/getContractulResultById/{id}") |
||||
|
public R<ContractualRes> getCheckResult(@NotNull(message = "主键不能为空") |
||||
|
@PathVariable Long id) throws JsonProcessingException { |
||||
|
return R.ok(jyjContractualTaskBatchService.getContractulResultById(id)); |
||||
|
} |
||||
|
@GetMapping("/getContractulPdf/{id}") |
||||
|
public void getContractulPdf(@PathVariable Long id, HttpServletResponse response) { |
||||
|
jyjContractualTaskBatchService.getContractulPdf(id,response); |
||||
|
} |
||||
|
} |
@ -0,0 +1,83 @@ |
|||||
|
package org.dromara.productManagement.domain; |
||||
|
|
||||
|
import org.dromara.common.tenant.core.TenantEntity; |
||||
|
import com.baomidou.mybatisplus.annotation.*; |
||||
|
import lombok.Data; |
||||
|
import lombok.EqualsAndHashCode; |
||||
|
import java.util.Date; |
||||
|
|
||||
|
import java.io.Serial; |
||||
|
|
||||
|
/** |
||||
|
* 合同信息保存对象 contractul_info |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
* @date 2025-03-10 |
||||
|
*/ |
||||
|
@Data |
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
@TableName("contractual_info") |
||||
|
public class ContractualInfo extends TenantEntity { |
||||
|
|
||||
|
@Serial |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
/** |
||||
|
* id |
||||
|
*/ |
||||
|
@TableId(value = "id") |
||||
|
private Long id; |
||||
|
|
||||
|
/** |
||||
|
* 合同任务id |
||||
|
*/ |
||||
|
private Long taskId; |
||||
|
|
||||
|
/** |
||||
|
* 合同名称 |
||||
|
*/ |
||||
|
private String fileName; |
||||
|
|
||||
|
/** |
||||
|
* 合同文本 |
||||
|
*/ |
||||
|
private String text; |
||||
|
|
||||
|
/** |
||||
|
* 采购人名称 |
||||
|
*/ |
||||
|
private String purchaserName; |
||||
|
|
||||
|
/** |
||||
|
* 供应商名称或姓名 |
||||
|
*/ |
||||
|
private String supplierName; |
||||
|
|
||||
|
/** |
||||
|
* 合同签订时间 |
||||
|
*/ |
||||
|
private String signDate; |
||||
|
|
||||
|
/** |
||||
|
* 合同金额 |
||||
|
*/ |
||||
|
private String contractAmount; |
||||
|
|
||||
|
/** |
||||
|
* 预算资金 |
||||
|
*/ |
||||
|
private String budgetAmount; |
||||
|
|
||||
|
/** |
||||
|
* 删除标志 |
||||
|
*/ |
||||
|
@TableLogic |
||||
|
private String delFlag; |
||||
|
|
||||
|
/** |
||||
|
* 文件名称 |
||||
|
*/ |
||||
|
private String filePath; |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,24 @@ |
|||||
|
package org.dromara.productManagement.domain; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import java.util.List; |
||||
|
|
||||
|
@Data |
||||
|
public class ContractualRes { |
||||
|
private List<ContractReviewResult> results; |
||||
|
|
||||
|
@Data |
||||
|
public static class ContractReviewResult { |
||||
|
private String title; |
||||
|
private List<ProblemDetail> contentList; |
||||
|
} |
||||
|
|
||||
|
@Data |
||||
|
public static class ProblemDetail { |
||||
|
private String problemTitle; |
||||
|
private String text; |
||||
|
private String problemDesc; |
||||
|
private Boolean isPosition; |
||||
|
private String accord; |
||||
|
} |
||||
|
} |
@ -0,0 +1,121 @@ |
|||||
|
package org.dromara.productManagement.domain; |
||||
|
|
||||
|
import com.alibaba.excel.annotation.ExcelProperty; |
||||
|
import org.dromara.common.tenant.core.TenantEntity; |
||||
|
import com.baomidou.mybatisplus.annotation.*; |
||||
|
import lombok.Data; |
||||
|
import lombok.EqualsAndHashCode; |
||||
|
|
||||
|
import java.io.Serial; |
||||
|
import java.util.Date; |
||||
|
|
||||
|
/** |
||||
|
* 合同批处理记录对象 jyj_contractual_task_batch |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
* @date 2025-03-05 |
||||
|
*/ |
||||
|
@Data |
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
@TableName("jyj_contractual_task_batch") |
||||
|
public class JyjContractualTaskBatch extends TenantEntity { |
||||
|
|
||||
|
@Serial |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
/** |
||||
|
* 主键ID |
||||
|
*/ |
||||
|
@TableId(value = "id") |
||||
|
private Long id; |
||||
|
|
||||
|
/** |
||||
|
* 任务名称 |
||||
|
*/ |
||||
|
private String taskName; |
||||
|
|
||||
|
/** |
||||
|
* 任务类型 |
||||
|
*/ |
||||
|
private String taskType; |
||||
|
|
||||
|
/** |
||||
|
* 文档名称 |
||||
|
*/ |
||||
|
private String documentName; |
||||
|
|
||||
|
/** |
||||
|
* OSS文件ID |
||||
|
*/ |
||||
|
private Long ossId; |
||||
|
|
||||
|
/** |
||||
|
* 进度状态 |
||||
|
*/ |
||||
|
private String progressStatus; |
||||
|
|
||||
|
/** |
||||
|
* 删除标志 |
||||
|
*/ |
||||
|
@TableLogic |
||||
|
private String delFlag; |
||||
|
|
||||
|
/** |
||||
|
* 版本号 |
||||
|
*/ |
||||
|
@Version |
||||
|
private Long version; |
||||
|
|
||||
|
/** |
||||
|
* 列队任务id |
||||
|
*/ |
||||
|
private String groupId; |
||||
|
|
||||
|
/** |
||||
|
* 合同总数 |
||||
|
*/ |
||||
|
private Long totalContracts; |
||||
|
|
||||
|
/** |
||||
|
* 已审批总数 |
||||
|
*/ |
||||
|
private Long approvedCount; |
||||
|
|
||||
|
/** |
||||
|
* 审核通过数量 |
||||
|
*/ |
||||
|
private Long passCount; |
||||
|
|
||||
|
/** |
||||
|
* 审核不通过数量 |
||||
|
*/ |
||||
|
private Long rejectCount; |
||||
|
|
||||
|
/** |
||||
|
* 非审查范围数量 |
||||
|
*/ |
||||
|
private Long irrelevantCount; |
||||
|
/** |
||||
|
* 审核失败数量 |
||||
|
*/ |
||||
|
private Long failCount; |
||||
|
|
||||
|
/** |
||||
|
* 进度(百分比) |
||||
|
*/ |
||||
|
private String progress; |
||||
|
/** |
||||
|
* 处理时间 |
||||
|
*/ |
||||
|
private String processingTime; |
||||
|
|
||||
|
/** |
||||
|
* 批次名称 |
||||
|
*/ |
||||
|
private String batchName; |
||||
|
/** |
||||
|
* 备注 |
||||
|
*/ |
||||
|
private String remark; |
||||
|
private Date latestTime; |
||||
|
} |
@ -0,0 +1,55 @@ |
|||||
|
package org.dromara.productManagement.domain.bo; |
||||
|
|
||||
|
import org.dromara.productManagement.domain.ContractualInfo; |
||||
|
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; |
||||
|
|
||||
|
/** |
||||
|
* 合同信息保存业务对象 contractul_info |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
* @date 2025-03-10 |
||||
|
*/ |
||||
|
@Data |
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
@AutoMapper(target = ContractualInfo.class, reverseConvertGenerate = false) |
||||
|
public class ContractualInfoBo extends BaseEntity { |
||||
|
private Long id; |
||||
|
/** |
||||
|
* 合同名称 |
||||
|
*/ |
||||
|
@NotBlank(message = "合同名称不能为空", groups = { AddGroup.class, EditGroup.class }) |
||||
|
private String fileName; |
||||
|
|
||||
|
/** |
||||
|
* 采购人名称 |
||||
|
*/ |
||||
|
@NotBlank(message = "采购人名称不能为空", groups = { AddGroup.class, EditGroup.class }) |
||||
|
private String purchaserName; |
||||
|
|
||||
|
/** |
||||
|
* 供应商名称或姓名 |
||||
|
*/ |
||||
|
@NotBlank(message = "供应商名称或姓名不能为空", groups = { AddGroup.class, EditGroup.class }) |
||||
|
private String supplierName; |
||||
|
|
||||
|
/** |
||||
|
* 合同签订时间 |
||||
|
*/ |
||||
|
@NotNull(message = "合同签订时间不能为空", groups = { AddGroup.class, EditGroup.class }) |
||||
|
private String signDate; |
||||
|
|
||||
|
/** |
||||
|
* 合同金额 |
||||
|
*/ |
||||
|
@NotBlank(message = "合同金额不能为空", groups = { AddGroup.class, EditGroup.class }) |
||||
|
private String contractAmount; |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,105 @@ |
|||||
|
package org.dromara.productManagement.domain.bo; |
||||
|
|
||||
|
import com.alibaba.excel.annotation.ExcelProperty; |
||||
|
import org.dromara.productManagement.domain.JyjContractualTaskBatch; |
||||
|
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; |
||||
|
|
||||
|
/** |
||||
|
* 合同批处理记录业务对象 jyj_contractual_task_batch |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
* @date 2025-03-05 |
||||
|
*/ |
||||
|
@Data |
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
@AutoMapper(target = JyjContractualTaskBatch.class, reverseConvertGenerate = false) |
||||
|
public class JyjContractualTaskBatchBo extends BaseEntity { |
||||
|
private Long id; |
||||
|
/** |
||||
|
* 任务名称 |
||||
|
*/ |
||||
|
private String taskName; |
||||
|
|
||||
|
/** |
||||
|
* 任务类型 |
||||
|
*/ |
||||
|
private String taskType; |
||||
|
|
||||
|
/** |
||||
|
* 文档名称 |
||||
|
*/ |
||||
|
private String documentName; |
||||
|
|
||||
|
/** |
||||
|
* OSS文件ID |
||||
|
*/ |
||||
|
@NotNull(message = "文档不能为空", groups = { AddGroup.class, EditGroup.class }) |
||||
|
private Long ossId; |
||||
|
|
||||
|
/** |
||||
|
* 进度状态 |
||||
|
*/ |
||||
|
private String progressStatus; |
||||
|
|
||||
|
/** |
||||
|
* 列队任务id |
||||
|
*/ |
||||
|
private String groupId; |
||||
|
|
||||
|
/** |
||||
|
* 合同总数 |
||||
|
*/ |
||||
|
private Long totalContracts; |
||||
|
|
||||
|
/** |
||||
|
* 已审批总数 |
||||
|
*/ |
||||
|
private Long approvedCount; |
||||
|
|
||||
|
/** |
||||
|
* 审核通过数量 |
||||
|
*/ |
||||
|
private Long passCount; |
||||
|
|
||||
|
/** |
||||
|
* 审核不通过数量 |
||||
|
*/ |
||||
|
private Long rejectCount; |
||||
|
|
||||
|
/** |
||||
|
* 非审查范围数量 |
||||
|
*/ |
||||
|
private Long irrelevantCount; |
||||
|
|
||||
|
/** |
||||
|
* 审核失败数量 |
||||
|
*/ |
||||
|
private Long failCount; |
||||
|
|
||||
|
/** |
||||
|
* 进度(百分比) |
||||
|
*/ |
||||
|
private String progress; |
||||
|
|
||||
|
/** |
||||
|
* 批次名称 |
||||
|
*/ |
||||
|
private String batchName; |
||||
|
/** |
||||
|
* 备注 |
||||
|
*/ |
||||
|
private String remark; |
||||
|
/** |
||||
|
* 处理时间 |
||||
|
*/ |
||||
|
private String processingTime; |
||||
|
private Date latestTime; |
||||
|
} |
@ -0,0 +1,60 @@ |
|||||
|
package org.dromara.productManagement.domain.vo; |
||||
|
|
||||
|
import java.util.Date; |
||||
|
|
||||
|
import org.dromara.productManagement.domain.ContractualInfo; |
||||
|
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; |
||||
|
import com.alibaba.excel.annotation.ExcelProperty; |
||||
|
import io.github.linpeilie.annotations.AutoMapper; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.io.Serial; |
||||
|
import java.io.Serializable; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 合同信息保存视图对象 contractul_info |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
* @date 2025-03-10 |
||||
|
*/ |
||||
|
@Data |
||||
|
@ExcelIgnoreUnannotated |
||||
|
@AutoMapper(target = ContractualInfo.class) |
||||
|
public class ContractualInfoVo implements Serializable { |
||||
|
|
||||
|
@Serial |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
private Long id; |
||||
|
/** |
||||
|
* 合同名称 |
||||
|
*/ |
||||
|
@ExcelProperty(value = "合同名称") |
||||
|
private String fileName; |
||||
|
|
||||
|
/** |
||||
|
* 采购人名称 |
||||
|
*/ |
||||
|
@ExcelProperty(value = "采购人名称") |
||||
|
private String purchaserName; |
||||
|
|
||||
|
/** |
||||
|
* 供应商名称或姓名 |
||||
|
*/ |
||||
|
@ExcelProperty(value = "供应商名称或姓名") |
||||
|
private String supplierName; |
||||
|
|
||||
|
/** |
||||
|
* 合同签订时间 |
||||
|
*/ |
||||
|
@ExcelProperty(value = "合同签订时间") |
||||
|
private String signDate; |
||||
|
|
||||
|
/** |
||||
|
* 合同金额 |
||||
|
*/ |
||||
|
@ExcelProperty(value = "合同金额") |
||||
|
private String contractAmount; |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,127 @@ |
|||||
|
package org.dromara.productManagement.domain.vo; |
||||
|
|
||||
|
import org.dromara.productManagement.domain.JyjContractualTaskBatch; |
||||
|
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; |
||||
|
import com.alibaba.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 java.io.Serial; |
||||
|
import java.io.Serializable; |
||||
|
import java.util.Date; |
||||
|
import java.util.List; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 合同批处理记录视图对象 jyj_contractual_task_batch |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
* @date 2025-03-05 |
||||
|
*/ |
||||
|
@Data |
||||
|
@ExcelIgnoreUnannotated |
||||
|
@AutoMapper(target = JyjContractualTaskBatch.class) |
||||
|
public class JyjContractualTaskBatchVo implements Serializable { |
||||
|
|
||||
|
@Serial |
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
private Long id; |
||||
|
/** |
||||
|
* 任务名称 |
||||
|
*/ |
||||
|
@ExcelProperty(value = "任务名称", converter = ExcelDictConvert.class) |
||||
|
@ExcelDictFormat(dictType = "contract_review") |
||||
|
private String taskName; |
||||
|
|
||||
|
/** |
||||
|
* 任务类型 |
||||
|
*/ |
||||
|
@ExcelProperty(value = "任务类型", converter = ExcelDictConvert.class) |
||||
|
@ExcelDictFormat(dictType = "task_type") |
||||
|
private String taskType; |
||||
|
|
||||
|
/** |
||||
|
* 文档名称 |
||||
|
*/ |
||||
|
@ExcelProperty(value = "文档名称") |
||||
|
private String documentName; |
||||
|
|
||||
|
/** |
||||
|
* OSS文件ID |
||||
|
*/ |
||||
|
@ExcelProperty(value = "OSS文件ID") |
||||
|
private Long ossId; |
||||
|
|
||||
|
/** |
||||
|
* 进度状态 |
||||
|
*/ |
||||
|
@ExcelProperty(value = "进度状态") |
||||
|
private String progressStatus; |
||||
|
|
||||
|
/** |
||||
|
* 列队任务id |
||||
|
*/ |
||||
|
@ExcelProperty(value = "列队任务id") |
||||
|
private String groupId; |
||||
|
|
||||
|
/** |
||||
|
* 合同总数 |
||||
|
*/ |
||||
|
@ExcelProperty(value = "合同总数") |
||||
|
private Long totalContracts; |
||||
|
|
||||
|
/** |
||||
|
* 已审批总数 |
||||
|
*/ |
||||
|
@ExcelProperty(value = "已审批总数") |
||||
|
private Long approvedCount; |
||||
|
|
||||
|
/** |
||||
|
* 审核通过数量 |
||||
|
*/ |
||||
|
@ExcelProperty(value = "审核通过数量") |
||||
|
private Long passCount; |
||||
|
|
||||
|
/** |
||||
|
* 审核不通过数量 |
||||
|
*/ |
||||
|
@ExcelProperty(value = "审核不通过数量") |
||||
|
private Long rejectCount; |
||||
|
|
||||
|
/** |
||||
|
* 非审查范围数量 |
||||
|
*/ |
||||
|
@ExcelProperty(value = "非审查范围数量") |
||||
|
private Long irrelevantCount; |
||||
|
/** |
||||
|
* 审核失败数量 |
||||
|
*/ |
||||
|
@ExcelProperty(value = "审核失败数量") |
||||
|
private Long failCount; |
||||
|
/** |
||||
|
* 进度(百分比) |
||||
|
*/ |
||||
|
@ExcelProperty(value = "进度(百分比)") |
||||
|
private String progress; |
||||
|
/** |
||||
|
* 批次名称 |
||||
|
*/ |
||||
|
@ExcelProperty(value = "批次名称") |
||||
|
private String batchName; |
||||
|
/** |
||||
|
* 备注 |
||||
|
*/ |
||||
|
@ExcelProperty(value = "备注") |
||||
|
private String remark; |
||||
|
/** |
||||
|
* 处理时间 |
||||
|
*/ |
||||
|
@ExcelProperty(value = "处理时间") |
||||
|
private String processingTime; |
||||
|
|
||||
|
private Date latestTime; |
||||
|
|
||||
|
} |
@ -0,0 +1,16 @@ |
|||||
|
package org.dromara.productManagement.mapper; |
||||
|
|
||||
|
|
||||
|
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; |
||||
|
import org.dromara.productManagement.domain.ContractualInfo; |
||||
|
import org.dromara.productManagement.domain.vo.ContractualInfoVo; |
||||
|
|
||||
|
/** |
||||
|
* 合同信息保存Mapper接口 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
* @date 2025-03-10 |
||||
|
*/ |
||||
|
public interface ContractualInfoMapper extends BaseMapperPlus<ContractualInfo, ContractualInfoVo> { |
||||
|
|
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
package org.dromara.productManagement.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.annotation.DataColumn; |
||||
|
import org.dromara.common.mybatis.annotation.DataPermission; |
||||
|
import org.dromara.productManagement.domain.DocumentTaskGroup; |
||||
|
import org.dromara.productManagement.domain.DocumentTasks; |
||||
|
import org.dromara.productManagement.domain.JyjContractualTaskBatch; |
||||
|
import org.dromara.productManagement.domain.bo.JyjContractualTaskBatchBo; |
||||
|
import org.dromara.productManagement.domain.vo.JyjContractualTaskBatchVo; |
||||
|
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; |
||||
|
|
||||
|
/** |
||||
|
* 合同批处理记录Mapper接口 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
* @date 2025-03-05 |
||||
|
*/ |
||||
|
@DataPermission({ |
||||
|
// @DataColumn(key = "deptName", value = "dept_id"),
|
||||
|
@DataColumn(key = "userName", value = "create_by") |
||||
|
}) |
||||
|
public interface JyjContractualTaskBatchMapper extends BaseMapperPlus<JyjContractualTaskBatch, JyjContractualTaskBatchVo> { |
||||
|
Page<JyjContractualTaskBatchVo> getBatchStatistics(@Param("page") Page<DocumentTasks> page, JyjContractualTaskBatchBo bo); |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,70 @@ |
|||||
|
package org.dromara.productManagement.service; |
||||
|
|
||||
|
import org.dromara.productManagement.domain.vo.ContractualInfoVo; |
||||
|
import org.dromara.productManagement.domain.bo.ContractualInfoBo; |
||||
|
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 Lion Li |
||||
|
* @date 2025-03-10 |
||||
|
*/ |
||||
|
public interface IContractualInfoService { |
||||
|
|
||||
|
/** |
||||
|
* 查询合同信息保存 |
||||
|
* |
||||
|
* @param id 主键 |
||||
|
* @return 合同信息保存 |
||||
|
*/ |
||||
|
ContractualInfoVo queryById(Long id); |
||||
|
|
||||
|
/** |
||||
|
* 分页查询合同信息保存列表 |
||||
|
* |
||||
|
* @param bo 查询条件 |
||||
|
* @param pageQuery 分页参数 |
||||
|
* @return 合同信息保存分页列表 |
||||
|
*/ |
||||
|
TableDataInfo<ContractualInfoVo> queryPageList(ContractualInfoBo bo, PageQuery pageQuery); |
||||
|
|
||||
|
/** |
||||
|
* 查询符合条件的合同信息保存列表 |
||||
|
* |
||||
|
* @param bo 查询条件 |
||||
|
* @return 合同信息保存列表 |
||||
|
*/ |
||||
|
List<ContractualInfoVo> queryList(ContractualInfoBo bo); |
||||
|
|
||||
|
/** |
||||
|
* 新增合同信息保存 |
||||
|
* |
||||
|
* @param bo 合同信息保存 |
||||
|
* @return 是否新增成功 |
||||
|
*/ |
||||
|
Boolean insertByBo(ContractualInfoBo bo); |
||||
|
|
||||
|
/** |
||||
|
* 修改合同信息保存 |
||||
|
* |
||||
|
* @param bo 合同信息保存 |
||||
|
* @return 是否修改成功 |
||||
|
*/ |
||||
|
Boolean updateByBo(ContractualInfoBo bo); |
||||
|
|
||||
|
/** |
||||
|
* 校验并批量删除合同信息保存信息 |
||||
|
* |
||||
|
* @param ids 待删除的主键集合 |
||||
|
* @param isValid 是否进行有效性校验 |
||||
|
* @return 是否删除成功 |
||||
|
*/ |
||||
|
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,82 @@ |
|||||
|
package org.dromara.productManagement.service; |
||||
|
|
||||
|
import cn.hutool.core.io.resource.InputStreamResource; |
||||
|
import com.fasterxml.jackson.core.JsonProcessingException; |
||||
|
import jakarta.servlet.http.HttpServletResponse; |
||||
|
import org.dromara.productManagement.domain.ContractualRes; |
||||
|
import org.dromara.productManagement.domain.vo.JyjContractualTaskBatchVo; |
||||
|
import org.dromara.productManagement.domain.bo.JyjContractualTaskBatchBo; |
||||
|
import org.dromara.common.mybatis.core.page.TableDataInfo; |
||||
|
import org.dromara.common.mybatis.core.page.PageQuery; |
||||
|
import org.dromara.system.domain.vo.SysOssVo; |
||||
|
import org.springframework.http.ResponseEntity; |
||||
|
import org.springframework.web.multipart.MultipartFile; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
import java.util.Collection; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* 合同批处理记录Service接口 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
* @date 2025-03-05 |
||||
|
*/ |
||||
|
public interface IJyjContractualTaskBatchService { |
||||
|
|
||||
|
/** |
||||
|
* 查询合同批处理记录 |
||||
|
* |
||||
|
* @param id 主键 |
||||
|
* @return 合同批处理记录 |
||||
|
*/ |
||||
|
JyjContractualTaskBatchVo queryById(Long id); |
||||
|
|
||||
|
/** |
||||
|
* 分页查询合同批处理记录列表 |
||||
|
* |
||||
|
* @param bo 查询条件 |
||||
|
* @param pageQuery 分页参数 |
||||
|
* @return 合同批处理记录分页列表 |
||||
|
*/ |
||||
|
TableDataInfo<JyjContractualTaskBatchVo> queryPageList(JyjContractualTaskBatchBo bo, PageQuery pageQuery); |
||||
|
|
||||
|
/** |
||||
|
* 查询符合条件的合同批处理记录列表 |
||||
|
* |
||||
|
* @param bo 查询条件 |
||||
|
* @return 合同批处理记录列表 |
||||
|
*/ |
||||
|
List<JyjContractualTaskBatchVo> queryList(JyjContractualTaskBatchBo bo); |
||||
|
|
||||
|
/** |
||||
|
* 新增合同批处理记录 |
||||
|
* |
||||
|
* @param bo 合同批处理记录 |
||||
|
* @return 是否新增成功 |
||||
|
*/ |
||||
|
Boolean insertByBo(JyjContractualTaskBatchBo bo); |
||||
|
|
||||
|
/** |
||||
|
* 修改合同批处理记录 |
||||
|
* |
||||
|
* @param bo 合同批处理记录 |
||||
|
* @return 是否修改成功 |
||||
|
*/ |
||||
|
Boolean updateByBo(JyjContractualTaskBatchBo bo); |
||||
|
|
||||
|
/** |
||||
|
* 校验并批量删除合同批处理记录信息 |
||||
|
* |
||||
|
* @param ids 待删除的主键集合 |
||||
|
* @param isValid 是否进行有效性校验 |
||||
|
* @return 是否删除成功 |
||||
|
*/ |
||||
|
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); |
||||
|
|
||||
|
HashMap<String,String> uploadFile(MultipartFile file) throws IOException; |
||||
|
ContractualRes getContractulResultById(Long id) throws JsonProcessingException; |
||||
|
|
||||
|
void getContractulPdf(Long id, HttpServletResponse response); |
||||
|
} |
@ -0,0 +1,134 @@ |
|||||
|
package org.dromara.productManagement.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.dromara.productManagement.service.IContractualInfoService; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.dromara.productManagement.domain.bo.ContractualInfoBo; |
||||
|
import org.dromara.productManagement.domain.vo.ContractualInfoVo; |
||||
|
import org.dromara.productManagement.domain.ContractualInfo; |
||||
|
import org.dromara.productManagement.mapper.ContractualInfoMapper; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
import java.util.Collection; |
||||
|
|
||||
|
/** |
||||
|
* 合同信息保存Service业务层处理 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
* @date 2025-03-10 |
||||
|
*/ |
||||
|
@RequiredArgsConstructor |
||||
|
@Service |
||||
|
public class ContractualInfoServiceImpl implements IContractualInfoService { |
||||
|
|
||||
|
private final ContractualInfoMapper baseMapper; |
||||
|
|
||||
|
/** |
||||
|
* 查询合同信息保存 |
||||
|
* |
||||
|
* @param id 主键 |
||||
|
* @return 合同信息保存 |
||||
|
*/ |
||||
|
@Override |
||||
|
public ContractualInfoVo queryById(Long id){ |
||||
|
return baseMapper.selectVoById(id); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 分页查询合同信息保存列表 |
||||
|
* |
||||
|
* @param bo 查询条件 |
||||
|
* @param pageQuery 分页参数 |
||||
|
* @return 合同信息保存分页列表 |
||||
|
*/ |
||||
|
@Override |
||||
|
public TableDataInfo<ContractualInfoVo> queryPageList(ContractualInfoBo bo, PageQuery pageQuery) { |
||||
|
LambdaQueryWrapper<ContractualInfo> lqw = buildQueryWrapper(bo); |
||||
|
Page<ContractualInfoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); |
||||
|
return TableDataInfo.build(result); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 查询符合条件的合同信息保存列表 |
||||
|
* |
||||
|
* @param bo 查询条件 |
||||
|
* @return 合同信息保存列表 |
||||
|
*/ |
||||
|
@Override |
||||
|
public List<ContractualInfoVo> queryList(ContractualInfoBo bo) { |
||||
|
LambdaQueryWrapper<ContractualInfo> lqw = buildQueryWrapper(bo); |
||||
|
return baseMapper.selectVoList(lqw); |
||||
|
} |
||||
|
|
||||
|
private LambdaQueryWrapper<ContractualInfo> buildQueryWrapper(ContractualInfoBo bo) { |
||||
|
Map<String, Object> params = bo.getParams(); |
||||
|
LambdaQueryWrapper<ContractualInfo> lqw = Wrappers.lambdaQuery(); |
||||
|
lqw.like(StringUtils.isNotBlank(bo.getFileName()), ContractualInfo::getFileName, bo.getFileName()); |
||||
|
lqw.like(StringUtils.isNotBlank(bo.getPurchaserName()), ContractualInfo::getPurchaserName, bo.getPurchaserName()); |
||||
|
lqw.like(StringUtils.isNotBlank(bo.getSupplierName()), ContractualInfo::getSupplierName, bo.getSupplierName()); |
||||
|
lqw.eq(bo.getSignDate() != null, ContractualInfo::getSignDate, bo.getSignDate()); |
||||
|
lqw.eq(StringUtils.isNotBlank(bo.getContractAmount()), ContractualInfo::getContractAmount, bo.getContractAmount()); |
||||
|
lqw.orderByDesc(ContractualInfo::getCreateTime); |
||||
|
return lqw; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 新增合同信息保存 |
||||
|
* |
||||
|
* @param bo 合同信息保存 |
||||
|
* @return 是否新增成功 |
||||
|
*/ |
||||
|
@Override |
||||
|
public Boolean insertByBo(ContractualInfoBo bo) { |
||||
|
ContractualInfo add = MapstructUtils.convert(bo, ContractualInfo.class); |
||||
|
validEntityBeforeSave(add); |
||||
|
boolean flag = baseMapper.insert(add) > 0; |
||||
|
if (flag) { |
||||
|
bo.setId(add.getId()); |
||||
|
} |
||||
|
return flag; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 修改合同信息保存 |
||||
|
* |
||||
|
* @param bo 合同信息保存 |
||||
|
* @return 是否修改成功 |
||||
|
*/ |
||||
|
@Override |
||||
|
public Boolean updateByBo(ContractualInfoBo bo) { |
||||
|
ContractualInfo update = MapstructUtils.convert(bo, ContractualInfo.class); |
||||
|
validEntityBeforeSave(update); |
||||
|
return baseMapper.updateById(update) > 0; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 保存前的数据校验 |
||||
|
*/ |
||||
|
private void validEntityBeforeSave(ContractualInfo entity){ |
||||
|
//TODO 做一些数据校验,如唯一约束
|
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 校验并批量删除合同信息保存信息 |
||||
|
* |
||||
|
* @param ids 待删除的主键集合 |
||||
|
* @param isValid 是否进行有效性校验 |
||||
|
* @return 是否删除成功 |
||||
|
*/ |
||||
|
@Override |
||||
|
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) { |
||||
|
if(isValid){ |
||||
|
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
|
} |
||||
|
return baseMapper.deleteByIds(ids) > 0; |
||||
|
} |
||||
|
} |
@ -0,0 +1,265 @@ |
|||||
|
package org.dromara.productManagement.service.impl; |
||||
|
|
||||
|
import com.fasterxml.jackson.core.JsonProcessingException; |
||||
|
import com.fasterxml.jackson.core.type.TypeReference; |
||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
import jakarta.servlet.http.HttpServletResponse; |
||||
|
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.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.dromara.productManagement.domain.*; |
||||
|
import org.dromara.productManagement.mapper.ContractualInfoMapper; |
||||
|
import org.dromara.productManagement.mapper.DocumentTaskResultsMapper; |
||||
|
import org.dromara.productManagement.mapper.DocumentTasksMapper; |
||||
|
import org.dromara.productManagement.utils.CompressedFileUtils; |
||||
|
import org.dromara.productManagement.utils.MyHttpUtils; |
||||
|
import org.dromara.productManagement.utils.MyTimeUtils; |
||||
|
import org.dromara.system.domain.vo.SysOssVo; |
||||
|
import org.dromara.system.service.ISysOssService; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.dromara.productManagement.domain.bo.JyjContractualTaskBatchBo; |
||||
|
import org.dromara.productManagement.domain.vo.JyjContractualTaskBatchVo; |
||||
|
import org.dromara.productManagement.mapper.JyjContractualTaskBatchMapper; |
||||
|
import org.dromara.productManagement.service.IJyjContractualTaskBatchService; |
||||
|
import org.springframework.web.multipart.MultipartFile; |
||||
|
|
||||
|
import java.io.*; |
||||
|
import java.text.SimpleDateFormat; |
||||
|
import java.util.*; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 合同批处理记录Service业务层处理 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
* @date 2025-03-05 |
||||
|
*/ |
||||
|
@RequiredArgsConstructor |
||||
|
@Service |
||||
|
@Slf4j |
||||
|
public class JyjContractualTaskBatchServiceImpl implements IJyjContractualTaskBatchService { |
||||
|
|
||||
|
private final JyjContractualTaskBatchMapper baseMapper; |
||||
|
protected final ISysOssService ossService; |
||||
|
private final DocumentTasksMapper documentTasksMapper; |
||||
|
private final DocumentTaskResultsMapper documentTaskResultsMapper; |
||||
|
private final ContractualInfoMapper contractualInfoMapper; |
||||
|
@Value("${chat.chatUrl}") |
||||
|
protected String chatUrl; |
||||
|
/** |
||||
|
* 查询合同批处理记录 |
||||
|
* |
||||
|
* @param id 主键 |
||||
|
* @return 合同批处理记录 |
||||
|
*/ |
||||
|
@Override |
||||
|
public JyjContractualTaskBatchVo queryById(Long id){ |
||||
|
return baseMapper.selectVoById(id); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 分页查询合同批处理记录列表 |
||||
|
* |
||||
|
* @param bo 查询条件 |
||||
|
* @param pageQuery 分页参数 |
||||
|
* @return 合同批处理记录分页列表 |
||||
|
*/ |
||||
|
@Override |
||||
|
public TableDataInfo<JyjContractualTaskBatchVo> queryPageList(JyjContractualTaskBatchBo bo, PageQuery pageQuery) { |
||||
|
LambdaQueryWrapper<JyjContractualTaskBatch> lqw = buildQueryWrapper(bo); |
||||
|
Page<JyjContractualTaskBatchVo> result = baseMapper.getBatchStatistics(pageQuery.build(), bo); |
||||
|
result.getRecords().forEach(vo -> { |
||||
|
//获取文件路径
|
||||
|
Long id = vo.getId(); |
||||
|
LambdaQueryWrapper<DocumentTasks> wrapper = new LambdaQueryWrapper<>(); |
||||
|
wrapper.eq(DocumentTasks::getGroupId, id); |
||||
|
List<DocumentTasks> documentTasksList = documentTasksMapper.selectList(wrapper); |
||||
|
//获取documentTasksList中最大的updateTime
|
||||
|
Date maxUpdateTime = documentTasksList.stream().max(Comparator.comparing(DocumentTasks::getUpdateTime)).get().getUpdateTime(); |
||||
|
String timeDifference = MyTimeUtils.formatTimeDifference(vo.getLatestTime(), maxUpdateTime); |
||||
|
vo.setProcessingTime(timeDifference); |
||||
|
//获取documentTasksList中最大的updateTime对应的documentTaskResults
|
||||
|
}); |
||||
|
return TableDataInfo.build(result); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 查询符合条件的合同批处理记录列表 |
||||
|
* |
||||
|
* @param bo 查询条件 |
||||
|
* @return 合同批处理记录列表 |
||||
|
*/ |
||||
|
@Override |
||||
|
public List<JyjContractualTaskBatchVo> queryList(JyjContractualTaskBatchBo bo) { |
||||
|
LambdaQueryWrapper<JyjContractualTaskBatch> lqw = buildQueryWrapper(bo); |
||||
|
return baseMapper.selectVoList(lqw); |
||||
|
} |
||||
|
|
||||
|
private LambdaQueryWrapper<JyjContractualTaskBatch> buildQueryWrapper(JyjContractualTaskBatchBo bo) { |
||||
|
Map<String, Object> params = bo.getParams(); |
||||
|
LambdaQueryWrapper<JyjContractualTaskBatch> lqw = Wrappers.lambdaQuery(); |
||||
|
lqw.like(StringUtils.isNotBlank(bo.getDocumentName()), JyjContractualTaskBatch::getDocumentName, bo.getDocumentName()); |
||||
|
lqw.eq(StringUtils.isNotBlank(bo.getProgressStatus()), JyjContractualTaskBatch::getProgressStatus, bo.getProgressStatus()); |
||||
|
lqw.like(StringUtils.isNotBlank(bo.getBatchName()), JyjContractualTaskBatch::getBatchName, bo.getBatchName()); |
||||
|
lqw.orderByDesc(JyjContractualTaskBatch::getCreateTime); |
||||
|
return lqw; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 新增合同批处理记录 |
||||
|
* |
||||
|
* @param bo 合同批处理记录 |
||||
|
* @return 是否新增成功 |
||||
|
*/ |
||||
|
@Override |
||||
|
public Boolean insertByBo(JyjContractualTaskBatchBo bo) { |
||||
|
JyjContractualTaskBatch add = MapstructUtils.convert(bo, JyjContractualTaskBatch.class); |
||||
|
//获取文件路径
|
||||
|
SysOssVo fileInfo = ossService.getById(bo.getOssId()); |
||||
|
String fileName = fileInfo.getOriginalName(); |
||||
|
|
||||
|
CompressedFileUtils.FileValidationResult fileValidationResult = CompressedFileUtils.processCompressedFileFromMinio(fileInfo); |
||||
|
int size = fileValidationResult.getValidFiles().size(); |
||||
|
add.setDocumentName(fileName); |
||||
|
add.setTotalContracts(Long.valueOf(size)); |
||||
|
//批次名称未填.系统填写
|
||||
|
if(!StringUtils.isNotBlank(add.getBatchName())){ |
||||
|
//查询当天的上传记录次数
|
||||
|
// 使用数据库的日期函数进行比较(这里以MySQL为例)
|
||||
|
LambdaQueryWrapper<JyjContractualTaskBatch> lqw = Wrappers.lambdaQuery(); |
||||
|
lqw.apply("DATE(create_time) = CURRENT_DATE()"); |
||||
|
|
||||
|
Long count = baseMapper.selectCount(lqw); |
||||
|
count = count + 1; |
||||
|
// 格式化批次名称
|
||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日第"); |
||||
|
String batchName = sdf.format(new Date()) + count + "批"; |
||||
|
add.setBatchName(batchName); |
||||
|
|
||||
|
} |
||||
|
boolean flag = baseMapper.insert(add) > 0; |
||||
|
|
||||
|
for(File file : fileValidationResult.getValidFiles()){ |
||||
|
//每个文件起一个任务
|
||||
|
DocumentTasks documentTasks = new DocumentTasks(); |
||||
|
documentTasks.setTaskName(bo.getTaskName()); |
||||
|
documentTasks.setDocumentName(file.getName()); |
||||
|
documentTasks.setProgressStatus("PENDING"); |
||||
|
documentTasks.setTaskType(bo.getTaskType()); |
||||
|
documentTasks.setGroupId(add.getId()); |
||||
|
documentTasks.setBatchName(add.getBatchName()); |
||||
|
// 在插入数据库前调用扩展点
|
||||
|
documentTasksMapper.insert(documentTasks); |
||||
|
// 在发送消息前调用扩展点
|
||||
|
Long priority = 1L; |
||||
|
MyHttpUtils.sendTaskStartMessage(chatUrl + "/back/taskStart", |
||||
|
documentTasks.getId(), bo.getTaskName(), file.getAbsolutePath(), priority); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
if (flag) { |
||||
|
bo.setId(add.getId()); |
||||
|
} |
||||
|
return flag; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 修改合同批处理记录 |
||||
|
* |
||||
|
* @param bo 合同批处理记录 |
||||
|
* @return 是否修改成功 |
||||
|
*/ |
||||
|
@Override |
||||
|
public Boolean updateByBo(JyjContractualTaskBatchBo bo) { |
||||
|
JyjContractualTaskBatch update = MapstructUtils.convert(bo, JyjContractualTaskBatch.class); |
||||
|
validEntityBeforeSave(update); |
||||
|
return baseMapper.updateById(update) > 0; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 保存前的数据校验 |
||||
|
*/ |
||||
|
private void validEntityBeforeSave(JyjContractualTaskBatch entity){ |
||||
|
//TODO 做一些数据校验,如唯一约束
|
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 校验并批量删除合同批处理记录信息 |
||||
|
* |
||||
|
* @param ids 待删除的主键集合 |
||||
|
* @param isValid 是否进行有效性校验 |
||||
|
* @return 是否删除成功 |
||||
|
*/ |
||||
|
@Override |
||||
|
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) { |
||||
|
if(isValid){ |
||||
|
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
|
} |
||||
|
return baseMapper.deleteByIds(ids) > 0; |
||||
|
} |
||||
|
@Override |
||||
|
public HashMap<String,String> uploadFile(MultipartFile file) throws IOException { |
||||
|
SysOssVo upload = ossService.upload(file); |
||||
|
HashMap<String,String> map = new HashMap<>(); |
||||
|
map.put("url", upload.getUrl()); |
||||
|
map.put("fileName", upload.getOriginalName()); |
||||
|
map.put("ossId", upload.getOssId().toString()); |
||||
|
CompressedFileUtils.FileStatistics stats = CompressedFileUtils.getFileStatistics(upload); |
||||
|
map.put("validFileCount", String.valueOf(stats.getValidFileCount())); |
||||
|
map.put("invalidFileCount", String.valueOf(stats.getInvalidFileCount())); |
||||
|
map.put("invalidFileNames", String.join(", ", stats.getInvalidFileNames())); |
||||
|
System.out.println("符合要求的文件数量: " + stats.getValidFileCount()); |
||||
|
System.out.println("不符合要求的文件数量: " + stats.getInvalidFileCount()); |
||||
|
System.out.println("不符合要求的文件列表: " + String.join(", ", stats.getInvalidFileNames())); |
||||
|
return map; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public ContractualRes getContractulResultById(Long id) throws JsonProcessingException { |
||||
|
LambdaQueryWrapper<DocumentTaskResults> wrapper = new LambdaQueryWrapper<>(); |
||||
|
wrapper.eq(DocumentTaskResults::getDocumentTaskId, id); |
||||
|
DocumentTaskResults documentTaskResults = documentTaskResultsMapper.selectOne(wrapper); |
||||
|
String result = documentTaskResults.getResult(); |
||||
|
//json 字符串转ContractualRes
|
||||
|
ObjectMapper mapper = new ObjectMapper(); |
||||
|
ContractualRes response = mapper.readValue(result, new TypeReference<ContractualRes>() {}); |
||||
|
return response; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void getContractulPdf(Long id, HttpServletResponse response) { |
||||
|
// PDF文件的绝对路径
|
||||
|
LambdaQueryWrapper<ContractualInfo> wrapper = new LambdaQueryWrapper<>(); |
||||
|
wrapper.eq(ContractualInfo::getTaskId, id); |
||||
|
ContractualInfo ContractualInfo = contractualInfoMapper.selectOne(wrapper); |
||||
|
String pdfPath = ContractualInfo.getFilePath(); |
||||
|
String fileName = ContractualInfo.getFileName(); |
||||
|
|
||||
|
File file = new File(pdfPath); |
||||
|
if (!file.exists()) { |
||||
|
throw new RuntimeException("文件不存在"); |
||||
|
} |
||||
|
response.setContentType("application/pdf"); |
||||
|
response.setHeader("Content-Disposition", "inline; filename=" + fileName); |
||||
|
response.setContentLength((int) file.length()); |
||||
|
try (FileInputStream inputStream = new FileInputStream(file); |
||||
|
OutputStream outputStream = response.getOutputStream()) { |
||||
|
|
||||
|
byte[] buffer = new byte[1024]; |
||||
|
int bytesRead; |
||||
|
while ((bytesRead = inputStream.read(buffer)) != -1) { |
||||
|
outputStream.write(buffer, 0, bytesRead); |
||||
|
} |
||||
|
outputStream.flush(); |
||||
|
} catch (IOException e) { |
||||
|
throw new RuntimeException("文件读取失败", e); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,351 @@ |
|||||
|
package org.dromara.productManagement.utils; |
||||
|
|
||||
|
import java.io.*; |
||||
|
import java.nio.charset.Charset; |
||||
|
import java.nio.charset.StandardCharsets; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
import java.util.zip.ZipEntry; |
||||
|
import java.util.zip.ZipFile; |
||||
|
import java.util.Enumeration; |
||||
|
import java.util.zip.ZipInputStream; |
||||
|
|
||||
|
import jakarta.annotation.PostConstruct; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.dromara.common.core.utils.SpringUtils; |
||||
|
import org.dromara.common.oss.core.OssClient; |
||||
|
import org.dromara.system.domain.SysOss; |
||||
|
import org.dromara.system.domain.vo.SysOssVo; |
||||
|
import org.mozilla.universalchardet.UniversalDetector; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.dromara.common.oss.factory.OssFactory; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
/** |
||||
|
* 压缩文件处理工具类 |
||||
|
* 仅支持处理ZIP格式的压缩文件 |
||||
|
*/ |
||||
|
@Component |
||||
|
@Slf4j |
||||
|
public class CompressedFileUtils { |
||||
|
|
||||
|
private static final List<String> ALLOWED_EXTENSIONS = new ArrayList<>(List.of(".pdf", ".ofd")); |
||||
|
private static String tempfilePath; // 保持为静态变量
|
||||
|
|
||||
|
@Value("${chat.tempfilePath}") // 默认值为 D:\\ce\\tempfile
|
||||
|
private String tempFilePathValue; // 用于注入的变量
|
||||
|
|
||||
|
@PostConstruct |
||||
|
public void init() { |
||||
|
tempfilePath = (tempFilePathValue != null) ? tempFilePathValue : null; // 设置默认值
|
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 文件验证结果类 |
||||
|
*/ |
||||
|
public static class FileValidationResult { |
||||
|
private final List<File> validFiles; |
||||
|
private final List<String> warnings; |
||||
|
|
||||
|
public FileValidationResult() { |
||||
|
this.validFiles = new ArrayList<>(); |
||||
|
this.warnings = new ArrayList<>(); |
||||
|
} |
||||
|
|
||||
|
public List<File> getValidFiles() { |
||||
|
return validFiles; |
||||
|
} |
||||
|
|
||||
|
public List<String> getWarnings() { |
||||
|
return warnings; |
||||
|
} |
||||
|
|
||||
|
public void addWarning(String warning) { |
||||
|
this.warnings.add(warning); |
||||
|
} |
||||
|
|
||||
|
public void addValidFile(File file) { |
||||
|
this.validFiles.add(file); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 从MinIO下载并处理压缩文件 |
||||
|
*/ |
||||
|
public static FileValidationResult processCompressedFileFromMinio(SysOssVo sysOss) { |
||||
|
FileValidationResult result = new FileValidationResult(); |
||||
|
File tempFile = null; |
||||
|
OssClient instance = OssFactory.instance(sysOss.getService()); |
||||
|
|
||||
|
try { |
||||
|
try (InputStream inputStream = instance.getObjectContent(sysOss.getFileName())) { |
||||
|
String originalFileName = sysOss.getOriginalName(); |
||||
|
tempFile = new File(tempfilePath, "temp_" + System.currentTimeMillis() + "_" + originalFileName); |
||||
|
createParentDirectories(tempFile); |
||||
|
|
||||
|
try (FileOutputStream fileOutputStream = new FileOutputStream(tempFile)) { |
||||
|
copyStream(inputStream, fileOutputStream); |
||||
|
} |
||||
|
|
||||
|
result = processCompressedFile(tempFile.getAbsolutePath(), tempfilePath); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
result.addWarning("从MinIO下载或处理文件时发生错误: " + e.getMessage()); |
||||
|
log.error("从MinIO下载或处理文件时发生错误: " + e.getMessage()); |
||||
|
|
||||
|
} finally { |
||||
|
if (tempFile != null) { |
||||
|
tempFile.deleteOnExit(); |
||||
|
if (!tempFile.delete()) { |
||||
|
result.addWarning("临时文件将在JVM退出时删除: " + tempFile.getAbsolutePath()); |
||||
|
log.warn("临时文件将在JVM退出时删除: " + tempFile.getAbsolutePath()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 处理压缩文件并返回处理结果 |
||||
|
*/ |
||||
|
public static FileValidationResult processCompressedFile(String compressedFilePath, String extractPath) throws IOException { |
||||
|
FileValidationResult result = new FileValidationResult(); |
||||
|
File compressedFile = new File(compressedFilePath); |
||||
|
|
||||
|
if (!compressedFile.exists()) { |
||||
|
result.addWarning("压缩文件不存在:" + compressedFilePath); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
if (!compressedFilePath.toLowerCase().endsWith(".zip")) { |
||||
|
result.addWarning("不支持的压缩文件格式,仅支持 ZIP 格式"); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
processZipFile(compressedFilePath, extractPath, result); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 处理ZIP文件 |
||||
|
*/ |
||||
|
// private static void processZipFile(String zipFile, String extractPath, FileValidationResult result) throws IOException {
|
||||
|
// InputStream inputStream = new FileInputStream(zipFile);
|
||||
|
// Charset charset = detectCharset(inputStream);
|
||||
|
// try (ZipFile zip = new ZipFile(zipFile, charset)) {
|
||||
|
// // 创建以压缩包名命名的文件夹
|
||||
|
// String zipFileName = new File(zipFile).getName();
|
||||
|
// String folderName = zipFileName.toLowerCase().endsWith(".zip")
|
||||
|
// ? zipFileName.substring(0, zipFileName.length() - 4)
|
||||
|
// : zipFileName;
|
||||
|
// String newExtractPath = new File(extractPath, folderName).getAbsolutePath();
|
||||
|
//
|
||||
|
// Enumeration<? extends ZipEntry> entries = zip.entries();
|
||||
|
// while (entries.hasMoreElements()) {
|
||||
|
// ZipEntry entry = entries.nextElement();
|
||||
|
// if (!entry.isDirectory()) {
|
||||
|
// String entryName = entry.getName();
|
||||
|
// if (isValidFileType(entryName)) {
|
||||
|
// File extractedFile = extractZipEntry(zip, entry, newExtractPath);
|
||||
|
// result.addValidFile(extractedFile);
|
||||
|
// } else {
|
||||
|
// result.addWarning("跳过不支持的文件类型: " + entryName);
|
||||
|
// }
|
||||
|
// }
|
||||
|
// }
|
||||
|
// } catch (IOException e) {
|
||||
|
// result.addWarning("处理ZIP文件时发生错误: " + e.getMessage());
|
||||
|
// }
|
||||
|
// }
|
||||
|
private static void processZipFile(String zipFile, String extractPath, FileValidationResult result) throws IOException { |
||||
|
InputStream inputStream = new FileInputStream(zipFile); |
||||
|
Charset charset = detectCharset(inputStream); |
||||
|
try (ZipFile zip = new ZipFile(zipFile, charset)) { |
||||
|
// 创建以压缩包名命名的文件夹
|
||||
|
String zipFileName = new File(zipFile).getName(); |
||||
|
String folderName = zipFileName.toLowerCase().endsWith(".zip") |
||||
|
? zipFileName.substring(0, zipFileName.length() - 4) |
||||
|
: zipFileName; |
||||
|
String newExtractPath = new File(extractPath, folderName).getAbsolutePath(); |
||||
|
|
||||
|
Enumeration<? extends ZipEntry> entries = zip.entries(); |
||||
|
while (entries.hasMoreElements()) { |
||||
|
ZipEntry entry = entries.nextElement(); |
||||
|
if (!entry.isDirectory()) { |
||||
|
String entryName = entry.getName(); |
||||
|
if (isValidFileType(entryName)) { |
||||
|
// 保持原始路径结构
|
||||
|
File extractedFile = new File(newExtractPath, entryName); |
||||
|
// 确保父目录存在
|
||||
|
extractedFile.getParentFile().mkdirs(); |
||||
|
extractZipEntry(zip, entry, extractedFile); |
||||
|
result.addValidFile(extractedFile); |
||||
|
} else { |
||||
|
result.addWarning("跳过不支持的文件类型: " + entryName); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} catch (IOException e) { |
||||
|
result.addWarning("处理ZIP文件时发生错误: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
/** |
||||
|
* 解压ZIP文件条目 |
||||
|
*/ |
||||
|
// private static File extractZipEntry(ZipFile zipFile, ZipEntry entry, String extractPath) throws IOException {
|
||||
|
// // 只获取文件名,不保留原目录结构
|
||||
|
// String fileName = new File(entry.getName()).getName();
|
||||
|
// File outputFile = new File(extractPath, fileName);
|
||||
|
// createParentDirectories(outputFile);
|
||||
|
//
|
||||
|
// try (InputStream inputStream = zipFile.getInputStream(entry);
|
||||
|
// FileOutputStream outputStream = new FileOutputStream(outputFile)) {
|
||||
|
// copyStream(inputStream, outputStream);
|
||||
|
// }
|
||||
|
// return outputFile;
|
||||
|
// }
|
||||
|
private static File extractZipEntry(ZipFile zipFile, ZipEntry entry, File outputFile) throws IOException { |
||||
|
try (InputStream inputStream = zipFile.getInputStream(entry); |
||||
|
FileOutputStream outputStream = new FileOutputStream(outputFile)) { |
||||
|
copyStream(inputStream, outputStream); |
||||
|
} |
||||
|
return outputFile; |
||||
|
} |
||||
|
/** |
||||
|
* 创建父目录 |
||||
|
*/ |
||||
|
private static void createParentDirectories(File file) { |
||||
|
File parentFile = file.getParentFile(); |
||||
|
if (parentFile != null && !parentFile.exists()) { |
||||
|
parentFile.mkdirs(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 复制流数据 |
||||
|
*/ |
||||
|
private static void copyStream(InputStream input, OutputStream output) throws IOException { |
||||
|
byte[] buffer = new byte[8192]; |
||||
|
int length; |
||||
|
while ((length = input.read(buffer)) > 0) { |
||||
|
output.write(buffer, 0, length); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查文件类型是否有效 |
||||
|
*/ |
||||
|
private static boolean isValidFileType(String fileName) { |
||||
|
return ALLOWED_EXTENSIONS.stream() |
||||
|
.anyMatch(ext -> fileName.toLowerCase().endsWith(ext)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 添加允许的文件扩展名 |
||||
|
*/ |
||||
|
public static void addAllowedExtension(String extension) { |
||||
|
if (extension != null && extension.startsWith(".")) { |
||||
|
ALLOWED_EXTENSIONS.add(extension.toLowerCase()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取当前支持的文件扩展名列表 |
||||
|
*/ |
||||
|
public static List<String> getAllowedExtensions() { |
||||
|
return new ArrayList<>(ALLOWED_EXTENSIONS); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 清除所有允许的文件扩展名 |
||||
|
*/ |
||||
|
public static void clearAllowedExtensions() { |
||||
|
ALLOWED_EXTENSIONS.clear(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 移除指定的允许文件扩展名 |
||||
|
*/ |
||||
|
public static void removeAllowedExtension(String extension) { |
||||
|
if (extension != null) { |
||||
|
ALLOWED_EXTENSIONS.remove(extension.toLowerCase()); |
||||
|
} |
||||
|
} |
||||
|
public static class FileStatistics { |
||||
|
private int validFileCount; |
||||
|
private int invalidFileCount; |
||||
|
private List<String> invalidFileNames; |
||||
|
|
||||
|
public FileStatistics() { |
||||
|
this.validFileCount = 0; |
||||
|
this.invalidFileCount = 0; |
||||
|
this.invalidFileNames = new ArrayList<>(); |
||||
|
} |
||||
|
|
||||
|
public int getValidFileCount() { |
||||
|
return validFileCount; |
||||
|
} |
||||
|
|
||||
|
public int getInvalidFileCount() { |
||||
|
return invalidFileCount; |
||||
|
} |
||||
|
|
||||
|
public List<String> getInvalidFileNames() { |
||||
|
return invalidFileNames; |
||||
|
} |
||||
|
|
||||
|
public void incrementValidCount() { |
||||
|
this.validFileCount++; |
||||
|
} |
||||
|
|
||||
|
public void addInvalidFile(String fileName) { |
||||
|
this.invalidFileCount++; |
||||
|
this.invalidFileNames.add(fileName); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取压缩文件中的文件统计数据 |
||||
|
*/ |
||||
|
public static FileStatistics getFileStatistics(SysOssVo sysOss) throws IOException { |
||||
|
FileStatistics statistics = new FileStatistics(); |
||||
|
OssClient instance = OssFactory.instance(sysOss.getService()); |
||||
|
|
||||
|
InputStream checkInputStream = instance.getObjectContent(sysOss.getFileName()); |
||||
|
Charset charset = detectCharset(checkInputStream); // 动态检测字符集,会消耗流的内容
|
||||
|
InputStream inputStream = instance.getObjectContent(sysOss.getFileName()); |
||||
|
ZipInputStream zipInputStream = new ZipInputStream(inputStream, charset); |
||||
|
ZipEntry entry; |
||||
|
while ((entry = zipInputStream.getNextEntry()) != null) { |
||||
|
if (!entry.isDirectory()) { |
||||
|
String entryName = entry.getName(); |
||||
|
if (isValidFileType(entryName)) { |
||||
|
statistics.incrementValidCount(); |
||||
|
} else { |
||||
|
statistics.addInvalidFile(entryName); |
||||
|
} |
||||
|
} |
||||
|
zipInputStream.closeEntry(); |
||||
|
} |
||||
|
|
||||
|
return statistics; |
||||
|
|
||||
|
} |
||||
|
private static Charset detectCharset(InputStream inputStream) throws IOException { |
||||
|
UniversalDetector detector = new UniversalDetector(null); |
||||
|
byte[] buf = new byte[4096]; |
||||
|
int nread; |
||||
|
inputStream.read(buf); |
||||
|
detector.handleData(buf, 0, buf.length); |
||||
|
detector.dataEnd(); |
||||
|
|
||||
|
String encoding = detector.getDetectedCharset(); |
||||
|
detector.reset(); |
||||
|
|
||||
|
if (encoding != null) { |
||||
|
return Charset.forName(encoding); |
||||
|
} |
||||
|
// 默认返回 UTF-8
|
||||
|
return Charset.forName("GBK"); |
||||
|
} |
||||
|
} |
@ -0,0 +1,152 @@ |
|||||
|
package org.dromara.productManagement.utils; |
||||
|
|
||||
|
import java.io.*; |
||||
|
import java.util.*; |
||||
|
import java.util.zip.ZipEntry; |
||||
|
import java.util.zip.ZipFile; |
||||
|
import java.util.function.Consumer; |
||||
|
|
||||
|
public class ZipFileUtils { |
||||
|
|
||||
|
/** |
||||
|
* ZIP文件处理结果类 |
||||
|
*/ |
||||
|
public static class ZipProcessResult { |
||||
|
private Map<String, byte[]> validFiles; |
||||
|
private List<String> invalidFiles; |
||||
|
|
||||
|
public ZipProcessResult(Map<String, byte[]> validFiles, List<String> invalidFiles) { |
||||
|
this.validFiles = validFiles; |
||||
|
this.invalidFiles = invalidFiles; |
||||
|
} |
||||
|
|
||||
|
public Map<String, byte[]> getValidFiles() { |
||||
|
return validFiles; |
||||
|
} |
||||
|
|
||||
|
public List<String> getInvalidFiles() { |
||||
|
return invalidFiles; |
||||
|
} |
||||
|
|
||||
|
public int getValidFileCount() { |
||||
|
return validFiles.size(); |
||||
|
} |
||||
|
|
||||
|
public int getInvalidFileCount() { |
||||
|
return invalidFiles.size(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String toString() { |
||||
|
StringBuilder sb = new StringBuilder(); |
||||
|
sb.append("符合要求的文件:\n"); |
||||
|
validFiles.keySet().forEach(file -> sb.append("- ").append(file) |
||||
|
.append(" (大小: ").append(validFiles.get(file).length).append(" bytes)\n")); |
||||
|
|
||||
|
sb.append("\n不符合要求的文件:\n"); |
||||
|
invalidFiles.forEach(file -> sb.append("- ").append(file).append("\n")); |
||||
|
|
||||
|
sb.append("\n统计信息:\n"); |
||||
|
sb.append("符合要求的文件数量: ").append(getValidFileCount()).append("\n"); |
||||
|
sb.append("不符合要求的文件数量: ").append(getInvalidFileCount()); |
||||
|
|
||||
|
return sb.toString(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 处理ZIP文件,获取其中的PDF和OFD文件内容 |
||||
|
* |
||||
|
* @param zipFilePath ZIP文件路径 |
||||
|
* @return 处理结果对象 |
||||
|
* @throws IOException 如果文件处理过程中发生错误 |
||||
|
*/ |
||||
|
public static ZipProcessResult processZipFile(String zipFilePath) throws IOException { |
||||
|
Map<String, byte[]> validFiles = new HashMap<>(); |
||||
|
List<String> invalidFiles = new ArrayList<>(); |
||||
|
|
||||
|
try (ZipFile zipFile = new ZipFile(new File(zipFilePath))) { |
||||
|
Enumeration<? extends ZipEntry> entries = zipFile.entries(); |
||||
|
|
||||
|
while (entries.hasMoreElements()) { |
||||
|
ZipEntry entry = entries.nextElement(); |
||||
|
if (!entry.isDirectory()) { |
||||
|
if (isValidFileType(entry.getName())) { |
||||
|
// 读取文件内容到内存
|
||||
|
byte[] content = readEntryContent(zipFile, entry); |
||||
|
validFiles.put(entry.getName(), content); |
||||
|
} else { |
||||
|
invalidFiles.add(entry.getName()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return new ZipProcessResult(validFiles, invalidFiles); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 处理ZIP文件中的有效文件,使用回调函数处理每个文件 |
||||
|
* |
||||
|
* @param zipFilePath ZIP文件路径 |
||||
|
* @param fileProcessor 文件处理器 |
||||
|
* @throws IOException 如果文件处理过程中发生错误 |
||||
|
*/ |
||||
|
public static void processValidFiles(String zipFilePath, |
||||
|
FileProcessor fileProcessor) throws IOException { |
||||
|
try (ZipFile zipFile = new ZipFile(new File(zipFilePath))) { |
||||
|
Enumeration<? extends ZipEntry> entries = zipFile.entries(); |
||||
|
|
||||
|
while (entries.hasMoreElements()) { |
||||
|
ZipEntry entry = entries.nextElement(); |
||||
|
if (!entry.isDirectory() && isValidFileType(entry.getName())) { |
||||
|
try (InputStream is = zipFile.getInputStream(entry)) { |
||||
|
fileProcessor.process(entry.getName(), is); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 文件处理器接口 |
||||
|
*/ |
||||
|
@FunctionalInterface |
||||
|
public interface FileProcessor { |
||||
|
void process(String fileName, InputStream content) throws IOException; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 读取ZIP条目的内容 |
||||
|
*/ |
||||
|
private static byte[] readEntryContent(ZipFile zipFile, ZipEntry entry) throws IOException { |
||||
|
try (InputStream is = zipFile.getInputStream(entry)) { |
||||
|
return is.readAllBytes(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查文件是否为PDF或OFD格式 |
||||
|
*/ |
||||
|
private static boolean isValidFileType(String fileName) { |
||||
|
fileName = fileName.toLowerCase(); |
||||
|
return fileName.endsWith(".pdf") || fileName.endsWith(".ofd"); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 保存处理结果中的有效文件到指定目录 |
||||
|
*/ |
||||
|
public static void saveValidFiles(ZipProcessResult result, String outputDir) throws IOException { |
||||
|
File dir = new File(outputDir); |
||||
|
if (!dir.exists()) { |
||||
|
dir.mkdirs(); |
||||
|
} |
||||
|
|
||||
|
for (Map.Entry<String, byte[]> entry : result.getValidFiles().entrySet()) { |
||||
|
File outputFile = new File(dir, new File(entry.getKey()).getName()); |
||||
|
try (FileOutputStream fos = new FileOutputStream(outputFile)) { |
||||
|
fos.write(entry.getValue()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,7 @@ |
|||||
|
<?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.productManagement.mapper.ContractualInfoMapper"> |
||||
|
|
||||
|
</mapper> |
@ -0,0 +1,51 @@ |
|||||
|
<?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.productManagement.mapper.JyjContractualTaskBatchMapper"> |
||||
|
|
||||
|
<select id="getBatchStatistics" resultType="org.dromara.productManagement.domain.vo.JyjContractualTaskBatchVo"> |
||||
|
SELECT |
||||
|
b.id AS id, |
||||
|
b.document_name AS document_name, |
||||
|
b.batch_name AS batch_name, |
||||
|
b.total_contracts AS total_contracts, |
||||
|
MAX(fr.create_time) as latest_time, |
||||
|
COUNT(CASE WHEN fr.result_type = 'reviewSuccess' THEN 1 END) AS pass_count, |
||||
|
COUNT(CASE WHEN fr.result_type = 'reviewFail' THEN 1 END) AS reject_count, |
||||
|
COUNT(CASE WHEN fr.result_type = 'notReviewable' THEN 1 END) AS irrelevant_count, |
||||
|
COUNT(CASE WHEN fr.progress_status = 'FAILURE' THEN 1 END) AS fail_count, |
||||
|
COUNT(CASE WHEN fr.progress_status IN ('SUCCESS', 'FAILURE') THEN 1 END) AS approved_count, |
||||
|
CASE |
||||
|
WHEN b.total_contracts > 0 THEN |
||||
|
CONCAT(FLOOR(COUNT(CASE WHEN fr.progress_status IN ('SUCCESS', 'FAILURE') THEN 1 END) * 100.0 / b.total_contracts), '%') |
||||
|
ELSE '0%' |
||||
|
END AS progress, |
||||
|
CASE |
||||
|
WHEN b.total_contracts > 0 AND |
||||
|
COUNT(CASE WHEN fr.progress_status IN ('SUCCESS', 'FAILURE') THEN 1 END) = b.total_contracts THEN 'SUCCESS' |
||||
|
ELSE 'STARTED' |
||||
|
END AS progress_status |
||||
|
FROM |
||||
|
jyj_contractual_task_batch b |
||||
|
LEFT JOIN |
||||
|
document_tasks fr ON b.id = fr.group_id |
||||
|
<where> |
||||
|
<if test="bo.documentName!= null and bo.documentName!= ''"> |
||||
|
and b.document_name LIKE CONCAT('%', #{bo.documentName}, '%') |
||||
|
</if> |
||||
|
<if test="bo.batchName!= null and bo.batchName!= ''"> |
||||
|
and b.batch_name LIKE CONCAT('%', #{bo.batchName}, '%') |
||||
|
</if> |
||||
|
</where> |
||||
|
|
||||
|
GROUP BY |
||||
|
b.id,b.document_name, b.batch_name, b.total_contracts |
||||
|
<if test="bo.progressStatus != null and bo.progressStatus != ''"> |
||||
|
having |
||||
|
progress_status=#{bo.progressStatus} |
||||
|
</if> |
||||
|
ORDER BY b.create_time DESC |
||||
|
</select> |
||||
|
|
||||
|
</mapper> |
Loading…
Reference in new issue