diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/controller/TenderTaskResultsController.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/controller/TenderTaskResultsController.java new file mode 100644 index 0000000..fa5d190 --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/controller/TenderTaskResultsController.java @@ -0,0 +1,96 @@ +package org.dromara.productManagement.controller; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.core.domain.R; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.productManagement.domain.vo.TenderTaskResultVO; +import org.dromara.productManagement.service.ITenderTaskResultsService; + +import java.util.List; + +/** + * 招投标任务结果 + * + * @author guoyan + * @date 2024-12-14 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/tenderTask/tenderTaskResults") +public class TenderTaskResultsController extends BaseController { + + private final ITenderTaskResultsService tenderTaskResultsService; + + /** + * 根据任务ID获取详细的招投标任务结果 + * + * @param taskId 任务ID + */ +// @SaCheckPermission("productManagement:TenderTaskResults:query") + @GetMapping("/taskDetail/{taskId}") + public R> getDetailResultsByTaskId(@NotNull(message = "任务ID不能为空") + @PathVariable String taskId) { + return R.ok(tenderTaskResultsService.getDetailResultsByTaskId(taskId)); + } + + /** + * 下载招投标任务结果 + * + * @param ids 主键串 + */ +// @SaCheckPermission("productManagement:TenderTaskResults:download") + @Log(title = "招投标任务结果", businessType = BusinessType.EXPORT) + @GetMapping("/downloadResult/{ids}") + public void download(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids, HttpServletResponse response) { + tenderTaskResultsService.downloadResult(ids, response); + } + + /** + * 获取招投标任务PDF文件流 + * + * @param taskId 任务ID + */ + @GetMapping("/getPdfStream/{taskId}") + public void getPdfStream(@NotNull(message = "任务ID不能为空") + @PathVariable String taskId, + HttpServletResponse response) { + tenderTaskResultsService.getPdfStream(taskId, response); + } + + /** + * 获取招投标文件PDF文件流 + * + * @param taskId 任务ID + */ + @GetMapping("/getBidPdfStream/{taskId}") + public void getBidPdfStream(@NotNull(message = "任务ID不能为空") + @PathVariable String taskId, + HttpServletResponse response) { + tenderTaskResultsService.getBidPdfStream(taskId, response); + } + + /** + * 更新招投标任务结果项的状态(已读/采纳) + * + * @param id 结果项ID + * @param field 字段名(isRead/isAdopted) + * @param value 值(0/1) + */ +// @SaCheckPermission("productManagement:TenderTaskResults:edit") + @Log(title = "更新招投标任务结果项状态", businessType = BusinessType.UPDATE) + @PutMapping("/updateResultItemStatus/{id}/{field}/{value}") + public R updateResultItemStatus( + @NotEmpty(message = "ID不能为空") @PathVariable("id") String id, + @NotEmpty(message = "字段名不能为空") @PathVariable("field") String field, + @NotEmpty(message = "值不能为空") @PathVariable("value") String value) { + return toAjax(tenderTaskResultsService.updateResultItemStatus(id, field, value)); + } +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/controller/TenderTaskTypeController.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/controller/TenderTaskTypeController.java new file mode 100644 index 0000000..ced2690 --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/controller/TenderTaskTypeController.java @@ -0,0 +1,105 @@ +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.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.TenderTaskTypeVo; +import org.dromara.productManagement.domain.bo.TenderTaskTypeBo; +import org.dromara.productManagement.service.ITenderTaskTypeService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 招投标类型 + * + * @author guoyan + * @date 2024-12-14 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/tenderTask/tenderTaskType") +public class TenderTaskTypeController extends BaseController { + + private final ITenderTaskTypeService tenderTaskTypeService; + + /** + * 查询招投标类型列表 + */ +// @SaCheckPermission("productManagement:TenderTaskType:list") + @GetMapping("/list") + public R> list(TenderTaskTypeBo bo) { + return R.ok(tenderTaskTypeService.queryList(bo)); + } + + /** + * 导出招投标类型列表 + */ +// @SaCheckPermission("productManagement:TenderTaskType:export") + @Log(title = "招投标类型", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(TenderTaskTypeBo bo, HttpServletResponse response) { + List list = tenderTaskTypeService.queryList(bo); + ExcelUtil.exportExcel(list, "招投标类型", TenderTaskTypeVo.class, response); + } + + /** + * 获取招投标类型详细信息 + * + * @param id 主键 + */ +// @SaCheckPermission("productManagement:TenderTaskType:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(tenderTaskTypeService.queryById(id)); + } + + /** + * 新增招投标类型 + */ +// @SaCheckPermission("productManagement:TenderTaskType:add") + @Log(title = "招投标类型", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody TenderTaskTypeBo bo) { + return toAjax(tenderTaskTypeService.insertByBo(bo)); + } + + /** + * 修改招投标类型 + */ +// @SaCheckPermission("productManagement:TenderTaskType:edit") + @Log(title = "招投标类型", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody TenderTaskTypeBo bo) { + return toAjax(tenderTaskTypeService.updateByBo(bo)); + } + + /** + * 删除招投标类型 + * + * @param ids 主键串 + */ +// @SaCheckPermission("productManagement:TenderTaskType:remove") + @Log(title = "招投标类型", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(tenderTaskTypeService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/controller/TenderTasksController.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/controller/TenderTasksController.java new file mode 100644 index 0000000..b670449 --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/controller/TenderTasksController.java @@ -0,0 +1,118 @@ +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.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.excel.utils.ExcelUtil; +import org.dromara.productManagement.domain.TenderTaskGroup; +import org.dromara.productManagement.domain.vo.TenderTasksVo; +import org.dromara.productManagement.domain.bo.TenderTasksBo; +import org.dromara.productManagement.service.ITenderTasksService; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.log.enums.BusinessType; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +/** + * 招投标审核任务 + * + * @author ruoyi + * @date 2024-01-01 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/tenderTask/tenderTasks") +@Tag(name = "招投标审核任务管理", description = "招投标审核任务管理") +public class TenderTasksController extends BaseController { + + private final ITenderTasksService tenderTasksService; + + /** + * 查询招投标审核任务列表(父子结构) + */ + @SaCheckPermission("tender:tasks:list") + @GetMapping("/list") + public TableDataInfo list(TenderTasksBo bo, PageQuery pageQuery) { + return tenderTasksService.queryGroupPageList(bo, pageQuery); + } + + /** + * 导出招投标审核任务列表 + */ + @SaCheckPermission("tender:tasks:export") + @Log(title = "招投标审核任务", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(TenderTasksBo bo, HttpServletResponse response) { + List list = tenderTasksService.queryList(bo); + ExcelUtil.exportExcel(list, "招投标审核任务", TenderTasksVo.class, response); + } + + /** + * 获取招投标审核任务详细信息 + */ + @SaCheckPermission("tender:tasks:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(tenderTasksService.queryById(id)); + } + + /** + * 新增招投标审核任务 + */ + @SaCheckPermission("tender:tasks:add") + @Log(title = "招投标审核任务", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody TenderTasksBo bo) { + return toAjax(tenderTasksService.insertByBo(bo)); + } + + /** + * 修改招投标审核任务 + */ + @SaCheckPermission("tender:tasks:edit") + @Log(title = "招投标审核任务", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody TenderTasksBo bo) { + return toAjax(tenderTasksService.updateByBo(bo)); + } + + /** + * 删除招投标审核任务 + */ + @SaCheckPermission("tender:tasks:remove") + @Log(title = "招投标审核任务", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(tenderTasksService.deleteWithValidByIds(List.of(ids), true)); + } + + /** + * 删除招投标任务文件 + */ + @SaCheckPermission("tender:tasks:remove") + @Log(title = "删除招投标任务文件", businessType = BusinessType.DELETE) + @DeleteMapping("/ossRemoveById/{ossid}") + public R ossRemoveById(@NotEmpty(message = "主键不能为空") + @PathVariable String ossid) { + return toAjax(tenderTasksService.ossRemoveById(ossid, true)); + } + +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/TenderTaskChild.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/TenderTaskChild.java new file mode 100644 index 0000000..fe24a45 --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/TenderTaskChild.java @@ -0,0 +1,91 @@ +package org.dromara.productManagement.domain; + +import lombok.Data; + +import java.util.Date; + +/** + * 招投标任务子项对象 + * + * @author ruoyi + * @date 2024-01-01 + */ +@Data +public class TenderTaskChild { + + /** + * 任务ID + */ + private Long id; + + /** + * 任务名称 + */ + private String taskName; + + /** + * 招标文件名称 + */ + private String tenderDocumentName; + + /** + * 投标文件名称 + */ + private String bidDocumentName; + + /** + * 进展状态 + */ + private String progressStatus; + + /** + * 任务组ID + */ + private Long groupId; + + /** + * 列队任务ID + */ + private String taskId; + + /** + * 审核结果 + */ + private String resultType; + + /** + * 招标文件oss存储id + */ + private String tenderDocOssId; + + /** + * 投标文件oss存储id + */ + private String bidDocZipOssId; + + /** + * 版本号 + */ + private Long version; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 任务持续时间 + */ + private String taskDuration; + + /** + * 创建用户 + */ + private String createUser; + +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/TenderTaskGroup.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/TenderTaskGroup.java new file mode 100644 index 0000000..b994b8b --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/TenderTaskGroup.java @@ -0,0 +1,67 @@ +package org.dromara.productManagement.domain; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 招投标任务分组对象 + * + * @author ruoyi + * @date 2024-01-01 + */ +@Data +public class TenderTaskGroup implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 分组ID + */ + private String id; + + /** + * 创建者ID + */ + private Long createBy; + + /** + * 招标文件名称 + */ + private String tenderDocumentName; + + /** + * 投标文件名称 + */ + private String bidDocumentName; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 创建用户 + */ + private String createUser; + + /** + * 进度信息 + */ + private String progress; + + /** + * 文件删除标志 + */ + private String deleteFlag; + + /** + * 子任务列表 + */ + private List childrenTasks; + +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/TenderTaskResultDetail.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/TenderTaskResultDetail.java new file mode 100644 index 0000000..b7c5f2f --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/TenderTaskResultDetail.java @@ -0,0 +1,51 @@ +package org.dromara.productManagement.domain; + +import org.dromara.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 招投标审核结果详情对象 tender_task_result_detail + * + * @author ruoyi + * @date 2024-01-01 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("tender_task_result_details") +public class TenderTaskResultDetail extends TenantEntity { + + @TableId(value = "id") + private String id; + + /** + * 分类id + */ + private String categoryId; + private String issueName; // 问题点名称 + + private String originalText; // 原文 + + private String comparedText; // 比对原文 + + private String modifiedContent; // 修改后的内容 + + private String modificationDisplay; // 展示修改情况 + + private String existingIssues; // 存在的问题 + + private String reviewBasis; // 审查依据 + + private String isRead; // 是否已读 + + private String isAdopted; // 是否采纳 + + /** + * 删除标志 + */ + @TableLogic + private String delFlag; + private int sortOrder; + +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/TenderTaskType.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/TenderTaskType.java new file mode 100644 index 0000000..3887ce4 --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/TenderTaskType.java @@ -0,0 +1,62 @@ +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.io.Serial; + +/** + * 招投标类型对象 tender_task_type + * + * @author guoyan + * @date 2024-12-14 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("tender_task_type") +public class TenderTaskType extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 类型ID + */ + @TableId(value = "id") + private Long id; + + /** + * 招投标类型名称 + */ + private String tenderName; + + /** + * 显示顺序 + */ + private Long sort; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 版本号 + */ + @Version + private Long version; + + /** + * 备注 + */ + private String remark; + +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/TenderTasks.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/TenderTasks.java new file mode 100644 index 0000000..f688d61 --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/TenderTasks.java @@ -0,0 +1,101 @@ +package org.dromara.productManagement.domain; + +import org.dromara.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +/** + * 招投标审核任务对象 tender_tasks + * + * @author ruoyi + * @date 2024-01-01 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("tender_tasks") +public class TenderTasks extends TenantEntity { + + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @TableId(value = "id") + private Long id; + + /** + * 任务名称 + */ + @NotBlank(message = "任务名称不能为空") + private String taskName; + + /** + * 招标文件名称 + */ + private String tenderDocumentName; + + /** + * 投标文件名称 + */ + private String bidDocumentName; + + /** + * 进展状态 + */ + private String progressStatus; + + /** + * 文档是否删除 (Y/N) + */ + private String deleteFlag; + + /** + * 删除标志 + */ + private String delFlag; + + /** + * 版本号 + */ + private Long version; + + /** + * 创建部门 + */ + private Long createDept; + + /** + * 任务组ID + */ + private Long groupId; + + /** + * 列队任务ID + */ + private String taskId; + + /** + * 审核结果 + */ + private String resultType; + + /** + * 招标文件oss存储id + */ + private String tenderDocOssId; + + /** + * 投标文件oss存储id + */ + private String bidDocZipOssId; + + /** + * PDF文件路径 + */ + private String pdfPath; + +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/bo/TenderTaskResultDetailBo.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/bo/TenderTaskResultDetailBo.java new file mode 100644 index 0000000..9c76105 --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/bo/TenderTaskResultDetailBo.java @@ -0,0 +1,87 @@ +package org.dromara.productManagement.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import jakarta.validation.constraints.*; +import org.dromara.productManagement.domain.TenderTaskResultDetail; + +/** + * 招投标审核结果详情业务对象 tender_task_result_detail + * + * @author ruoyi + * @date 2024-01-01 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = TenderTaskResultDetail.class, reverseConvertGenerate = false) +public class TenderTaskResultDetailBo extends BaseEntity { + + /** + * 主键ID + */ + @NotBlank(message = "主键ID不能为空", groups = { EditGroup.class }) + private String id; + + /** + * 分类id + */ + private String categoryId; + + /** + * 问题点名称 + */ + private String issueName; + + /** + * 原文 + */ + private String originalText; + + /** + * 比对原文 + */ + private String comparedText; + + /** + * 修改后的内容 + */ + private String modifiedContent; + + /** + * 展示修改情况 + */ + private String modificationDisplay; + + /** + * 存在的问题 + */ + private String existingIssues; + + /** + * 审查依据 + */ + private String reviewBasis; + + /** + * 是否已读 + */ + private String isRead; + + /** + * 是否采纳 + */ + private String isAdopted; + + /** + * 删除标志 + */ + private String delFlag; + + private int sortOrder; + +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/bo/TenderTaskTypeBo.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/bo/TenderTaskTypeBo.java new file mode 100644 index 0000000..73a6650 --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/bo/TenderTaskTypeBo.java @@ -0,0 +1,51 @@ +package org.dromara.productManagement.domain.bo; + +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 org.dromara.common.tenant.core.TenantEntity; +import org.dromara.productManagement.domain.TenderTaskType; + +/** + * 招投标类型业务对象 + * + * @author guoyan + * @date 2024-12-14 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = TenderTaskType.class, reverseConvertGenerate = false) +public class TenderTaskTypeBo extends TenantEntity { + + /** + * 类型ID + */ + @NotNull(message = "类型ID不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 招投标类型名称 + */ + @NotBlank(message = "招投标类型名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String tenderName; + + /** + * 显示顺序 + */ + private Long sort; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 备注 + */ + private String remark; + +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/bo/TenderTasksBo.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/bo/TenderTasksBo.java new file mode 100644 index 0000000..a7a7440 --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/bo/TenderTasksBo.java @@ -0,0 +1,104 @@ +package org.dromara.productManagement.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import jakarta.validation.constraints.*; +import org.dromara.productManagement.domain.TenderTasks; + +import java.util.List; + +/** + * 招投标审核任务业务对象 tender_tasks + * + * @author ruoyi + * @date 2024-01-01 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = TenderTasks.class, reverseConvertGenerate = false) +public class TenderTasksBo extends BaseEntity { + + /** + * 主键ID + */ + @NotNull(message = "主键ID不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 任务名称 + */ + @NotBlank(message = "任务名称不能为空") + private String taskName; + + /** + * 任务名称列表(用于多选) + */ + @NotEmpty(message = "任务名称列表不能为空", groups = { AddGroup.class }) + private List<@NotBlank(message = "任务名称不能为空") String> taskNameList; + + /** + * 招标文件名称 + */ + private String tenderDocumentName; + + /** + * 投标文件名称 + */ + private String bidDocumentName; + + /** + * 进展状态 + */ + private String progressStatus; + + /** + * 文档是否删除 (Y/N) + */ + private String deleteFlag; + + /** + * 删除标志 + */ + private String delFlag; + + /** + * 版本号 + */ + private Long version; + + /** + * 创建部门 + */ + private Long createDept; + + /** + * 任务组ID + */ + private Long groupId; + + /** + * 列队任务ID + */ + private String taskId; + + /** + * 审核结果 + */ + private String resultType; + + /** + * 招标文件oss存储id + */ + private String tenderDocOssId; + + /** + * 投标文件oss存储id + */ + private String bidDocZipOssId; + +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/vo/TenderTaskResultDetailVo.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/vo/TenderTaskResultDetailVo.java new file mode 100644 index 0000000..45270ae --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/vo/TenderTaskResultDetailVo.java @@ -0,0 +1,130 @@ +package org.dromara.productManagement.domain.vo; + + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import lombok.Data; +import org.dromara.productManagement.domain.TenderTaskResultDetail; + +import java.util.Date; + +/** + * 招投标审核结果详情视图对象 tender_task_result_detail + * + * @author ruoyi + * @date 2024-01-01 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = TenderTaskResultDetail.class) +public class TenderTaskResultDetailVo { + + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @ExcelProperty(value = "主键ID") + private String id; + + /** + * 分类id + */ + @ExcelProperty(value = "分类ID") + private String categoryId; + + /** + * 问题点名称 + */ + @ExcelProperty(value = "问题点名称") + private String issueName; + + /** + * 原文 + */ + @ExcelProperty(value = "原文") + private String originalText; + + /** + * 比对原文 + */ + @ExcelProperty(value = "比对原文") + private String comparedText; + + /** + * 修改后的内容 + */ + @ExcelProperty(value = "修改后的内容") + private String modifiedContent; + + /** + * 展示修改情况 + */ + @ExcelProperty(value = "展示修改情况") + private String modificationDisplay; + + /** + * 存在的问题 + */ + @ExcelProperty(value = "存在的问题") + private String existingIssues; + + /** + * 审查依据 + */ + @ExcelProperty(value = "审查依据") + private String reviewBasis; + + /** + * 是否已读 + */ + @ExcelDictFormat(dictType = "is_read") + private String isRead; + + /** + * 是否采纳 + */ + @ExcelDictFormat(dictType = "is_adopted") + private String isAdopted; + + /** + * 删除标志 + */ + @ExcelDictFormat(dictType = "del_flag") + private String delFlag; + + /** + * 租户ID + */ + @ExcelProperty(value = "租户ID") + private String tenantId; + + /** + * 创建人 + */ + @ExcelProperty(value = "创建人") + private Long createBy; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + + /** + * 更新人 + */ + @ExcelProperty(value = "更新人") + private Long updateBy; + + /** + * 更新时间 + */ + @ExcelProperty(value = "更新时间") + private Date updateTime; + private int sortOrder; + +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/vo/TenderTaskResultVO.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/vo/TenderTaskResultVO.java new file mode 100644 index 0000000..a006c0d --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/vo/TenderTaskResultVO.java @@ -0,0 +1,45 @@ +package org.dromara.productManagement.domain.vo; + +import lombok.Data; + +import java.util.List; + +/** + * 招投标任务结果视图对象 + * + * @author guoyan + * @date 2024-12-14 + */ +@Data +public class TenderTaskResultVO { + + private String name; // 分类名称 + + private List results; + + @Data + public static class ResultItem { + + private String id; // 唯一标识ID + + private Integer serialNumber; // 序号 + + private String issueName; // 问题点名称 + + private String originalText; // 原文 + + private String comparedText; // 比对原文 + + private String modifiedContent; // 修改后的内容 + + private String modificationDisplay; // 展示修改情况 + + private String existingIssues; // 存在的问题 + + private String reviewBasis; // 审查依据(JSON字符串) + + private String isRead; // 是否已读 + + private String isAdopted; // 是否采纳 + } +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/vo/TenderTaskTypeVo.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/vo/TenderTaskTypeVo.java new file mode 100644 index 0000000..c21fe94 --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/vo/TenderTaskTypeVo.java @@ -0,0 +1,69 @@ +package org.dromara.productManagement.domain.vo; + +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 org.dromara.productManagement.domain.TenderTaskType; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 招投标类型视图对象 tender_task_type + * + * @author guoyan + * @date 2024-12-14 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = TenderTaskType.class) +public class TenderTaskTypeVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 类型ID + */ + @ExcelProperty(value = "类型ID") + private Long id; + + /** + * 招投标类型名称 + */ + @ExcelProperty(value = "招投标类型名称") + private String tenderName; + + /** + * 显示顺序 + */ + @ExcelProperty(value = "显示顺序") + private Long sort; + + /** + * 状态(0正常 1停用) + */ + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/vo/TenderTasksVo.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/vo/TenderTasksVo.java new file mode 100644 index 0000000..cf21edc --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/domain/vo/TenderTasksVo.java @@ -0,0 +1,150 @@ +package org.dromara.productManagement.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +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 lombok.Data; +import org.dromara.productManagement.domain.TenderTasks; + +import java.util.Date; + +/** + * 招投标审核任务视图对象 tender_tasks + * + * @author ruoyi + * @date 2024-01-01 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = TenderTasks.class) +public class TenderTasksVo { + + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @ExcelProperty(value = "主键ID") + private Long id; + + /** + * 任务名称 + */ + @ExcelProperty(value = "任务名称") + private String taskName; + + /** + * 招标文件名称 + */ + @ExcelProperty(value = "招标文件名称") + private String tenderDocumentName; + + /** + * 投标文件名称 + */ + @ExcelProperty(value = "投标文件名称") + private String bidDocumentName; + + /** + * 进展状态 + */ + @ExcelProperty(value = "进展状态") + @ExcelDictFormat(dictType = "progress_status") + private String progressStatus; + + /** + * 文档是否删除 + */ + @ExcelProperty(value = "文档是否删除") + @ExcelDictFormat(dictType = "delete_flag") + private String deleteFlag; + + /** + * 删除标志 + */ + @ExcelProperty(value = "删除标志") + @ExcelDictFormat(dictType = "del_flag") + private String delFlag; + + /** + * 版本号 + */ + @ExcelProperty(value = "版本号") + private Long version; + + /** + * 租户ID + */ + @ExcelProperty(value = "租户ID") + private String tenantId; + + /** + * 创建部门 + */ + @ExcelProperty(value = "创建部门") + private Long createDept; + + /** + * 任务组ID + */ + @ExcelProperty(value = "任务组ID") + private Long groupId; + + /** + * 列队任务ID + */ + @ExcelProperty(value = "列队任务ID") + private String taskId; + + /** + * 审核结果 + */ + @ExcelProperty(value = "审核结果") + @ExcelDictFormat(dictType = "review_result") + private String resultType; + + /** + * 招标文件oss存储id + */ + @ExcelProperty(value = "招标文件OSS存储ID") + private String tenderDocOssId; + + /** + * 投标文件oss存储id + */ + @ExcelProperty(value = "投标文件OSS存储ID") + private String bidDocZipOssId; + + /** + * PDF文件路径 + */ + @ExcelProperty(value = "PDF文件路径") + private String pdfPath; + + /** + * 创建人 + */ + @ExcelProperty(value = "创建人") + private Long createBy; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + + /** + * 更新人 + */ + @ExcelProperty(value = "更新人") + private Long updateBy; + + /** + * 更新时间 + */ + @ExcelProperty(value = "更新时间") + private Date updateTime; + +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/enums/TenderReviewStatusEnum.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/enums/TenderReviewStatusEnum.java new file mode 100644 index 0000000..ce29da7 --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/enums/TenderReviewStatusEnum.java @@ -0,0 +1,33 @@ +package org.dromara.tenderreview.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 招投标审核状态枚举 + * + * @author ruoyi + * @date 2024-01-01 + */ +@Getter +@AllArgsConstructor +public enum TenderReviewStatusEnum { + + PENDING("0", "待审核"), + REVIEWING("1", "审核中"), + PASSED("2", "审核通过"), + REJECTED("3", "审核不通过"); + + private final String code; + private final String desc; + + public static TenderReviewStatusEnum getByCode(String code) { + for (TenderReviewStatusEnum status : values()) { + if (status.getCode().equals(code)) { + return status; + } + } + return null; + } + +} \ No newline at end of file diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/mapper/TenderTaskResultDetailMapper.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/mapper/TenderTaskResultDetailMapper.java new file mode 100644 index 0000000..4be6857 --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/mapper/TenderTaskResultDetailMapper.java @@ -0,0 +1,14 @@ +package org.dromara.productManagement.mapper; + +import org.dromara.productManagement.domain.TenderTaskResultDetail; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 招投标任务结果详情Mapper接口 + * + * @author guoyan + * @date 2024-12-14 + */ +public interface TenderTaskResultDetailMapper extends BaseMapperPlus { + +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/mapper/TenderTaskTypeMapper.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/mapper/TenderTaskTypeMapper.java new file mode 100644 index 0000000..8e3b390 --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/mapper/TenderTaskTypeMapper.java @@ -0,0 +1,16 @@ +package org.dromara.productManagement.mapper; + + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.productManagement.domain.TenderTaskType; +import org.dromara.productManagement.domain.vo.TenderTaskTypeVo; + +/** + * 招投标类型Mapper接口 + * + * @author guoyan + * @date 2024-12-14 + */ +public interface TenderTaskTypeMapper extends BaseMapperPlus { + +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/mapper/TenderTasksMapper.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/mapper/TenderTasksMapper.java new file mode 100644 index 0000000..28cf954 --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/mapper/TenderTasksMapper.java @@ -0,0 +1,41 @@ +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.core.mapper.BaseMapperPlus; +import org.dromara.productManagement.domain.TenderTaskGroup; +import org.dromara.productManagement.domain.TenderTasks; +import org.dromara.productManagement.domain.vo.TenderTaskResultVO; +import org.dromara.productManagement.domain.vo.TenderTasksVo; + +import java.util.List; + +/** + * 招投标审核任务Mapper接口 + * + * @author ruoyi + * @date 2024-01-01 + */ +public interface TenderTasksMapper extends BaseMapperPlus { + + /** + * 根据任务ID获取详细的文档任务结果 + * + * @param taskId 任务ID + * @return 文档任务结果详情列表 + */ + List getResultsByTaskId(@Param("taskId") String taskId); + + /** + * 分页查询招投标任务分组列表 + * + * @param page 分页参数 + * @param wrapper 查询条件 + * @return 招投标任务分组分页列表 + */ + Page selectTenderTaskGroups(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper wrapper); + +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/ITenderTaskResultsService.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/ITenderTaskResultsService.java new file mode 100644 index 0000000..e38d787 --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/ITenderTaskResultsService.java @@ -0,0 +1,57 @@ +package org.dromara.productManagement.service; + +import org.dromara.productManagement.domain.vo.TenderTaskResultVO; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +/** + * 招投标任务结果Service接口 + * + * @author guoyan + * @date 2024-12-14 + */ +public interface ITenderTaskResultsService { + + /** + * 根据任务ID查询详细的招投标任务结果 + * + * @param taskId 任务ID + * @return 详细的招投标任务结果列表 + */ + List getDetailResultsByTaskId(String taskId); + + /** + * 下载招投标任务结果 + * + * @param ids 主键数组 + * @param response HTTP响应对象 + */ + void downloadResult(Long[] ids, HttpServletResponse response); + + /** + * 获取招投标任务PDF文件流 + * + * @param taskId 任务ID + * @param response HTTP响应对象 + */ + void getPdfStream(String taskId, HttpServletResponse response); + + /** + * 获取招投标文件PDF文件流 + * + * @param taskId 任务ID + * @param response HTTP响应对象 + */ + void getBidPdfStream(String taskId, HttpServletResponse response); + + /** + * 更新招投标任务结果项的状态(已读/采纳) + * + * @param id 结果项ID + * @param field 字段名(isRead/isAdopted) + * @param value 值(0/1) + * @return 是否更新成功 + */ + Boolean updateResultItemStatus(String id, String field, String value); +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/ITenderTaskTypeService.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/ITenderTaskTypeService.java new file mode 100644 index 0000000..43af3cf --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/ITenderTaskTypeService.java @@ -0,0 +1,68 @@ +package org.dromara.productManagement.service; + +import org.dromara.productManagement.domain.bo.TenderTaskTypeBo; +import org.dromara.productManagement.domain.vo.TenderTaskTypeVo; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +import java.util.Collection; +import java.util.List; + +/** + * 招投标类型Service接口 + * + * @author guoyan + * @date 2024-12-14 + */ +public interface ITenderTaskTypeService { + + /** + * 查询招投标类型 + * + * @param id 主键 + * @return 招投标类型 + */ + TenderTaskTypeVo queryById(Long id); + + /** + * 分页查询招投标类型列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 招投标类型分页列表 + */ + TableDataInfo queryPageList(TenderTaskTypeBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的招投标类型列表 + * + * @param bo 查询条件 + * @return 招投标类型列表 + */ + List queryList(TenderTaskTypeBo bo); + + /** + * 新增招投标类型 + * + * @param bo 招投标类型 + * @return 是否新增成功 + */ + Boolean insertByBo(TenderTaskTypeBo bo); + + /** + * 修改招投标类型 + * + * @param bo 招投标类型 + * @return 是否修改成功 + */ + Boolean updateByBo(TenderTaskTypeBo bo); + + /** + * 校验并批量删除招投标类型信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/ITenderTasksService.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/ITenderTasksService.java new file mode 100644 index 0000000..771036f --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/ITenderTasksService.java @@ -0,0 +1,61 @@ +package org.dromara.productManagement.service; + +import org.dromara.productManagement.domain.TenderTaskGroup; +import org.dromara.productManagement.domain.vo.TenderTasksVo; +import org.dromara.productManagement.domain.bo.TenderTasksBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.Collection; +import java.util.List; + +/** + * 招投标审核任务Service接口 + * + * @author ruoyi + * @date 2024-01-01 + */ +public interface ITenderTasksService { + + /** + * 查询招投标审核任务 + */ + TenderTasksVo queryById(Long id); + + /** + * 查询招投标审核任务列表 + */ + TableDataInfo queryPageList(TenderTasksBo bo, PageQuery pageQuery); + + /** + * 分页查询招投标任务分组列表 + */ + TableDataInfo queryGroupPageList(TenderTasksBo bo, PageQuery pageQuery); + + /** + * 查询招投标审核任务列表 + */ + List queryList(TenderTasksBo bo); + + /** + * 新增招投标审核任务 + */ + Boolean insertByBo(TenderTasksBo bo); + + /** + * 修改招投标审核任务 + */ + Boolean updateByBo(TenderTasksBo bo); + + /** + * 校验并批量删除招投标审核任务信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 删除招投标任务文件 + */ + Boolean ossRemoveById(String ossId, Boolean isValid); + +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/impl/TenderTaskResultsServiceImpl.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/impl/TenderTaskResultsServiceImpl.java new file mode 100644 index 0000000..49f1066 --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/impl/TenderTaskResultsServiceImpl.java @@ -0,0 +1,823 @@ +package org.dromara.productManagement.service.impl; + +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.lowagie.text.pdf.BaseFont; +import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension; +import com.vladsch.flexmark.ext.tables.TablesExtension; +import com.vladsch.flexmark.html.HtmlRenderer; +import com.vladsch.flexmark.parser.Parser; +import com.vladsch.flexmark.util.ast.Node; +import com.vladsch.flexmark.util.data.MutableDataSet; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.dromara.common.core.service.DictService; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.productManagement.domain.TenderTaskResultDetail; +import org.dromara.productManagement.domain.vo.TenderTaskResultVO; +import org.dromara.productManagement.domain.vo.TenderTasksVo; +import org.dromara.productManagement.mapper.TenderTaskResultDetailMapper; +import org.dromara.productManagement.mapper.TenderTasksMapper; +import org.dromara.productManagement.service.ITenderTaskResultsService; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.safety.Safelist; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.xhtmlrenderer.pdf.ITextRenderer; + +import jakarta.servlet.http.HttpServletResponse; +import javax.sql.DataSource; +import java.io.*; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; +import java.util.ArrayList; + +/** + * 招投标任务结果Service业务层处理 + * + * @author guoyan + * @date 2024-12-14 + */ +@RequiredArgsConstructor +@Service +@Slf4j +public class TenderTaskResultsServiceImpl implements ITenderTaskResultsService { + + private final TenderTaskResultDetailMapper tenderTaskResultDetailMapper; + private final TenderTasksMapper tenderTasksMapper; + private final DictService dictService; + + @Autowired + private DataSource dataSource; + + /** + * 根据任务ID查询详细的招投标任务结果 + */ + @Override + @DS("slave") + public List getDetailResultsByTaskId(String taskId) { + + List originalResults = tenderTasksMapper.getResultsByTaskId(taskId); + // 如果没有结果,直接返回 + if (originalResults == null || originalResults.isEmpty()) { + return originalResults; + } + + // 为每个原始分类中的结果设置序号 + for (TenderTaskResultVO category : originalResults) { + if (category.getResults() != null) { + for (int i = 0; i < category.getResults().size(); i++) { + TenderTaskResultVO.ResultItem item = category.getResults().get(i); + item.setSerialNumber(i + 1); + } + } + } + + return originalResults; + } + + /** + * 更新招投标任务结果项的状态(已读/采纳) + */ + @Override + @DS("slave") + public Boolean updateResultItemStatus(String id, String field, String value) { + // 验证字段名是否合法 + if (!"isRead".equals(field) && !"isAdopted".equals(field)) { + throw new RuntimeException("不支持更新的字段: " + field); + } + + // 验证值是否合法 + if (!"0".equals(value) && !"1".equals(value)) { + throw new RuntimeException("无效的值: " + value); + } + + try { + LambdaUpdateWrapper updateWrapper = Wrappers.lambdaUpdate(TenderTaskResultDetail.class); + updateWrapper.eq(TenderTaskResultDetail::getId, id); + + if ("isRead".equals(field)) { + updateWrapper.set(TenderTaskResultDetail::getIsRead, value); + } else { + updateWrapper.set(TenderTaskResultDetail::getIsAdopted, value); + } + + return tenderTaskResultDetailMapper.update(null, updateWrapper) > 0; + } catch (Exception e) { + throw new RuntimeException("更新状态失败: " + e.getMessage(), e); + } + } + + /** + * 下载招投标任务结果 + */ + @Override + @DS("slave") + public void downloadResult(Long[] ids, HttpServletResponse response) { + try { + if (ids.length > 0) { + if (ids.length > 1) { + // 多文件压缩下载 + String tempDir = System.getProperty("java.io.tmpdir"); + String zipFileName = "tender_results_export.zip"; + String zipFilePath = tempDir + File.separator + zipFileName; + + try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFilePath))) { + for (Long taskId : ids) { + TenderTasksVo tenderTasksVo = tenderTasksMapper.selectVoById(taskId); + if (tenderTasksVo == null) continue; + + String documentName = tenderTasksVo.getTenderDocumentName(); + String taskName = tenderTasksVo.getTaskName(); + String taskType = "tender_review"; + String label = dictService.getDictLabel(taskType, taskName); + + // 获取详细的任务结果 + List resultDetails = getDetailResultsByTaskId(String.valueOf(taskId)); + if (resultDetails != null && !resultDetails.isEmpty()) { + // 根据任务类型生成Markdown + String markdown = generateTenderMarkdownByTaskTypeAndCategories(taskName, resultDetails); + + if (StringUtils.isNotBlank(markdown)) { + // 生成文档标题 + String title = "招投标文件分析报告"; + String fullMarkdown = String.format("# %s\n\n**文档名称**: %s \n**任务类型**: %s\n\n%s", + title, documentName, label, markdown); + + // 转换为PDF + String tempPdfPath = tempDir + File.separator + "tender_result_" + taskId + ".pdf"; + convertMarkdownToPdf(fullMarkdown, tempPdfPath); + + // 添加到ZIP文件 + String pdfFileName = String.format("%s_%s.pdf", documentName, label); + addToZip(tempPdfPath, pdfFileName, zos); + + // 删除临时PDF文件 + Files.deleteIfExists(new File(tempPdfPath).toPath()); + } + } + } + } + + // 下载ZIP文件 + downloadFile(response, zipFilePath, zipFileName); + + // 删除临时ZIP文件 + Files.deleteIfExists(new File(zipFilePath).toPath()); + + } else { + // 单文件PDF下载 + Long taskId = ids[0]; + TenderTasksVo tenderTasksVo = tenderTasksMapper.selectVoById(taskId); + if (tenderTasksVo == null) { + throw new RuntimeException("任务不存在"); + } + + String documentName = tenderTasksVo.getBidDocumentName(); + String taskName = tenderTasksVo.getTaskName(); + String taskType = "tender_review"; + String label = dictService.getDictLabel(taskType, taskName); + + // 获取详细的任务结果 + List resultDetails = getDetailResultsByTaskId(String.valueOf(taskId)); + if (resultDetails != null && !resultDetails.isEmpty()) { + // 根据任务类型生成Markdown + String markdown = generateTenderMarkdownByTaskTypeAndCategories(taskName, resultDetails); + + if (StringUtils.isNotBlank(markdown)) { + // 生成文档标题 + String title = "招投标文件分析报告"; + String fullMarkdown = String.format("# %s\n\n**文档名称**: %s \n**任务类型**: %s\n\n%s", + title, documentName, label, markdown); + + // 转换为PDF + String tempDir = System.getProperty("java.io.tmpdir"); + String tempPdfPath = tempDir + File.separator + "tender_result_" + taskId + ".pdf"; + convertMarkdownToPdf(fullMarkdown, tempPdfPath); + + // 下载文件 + String fileName = String.format("%s_%s.pdf", documentName, label); + downloadFile(response, tempPdfPath, fileName); + + // 删除临时文件 + Files.deleteIfExists(new File(tempPdfPath).toPath()); + } + } + } + } + } catch (Exception e) { + log.error("下载结果失败", e); + throw new RuntimeException("下载结果失败: " + e.getMessage()); + } + } + + /** + * 获取招投标任务PDF文件流 + */ + /** + * 获取招投标任务PDF文件流 + */ + @Override + @DS("slave") + public void getPdfStream(String taskId, HttpServletResponse response) { + try { + // 查询任务信息 + TenderTasksVo task = tenderTasksMapper.selectVoById(Long.valueOf(taskId)); + if (task == null) { + throw new RuntimeException("任务不存在"); + } + + String pdfPath = task.getPdfPath(); + String filePath = ""; + + if (StringUtils.isNotEmpty(pdfPath)) { + // 如果pdfPath存在,直接使用该路径 + filePath = pdfPath; + } else { + throw new RuntimeException("文件信息不存在"); + } + + log.info("开始输出招投标PDF文件: " + filePath); + + // 读取文件并输出到response + File file = new File(filePath); + if (!file.exists()) { + throw new RuntimeException("PDF文件不存在: " + filePath); + } + + log.info("招投标PDF文件存在,开始输出: " + filePath); + + // // 使用JDBC更新数据库 + // try (Connection conn = dataSource.getConnection()) { + // String sql = "UPDATE tender_tasks SET pdf_path = ? WHERE id = ?"; + // try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + // pstmt.setString(1, filePath); + // pstmt.setLong(2, Long.parseLong(taskId)); + // pstmt.executeUpdate(); + // } + // } catch (SQLException e) { + // log.error("更新招投标PDF路径失败", e); + // throw new RuntimeException("更新招投标PDF路径失败: " + e.getMessage()); + // } + + response.setContentType("application/pdf"); + response.setHeader("Content-Disposition", "inline; filename=" + URLEncoder.encode(file.getName(), StandardCharsets.UTF_8.name())); + + try (FileInputStream fis = new FileInputStream(file); + BufferedInputStream bis = new BufferedInputStream(fis, 8192); + OutputStream os = response.getOutputStream()) { + byte[] buffer = new byte[8192]; + int bytesRead; + while ((bytesRead = bis.read(buffer)) != -1) { + os.write(buffer, 0, bytesRead); + } + os.flush(); + } + } catch (Exception e) { + log.error("获取招投标PDF文件流失败", e); + throw new RuntimeException("获取招投标PDF文件流失败: " + e.getMessage()); + } + } + + /** + * 获取招投标文件PDF文件流 + */ + @Override + @DS("slave") + public void getBidPdfStream(String taskId, HttpServletResponse response) { + try { + // 设置响应头 + response.setContentType("application/pdf"); + response.setHeader("Content-Disposition", + "attachment; filename=tender_bid_document_" + taskId + ".pdf"); + + // 这里需要实现具体的招投标文件PDF获取逻辑 + // 目前先返回一个简单的提示 + response.getWriter().write("招投标文件PDF获取功能待实现"); + } catch (Exception e) { + throw new RuntimeException("获取招投标文件PDF失败", e); + } + } + + /** + * 根据任务类型和分类生成Markdown内容(统一使用多tabs模式) + * + * @param taskName 任务类型名称 + * @param resultDetails 结果详情列表 + * @return Markdown内容 + */ + private String generateTenderMarkdownByTaskTypeAndCategories(String taskName, List resultDetails) { + // 统一使用多tabs模式,根据任务类型获取tabs配置 + return generateTenderMarkdownByTabsConfig(taskName, resultDetails); + } + + /** + * 根据任务类型的tabs配置生成Markdown内容 + * + * @param taskName 任务类型名称 + * @param resultDetails 结果详情列表 + * @return Markdown内容 + */ + private String generateTenderMarkdownByTabsConfig(String taskName, List resultDetails) { + StringBuilder markdown = new StringBuilder(); + + // 获取任务类型对应的tabs配置 + List tabConfigs = getTenderTabConfigsByTaskType(taskName); + log.info("任务类型: {}, 配置的tabs数量: {}", taskName, tabConfigs.size()); + + // 记录可用的分类名称 + List availableCategories = resultDetails.stream() + .map(TenderTaskResultVO::getName) + .collect(java.util.stream.Collectors.toList()); + log.info("可用的分类名称: {}", availableCategories); + + // 按照tabs配置的顺序处理每个tab + for (TenderTabConfig tabConfig : tabConfigs) { + String tabName = tabConfig.getTabName(); + log.info("处理tab: {}, 字段配置数量: {}", tabName, tabConfig.getFieldConfigs().size()); + + // 查找对应的分类数据 + TenderTaskResultVO matchingCategory = null; + for (TenderTaskResultVO category : resultDetails) { + if (tabName.equals(category.getName())) { + matchingCategory = category; + break; + } + } + + // 如果找到对应的分类数据,添加到markdown中 + if (matchingCategory != null && matchingCategory.getResults() != null && !matchingCategory.getResults().isEmpty()) { + log.info("找到匹配的分类数据: {}, 结果数量: {}", tabName, matchingCategory.getResults().size()); + // 添加分类标题 + markdown.append("## ").append(tabName).append("\n\n"); + + // 处理该分类下的每个结果项 + for (TenderTaskResultVO.ResultItem item : matchingCategory.getResults()) { + markdown.append("### ").append(item.getSerialNumber()).append(". ").append(item.getExistingIssues()).append("\n\n"); + + // 根据tab配置显示各字段内容 + for (TenderFieldConfig fieldConfig : tabConfig.getFieldConfigs()) { + String fieldValue = getTenderFieldValueWithJsonSupport(item, fieldConfig.getField()); + if (StringUtils.isNotBlank(fieldValue)) { + markdown.append("**").append(fieldConfig.getTitle()).append("**\n\n").append(fieldValue).append("\n\n"); + } + } + + // 添加分隔线 + markdown.append("---\n\n"); + } + } else { + log.warn("未找到匹配的分类数据: {}", tabName); + } + } + + return markdown.toString(); + } + + /** + * 根据任务类型获取对应的tabs配置 + * + * @param taskName 任务类型名称 + * @return tabs配置列表 + */ + private List getTenderTabConfigsByTaskType(String taskName) { + List configs = new ArrayList<>(); + + // 根据任务类型返回不同的tabs配置 + switch (taskName) { + case "bidConsistencyReview": + // 投标一致性审查 - 4个tabs + configs.add(new TenderTabConfig("文档元数据", Arrays.asList( + new TenderFieldConfig("reviewBasis.review_points", "元数据要点") + ))); + configs.add(new TenderTabConfig("重点关注相似内容", Arrays.asList( + new TenderFieldConfig("modificationDisplay", "各文档具体内容"), + new TenderFieldConfig("reviewBasis.error_review_points", "错别字") + ))); +// configs.add(new TenderTabConfig("错别字", Arrays.asList( +// new TenderFieldConfig("reviewBasis.error_review_points", "错别字详情"), +// new TenderFieldConfig("modificationDisplay", "修改情况") +// ))); + configs.add(new TenderTabConfig("一般相似内容", Arrays.asList( + new TenderFieldConfig("reviewBasis.review_points", "各文档具体内容") + ))); + break; + case "tenderComplianceReview": + // 招投标合规性审查 + configs.add(new TenderTabConfig("合规性检查", Arrays.asList( + new TenderFieldConfig("originalText", "原文"), + new TenderFieldConfig("reviewBasis.review_content", "审查意见"), + new TenderFieldConfig("reviewBasis.review_points", "审查要点"), + new TenderFieldConfig("modificationDisplay", "修改情况") + ))); + break; + case "bidDocumentAnalysis": + // 投标文档分析 + configs.add(new TenderTabConfig("文档分析", Arrays.asList( + new TenderFieldConfig("originalText", "原文"), + new TenderFieldConfig("comparedText", "比对原文"), + new TenderFieldConfig("reviewBasis.review_content", "分析结果"), + new TenderFieldConfig("modificationDisplay", "修改建议") + ))); + break; + case "tenderDocumentCheck": + // 招标文档检查 + configs.add(new TenderTabConfig("文档检查", Arrays.asList( + new TenderFieldConfig("originalText", "原文"), + new TenderFieldConfig("reviewBasis.review_points", "检查要点"), + new TenderFieldConfig("modifiedContent", "修改建议"), + new TenderFieldConfig("modificationDisplay", "修改情况") + ))); + break; + case "contractComplianceReview": + // 合同合规性审查 + configs.add(new TenderTabConfig("合同审查", Arrays.asList( + new TenderFieldConfig("originalText", "原文"), + new TenderFieldConfig("reviewBasis.review_content", "审查意见"), + new TenderFieldConfig("reviewBasis.review_points", "审查要点"), + new TenderFieldConfig("modificationDisplay", "修改情况") + ))); + break; + default: + // 默认配置 - 使用通用的4个tabs结构 + configs.add(new TenderTabConfig("文档元数据", Arrays.asList( + new TenderFieldConfig("reviewBasis.review_points", "元数据要点") + ))); + configs.add(new TenderTabConfig("重点关注相似内容", Arrays.asList( + new TenderFieldConfig("modificationDisplay", "各文档具体内容"), + new TenderFieldConfig("reviewBasis.error_review_points", "错别字") + ))); + configs.add(new TenderTabConfig("错别字", Arrays.asList( + new TenderFieldConfig("reviewBasis.error_review_points", "错别字详情"), + new TenderFieldConfig("modificationDisplay", "修改情况") + ))); + configs.add(new TenderTabConfig("一般相似内容", Arrays.asList( + new TenderFieldConfig("modificationDisplay", "各文档具体内容") + ))); + break; + } + + return configs; + } + + /** + * 获取结果项对象的字段值,支持从reviewBasis JSON中提取数据 + * + * @param item 结果项对象 + * @param fieldName 字段名(支持嵌套字段,如 reviewBasis.reviewContent) + * @return 字段值 + */ + private String getTenderFieldValueWithJsonSupport(TenderTaskResultVO.ResultItem item, String fieldName) { + try { + // 处理嵌套字段,如 reviewBasis.reviewContent + if (fieldName.contains(".")) { + String[] parts = fieldName.split("\\.", 2); + String mainField = parts[0]; + String subField = parts[1]; + + // 获取主字段值 + Object mainValue = getFieldValueByReflection(item, mainField); + if (mainValue == null) { + return ""; + } + + // 如果主字段是JSON字符串,解析并提取子字段 + if (mainValue instanceof String && "reviewBasis".equals(mainField)) { + try { + // 使用简单的JSON解析方式 + String jsonStr = (String) mainValue; + return extractJsonField(jsonStr, subField); + } catch (Exception e) { + log.error("解析JSON字段失败: {}, {}", fieldName, e.getMessage()); + return ""; + } + } + } + + // 处理普通字段 + Object value = getFieldValueByReflection(item, fieldName); + if (value != null) { + String stringValue = value.toString(); + // 对于普通字段也处理
标签 + return stringValue + .replace("
", "\n\n") + .replace("
", "\n\n") + .replace("
", "\n\n") + .replace("
", "\n\n"); + } + return ""; + } catch (Exception e) { + log.error("获取字段值失败: {}, {}", fieldName, e.getMessage()); + return ""; + } + } + + /** + * 通过反射获取字段值 + */ + private Object getFieldValueByReflection(TenderTaskResultVO.ResultItem item, String fieldName) throws Exception { + java.lang.reflect.Method method = item.getClass().getMethod("get" + StringUtils.capitalize(fieldName)); + return method.invoke(item); + } + + /** + * 从JSON字符串中提取指定字段的值 + */ + private String extractJsonField(String jsonStr, String fieldName) { + if (StringUtils.isBlank(jsonStr) || StringUtils.isBlank(fieldName)) { + return ""; + } + + try { + // 支持前端配置中的各种字段 + switch (fieldName) { + case "reviewContent": + case "review_content": + return extractStringField(jsonStr, fieldName); + case "reviewPoints": + case "review_points": + case "error_review_points": + return extractArrayField(jsonStr, fieldName, "\n\n• "); + default: + // 尝试作为字符串字段提取 + String stringResult = extractStringField(jsonStr, fieldName); + if (StringUtils.isNotBlank(stringResult)) { + return stringResult; + } + // 尝试作为数组字段提取 + return extractArrayField(jsonStr, fieldName, "\n\n• "); + } + } catch (Exception e) { + log.error("提取JSON字段失败: {}, {}", fieldName, e.getMessage()); + return ""; + } + } + + /** + * 从JSON中提取字符串字段 + */ + private String extractStringField(String jsonStr, String fieldName) { + int start = jsonStr.indexOf("\"" + fieldName + "\""); + if (start == -1) return ""; + + start = jsonStr.indexOf(":", start) + 1; + start = jsonStr.indexOf("\"", start) + 1; + int end = jsonStr.indexOf("\"", start); + + if (start > 0 && end > start) { + return jsonStr.substring(start, end) + .replace("\\n", "\n") + .replace("\\\"", "\"") + .replace("\\\\", "\\") + .replace("\\t", "\t") + .replace("
", "\n\n") + .replace("
", "\n\n") + .replace("
", "\n\n") + .replace("
", "\n\n"); + } + + return ""; + } + + /** + * 从JSON中提取数组字段并格式化 + */ + private String extractArrayField(String jsonStr, String fieldName, String prefix) { + int start = jsonStr.indexOf("\"" + fieldName + "\""); + if (start == -1) return ""; + + start = jsonStr.indexOf("[", start); + int end = jsonStr.indexOf("]", start) + 1; + + if (start > 0 && end > start) { + String arrayStr = jsonStr.substring(start, end); + // 处理数组,提取字符串元素 + String result = arrayStr.replaceAll("\\[|\\]", "") + .replaceAll("\"\\s*,\\s*\"", "\",\""); + + if (StringUtils.isNotBlank(result)) { + String[] elements = result.split("\",\""); + StringBuilder formatted = new StringBuilder(); + + for (String element : elements) { + String cleanElement = element.replaceAll("^\"|\"$", "") + .replace("\\n", "\n") + .replace("\\\"", "\"") + .replace("\\\\", "\\") + .replace("\\t", "\t") + .replace("
", "\n\n") + .replace("
", "\n\n") + .replace("
", "\n\n") + .replace("
", "\n\n"); + + if (StringUtils.isNotBlank(cleanElement)) { + if (formatted.length() > 0) { + formatted.append(prefix); + } else { + formatted.append("• "); + } + formatted.append(cleanElement); + } + } + + return formatted.toString(); + } + } + + return ""; + } + + /** + * Markdown转PDF方法 + */ + private void convertMarkdownToPdf(String markdown, String outputPath) throws Exception { + MutableDataSet options = new MutableDataSet(); + options.set(Parser.EXTENSIONS, Arrays.asList( + TablesExtension.create(), + StrikethroughExtension.create() + )); + + Parser parser = Parser.builder(options).build(); + HtmlRenderer renderer = HtmlRenderer.builder(options) + .extensions(Arrays.asList( + TablesExtension.create(), + StrikethroughExtension.create() + )) + .build(); + + Node document = parser.parse(markdown); + String htmlContent = renderer.render(document); + + // 使用 JSoup 清理 + Document.OutputSettings settings = new Document.OutputSettings(); + settings.prettyPrint(false); + + Safelist safelist = Safelist.relaxed() + .addTags("em", "strong", "div", "span", "br", "table", "thead", "tbody", "tr", "th", "td", "font") + .addAttributes(":all", "style", "class", "color") + .addAttributes("table", "border", "cellpadding", "cellspacing") + .addAttributes("font", "color"); + htmlContent = Jsoup.clean(htmlContent, "", safelist, settings); + + // 创建完整的HTML文档 + String html = String.format(""" + + + + + + + + %s + + + """, htmlContent.replace("
", "\n")); + + // 配置Flying Saucer + ITextRenderer pdfRenderer = new ITextRenderer(); + + // 加载字体 + try (InputStream is = getClass().getResourceAsStream("/fonts/msyh.ttc")) { + if (is != null) { + File tempFont = File.createTempFile("msyh", ".ttc"); + FileUtils.copyInputStreamToFile(is, tempFont); + pdfRenderer.getFontResolver().addFont(tempFont.getAbsolutePath(), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); + tempFont.deleteOnExit(); + } + } catch (Exception e) { + log.warn("加载字体失败,使用默认字体: {}", e.getMessage()); + } + + pdfRenderer.setDocumentFromString(html); + pdfRenderer.getSharedContext().setBaseURL("file:///"); + pdfRenderer.layout(); + + try (OutputStream os = new FileOutputStream(outputPath)) { + pdfRenderer.createPDF(os, true); + } + } + + /** + * 添加文件到ZIP + */ + private void addToZip(String filePath, String fileName, ZipOutputStream zos) throws IOException { + byte[] buffer = new byte[1024]; + try (FileInputStream fis = new FileInputStream(filePath)) { + zos.putNextEntry(new ZipEntry(fileName)); + int length; + while ((length = fis.read(buffer)) > 0) { + zos.write(buffer, 0, length); + } + zos.closeEntry(); + } + } + + /** + * 文件下载方法 + */ + private void downloadFile(HttpServletResponse response, String filePath, String fileName) throws IOException { + File file = new File(filePath); + if (!file.exists()) { + throw new RuntimeException("文件不存在"); + } + + response.setContentType("application/octet-stream"); + response.setHeader("Content-Disposition", "attachment;filename=" + + URLEncoder.encode(fileName, StandardCharsets.UTF_8.name())); + + try (FileInputStream fis = new FileInputStream(file); + BufferedInputStream bis = new BufferedInputStream(fis); + OutputStream os = response.getOutputStream()) { + + byte[] buffer = new byte[1024]; + int i; + while ((i = bis.read(buffer)) != -1) { + os.write(buffer, 0, i); + } + } + } + + /** + * 招投标任务字段配置类 + */ + private static class TenderFieldConfig { + private String field; + private String title; + + public TenderFieldConfig(String field, String title) { + this.field = field; + this.title = title; + } + + public String getField() { + return field; + } + + public String getTitle() { + return title; + } + } + + /** + * 招投标任务tabs配置类 + */ + private static class TenderTabConfig { + private String tabName; + private List fieldConfigs; + + public TenderTabConfig(String tabName, List fieldConfigs) { + this.tabName = tabName; + this.fieldConfigs = fieldConfigs; + } + + public String getTabName() { + return tabName; + } + + public List getFieldConfigs() { + return fieldConfigs; + } + } +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/impl/TenderTaskTypeServiceImpl.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/impl/TenderTaskTypeServiceImpl.java new file mode 100644 index 0000000..abda73b --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/impl/TenderTaskTypeServiceImpl.java @@ -0,0 +1,144 @@ +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.ITenderTaskTypeService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.dromara.productManagement.domain.bo.TenderTaskTypeBo; +import org.dromara.productManagement.domain.vo.TenderTaskTypeVo; +import org.dromara.productManagement.domain.TenderTaskType; +import org.dromara.productManagement.mapper.TenderTaskTypeMapper; + +import java.util.List; +import java.util.Collection; +import java.util.Map; + +/** + * 招投标类型Service业务层处理 + * + * @author guoyan + * @date 2024-12-14 + */ +@RequiredArgsConstructor +@Service +@Transactional +public class TenderTaskTypeServiceImpl implements ITenderTaskTypeService { + + private final TenderTaskTypeMapper baseMapper; + + /** + * 查询招投标类型 + * + * @param id 招投标类型主键 + * @return 招投标类型 + */ + @Override + public TenderTaskTypeVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 查询招投标类型列表 + * + * @param bo 招投标类型 + * @return 招投标类型 + */ + @Override + public TableDataInfo queryPageList(TenderTaskTypeBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询招投标类型列表 + * + * @param bo 招投标类型 + * @return 招投标类型 + */ + @Override + public List queryList(TenderTaskTypeBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(TenderTaskTypeBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getTenderName()), TenderTaskType::getTenderName, bo.getTenderName()); + lqw.eq(bo.getSort() != null, TenderTaskType::getSort, bo.getSort()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), TenderTaskType::getStatus, bo.getStatus()); + return lqw; + } + + /** + * 新增招投标类型 + * + * @param bo 招投标类型 + * @return 结果 + */ + @Override + public Boolean insertByBo(TenderTaskTypeBo bo) { + TenderTaskType add = MapstructUtils.convert(bo, TenderTaskType.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改招投标类型 + * + * @param bo 招投标类型 + * @return 结果 + */ + @Override + public Boolean updateByBo(TenderTaskTypeBo bo) { + TenderTaskType update = MapstructUtils.convert(bo, TenderTaskType.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + * + * @param entity 实体类数据 + */ + private void validEntityBeforeSave(TenderTaskType entity) { + // 校验招投标类型名称是否重复 + if (StringUtils.isNotEmpty(entity.getTenderName())) { + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + queryWrapper.eq(TenderTaskType::getTenderName, entity.getTenderName()); + if (entity.getId() != null) { + queryWrapper.ne(TenderTaskType::getId, entity.getId()); + } + if (baseMapper.selectCount(queryWrapper) > 0) { + throw new RuntimeException("招投标类型名称已存在"); + } + } + } + + /** + * 批量删除招投标类型 + * + * @param ids 需要删除的招投标类型主键 + * @return 结果 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // 校验是否存在关联的招投标任务 + // 这里可以添加业务校验逻辑 + } + return baseMapper.deleteBatchIds(ids) > 0; + } +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/impl/TenderTasksServiceImpl.java b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/impl/TenderTasksServiceImpl.java new file mode 100644 index 0000000..f6f72d9 --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/impl/TenderTasksServiceImpl.java @@ -0,0 +1,347 @@ +package org.dromara.productManagement.service.impl; + +import cn.dev33.satoken.stp.StpUtil; +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; +import okhttp3.*; +import org.dromara.common.satoken.utils.LoginHelper; + +import org.dromara.productManagement.service.ITenderTasksService; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysOssService; +import org.dromara.system.service.ISysUserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +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.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.productManagement.domain.TenderTaskGroup; +import org.dromara.productManagement.domain.bo.TenderTasksBo; +import org.dromara.productManagement.domain.vo.TenderTasksVo; +import org.dromara.productManagement.domain.TenderTasks; +import org.dromara.productManagement.mapper.TenderTasksMapper; +import jakarta.servlet.http.HttpServletResponse; + +import javax.sql.DataSource; +import java.io.*; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; + +/** + * 招投标审核任务Service业务层处理 + * + * @author ruoyi + * @date 2024-01-01 + */ +@RequiredArgsConstructor +@Service +@Slf4j +public class TenderTasksServiceImpl implements ITenderTasksService { + + private final TenderTasksMapper baseMapper; + protected final ISysOssService ossService; + protected final ISysUserService userService; + @Value("${chat.chatUrl}") + private String backTaskUrl; + @Autowired + private DataSource dataSource; + /** + * 查询招投标审核任务 + */ + @Override + public TenderTasksVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 查询招投标审核任务列表 + */ + @Override + @DS("slave") + public TableDataInfo queryPageList(TenderTasksBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 分页查询招投标任务分组列表 + */ + @Override + @DS("slave") + public TableDataInfo queryGroupPageList(TenderTasksBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildGroupQueryWrapper(bo); + Page tenderTaskGroupPage = baseMapper.selectTenderTaskGroups(pageQuery.build(), lqw); + tenderTaskGroupPage.getRecords().forEach(vo -> { + Long createBy = vo.getCreateBy(); + // 切换到主库查询用户信息 + DynamicDataSourceContextHolder.push("master"); + try { + vo.setCreateUser(userService.selectUserById(createBy).getNickName()); + } finally { + // 确保在finally块中恢复数据源,防止异常导致数据源未切回 + DynamicDataSourceContextHolder.poll(); + } + }); + return TableDataInfo.build(tenderTaskGroupPage); + } + + /** + * 查询招投标审核任务列表 + */ + @Override + public List queryList(TenderTasksBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(TenderTasksBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getTaskName()), TenderTasks::getTaskName, bo.getTaskName()); + lqw.like(StringUtils.isNotBlank(bo.getTenderDocumentName()), TenderTasks::getTenderDocumentName, bo.getTenderDocumentName()); + lqw.like(StringUtils.isNotBlank(bo.getBidDocumentName()), TenderTasks::getBidDocumentName, bo.getBidDocumentName()); + lqw.eq(StringUtils.isNotBlank(bo.getProgressStatus()), TenderTasks::getProgressStatus, bo.getProgressStatus()); + lqw.eq(StringUtils.isNotBlank(bo.getResultType()), TenderTasks::getResultType, bo.getResultType()); + lqw.orderByDesc(TenderTasks::getCreateTime); + return lqw; + } + + private LambdaQueryWrapper buildGroupQueryWrapper(TenderTasksBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + + // 处理 taskNameList 是 List 的情况 + List taskNames = bo.getTaskNameList(); + if (taskNames != null && !taskNames.isEmpty()) { + lqw.in(TenderTasks::getTaskName, taskNames); + } + + lqw.like(StringUtils.isNotBlank(bo.getTaskName()), TenderTasks::getTaskName, bo.getTaskName()); + lqw.like(StringUtils.isNotBlank(bo.getTenderDocumentName()), TenderTasks::getTenderDocumentName, bo.getTenderDocumentName()); + lqw.like(StringUtils.isNotBlank(bo.getBidDocumentName()), TenderTasks::getBidDocumentName, bo.getBidDocumentName()); + lqw.eq(StringUtils.isNotBlank(bo.getProgressStatus()), TenderTasks::getProgressStatus, bo.getProgressStatus()); + lqw.eq(StringUtils.isNotBlank(bo.getResultType()), TenderTasks::getResultType, bo.getResultType()); + lqw.orderByDesc(TenderTasks::getCreateTime); + if (!StpUtil.hasRole("superadmin")) { + lqw.eq(TenderTasks::getCreateBy, LoginHelper.getUserId()); + } + //分组,作为父项(按文件名分组而不是任务名) + lqw.groupBy(TenderTasks::getCreateBy, + TenderTasks::getTenderDocumentName, + TenderTasks::getBidDocumentName, + TenderTasks::getCreateTime, + TenderTasks::getDeleteFlag); + return lqw; + } + + /** + * 新增招投标审核任务 + */ + @Override + @DS("slave") + public Boolean insertByBo(TenderTasksBo bo) { + List taskNameList = bo.getTaskNameList(); + String bidDocOssId = bo.getBidDocZipOssId(); + String tenderDocOssId = bo.getTenderDocOssId(); + + String bidDocUrl = ""; + String bidDocFileName = ""; + String tenderDocUrl = ""; + String tenderFileName = ""; + + // 切换到主库查询OSS信息 + DynamicDataSourceContextHolder.push("master"); + try { + if (bidDocOssId==null && tenderDocOssId==null){ + throw new RuntimeException("请上传投标文件或者招标文件"); + } + if (bidDocOssId!=null ){ + SysOssVo bidDocFiles = ossService.getById(Long.valueOf(bidDocOssId)); + if (bidDocFiles!=null) { + bidDocUrl = bidDocFiles.getUrl(); + bidDocFileName = bidDocFiles.getOriginalName(); + } + } + if (tenderDocOssId!=null ){ + SysOssVo tenderDocFiles = ossService.getById(Long.valueOf(tenderDocOssId)); + if (tenderDocFiles!=null) { + tenderDocUrl = tenderDocFiles.getUrl(); + tenderFileName = tenderDocFiles.getOriginalName(); + } + } + } finally { + // 确保在finally块中恢复数据源,防止异常导致数据源未切回 + DynamicDataSourceContextHolder.poll(); + } + if(bidDocOssId==null && tenderDocOssId==null){ + throw new RuntimeException("请上传投标文件或者招标文件"); + } + + if (taskNameList != null && !taskNameList.isEmpty()) { + for (String taskName : taskNameList) { + // 创建 TenderTasks 实体并设置属性 + TenderTasks add = MapstructUtils.convert(bo, TenderTasks.class); + add.setTaskName(taskName); + add.setBidDocumentName(bidDocFileName); + add.setTenderDocumentName(tenderFileName); + add.setProgressStatus("PENDING"); + // 验证实体并保存 + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + + if (flag) { + // 发起请求 + OkHttpClient client = new OkHttpClient.Builder().build(); + HttpUrl.Builder urlBuilder = HttpUrl.parse(backTaskUrl + "/back/taskStart").newBuilder(); + urlBuilder.addQueryParameter("userId", String.valueOf(LoginHelper.getUserId())); + urlBuilder.addQueryParameter("taskId", String.valueOf(add.getId())); + urlBuilder.addQueryParameter("filename", bidDocUrl + "\n" + tenderDocUrl); + urlBuilder.addQueryParameter("taskName", taskName); + urlBuilder.addQueryParameter("priority", "1"); + Request request = new Request.Builder() + .url(urlBuilder.build()) + .build(); + // 使用异步调用 + client.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + e.printStackTrace(); // 处理请求失败 + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + // 忽略返回内容 + response.close(); // 确保响应被关闭 + } + }); + } else { + throw new RuntimeException("新增招投标审核任务失败"); + } + } + } + return true; + } + + /** + * 修改招投标审核任务 + */ + @Override + public Boolean updateByBo(TenderTasksBo bo) { + TenderTasks update = MapstructUtils.convert(bo, TenderTasks.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(TenderTasks entity){ + // 可以在此处添加业务校验逻辑 + } + + /** + * 批量删除招投标审核任务 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + // 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteBatchIds(ids) > 0; + } + + /** + * 删除招投标任务文件 + */ + @Override + @DS("slave") + public Boolean ossRemoveById(String ossId, Boolean isValid) { + try { + log.info("开始删除招投标任务文件,ossId: {}", ossId); + + // 查找包含该ossId的招投标任务(从库查询) + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(TenderTasks::getTenderDocOssId, ossId) + .or() + .eq(TenderTasks::getBidDocZipOssId, ossId); + + List tasks = baseMapper.selectVoList(queryWrapper); + + if (tasks.isEmpty()) { + log.warn("未找到包含ossId: {} 的招投标任务", ossId); + return false; + } + + // 切换到主库进行删除和更新操作 + DynamicDataSourceContextHolder.push("master"); + try { + // 删除文件服务中的文件 + ossService.deleteWithValidByIds(Collections.singletonList(Long.valueOf(ossId)), true); + log.info("已删除文件服务中的文件,ossId: {}", ossId); + + // 对于找到的每个任务,需要检查并删除相关的其他文件 + for (TenderTasksVo task : tasks) { + String tenderDocOssId = task.getTenderDocOssId(); + String bidDocZipOssId = task.getBidDocZipOssId(); + + // 如果删除的是招标文件,还需要删除投标文件(如果有的话) + if (ossId.equals(tenderDocOssId) && StringUtils.isNotBlank(bidDocZipOssId)) { + try { + ossService.deleteWithValidByIds(Collections.singletonList(Long.valueOf(bidDocZipOssId)), true); + log.info("已删除关联的投标文件,ossId: {}", bidDocZipOssId); + } catch (Exception e) { + log.warn("删除关联投标文件失败,ossId: {}, 错误: {}", bidDocZipOssId, e.getMessage()); + } + } + + // 如果删除的是投标文件,还需要删除招标文件(如果有的话) + if (ossId.equals(bidDocZipOssId) && StringUtils.isNotBlank(tenderDocOssId)) { + try { + ossService.deleteWithValidByIds(Collections.singletonList(Long.valueOf(tenderDocOssId)), true); + log.info("已删除关联的招标文件,ossId: {}", tenderDocOssId); + } catch (Exception e) { + log.warn("删除关联招标文件失败,ossId: {}, 错误: {}", tenderDocOssId, e.getMessage()); + } + } + } + } finally { + // 确保在finally块中恢复数据源,防止异常导致数据源未切回 + DynamicDataSourceContextHolder.poll(); + } + // 更新数据库中的deleteFlag字段 + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.eq(TenderTasks::getTenderDocOssId, ossId) + .or() + .eq(TenderTasks::getBidDocZipOssId, ossId); + updateWrapper.set(TenderTasks::getDeleteFlag, "Y"); + + int updateCount = baseMapper.update(null, updateWrapper); + log.info("已更新数据库deleteFlag字段,影响行数: {}", updateCount); + + + return true; + + } catch (Exception e) { + log.error("删除招投标任务文件失败,ossId: {}, 错误: {}", ossId, e.getMessage(), e); + throw new RuntimeException("删除招投标任务文件失败: " + e.getMessage()); + } + } + +} diff --git a/zaojiaManagement/zaojia-productManagement/src/main/resources/mapper/productManagement/TenderTaskResultDetailMapper.xml b/zaojiaManagement/zaojia-productManagement/src/main/resources/mapper/productManagement/TenderTaskResultDetailMapper.xml new file mode 100644 index 0000000..39481a6 --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/resources/mapper/productManagement/TenderTaskResultDetailMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/zaojiaManagement/zaojia-productManagement/src/main/resources/mapper/productManagement/TenderTasksMapper.xml b/zaojiaManagement/zaojia-productManagement/src/main/resources/mapper/productManagement/TenderTasksMapper.xml new file mode 100644 index 0000000..5833fb6 --- /dev/null +++ b/zaojiaManagement/zaojia-productManagement/src/main/resources/mapper/productManagement/TenderTasksMapper.xml @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +