27 changed files with 3078 additions and 0 deletions
@ -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<List<TenderTaskResultVO>> 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<Void> 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)); |
|||
} |
|||
} |
@ -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<TenderTaskTypeVo>> 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<TenderTaskTypeVo> list = tenderTaskTypeService.queryList(bo); |
|||
ExcelUtil.exportExcel(list, "招投标类型", TenderTaskTypeVo.class, response); |
|||
} |
|||
|
|||
/** |
|||
* 获取招投标类型详细信息 |
|||
* |
|||
* @param id 主键 |
|||
*/ |
|||
// @SaCheckPermission("productManagement:TenderTaskType:query")
|
|||
@GetMapping("/{id}") |
|||
public R<TenderTaskTypeVo> 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<Void> 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<Void> 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<Void> remove(@NotEmpty(message = "主键不能为空") |
|||
@PathVariable Long[] ids) { |
|||
return toAjax(tenderTaskTypeService.deleteWithValidByIds(List.of(ids), true)); |
|||
} |
|||
} |
@ -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<TenderTaskGroup> 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<TenderTasksVo> list = tenderTasksService.queryList(bo); |
|||
ExcelUtil.exportExcel(list, "招投标审核任务", TenderTasksVo.class, response); |
|||
} |
|||
|
|||
/** |
|||
* 获取招投标审核任务详细信息 |
|||
*/ |
|||
@SaCheckPermission("tender:tasks:query") |
|||
@GetMapping("/{id}") |
|||
public R<TenderTasksVo> 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<Void> 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<Void> 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<Void> 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<Void> ossRemoveById(@NotEmpty(message = "主键不能为空") |
|||
@PathVariable String ossid) { |
|||
return toAjax(tenderTasksService.ossRemoveById(ossid, true)); |
|||
} |
|||
|
|||
} |
@ -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; |
|||
|
|||
} |
@ -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<TenderTaskChild> childrenTasks; |
|||
|
|||
} |
@ -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; |
|||
|
|||
} |
@ -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; |
|||
|
|||
} |
@ -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; |
|||
|
|||
} |
@ -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; |
|||
|
|||
} |
@ -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; |
|||
|
|||
} |
@ -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; |
|||
|
|||
} |
@ -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; |
|||
|
|||
} |
@ -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<ResultItem> 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; // 是否采纳
|
|||
} |
|||
} |
@ -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; |
|||
|
|||
} |
@ -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; |
|||
|
|||
} |
@ -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; |
|||
} |
|||
|
|||
} |
@ -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<TenderTaskResultDetail, TenderTaskResultDetail> { |
|||
|
|||
} |
@ -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<TenderTaskType, TenderTaskTypeVo> { |
|||
|
|||
} |
@ -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<TenderTasks, TenderTasksVo> { |
|||
|
|||
/** |
|||
* 根据任务ID获取详细的文档任务结果 |
|||
* |
|||
* @param taskId 任务ID |
|||
* @return 文档任务结果详情列表 |
|||
*/ |
|||
List<TenderTaskResultVO> getResultsByTaskId(@Param("taskId") String taskId); |
|||
|
|||
/** |
|||
* 分页查询招投标任务分组列表 |
|||
* |
|||
* @param page 分页参数 |
|||
* @param wrapper 查询条件 |
|||
* @return 招投标任务分组分页列表 |
|||
*/ |
|||
Page<TenderTaskGroup> selectTenderTaskGroups(@Param("page") Page<TenderTasks> page, @Param(Constants.WRAPPER) Wrapper<TenderTasks> wrapper); |
|||
|
|||
} |
@ -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<TenderTaskResultVO> 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); |
|||
} |
@ -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<TenderTaskTypeVo> queryPageList(TenderTaskTypeBo bo, PageQuery pageQuery); |
|||
|
|||
/** |
|||
* 查询符合条件的招投标类型列表 |
|||
* |
|||
* @param bo 查询条件 |
|||
* @return 招投标类型列表 |
|||
*/ |
|||
List<TenderTaskTypeVo> 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<Long> ids, Boolean isValid); |
|||
} |
@ -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<TenderTasksVo> queryPageList(TenderTasksBo bo, PageQuery pageQuery); |
|||
|
|||
/** |
|||
* 分页查询招投标任务分组列表 |
|||
*/ |
|||
TableDataInfo<TenderTaskGroup> queryGroupPageList(TenderTasksBo bo, PageQuery pageQuery); |
|||
|
|||
/** |
|||
* 查询招投标审核任务列表 |
|||
*/ |
|||
List<TenderTasksVo> queryList(TenderTasksBo bo); |
|||
|
|||
/** |
|||
* 新增招投标审核任务 |
|||
*/ |
|||
Boolean insertByBo(TenderTasksBo bo); |
|||
|
|||
/** |
|||
* 修改招投标审核任务 |
|||
*/ |
|||
Boolean updateByBo(TenderTasksBo bo); |
|||
|
|||
/** |
|||
* 校验并批量删除招投标审核任务信息 |
|||
*/ |
|||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); |
|||
|
|||
/** |
|||
* 删除招投标任务文件 |
|||
*/ |
|||
Boolean ossRemoveById(String ossId, Boolean isValid); |
|||
|
|||
} |
@ -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<TenderTaskResultVO> getDetailResultsByTaskId(String taskId) { |
|||
|
|||
List<TenderTaskResultVO> 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<TenderTaskResultDetail> 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<TenderTaskResultVO> 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<TenderTaskResultVO> 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<TenderTaskResultVO> resultDetails) { |
|||
// 统一使用多tabs模式,根据任务类型获取tabs配置
|
|||
return generateTenderMarkdownByTabsConfig(taskName, resultDetails); |
|||
} |
|||
|
|||
/** |
|||
* 根据任务类型的tabs配置生成Markdown内容 |
|||
* |
|||
* @param taskName 任务类型名称 |
|||
* @param resultDetails 结果详情列表 |
|||
* @return Markdown内容 |
|||
*/ |
|||
private String generateTenderMarkdownByTabsConfig(String taskName, List<TenderTaskResultVO> resultDetails) { |
|||
StringBuilder markdown = new StringBuilder(); |
|||
|
|||
// 获取任务类型对应的tabs配置
|
|||
List<TenderTabConfig> tabConfigs = getTenderTabConfigsByTaskType(taskName); |
|||
log.info("任务类型: {}, 配置的tabs数量: {}", taskName, tabConfigs.size()); |
|||
|
|||
// 记录可用的分类名称
|
|||
List<String> 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<TenderTabConfig> getTenderTabConfigsByTaskType(String taskName) { |
|||
List<TenderTabConfig> 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(); |
|||
// 对于普通字段也处理<br>标签
|
|||
return stringValue |
|||
.replace("<br>", "\n\n") |
|||
.replace("<br/>", "\n\n") |
|||
.replace("<BR>", "\n\n") |
|||
.replace("<BR/>", "\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("<br>", "\n\n") |
|||
.replace("<br/>", "\n\n") |
|||
.replace("<BR>", "\n\n") |
|||
.replace("<BR/>", "\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("<br>", "\n\n") |
|||
.replace("<br/>", "\n\n") |
|||
.replace("<BR>", "\n\n") |
|||
.replace("<BR/>", "\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(""" |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<meta charset="UTF-8"/> |
|||
<style type="text/css"> |
|||
body { |
|||
font-family: Microsoft YaHei, SimSun, Arial; |
|||
line-height: 1.6; |
|||
margin: 20px; |
|||
font-size: 14px; |
|||
} |
|||
p { margin: 10px 0; } |
|||
pre { |
|||
background-color: #f5f5f5; |
|||
padding: 10px; |
|||
border-radius: 4px; |
|||
} |
|||
table { |
|||
border-collapse: collapse; |
|||
width: 100%%; |
|||
margin: 10px 0; |
|||
} |
|||
th, td { |
|||
border: 1px solid #ddd; |
|||
padding: 8px; |
|||
text-align: left; |
|||
} |
|||
th { |
|||
background-color: #f5f5f5; |
|||
font-weight: bold; |
|||
} |
|||
.highlight { |
|||
background-color: #ffff00; |
|||
} |
|||
font[color=red] { |
|||
color: red; |
|||
font-weight: bold; |
|||
} |
|||
</style> |
|||
</head> |
|||
<body> |
|||
%s |
|||
</body> |
|||
</html> |
|||
""", htmlContent.replace("<br>", "\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<TenderFieldConfig> fieldConfigs; |
|||
|
|||
public TenderTabConfig(String tabName, List<TenderFieldConfig> fieldConfigs) { |
|||
this.tabName = tabName; |
|||
this.fieldConfigs = fieldConfigs; |
|||
} |
|||
|
|||
public String getTabName() { |
|||
return tabName; |
|||
} |
|||
|
|||
public List<TenderFieldConfig> getFieldConfigs() { |
|||
return fieldConfigs; |
|||
} |
|||
} |
|||
} |
@ -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<TenderTaskTypeVo> queryPageList(TenderTaskTypeBo bo, PageQuery pageQuery) { |
|||
LambdaQueryWrapper<TenderTaskType> lqw = buildQueryWrapper(bo); |
|||
Page<TenderTaskTypeVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); |
|||
return TableDataInfo.build(result); |
|||
} |
|||
|
|||
/** |
|||
* 查询招投标类型列表 |
|||
* |
|||
* @param bo 招投标类型 |
|||
* @return 招投标类型 |
|||
*/ |
|||
@Override |
|||
public List<TenderTaskTypeVo> queryList(TenderTaskTypeBo bo) { |
|||
LambdaQueryWrapper<TenderTaskType> lqw = buildQueryWrapper(bo); |
|||
return baseMapper.selectVoList(lqw); |
|||
} |
|||
|
|||
private LambdaQueryWrapper<TenderTaskType> buildQueryWrapper(TenderTaskTypeBo bo) { |
|||
Map<String, Object> params = bo.getParams(); |
|||
LambdaQueryWrapper<TenderTaskType> 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<TenderTaskType> 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<Long> ids, Boolean isValid) { |
|||
if (isValid) { |
|||
// 校验是否存在关联的招投标任务
|
|||
// 这里可以添加业务校验逻辑
|
|||
} |
|||
return baseMapper.deleteBatchIds(ids) > 0; |
|||
} |
|||
} |
@ -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<TenderTasksVo> queryPageList(TenderTasksBo bo, PageQuery pageQuery) { |
|||
LambdaQueryWrapper<TenderTasks> lqw = buildQueryWrapper(bo); |
|||
Page<TenderTasksVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); |
|||
return TableDataInfo.build(result); |
|||
} |
|||
|
|||
/** |
|||
* 分页查询招投标任务分组列表 |
|||
*/ |
|||
@Override |
|||
@DS("slave") |
|||
public TableDataInfo<TenderTaskGroup> queryGroupPageList(TenderTasksBo bo, PageQuery pageQuery) { |
|||
LambdaQueryWrapper<TenderTasks> lqw = buildGroupQueryWrapper(bo); |
|||
Page<TenderTaskGroup> 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<TenderTasksVo> queryList(TenderTasksBo bo) { |
|||
LambdaQueryWrapper<TenderTasks> lqw = buildQueryWrapper(bo); |
|||
return baseMapper.selectVoList(lqw); |
|||
} |
|||
|
|||
private LambdaQueryWrapper<TenderTasks> buildQueryWrapper(TenderTasksBo bo) { |
|||
Map<String, Object> params = bo.getParams(); |
|||
LambdaQueryWrapper<TenderTasks> 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<TenderTasks> buildGroupQueryWrapper(TenderTasksBo bo) { |
|||
Map<String, Object> params = bo.getParams(); |
|||
LambdaQueryWrapper<TenderTasks> lqw = Wrappers.lambdaQuery(); |
|||
|
|||
// 处理 taskNameList 是 List<String> 的情况
|
|||
List<String> 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<String> 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<Long> 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<TenderTasks> queryWrapper = new LambdaQueryWrapper<>(); |
|||
queryWrapper.eq(TenderTasks::getTenderDocOssId, ossId) |
|||
.or() |
|||
.eq(TenderTasks::getBidDocZipOssId, ossId); |
|||
|
|||
List<TenderTasksVo> 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<TenderTasks> 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()); |
|||
} |
|||
} |
|||
|
|||
} |
@ -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.TenderTaskResultDetailMapper"> |
|||
|
|||
</mapper> |
@ -0,0 +1,140 @@ |
|||
<?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.TenderTasksMapper"> |
|||
|
|||
<resultMap id="TenderTaskGroupResult" type="org.dromara.productManagement.domain.TenderTaskGroup"> |
|||
<id property="id" column="group_id"/> |
|||
<result property="createBy" column="create_by"/> |
|||
<result property="tenderDocumentName" column="tender_document_name"/> |
|||
<result property="bidDocumentName" column="bid_document_name"/> |
|||
<result property="createTime" column="group_create_time"/> |
|||
<result property="progress" column="progress"/> |
|||
<result property="deleteFlag" column="delete_flag"/> |
|||
<!-- 使用collection标签正确映射子任务列表 --> |
|||
<collection property="childrenTasks" |
|||
column="{createBy=create_by, |
|||
tenderDocumentName=tender_document_name, |
|||
bidDocumentName=bid_document_name, |
|||
groupDate=group_create_time}" |
|||
select="selectChildTasks"/> |
|||
</resultMap> |
|||
|
|||
<!-- 父级查询 --> |
|||
<select id="selectTenderTaskGroups" resultMap="TenderTaskGroupResult"> |
|||
SELECT |
|||
UUID() as group_id, |
|||
create_by, |
|||
tender_document_name, |
|||
bid_document_name, |
|||
create_time as group_create_time, |
|||
delete_flag, |
|||
CASE |
|||
WHEN (SUM(CASE WHEN progress_status IN ('SUCCESS', 'FAILURE') THEN 1 ELSE 0 END) * 100.0) / COUNT(*) = 100 |
|||
THEN |
|||
CASE |
|||
WHEN SUM(CASE WHEN progress_status = 'FAILURE' THEN 1 ELSE 0 END) > 0 |
|||
THEN CONCAT( |
|||
'100%(', |
|||
COUNT(*), |
|||
'/', |
|||
COUNT(*), |
|||
',失败:', |
|||
SUM(CASE WHEN progress_status = 'FAILURE' THEN 1 ELSE 0 END), |
|||
')' |
|||
) |
|||
ELSE CONCAT('100%(', COUNT(*), '/', COUNT(*), ')') |
|||
END |
|||
ELSE |
|||
CONCAT( |
|||
FLOOR((SUM(CASE WHEN progress_status IN ('SUCCESS', 'FAILURE') THEN 1 ELSE 0 END) * 100.0) / COUNT(*)), |
|||
'%(', |
|||
SUM(CASE WHEN progress_status IN ('SUCCESS', 'FAILURE') THEN 1 ELSE 0 END), |
|||
'/', |
|||
COUNT(*), |
|||
')' |
|||
) |
|||
END as progress |
|||
FROM tender_tasks |
|||
${ew.getCustomSqlSegment} |
|||
</select> |
|||
|
|||
<!-- 子任务查询 --> |
|||
<select id="selectChildTasks" resultType="org.dromara.productManagement.domain.TenderTaskChild"> |
|||
SELECT |
|||
id, |
|||
task_name, |
|||
tender_document_name, |
|||
bid_document_name, |
|||
progress_status, |
|||
group_id, |
|||
task_id, |
|||
result_type, |
|||
tender_doc_oss_id, |
|||
bid_doc_zip_oss_id, |
|||
version, |
|||
create_time, |
|||
update_time, |
|||
CASE |
|||
WHEN update_time IS NOT NULL THEN |
|||
CASE |
|||
WHEN TIMESTAMPDIFF(HOUR, create_time, update_time) >= 1 THEN |
|||
CONCAT( |
|||
FLOOR(TIMESTAMPDIFF(MINUTE, create_time, update_time) / 60), |
|||
'小时', |
|||
MOD(TIMESTAMPDIFF(MINUTE, create_time, update_time), 60), |
|||
'分钟' |
|||
) |
|||
ELSE |
|||
CONCAT( |
|||
TIMESTAMPDIFF(MINUTE, create_time, update_time), |
|||
'分钟' |
|||
) |
|||
END |
|||
ELSE NULL |
|||
END as task_duration |
|||
FROM tender_tasks |
|||
WHERE del_flag = '0' |
|||
AND create_by = #{createBy} |
|||
AND tender_document_name = #{tenderDocumentName} |
|||
AND bid_document_name = #{bidDocumentName} |
|||
AND create_time = #{groupDate} |
|||
ORDER BY create_time DESC |
|||
</select> |
|||
|
|||
<resultMap type="org.dromara.productManagement.domain.vo.TenderTaskResultVO$ResultItem" id="TenderTaskResult"> |
|||
<result property="id" column="id"/> |
|||
<result property="serialNumber" column="serial_number"/> |
|||
<result property="issueName" column="issue_name"/> |
|||
<result property="originalText" column="original_text"/> |
|||
<result property="comparedText" column="compared_text"/> |
|||
<result property="modifiedContent" column="modified_content"/> |
|||
<result property="modificationDisplay" column="modification_display"/> |
|||
<result property="existingIssues" column="existing_issues"/> |
|||
<result property="reviewBasis" column="review_basis"/> |
|||
<result property="isRead" column="is_read"/> |
|||
<result property="isAdopted" column="is_adopted"/> |
|||
<!-- 审查依据现在直接存储为JSON字符串 --> |
|||
</resultMap> |
|||
|
|||
<resultMap id="tenderResultVOMap" type="org.dromara.productManagement.domain.vo.TenderTaskResultVO"> |
|||
<result property="name" column="category_name"/> |
|||
<collection property="results" javaType="java.util.ArrayList" ofType="org.dromara.productManagement.domain.vo.TenderTaskResultVO$ResultItem" |
|||
column="category_id" select="getTenderResultItemsByCategoryId"/> |
|||
</resultMap> |
|||
|
|||
<select id="getResultsByTaskId" resultMap="tenderResultVOMap"> |
|||
SELECT id as category_id, category_name |
|||
FROM tender_task_categories |
|||
WHERE tender_task_id = #{taskId} |
|||
</select> |
|||
|
|||
<select id="getTenderResultItemsByCategoryId" resultMap="TenderTaskResult"> |
|||
SELECT id, issue_name, original_text, compared_text, modified_content, |
|||
modification_display, existing_issues, review_basis, is_read, is_adopted,sort_order |
|||
FROM tender_task_result_details |
|||
WHERE category_id = #{category_id} |
|||
order by sort_order asc |
|||
</select> |
|||
</mapper> |
Loading…
Reference in new issue