完善招投标导入测试与文档
This commit is contained in:
@@ -80,7 +80,7 @@
|
|||||||
mvn clean compile
|
mvn clean compile
|
||||||
|
|
||||||
# 启动主应用(Jar)
|
# 启动主应用(Jar)
|
||||||
cd ruoyi-admin/target && java -jar ruoyi-admin.jar
|
sh bin/restart_java_backend.sh
|
||||||
|
|
||||||
# 打包全部模块
|
# 打包全部模块
|
||||||
mvn clean package
|
mvn clean package
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ follow_logs() {
|
|||||||
start_action() {
|
start_action() {
|
||||||
running_pids=$(collect_pids)
|
running_pids=$(collect_pids)
|
||||||
if [ -n "${running_pids:-}" ]; then
|
if [ -n "${running_pids:-}" ]; then
|
||||||
log_error "检测到已有后端进程在运行: $running_pids,请先执行 stop 或 restart"
|
log_error "检测到已有后端进程在运行: ${running_pids},请先执行 stop 或 restart"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionAddDTO;
|
|||||||
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionEditDTO;
|
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionEditDTO;
|
||||||
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionQueryDTO;
|
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionQueryDTO;
|
||||||
import com.ruoyi.info.collection.domain.excel.CcdiPurchaseTransactionExcel;
|
import com.ruoyi.info.collection.domain.excel.CcdiPurchaseTransactionExcel;
|
||||||
|
import com.ruoyi.info.collection.domain.excel.CcdiPurchaseTransactionSupplierExcel;
|
||||||
import com.ruoyi.info.collection.domain.vo.CcdiPurchaseTransactionVO;
|
import com.ruoyi.info.collection.domain.vo.CcdiPurchaseTransactionVO;
|
||||||
import com.ruoyi.info.collection.domain.vo.ImportResultVO;
|
import com.ruoyi.info.collection.domain.vo.ImportResultVO;
|
||||||
import com.ruoyi.info.collection.domain.vo.ImportStatusVO;
|
import com.ruoyi.info.collection.domain.vo.ImportStatusVO;
|
||||||
@@ -33,12 +34,12 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 采购交易信息Controller
|
* 招投标信息维护Controller
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
* @date 2026-02-06
|
* @date 2026-02-06
|
||||||
*/
|
*/
|
||||||
@Tag(name = "采购交易信息管理")
|
@Tag(name = "招投标信息维护")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/ccdi/purchaseTransaction")
|
@RequestMapping("/ccdi/purchaseTransaction")
|
||||||
public class CcdiPurchaseTransactionController extends BaseController {
|
public class CcdiPurchaseTransactionController extends BaseController {
|
||||||
@@ -50,9 +51,9 @@ public class CcdiPurchaseTransactionController extends BaseController {
|
|||||||
private ICcdiPurchaseTransactionImportService transactionImportService;
|
private ICcdiPurchaseTransactionImportService transactionImportService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询采购交易列表
|
* 查询招投标信息列表
|
||||||
*/
|
*/
|
||||||
@Operation(summary = "查询采购交易列表")
|
@Operation(summary = "查询招投标信息列表")
|
||||||
@PreAuthorize("@ss.hasPermi('ccdi:purchaseTransaction:list')")
|
@PreAuthorize("@ss.hasPermi('ccdi:purchaseTransaction:list')")
|
||||||
@GetMapping("/list")
|
@GetMapping("/list")
|
||||||
public TableDataInfo list(CcdiPurchaseTransactionQueryDTO queryDTO) {
|
public TableDataInfo list(CcdiPurchaseTransactionQueryDTO queryDTO) {
|
||||||
@@ -64,9 +65,9 @@ public class CcdiPurchaseTransactionController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取采购交易详细信息
|
* 获取招投标信息详细信息
|
||||||
*/
|
*/
|
||||||
@Operation(summary = "获取采购交易详细信息")
|
@Operation(summary = "获取招投标信息详细信息")
|
||||||
@Parameter(name = "purchaseId", description = "采购事项ID", required = true)
|
@Parameter(name = "purchaseId", description = "采购事项ID", required = true)
|
||||||
@PreAuthorize("@ss.hasPermi('ccdi:purchaseTransaction:query')")
|
@PreAuthorize("@ss.hasPermi('ccdi:purchaseTransaction:query')")
|
||||||
@GetMapping(value = "/{purchaseId}")
|
@GetMapping(value = "/{purchaseId}")
|
||||||
@@ -75,66 +76,81 @@ public class CcdiPurchaseTransactionController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增采购交易
|
* 新增招投标信息
|
||||||
*/
|
*/
|
||||||
@Operation(summary = "新增采购交易")
|
@Operation(summary = "新增招投标信息")
|
||||||
@PreAuthorize("@ss.hasPermi('ccdi:purchaseTransaction:add')")
|
@PreAuthorize("@ss.hasPermi('ccdi:purchaseTransaction:add')")
|
||||||
@Log(title = "采购交易信息", businessType = BusinessType.INSERT)
|
@Log(title = "招投标信息维护", businessType = BusinessType.INSERT)
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public AjaxResult add(@Validated @RequestBody CcdiPurchaseTransactionAddDTO addDTO) {
|
public AjaxResult add(@Validated @RequestBody CcdiPurchaseTransactionAddDTO addDTO) {
|
||||||
return toAjax(transactionService.insertTransaction(addDTO));
|
return toAjax(transactionService.insertTransaction(addDTO));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改采购交易
|
* 修改招投标信息
|
||||||
*/
|
*/
|
||||||
@Operation(summary = "修改采购交易")
|
@Operation(summary = "修改招投标信息")
|
||||||
@PreAuthorize("@ss.hasPermi('ccdi:purchaseTransaction:edit')")
|
@PreAuthorize("@ss.hasPermi('ccdi:purchaseTransaction:edit')")
|
||||||
@Log(title = "采购交易信息", businessType = BusinessType.UPDATE)
|
@Log(title = "招投标信息维护", businessType = BusinessType.UPDATE)
|
||||||
@PutMapping
|
@PutMapping
|
||||||
public AjaxResult edit(@Validated @RequestBody CcdiPurchaseTransactionEditDTO editDTO) {
|
public AjaxResult edit(@Validated @RequestBody CcdiPurchaseTransactionEditDTO editDTO) {
|
||||||
return toAjax(transactionService.updateTransaction(editDTO));
|
return toAjax(transactionService.updateTransaction(editDTO));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除采购交易
|
* 删除招投标信息
|
||||||
*/
|
*/
|
||||||
@Operation(summary = "删除采购交易")
|
@Operation(summary = "删除招投标信息")
|
||||||
@Parameter(name = "purchaseIds", description = "采购事项ID数组", required = true)
|
@Parameter(name = "purchaseIds", description = "采购事项ID数组", required = true)
|
||||||
@PreAuthorize("@ss.hasPermi('ccdi:purchaseTransaction:remove')")
|
@PreAuthorize("@ss.hasPermi('ccdi:purchaseTransaction:remove')")
|
||||||
@Log(title = "采购交易信息", businessType = BusinessType.DELETE)
|
@Log(title = "招投标信息维护", businessType = BusinessType.DELETE)
|
||||||
@DeleteMapping("/{purchaseIds}")
|
@DeleteMapping("/{purchaseIds}")
|
||||||
public AjaxResult remove(@PathVariable String[] purchaseIds) {
|
public AjaxResult remove(@PathVariable String[] purchaseIds) {
|
||||||
return toAjax(transactionService.deleteTransactionByIds(purchaseIds));
|
return toAjax(transactionService.deleteTransactionByIds(purchaseIds));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 下载带字典下拉框的导入模板
|
* 下载双Sheet导入模板
|
||||||
* 使用@DictDropdown注解自动添加下拉框
|
|
||||||
*/
|
*/
|
||||||
@Operation(summary = "下载导入模板")
|
@Operation(summary = "下载导入模板")
|
||||||
@PostMapping("/importTemplate")
|
@PostMapping("/importTemplate")
|
||||||
public void importTemplate(HttpServletResponse response) {
|
public void importTemplate(HttpServletResponse response) {
|
||||||
EasyExcelUtil.importTemplateWithDictDropdown(response, CcdiPurchaseTransactionExcel.class, "采购交易信息");
|
EasyExcelUtil.importTemplateWithDictDropdown(
|
||||||
|
response,
|
||||||
|
CcdiPurchaseTransactionExcel.class,
|
||||||
|
"招投标主信息",
|
||||||
|
CcdiPurchaseTransactionSupplierExcel.class,
|
||||||
|
"供应商明细",
|
||||||
|
"招投标信息维护导入模板"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 异步导入采购交易
|
* 异步导入招投标信息
|
||||||
*/
|
*/
|
||||||
@Operation(summary = "异步导入采购交易")
|
@Operation(summary = "异步导入招投标信息")
|
||||||
@Parameter(name = "file", description = "导入文件", required = true)
|
@Parameter(name = "file", description = "导入文件", required = true)
|
||||||
@PreAuthorize("@ss.hasPermi('ccdi:purchaseTransaction:import')")
|
@PreAuthorize("@ss.hasPermi('ccdi:purchaseTransaction:import')")
|
||||||
@Log(title = "采购交易信息", businessType = BusinessType.IMPORT)
|
@Log(title = "招投标信息维护", businessType = BusinessType.IMPORT)
|
||||||
@PostMapping("/importData")
|
@PostMapping("/importData")
|
||||||
public AjaxResult importData(@Parameter(description = "导入文件") MultipartFile file) throws Exception {
|
public AjaxResult importData(@Parameter(description = "导入文件") MultipartFile file) throws Exception {
|
||||||
List<CcdiPurchaseTransactionExcel> list = EasyExcelUtil.importExcel(file.getInputStream(), CcdiPurchaseTransactionExcel.class);
|
List<CcdiPurchaseTransactionExcel> mainList = EasyExcelUtil.importExcel(
|
||||||
|
file.getInputStream(),
|
||||||
|
CcdiPurchaseTransactionExcel.class,
|
||||||
|
"招投标主信息"
|
||||||
|
);
|
||||||
|
List<CcdiPurchaseTransactionSupplierExcel> supplierList = EasyExcelUtil.importExcel(
|
||||||
|
file.getInputStream(),
|
||||||
|
CcdiPurchaseTransactionSupplierExcel.class,
|
||||||
|
"供应商明细"
|
||||||
|
);
|
||||||
|
|
||||||
if (list == null || list.isEmpty()) {
|
if ((mainList == null || mainList.isEmpty()) && (supplierList == null || supplierList.isEmpty())) {
|
||||||
return error("至少需要一条数据");
|
return error("至少需要一条数据");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提交异步任务
|
// 提交异步任务
|
||||||
String taskId = transactionService.importTransaction(list);
|
String taskId = transactionService.importTransaction(mainList, supplierList);
|
||||||
|
|
||||||
// 立即返回,不等待后台任务完成
|
// 立即返回,不等待后台任务完成
|
||||||
ImportResultVO result = new ImportResultVO();
|
ImportResultVO result = new ImportResultVO();
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package com.ruoyi.info.collection.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 招投标供应商明细对象 ccdi_purchase_transaction_supplier
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CcdiPurchaseTransactionSupplier implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/** 采购事项ID */
|
||||||
|
private String purchaseId;
|
||||||
|
|
||||||
|
/** 供应商名称 */
|
||||||
|
private String supplierName;
|
||||||
|
|
||||||
|
/** 供应商统一信用代码 */
|
||||||
|
private String supplierUscc;
|
||||||
|
|
||||||
|
/** 供应商联系人 */
|
||||||
|
private String contactPerson;
|
||||||
|
|
||||||
|
/** 供应商联系电话 */
|
||||||
|
private String contactPhone;
|
||||||
|
|
||||||
|
/** 供应商银行账户 */
|
||||||
|
private String supplierBankAccount;
|
||||||
|
|
||||||
|
/** 是否中标:1-是,0-否 */
|
||||||
|
private Integer isBidWinner;
|
||||||
|
|
||||||
|
/** 排序 */
|
||||||
|
private Integer sortOrder;
|
||||||
|
|
||||||
|
/** 创建时间 */
|
||||||
|
@TableField(fill = FieldFill.INSERT)
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
/** 更新时间 */
|
||||||
|
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||||
|
private Date updateTime;
|
||||||
|
|
||||||
|
/** 创建人 */
|
||||||
|
@TableField(fill = FieldFill.INSERT)
|
||||||
|
private String createdBy;
|
||||||
|
|
||||||
|
/** 更新人 */
|
||||||
|
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||||
|
private String updatedBy;
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package com.ruoyi.info.collection.domain.dto;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.*;
|
import jakarta.validation.constraints.*;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@@ -9,15 +10,16 @@ import java.io.Serial;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 采购交易信息新增DTO
|
* 招投标信息新增DTO
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
* @date 2026-02-06
|
* @date 2026-02-06
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@Schema(description = "采购交易信息新增")
|
@Schema(description = "招投标信息新增")
|
||||||
public class CcdiPurchaseTransactionAddDTO implements Serializable {
|
public class CcdiPurchaseTransactionAddDTO implements Serializable {
|
||||||
|
|
||||||
@Serial
|
@Serial
|
||||||
@@ -88,30 +90,10 @@ public class CcdiPurchaseTransactionAddDTO implements Serializable {
|
|||||||
@Schema(description = "采购方式")
|
@Schema(description = "采购方式")
|
||||||
private String purchaseMethod;
|
private String purchaseMethod;
|
||||||
|
|
||||||
/** 中标供应商名称 */
|
/** 供应商明细 */
|
||||||
@Size(max = 200, message = "中标供应商名称长度不能超过200个字符")
|
@Valid
|
||||||
@Schema(description = "中标供应商名称")
|
@Schema(description = "供应商明细列表")
|
||||||
private String supplierName;
|
private List<CcdiPurchaseTransactionSupplierDTO> supplierList;
|
||||||
|
|
||||||
/** 供应商联系人 */
|
|
||||||
@Size(max = 50, message = "供应商联系人长度不能超过50个字符")
|
|
||||||
@Schema(description = "供应商联系人")
|
|
||||||
private String contactPerson;
|
|
||||||
|
|
||||||
/** 供应商联系电话 */
|
|
||||||
@Pattern(regexp = "^1[3-9]\\d{9}$|^0\\d{2,3}-?\\d{7,8}$", message = "供应商联系电话格式不正确")
|
|
||||||
@Schema(description = "供应商联系电话")
|
|
||||||
private String contactPhone;
|
|
||||||
|
|
||||||
/** 供应商统一信用代码 */
|
|
||||||
@Pattern(regexp = "^[0-9A-HJ-NPQRTUWXY]{2}\\d{6}[0-9A-HJ-NPQRTUWXY]{10}$", message = "供应商统一信用代码格式不正确")
|
|
||||||
@Schema(description = "供应商统一信用代码")
|
|
||||||
private String supplierUscc;
|
|
||||||
|
|
||||||
/** 供应商银行账户 */
|
|
||||||
@Size(max = 50, message = "供应商银行账户长度不能超过50个字符")
|
|
||||||
@Schema(description = "供应商银行账户")
|
|
||||||
private String supplierBankAccount;
|
|
||||||
|
|
||||||
/** 采购申请日期(或立项日期) */
|
/** 采购申请日期(或立项日期) */
|
||||||
@NotNull(message = "采购申请日期不能为空")
|
@NotNull(message = "采购申请日期不能为空")
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.ruoyi.info.collection.domain.dto;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.*;
|
import jakarta.validation.constraints.*;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@@ -9,15 +10,16 @@ import java.io.Serial;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 采购交易信息编辑DTO
|
* 招投标信息编辑DTO
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
* @date 2026-02-06
|
* @date 2026-02-06
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@Schema(description = "采购交易信息编辑")
|
@Schema(description = "招投标信息编辑")
|
||||||
public class CcdiPurchaseTransactionEditDTO implements Serializable {
|
public class CcdiPurchaseTransactionEditDTO implements Serializable {
|
||||||
|
|
||||||
@Serial
|
@Serial
|
||||||
@@ -88,30 +90,10 @@ public class CcdiPurchaseTransactionEditDTO implements Serializable {
|
|||||||
@Schema(description = "采购方式")
|
@Schema(description = "采购方式")
|
||||||
private String purchaseMethod;
|
private String purchaseMethod;
|
||||||
|
|
||||||
/** 中标供应商名称 */
|
/** 供应商明细 */
|
||||||
@Size(max = 200, message = "中标供应商名称长度不能超过200个字符")
|
@Valid
|
||||||
@Schema(description = "中标供应商名称")
|
@Schema(description = "供应商明细列表")
|
||||||
private String supplierName;
|
private List<CcdiPurchaseTransactionSupplierDTO> supplierList;
|
||||||
|
|
||||||
/** 供应商联系人 */
|
|
||||||
@Size(max = 50, message = "供应商联系人长度不能超过50个字符")
|
|
||||||
@Schema(description = "供应商联系人")
|
|
||||||
private String contactPerson;
|
|
||||||
|
|
||||||
/** 供应商联系电话 */
|
|
||||||
@Pattern(regexp = "^1[3-9]\\d{9}$|^0\\d{2,3}-?\\d{7,8}$", message = "供应商联系电话格式不正确")
|
|
||||||
@Schema(description = "供应商联系电话")
|
|
||||||
private String contactPhone;
|
|
||||||
|
|
||||||
/** 供应商统一信用代码 */
|
|
||||||
@Pattern(regexp = "^[0-9A-HJ-NPQRTUWXY]{2}\\d{6}[0-9A-HJ-NPQRTUWXY]{10}$", message = "供应商统一信用代码格式不正确")
|
|
||||||
@Schema(description = "供应商统一信用代码")
|
|
||||||
private String supplierUscc;
|
|
||||||
|
|
||||||
/** 供应商银行账户 */
|
|
||||||
@Size(max = 50, message = "供应商银行账户长度不能超过50个字符")
|
|
||||||
@Schema(description = "供应商银行账户")
|
|
||||||
private String supplierBankAccount;
|
|
||||||
|
|
||||||
/** 采购申请日期(或立项日期) */
|
/** 采购申请日期(或立项日期) */
|
||||||
@NotNull(message = "采购申请日期不能为空")
|
@NotNull(message = "采购申请日期不能为空")
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ import java.io.Serializable;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 采购交易信息查询DTO
|
* 招投标信息查询DTO
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
* @date 2026-02-06
|
* @date 2026-02-06
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@Schema(description = "采购交易信息查询条件")
|
@Schema(description = "招投标信息查询条件")
|
||||||
public class CcdiPurchaseTransactionQueryDTO implements Serializable {
|
public class CcdiPurchaseTransactionQueryDTO implements Serializable {
|
||||||
|
|
||||||
@Serial
|
@Serial
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package com.ruoyi.info.collection.domain.dto;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.Pattern;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 招投标供应商明细DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "招投标供应商明细")
|
||||||
|
public class CcdiPurchaseTransactionSupplierDTO implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@NotBlank(message = "供应商名称不能为空")
|
||||||
|
@Size(max = 200, message = "供应商名称长度不能超过200个字符")
|
||||||
|
@Schema(description = "供应商名称")
|
||||||
|
private String supplierName;
|
||||||
|
|
||||||
|
@Pattern(
|
||||||
|
regexp = "^$|^[0-9A-HJ-NPQRTUWXY]{2}\\d{6}[0-9A-HJ-NPQRTUWXY]{10}$",
|
||||||
|
message = "供应商统一信用代码格式不正确"
|
||||||
|
)
|
||||||
|
@Schema(description = "供应商统一信用代码")
|
||||||
|
private String supplierUscc;
|
||||||
|
|
||||||
|
@Size(max = 50, message = "供应商联系人长度不能超过50个字符")
|
||||||
|
@Schema(description = "供应商联系人")
|
||||||
|
private String contactPerson;
|
||||||
|
|
||||||
|
@Pattern(
|
||||||
|
regexp = "^$|^1[3-9]\\d{9}$|^0\\d{2,3}-?\\d{7,8}$",
|
||||||
|
message = "供应商联系电话格式不正确"
|
||||||
|
)
|
||||||
|
@Schema(description = "供应商联系电话")
|
||||||
|
private String contactPhone;
|
||||||
|
|
||||||
|
@Size(max = 50, message = "供应商银行账户长度不能超过50个字符")
|
||||||
|
@Schema(description = "供应商银行账户")
|
||||||
|
private String supplierBankAccount;
|
||||||
|
|
||||||
|
@Schema(description = "是否中标:1-是,0-否")
|
||||||
|
private Integer isBidWinner;
|
||||||
|
|
||||||
|
@Schema(description = "排序")
|
||||||
|
private Integer sortOrder;
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ import java.math.BigDecimal;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 采购交易信息Excel导入导出对象
|
* 招投标主信息Excel导入导出对象
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
* @date 2026-02-06
|
* @date 2026-02-06
|
||||||
@@ -88,107 +88,82 @@ public class CcdiPurchaseTransactionExcel implements Serializable {
|
|||||||
@Required
|
@Required
|
||||||
private String purchaseMethod;
|
private String purchaseMethod;
|
||||||
|
|
||||||
/** 中标供应商名称 */
|
|
||||||
@ExcelProperty(value = "中标供应商名称", index = 12)
|
|
||||||
@ColumnWidth(25)
|
|
||||||
private String supplierName;
|
|
||||||
|
|
||||||
/** 供应商联系人 */
|
|
||||||
@ExcelProperty(value = "供应商联系人", index = 13)
|
|
||||||
@ColumnWidth(15)
|
|
||||||
private String contactPerson;
|
|
||||||
|
|
||||||
/** 供应商联系电话 */
|
|
||||||
@ExcelProperty(value = "供应商联系电话", index = 14)
|
|
||||||
@ColumnWidth(18)
|
|
||||||
private String contactPhone;
|
|
||||||
|
|
||||||
/** 供应商统一信用代码 */
|
|
||||||
@ExcelProperty(value = "供应商统一信用代码", index = 15)
|
|
||||||
@ColumnWidth(25)
|
|
||||||
private String supplierUscc;
|
|
||||||
|
|
||||||
/** 供应商银行账户 */
|
|
||||||
@ExcelProperty(value = "供应商银行账户", index = 16)
|
|
||||||
@ColumnWidth(20)
|
|
||||||
private String supplierBankAccount;
|
|
||||||
|
|
||||||
/** 采购申请日期(或立项日期) */
|
/** 采购申请日期(或立项日期) */
|
||||||
@ExcelProperty(value = "采购申请日期", index = 17)
|
@ExcelProperty(value = "采购申请日期", index = 12)
|
||||||
@ColumnWidth(18)
|
@ColumnWidth(18)
|
||||||
@Required
|
@Required
|
||||||
private Date applyDate;
|
private Date applyDate;
|
||||||
|
|
||||||
/** 采购计划批准日期 */
|
/** 采购计划批准日期 */
|
||||||
@ExcelProperty(value = "采购计划批准日期", index = 18)
|
@ExcelProperty(value = "采购计划批准日期", index = 13)
|
||||||
@ColumnWidth(18)
|
@ColumnWidth(18)
|
||||||
private Date planApproveDate;
|
private Date planApproveDate;
|
||||||
|
|
||||||
/** 采购公告发布日期 */
|
/** 采购公告发布日期 */
|
||||||
@ExcelProperty(value = "采购公告发布日期", index = 19)
|
@ExcelProperty(value = "采购公告发布日期", index = 14)
|
||||||
@ColumnWidth(18)
|
@ColumnWidth(18)
|
||||||
private Date announceDate;
|
private Date announceDate;
|
||||||
|
|
||||||
/** 开标日期 */
|
/** 开标日期 */
|
||||||
@ExcelProperty(value = "开标日期", index = 20)
|
@ExcelProperty(value = "开标日期", index = 15)
|
||||||
@ColumnWidth(18)
|
@ColumnWidth(18)
|
||||||
private Date bidOpenDate;
|
private Date bidOpenDate;
|
||||||
|
|
||||||
/** 合同签订日期 */
|
/** 合同签订日期 */
|
||||||
@ExcelProperty(value = "合同签订日期", index = 21)
|
@ExcelProperty(value = "合同签订日期", index = 16)
|
||||||
@ColumnWidth(18)
|
@ColumnWidth(18)
|
||||||
private Date contractSignDate;
|
private Date contractSignDate;
|
||||||
|
|
||||||
/** 预计交货日期 */
|
/** 预计交货日期 */
|
||||||
@ExcelProperty(value = "预计交货日期", index = 22)
|
@ExcelProperty(value = "预计交货日期", index = 17)
|
||||||
@ColumnWidth(18)
|
@ColumnWidth(18)
|
||||||
private Date expectedDeliveryDate;
|
private Date expectedDeliveryDate;
|
||||||
|
|
||||||
/** 实际交货日期 */
|
/** 实际交货日期 */
|
||||||
@ExcelProperty(value = "实际交货日期", index = 23)
|
@ExcelProperty(value = "实际交货日期", index = 18)
|
||||||
@ColumnWidth(18)
|
@ColumnWidth(18)
|
||||||
private Date actualDeliveryDate;
|
private Date actualDeliveryDate;
|
||||||
|
|
||||||
/** 验收日期 */
|
/** 验收日期 */
|
||||||
@ExcelProperty(value = "验收日期", index = 24)
|
@ExcelProperty(value = "验收日期", index = 19)
|
||||||
@ColumnWidth(18)
|
@ColumnWidth(18)
|
||||||
private Date acceptanceDate;
|
private Date acceptanceDate;
|
||||||
|
|
||||||
/** 结算日期 */
|
/** 结算日期 */
|
||||||
@ExcelProperty(value = "结算日期", index = 25)
|
@ExcelProperty(value = "结算日期", index = 20)
|
||||||
@ColumnWidth(18)
|
@ColumnWidth(18)
|
||||||
private Date settlementDate;
|
private Date settlementDate;
|
||||||
|
|
||||||
/** 申请人工号 */
|
/** 申请人工号 */
|
||||||
@ExcelProperty(value = "申请人工号", index = 26)
|
@ExcelProperty(value = "申请人工号", index = 21)
|
||||||
@ColumnWidth(15)
|
@ColumnWidth(15)
|
||||||
@Required
|
@Required
|
||||||
private String applicantId;
|
private String applicantId;
|
||||||
|
|
||||||
/** 申请人姓名 */
|
/** 申请人姓名 */
|
||||||
@ExcelProperty(value = "申请人姓名", index = 27)
|
@ExcelProperty(value = "申请人姓名", index = 22)
|
||||||
@ColumnWidth(15)
|
@ColumnWidth(15)
|
||||||
@Required
|
@Required
|
||||||
private String applicantName;
|
private String applicantName;
|
||||||
|
|
||||||
/** 申请部门 */
|
/** 申请部门 */
|
||||||
@ExcelProperty(value = "申请部门", index = 28)
|
@ExcelProperty(value = "申请部门", index = 23)
|
||||||
@ColumnWidth(18)
|
@ColumnWidth(18)
|
||||||
@Required
|
@Required
|
||||||
private String applyDepartment;
|
private String applyDepartment;
|
||||||
|
|
||||||
/** 采购负责人工号 */
|
/** 采购负责人工号 */
|
||||||
@ExcelProperty(value = "采购负责人工号", index = 29)
|
@ExcelProperty(value = "采购负责人工号", index = 24)
|
||||||
@ColumnWidth(15)
|
@ColumnWidth(15)
|
||||||
private String purchaseLeaderId;
|
private String purchaseLeaderId;
|
||||||
|
|
||||||
/** 采购负责人姓名 */
|
/** 采购负责人姓名 */
|
||||||
@ExcelProperty(value = "采购负责人姓名", index = 30)
|
@ExcelProperty(value = "采购负责人姓名", index = 25)
|
||||||
@ColumnWidth(15)
|
@ColumnWidth(15)
|
||||||
private String purchaseLeaderName;
|
private String purchaseLeaderName;
|
||||||
|
|
||||||
/** 采购部门 */
|
/** 采购部门 */
|
||||||
@ExcelProperty(value = "采购部门", index = 31)
|
@ExcelProperty(value = "采购部门", index = 26)
|
||||||
@ColumnWidth(18)
|
@ColumnWidth(18)
|
||||||
private String purchaseDepartment;
|
private String purchaseDepartment;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package com.ruoyi.info.collection.domain.excel;
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import com.alibaba.excel.annotation.write.style.ColumnWidth;
|
||||||
|
import com.ruoyi.common.annotation.DictDropdown;
|
||||||
|
import com.ruoyi.common.annotation.Required;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 招投标供应商明细Excel对象
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CcdiPurchaseTransactionSupplierExcel implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "采购事项ID", index = 0)
|
||||||
|
@ColumnWidth(20)
|
||||||
|
@Required
|
||||||
|
private String purchaseId;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "供应商名称", index = 1)
|
||||||
|
@ColumnWidth(25)
|
||||||
|
@Required
|
||||||
|
private String supplierName;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "供应商统一信用代码", index = 2)
|
||||||
|
@ColumnWidth(25)
|
||||||
|
private String supplierUscc;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "供应商联系人", index = 3)
|
||||||
|
@ColumnWidth(15)
|
||||||
|
private String contactPerson;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "供应商联系电话", index = 4)
|
||||||
|
@ColumnWidth(18)
|
||||||
|
private String contactPhone;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "供应商银行账户", index = 5)
|
||||||
|
@ColumnWidth(20)
|
||||||
|
private String supplierBankAccount;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "是否中标", index = 6)
|
||||||
|
@ColumnWidth(12)
|
||||||
|
@DictDropdown(dictType = "ccdi_yes_no_flag")
|
||||||
|
private String isBidWinner;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "排序", index = 7)
|
||||||
|
@ColumnWidth(10)
|
||||||
|
private Integer sortOrder;
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.ruoyi.info.collection.domain.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 招投标供应商明细VO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "招投标供应商明细")
|
||||||
|
public class CcdiPurchaseTransactionSupplierVO implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "主键ID")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "采购事项ID")
|
||||||
|
private String purchaseId;
|
||||||
|
|
||||||
|
@Schema(description = "供应商名称")
|
||||||
|
private String supplierName;
|
||||||
|
|
||||||
|
@Schema(description = "供应商统一信用代码")
|
||||||
|
private String supplierUscc;
|
||||||
|
|
||||||
|
@Schema(description = "供应商联系人")
|
||||||
|
private String contactPerson;
|
||||||
|
|
||||||
|
@Schema(description = "供应商联系电话")
|
||||||
|
private String contactPhone;
|
||||||
|
|
||||||
|
@Schema(description = "供应商银行账户")
|
||||||
|
private String supplierBankAccount;
|
||||||
|
|
||||||
|
@Schema(description = "是否中标:1-是,0-否")
|
||||||
|
private Integer isBidWinner;
|
||||||
|
|
||||||
|
@Schema(description = "排序")
|
||||||
|
private Integer sortOrder;
|
||||||
|
}
|
||||||
@@ -8,15 +8,16 @@ import java.io.Serial;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 采购交易信息VO
|
* 招投标信息VO
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
* @date 2026-02-06
|
* @date 2026-02-06
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@Schema(description = "采购交易信息")
|
@Schema(description = "招投标信息")
|
||||||
public class CcdiPurchaseTransactionVO implements Serializable {
|
public class CcdiPurchaseTransactionVO implements Serializable {
|
||||||
|
|
||||||
@Serial
|
@Serial
|
||||||
@@ -90,6 +91,14 @@ public class CcdiPurchaseTransactionVO implements Serializable {
|
|||||||
@Schema(description = "供应商银行账户")
|
@Schema(description = "供应商银行账户")
|
||||||
private String supplierBankAccount;
|
private String supplierBankAccount;
|
||||||
|
|
||||||
|
/** 参与供应商数 */
|
||||||
|
@Schema(description = "参与供应商数")
|
||||||
|
private Integer supplierCount;
|
||||||
|
|
||||||
|
/** 供应商明细 */
|
||||||
|
@Schema(description = "供应商明细列表")
|
||||||
|
private List<CcdiPurchaseTransactionSupplierVO> supplierList;
|
||||||
|
|
||||||
/** 采购申请日期(或立项日期) */
|
/** 采购申请日期(或立项日期) */
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
@Schema(description = "采购申请日期")
|
@Schema(description = "采购申请日期")
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ import lombok.Data;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 采购交易信息导入失败记录VO
|
* 招投标信息导入失败记录VO
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
* @date 2026-02-06
|
* @date 2026-02-06
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@Schema(description = "采购交易信息导入失败记录")
|
@Schema(description = "招投标信息导入失败记录")
|
||||||
public class PurchaseTransactionImportFailureVO {
|
public class PurchaseTransactionImportFailureVO {
|
||||||
|
|
||||||
/** 采购事项ID */
|
/** 采购事项ID */
|
||||||
|
|||||||
@@ -35,6 +35,14 @@ public interface CcdiPurchaseTransactionMapper extends BaseMapper<CcdiPurchaseTr
|
|||||||
*/
|
*/
|
||||||
CcdiPurchaseTransactionVO selectTransactionById(@Param("purchaseId") String purchaseId);
|
CcdiPurchaseTransactionVO selectTransactionById(@Param("purchaseId") String purchaseId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除指定采购事项ID对应的供应商明细
|
||||||
|
*
|
||||||
|
* @param purchaseIds 采购事项ID列表
|
||||||
|
* @return 删除行数
|
||||||
|
*/
|
||||||
|
int deleteSuppliersByPurchaseIds(@Param("purchaseIds") List<String> purchaseIds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量插入采购交易数据
|
* 批量插入采购交易数据
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.ruoyi.info.collection.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.ruoyi.info.collection.domain.CcdiPurchaseTransactionSupplier;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 招投标供应商明细Mapper
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface CcdiPurchaseTransactionSupplierMapper extends BaseMapper<CcdiPurchaseTransactionSupplier> {
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.ruoyi.info.collection.service;
|
package com.ruoyi.info.collection.service;
|
||||||
|
|
||||||
import com.ruoyi.info.collection.domain.excel.CcdiPurchaseTransactionExcel;
|
import com.ruoyi.info.collection.domain.excel.CcdiPurchaseTransactionExcel;
|
||||||
|
import com.ruoyi.info.collection.domain.excel.CcdiPurchaseTransactionSupplierExcel;
|
||||||
import com.ruoyi.info.collection.domain.vo.PurchaseTransactionImportFailureVO;
|
import com.ruoyi.info.collection.domain.vo.PurchaseTransactionImportFailureVO;
|
||||||
import com.ruoyi.info.collection.domain.vo.ImportStatusVO;
|
import com.ruoyi.info.collection.domain.vo.ImportStatusVO;
|
||||||
|
|
||||||
@@ -17,11 +18,17 @@ public interface ICcdiPurchaseTransactionImportService {
|
|||||||
/**
|
/**
|
||||||
* 异步导入采购交易数据
|
* 异步导入采购交易数据
|
||||||
*
|
*
|
||||||
* @param excelList Excel数据列表
|
* @param mainExcelList 主信息Excel数据列表
|
||||||
* @param taskId 任务ID
|
* @param supplierExcelList 供应商明细Excel数据列表
|
||||||
* @param userName 当前用户名
|
* @param taskId 任务ID
|
||||||
|
* @param userName 当前用户名
|
||||||
*/
|
*/
|
||||||
void importTransactionAsync(List<CcdiPurchaseTransactionExcel> excelList, String taskId, String userName);
|
void importTransactionAsync(
|
||||||
|
List<CcdiPurchaseTransactionExcel> mainExcelList,
|
||||||
|
List<CcdiPurchaseTransactionSupplierExcel> supplierExcelList,
|
||||||
|
String taskId,
|
||||||
|
String userName
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询导入状态
|
* 查询导入状态
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionAddDTO;
|
|||||||
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionEditDTO;
|
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionEditDTO;
|
||||||
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionQueryDTO;
|
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionQueryDTO;
|
||||||
import com.ruoyi.info.collection.domain.excel.CcdiPurchaseTransactionExcel;
|
import com.ruoyi.info.collection.domain.excel.CcdiPurchaseTransactionExcel;
|
||||||
|
import com.ruoyi.info.collection.domain.excel.CcdiPurchaseTransactionSupplierExcel;
|
||||||
import com.ruoyi.info.collection.domain.vo.CcdiPurchaseTransactionVO;
|
import com.ruoyi.info.collection.domain.vo.CcdiPurchaseTransactionVO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -77,8 +78,12 @@ public interface ICcdiPurchaseTransactionService {
|
|||||||
/**
|
/**
|
||||||
* 导入采购交易数据(异步)
|
* 导入采购交易数据(异步)
|
||||||
*
|
*
|
||||||
* @param excelList Excel实体列表
|
* @param mainExcelList 主信息Excel实体列表
|
||||||
|
* @param supplierExcelList 供应商明细Excel实体列表
|
||||||
* @return 任务ID
|
* @return 任务ID
|
||||||
*/
|
*/
|
||||||
String importTransaction(List<CcdiPurchaseTransactionExcel> excelList);
|
String importTransaction(
|
||||||
|
List<CcdiPurchaseTransactionExcel> mainExcelList,
|
||||||
|
List<CcdiPurchaseTransactionSupplierExcel> supplierExcelList
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,15 @@ package com.ruoyi.info.collection.service.impl;
|
|||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.ruoyi.info.collection.domain.CcdiPurchaseTransaction;
|
import com.ruoyi.info.collection.domain.CcdiPurchaseTransaction;
|
||||||
|
import com.ruoyi.info.collection.domain.CcdiPurchaseTransactionSupplier;
|
||||||
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionAddDTO;
|
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionAddDTO;
|
||||||
import com.ruoyi.info.collection.domain.excel.CcdiPurchaseTransactionExcel;
|
import com.ruoyi.info.collection.domain.excel.CcdiPurchaseTransactionExcel;
|
||||||
|
import com.ruoyi.info.collection.domain.excel.CcdiPurchaseTransactionSupplierExcel;
|
||||||
import com.ruoyi.info.collection.domain.vo.ImportResult;
|
import com.ruoyi.info.collection.domain.vo.ImportResult;
|
||||||
import com.ruoyi.info.collection.domain.vo.ImportStatusVO;
|
import com.ruoyi.info.collection.domain.vo.ImportStatusVO;
|
||||||
import com.ruoyi.info.collection.domain.vo.PurchaseTransactionImportFailureVO;
|
import com.ruoyi.info.collection.domain.vo.PurchaseTransactionImportFailureVO;
|
||||||
import com.ruoyi.info.collection.mapper.CcdiPurchaseTransactionMapper;
|
import com.ruoyi.info.collection.mapper.CcdiPurchaseTransactionMapper;
|
||||||
|
import com.ruoyi.info.collection.mapper.CcdiPurchaseTransactionSupplierMapper;
|
||||||
import com.ruoyi.info.collection.service.ICcdiPurchaseTransactionImportService;
|
import com.ruoyi.info.collection.service.ICcdiPurchaseTransactionImportService;
|
||||||
import com.ruoyi.info.collection.utils.ImportLogUtils;
|
import com.ruoyi.info.collection.utils.ImportLogUtils;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
@@ -41,79 +44,119 @@ public class CcdiPurchaseTransactionImportServiceImpl implements ICcdiPurchaseTr
|
|||||||
@Resource
|
@Resource
|
||||||
private CcdiPurchaseTransactionMapper transactionMapper;
|
private CcdiPurchaseTransactionMapper transactionMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CcdiPurchaseTransactionSupplierMapper supplierMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private RedisTemplate<String, Object> redisTemplate;
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Async
|
@Async
|
||||||
@Transactional
|
@Transactional
|
||||||
public void importTransactionAsync(List<CcdiPurchaseTransactionExcel> excelList, String taskId, String userName) {
|
public void importTransactionAsync(
|
||||||
|
List<CcdiPurchaseTransactionExcel> mainExcelList,
|
||||||
|
List<CcdiPurchaseTransactionSupplierExcel> supplierExcelList,
|
||||||
|
String taskId,
|
||||||
|
String userName
|
||||||
|
) {
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
|
List<CcdiPurchaseTransactionExcel> safeMainList = mainExcelList == null ? List.of() : mainExcelList;
|
||||||
|
List<CcdiPurchaseTransactionSupplierExcel> safeSupplierList = supplierExcelList == null ? List.of() : supplierExcelList;
|
||||||
|
int totalCount = countImportUnits(safeMainList, safeSupplierList);
|
||||||
|
|
||||||
// 记录导入开始
|
// 记录导入开始
|
||||||
ImportLogUtils.logImportStart(log, taskId, "采购交易信息", excelList.size(), userName);
|
ImportLogUtils.logImportStart(log, taskId, "招投标信息维护", totalCount, userName);
|
||||||
|
|
||||||
List<CcdiPurchaseTransaction> newRecords = new ArrayList<>();
|
List<CcdiPurchaseTransaction> newTransactions = new ArrayList<>();
|
||||||
|
List<CcdiPurchaseTransactionSupplier> newSuppliers = new ArrayList<>();
|
||||||
List<PurchaseTransactionImportFailureVO> failures = new ArrayList<>();
|
List<PurchaseTransactionImportFailureVO> failures = new ArrayList<>();
|
||||||
|
|
||||||
// 批量查询已存在的采购事项ID
|
// 批量查询已存在的采购事项ID
|
||||||
ImportLogUtils.logBatchQueryStart(log, taskId, "已存在的采购事项ID", excelList.size());
|
ImportLogUtils.logBatchQueryStart(log, taskId, "已存在的采购事项ID", safeMainList.size());
|
||||||
Set<String> existingIds = getExistingPurchaseIds(excelList);
|
Set<String> existingIds = getExistingPurchaseIds(safeMainList);
|
||||||
ImportLogUtils.logBatchQueryComplete(log, taskId, "采购事项ID", existingIds.size());
|
ImportLogUtils.logBatchQueryComplete(log, taskId, "采购事项ID", existingIds.size());
|
||||||
|
|
||||||
// 用于跟踪Excel文件内已处理的采购事项ID
|
Map<String, List<CcdiPurchaseTransactionExcel>> mainGroupMap = safeMainList.stream()
|
||||||
Set<String> processedIds = new HashSet<>();
|
.filter(item -> StringUtils.isNotEmpty(item.getPurchaseId()))
|
||||||
|
.collect(Collectors.groupingBy(
|
||||||
|
CcdiPurchaseTransactionExcel::getPurchaseId,
|
||||||
|
LinkedHashMap::new,
|
||||||
|
Collectors.toList()
|
||||||
|
));
|
||||||
|
Map<String, List<CcdiPurchaseTransactionSupplierExcel>> supplierGroupMap = safeSupplierList.stream()
|
||||||
|
.filter(item -> StringUtils.isNotEmpty(item.getPurchaseId()))
|
||||||
|
.collect(Collectors.groupingBy(
|
||||||
|
CcdiPurchaseTransactionSupplierExcel::getPurchaseId,
|
||||||
|
LinkedHashMap::new,
|
||||||
|
Collectors.toList()
|
||||||
|
));
|
||||||
|
LinkedHashSet<String> purchaseIds = new LinkedHashSet<>();
|
||||||
|
purchaseIds.addAll(mainGroupMap.keySet());
|
||||||
|
purchaseIds.addAll(supplierGroupMap.keySet());
|
||||||
|
|
||||||
// 分类数据
|
for (CcdiPurchaseTransactionSupplierExcel supplierExcel : safeSupplierList) {
|
||||||
for (int i = 0; i < excelList.size(); i++) {
|
if (StringUtils.isEmpty(supplierExcel.getPurchaseId())) {
|
||||||
CcdiPurchaseTransactionExcel excel = excelList.get(i);
|
failures.add(buildFailure(null, null, "供应商明细Sheet中的采购事项ID不能为空"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
for (String purchaseId : purchaseIds) {
|
||||||
|
index++;
|
||||||
|
List<CcdiPurchaseTransactionExcel> mainRows = mainGroupMap.getOrDefault(purchaseId, List.of());
|
||||||
|
List<CcdiPurchaseTransactionSupplierExcel> supplierRows = supplierGroupMap.getOrDefault(purchaseId, List.of());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 转换为AddDTO进行验证
|
if (existingIds.contains(purchaseId)) {
|
||||||
CcdiPurchaseTransactionAddDTO addDTO = new CcdiPurchaseTransactionAddDTO();
|
throw new RuntimeException(String.format("采购事项ID[%s]已存在,请勿重复导入", purchaseId));
|
||||||
BeanUtils.copyProperties(excel, addDTO);
|
}
|
||||||
|
if (mainRows.isEmpty()) {
|
||||||
// 验证数据
|
throw new RuntimeException(String.format("采购事项ID[%s]缺少招投标主信息", purchaseId));
|
||||||
validateTransactionData(addDTO, existingIds);
|
}
|
||||||
|
if (mainRows.size() > 1) {
|
||||||
CcdiPurchaseTransaction transaction = new CcdiPurchaseTransaction();
|
throw new RuntimeException(String.format("采购事项ID[%s]在招投标主信息Sheet中重复", purchaseId));
|
||||||
BeanUtils.copyProperties(excel, transaction);
|
|
||||||
|
|
||||||
if (existingIds.contains(excel.getPurchaseId())) {
|
|
||||||
// 采购事项ID已存在,直接报错
|
|
||||||
throw new RuntimeException(String.format("采购事项ID[%s]已存在,请勿重复导入", excel.getPurchaseId()));
|
|
||||||
} else if (processedIds.contains(excel.getPurchaseId())) {
|
|
||||||
// Excel文件内部重复
|
|
||||||
throw new RuntimeException(String.format("采购事项ID[%s]在导入文件中重复,已跳过此条记录", excel.getPurchaseId()));
|
|
||||||
} else {
|
|
||||||
transaction.setCreatedBy(userName);
|
|
||||||
transaction.setUpdatedBy(userName);
|
|
||||||
newRecords.add(transaction);
|
|
||||||
processedIds.add(excel.getPurchaseId()); // 标记为已处理
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CcdiPurchaseTransactionExcel mainExcel = mainRows.getFirst();
|
||||||
|
CcdiPurchaseTransactionAddDTO addDTO = new CcdiPurchaseTransactionAddDTO();
|
||||||
|
BeanUtils.copyProperties(mainExcel, addDTO);
|
||||||
|
|
||||||
|
validateTransactionData(addDTO);
|
||||||
|
List<CcdiPurchaseTransactionSupplier> suppliers = buildSupplierEntities(purchaseId, supplierRows, userName);
|
||||||
|
|
||||||
|
CcdiPurchaseTransaction transaction = new CcdiPurchaseTransaction();
|
||||||
|
BeanUtils.copyProperties(mainExcel, transaction);
|
||||||
|
fillWinnerSummary(transaction, suppliers);
|
||||||
|
transaction.setCreatedBy(userName);
|
||||||
|
transaction.setUpdatedBy(userName);
|
||||||
|
newTransactions.add(transaction);
|
||||||
|
newSuppliers.addAll(suppliers);
|
||||||
|
|
||||||
// 记录进度
|
// 记录进度
|
||||||
ImportLogUtils.logProgress(log, taskId, i + 1, excelList.size(),
|
ImportLogUtils.logProgress(log, taskId, index, Math.max(totalCount, purchaseIds.size()),
|
||||||
newRecords.size(), failures.size());
|
newTransactions.size(), failures.size());
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
PurchaseTransactionImportFailureVO failure = new PurchaseTransactionImportFailureVO();
|
CcdiPurchaseTransactionExcel mainExcel = mainRows.isEmpty() ? null : mainRows.getFirst();
|
||||||
BeanUtils.copyProperties(excel, failure);
|
failures.add(buildFailure(mainExcel, purchaseId, e.getMessage()));
|
||||||
failure.setErrorMessage(e.getMessage());
|
|
||||||
failures.add(failure);
|
|
||||||
|
|
||||||
// 记录验证失败日志
|
// 记录验证失败日志
|
||||||
String keyData = String.format("采购事项ID=%s, 采购类别=%s, 标的物=%s",
|
String keyData = String.format("采购事项ID=%s, 采购类别=%s, 标的物=%s",
|
||||||
excel.getPurchaseId(), excel.getPurchaseCategory(), excel.getSubjectName());
|
purchaseId,
|
||||||
ImportLogUtils.logValidationError(log, taskId, i + 1, e.getMessage(), keyData);
|
mainExcel == null ? "" : mainExcel.getPurchaseCategory(),
|
||||||
|
mainExcel == null ? "" : mainExcel.getSubjectName());
|
||||||
|
ImportLogUtils.logValidationError(log, taskId, index, e.getMessage(), keyData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 批量插入新数据
|
// 批量插入新数据
|
||||||
if (!newRecords.isEmpty()) {
|
if (!newTransactions.isEmpty()) {
|
||||||
ImportLogUtils.logBatchOperationStart(log, taskId, "插入",
|
ImportLogUtils.logBatchOperationStart(log, taskId, "插入",
|
||||||
(newRecords.size() + 499) / 500, 500);
|
(newTransactions.size() + 499) / 500, 500);
|
||||||
saveBatch(newRecords, 500);
|
saveBatch(newTransactions, 500);
|
||||||
|
}
|
||||||
|
if (!newSuppliers.isEmpty()) {
|
||||||
|
saveSupplierBatch(newSuppliers, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存失败记录到Redis
|
// 保存失败记录到Redis
|
||||||
@@ -128,8 +171,8 @@ public class CcdiPurchaseTransactionImportServiceImpl implements ICcdiPurchaseTr
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImportResult result = new ImportResult();
|
ImportResult result = new ImportResult();
|
||||||
result.setTotalCount(excelList.size());
|
result.setTotalCount(totalCount);
|
||||||
result.setSuccessCount(newRecords.size());
|
result.setSuccessCount(newTransactions.size());
|
||||||
result.setFailureCount(failures.size());
|
result.setFailureCount(failures.size());
|
||||||
|
|
||||||
// 更新最终状态
|
// 更新最终状态
|
||||||
@@ -138,8 +181,8 @@ public class CcdiPurchaseTransactionImportServiceImpl implements ICcdiPurchaseTr
|
|||||||
|
|
||||||
// 记录导入完成
|
// 记录导入完成
|
||||||
long duration = System.currentTimeMillis() - startTime;
|
long duration = System.currentTimeMillis() - startTime;
|
||||||
ImportLogUtils.logImportComplete(log, taskId, "采购交易信息",
|
ImportLogUtils.logImportComplete(log, taskId, "招投标信息维护",
|
||||||
excelList.size(), result.getSuccessCount(), result.getFailureCount(), duration);
|
totalCount, result.getSuccessCount(), result.getFailureCount(), duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -243,13 +286,22 @@ public class CcdiPurchaseTransactionImportServiceImpl implements ICcdiPurchaseTr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void saveSupplierBatch(List<CcdiPurchaseTransactionSupplier> list, int batchSize) {
|
||||||
|
for (int i = 0; i < list.size(); i += batchSize) {
|
||||||
|
int end = Math.min(i + batchSize, list.size());
|
||||||
|
List<CcdiPurchaseTransactionSupplier> subList = list.subList(i, end);
|
||||||
|
for (CcdiPurchaseTransactionSupplier supplier : subList) {
|
||||||
|
supplierMapper.insert(supplier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证采购交易数据
|
* 验证采购交易数据
|
||||||
*
|
*
|
||||||
* @param addDTO 新增DTO
|
* @param addDTO 新增DTO
|
||||||
* @param existingIds 已存在的采购事项ID集合
|
|
||||||
*/
|
*/
|
||||||
private void validateTransactionData(CcdiPurchaseTransactionAddDTO addDTO, Set<String> existingIds) {
|
private void validateTransactionData(CcdiPurchaseTransactionAddDTO addDTO) {
|
||||||
// 验证必填字段
|
// 验证必填字段
|
||||||
if (StringUtils.isEmpty(addDTO.getPurchaseId())) {
|
if (StringUtils.isEmpty(addDTO.getPurchaseId())) {
|
||||||
throw new RuntimeException("采购事项ID不能为空");
|
throw new RuntimeException("采购事项ID不能为空");
|
||||||
@@ -310,4 +362,161 @@ public class CcdiPurchaseTransactionImportServiceImpl implements ICcdiPurchaseTr
|
|||||||
throw new RuntimeException("结算金额必须大于0");
|
throw new RuntimeException("结算金额必须大于0");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<CcdiPurchaseTransactionSupplier> buildSupplierEntities(
|
||||||
|
String purchaseId,
|
||||||
|
List<CcdiPurchaseTransactionSupplierExcel> supplierRows,
|
||||||
|
String userName
|
||||||
|
) {
|
||||||
|
List<CcdiPurchaseTransactionSupplierExcel> normalizedRows = supplierRows == null
|
||||||
|
? List.of()
|
||||||
|
: supplierRows.stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.filter(this::hasAnySupplierValue)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
long winnerCount = normalizedRows.stream()
|
||||||
|
.filter(item -> parseIsBidWinner(item.getIsBidWinner()) == 1)
|
||||||
|
.count();
|
||||||
|
if (winnerCount > 1) {
|
||||||
|
throw new RuntimeException(String.format("采购事项ID[%s]存在多条中标供应商", purchaseId));
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> duplicateSupplierKeys = new LinkedHashSet<>();
|
||||||
|
List<CcdiPurchaseTransactionSupplier> result = new ArrayList<>();
|
||||||
|
for (int i = 0; i < normalizedRows.size(); i++) {
|
||||||
|
CcdiPurchaseTransactionSupplierExcel supplierRow = normalizedRows.get(i);
|
||||||
|
validateSupplierRow(supplierRow);
|
||||||
|
|
||||||
|
String duplicateKey = StringUtils.trimToEmpty(supplierRow.getSupplierName()) + "|"
|
||||||
|
+ StringUtils.trimToEmpty(supplierRow.getSupplierUscc());
|
||||||
|
if (!duplicateSupplierKeys.add(duplicateKey)) {
|
||||||
|
throw new RuntimeException(String.format("采购事项ID[%s]存在重复供应商", purchaseId));
|
||||||
|
}
|
||||||
|
|
||||||
|
CcdiPurchaseTransactionSupplier supplier = new CcdiPurchaseTransactionSupplier();
|
||||||
|
supplier.setPurchaseId(purchaseId);
|
||||||
|
supplier.setSupplierName(StringUtils.trim(supplierRow.getSupplierName()));
|
||||||
|
supplier.setSupplierUscc(StringUtils.trimToNull(supplierRow.getSupplierUscc()));
|
||||||
|
supplier.setContactPerson(StringUtils.trimToNull(supplierRow.getContactPerson()));
|
||||||
|
supplier.setContactPhone(StringUtils.trimToNull(supplierRow.getContactPhone()));
|
||||||
|
supplier.setSupplierBankAccount(StringUtils.trimToNull(supplierRow.getSupplierBankAccount()));
|
||||||
|
supplier.setIsBidWinner(parseIsBidWinner(supplierRow.getIsBidWinner()));
|
||||||
|
supplier.setSortOrder(supplierRow.getSortOrder() == null ? i + 1 : supplierRow.getSortOrder());
|
||||||
|
supplier.setCreatedBy(userName);
|
||||||
|
supplier.setUpdatedBy(userName);
|
||||||
|
result.add(supplier);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateSupplierRow(CcdiPurchaseTransactionSupplierExcel supplierRow) {
|
||||||
|
if (StringUtils.isEmpty(supplierRow.getSupplierName())) {
|
||||||
|
throw new RuntimeException("供应商名称不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.length(supplierRow.getSupplierName()) > 200) {
|
||||||
|
throw new RuntimeException("供应商名称长度不能超过200个字符");
|
||||||
|
}
|
||||||
|
if (StringUtils.length(supplierRow.getContactPerson()) > 50) {
|
||||||
|
throw new RuntimeException("供应商联系人长度不能超过50个字符");
|
||||||
|
}
|
||||||
|
if (StringUtils.length(supplierRow.getSupplierBankAccount()) > 50) {
|
||||||
|
throw new RuntimeException("供应商银行账户长度不能超过50个字符");
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(supplierRow.getContactPhone())
|
||||||
|
&& !supplierRow.getContactPhone().matches("^1[3-9]\\d{9}$|^0\\d{2,3}-?\\d{7,8}$")) {
|
||||||
|
throw new RuntimeException("供应商联系电话格式不正确");
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(supplierRow.getSupplierUscc())
|
||||||
|
&& !supplierRow.getSupplierUscc().matches("^[0-9A-HJ-NPQRTUWXY]{2}\\d{6}[0-9A-HJ-NPQRTUWXY]{10}$")) {
|
||||||
|
throw new RuntimeException("供应商统一信用代码格式不正确");
|
||||||
|
}
|
||||||
|
parseIsBidWinner(supplierRow.getIsBidWinner());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasAnySupplierValue(CcdiPurchaseTransactionSupplierExcel supplierRow) {
|
||||||
|
return StringUtils.isNotEmpty(supplierRow.getPurchaseId())
|
||||||
|
|| StringUtils.isNotEmpty(supplierRow.getSupplierName())
|
||||||
|
|| StringUtils.isNotEmpty(supplierRow.getSupplierUscc())
|
||||||
|
|| StringUtils.isNotEmpty(supplierRow.getContactPerson())
|
||||||
|
|| StringUtils.isNotEmpty(supplierRow.getContactPhone())
|
||||||
|
|| StringUtils.isNotEmpty(supplierRow.getSupplierBankAccount())
|
||||||
|
|| StringUtils.isNotEmpty(supplierRow.getIsBidWinner())
|
||||||
|
|| supplierRow.getSortOrder() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int parseIsBidWinner(String rawValue) {
|
||||||
|
if (StringUtils.isEmpty(rawValue)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
String normalized = StringUtils.trim(rawValue);
|
||||||
|
if ("1".equals(normalized) || "是".equals(normalized) || "Y".equalsIgnoreCase(normalized)
|
||||||
|
|| "TRUE".equalsIgnoreCase(normalized)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ("0".equals(normalized) || "否".equals(normalized) || "N".equalsIgnoreCase(normalized)
|
||||||
|
|| "FALSE".equalsIgnoreCase(normalized)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
throw new RuntimeException("是否中标仅支持填写“是/否”或“1/0”");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillWinnerSummary(
|
||||||
|
CcdiPurchaseTransaction transaction,
|
||||||
|
List<CcdiPurchaseTransactionSupplier> supplierList
|
||||||
|
) {
|
||||||
|
CcdiPurchaseTransactionSupplier winner = supplierList.stream()
|
||||||
|
.filter(item -> Objects.equals(item.getIsBidWinner(), 1))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
if (winner == null) {
|
||||||
|
transaction.setSupplierName(null);
|
||||||
|
transaction.setSupplierUscc(null);
|
||||||
|
transaction.setContactPerson(null);
|
||||||
|
transaction.setContactPhone(null);
|
||||||
|
transaction.setSupplierBankAccount(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
transaction.setSupplierName(winner.getSupplierName());
|
||||||
|
transaction.setSupplierUscc(winner.getSupplierUscc());
|
||||||
|
transaction.setContactPerson(winner.getContactPerson());
|
||||||
|
transaction.setContactPhone(winner.getContactPhone());
|
||||||
|
transaction.setSupplierBankAccount(winner.getSupplierBankAccount());
|
||||||
|
}
|
||||||
|
|
||||||
|
private PurchaseTransactionImportFailureVO buildFailure(
|
||||||
|
CcdiPurchaseTransactionExcel mainExcel,
|
||||||
|
String purchaseId,
|
||||||
|
String errorMessage
|
||||||
|
) {
|
||||||
|
PurchaseTransactionImportFailureVO failure = new PurchaseTransactionImportFailureVO();
|
||||||
|
if (mainExcel != null) {
|
||||||
|
BeanUtils.copyProperties(mainExcel, failure);
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(purchaseId)) {
|
||||||
|
failure.setPurchaseId(purchaseId);
|
||||||
|
}
|
||||||
|
failure.setErrorMessage(errorMessage);
|
||||||
|
return failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int countImportUnits(
|
||||||
|
List<CcdiPurchaseTransactionExcel> mainExcelList,
|
||||||
|
List<CcdiPurchaseTransactionSupplierExcel> supplierExcelList
|
||||||
|
) {
|
||||||
|
LinkedHashSet<String> purchaseIds = new LinkedHashSet<>();
|
||||||
|
purchaseIds.addAll(
|
||||||
|
mainExcelList.stream()
|
||||||
|
.map(CcdiPurchaseTransactionExcel::getPurchaseId)
|
||||||
|
.filter(StringUtils::isNotEmpty)
|
||||||
|
.collect(Collectors.toCollection(LinkedHashSet::new))
|
||||||
|
);
|
||||||
|
purchaseIds.addAll(
|
||||||
|
supplierExcelList.stream()
|
||||||
|
.map(CcdiPurchaseTransactionSupplierExcel::getPurchaseId)
|
||||||
|
.filter(StringUtils::isNotEmpty)
|
||||||
|
.collect(Collectors.toCollection(LinkedHashSet::new))
|
||||||
|
);
|
||||||
|
return purchaseIds.size();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,24 +2,34 @@ package com.ruoyi.info.collection.service.impl;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.ruoyi.info.collection.domain.CcdiPurchaseTransaction;
|
import com.ruoyi.info.collection.domain.CcdiPurchaseTransaction;
|
||||||
|
import com.ruoyi.info.collection.domain.CcdiPurchaseTransactionSupplier;
|
||||||
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionAddDTO;
|
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionAddDTO;
|
||||||
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionEditDTO;
|
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionEditDTO;
|
||||||
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionQueryDTO;
|
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionQueryDTO;
|
||||||
|
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionSupplierDTO;
|
||||||
import com.ruoyi.info.collection.domain.excel.CcdiPurchaseTransactionExcel;
|
import com.ruoyi.info.collection.domain.excel.CcdiPurchaseTransactionExcel;
|
||||||
|
import com.ruoyi.info.collection.domain.excel.CcdiPurchaseTransactionSupplierExcel;
|
||||||
import com.ruoyi.info.collection.domain.vo.CcdiPurchaseTransactionVO;
|
import com.ruoyi.info.collection.domain.vo.CcdiPurchaseTransactionVO;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.CcdiPurchaseTransactionSupplierVO;
|
||||||
import com.ruoyi.info.collection.mapper.CcdiPurchaseTransactionMapper;
|
import com.ruoyi.info.collection.mapper.CcdiPurchaseTransactionMapper;
|
||||||
|
import com.ruoyi.info.collection.mapper.CcdiPurchaseTransactionSupplierMapper;
|
||||||
import com.ruoyi.info.collection.service.ICcdiPurchaseTransactionImportService;
|
import com.ruoyi.info.collection.service.ICcdiPurchaseTransactionImportService;
|
||||||
import com.ruoyi.info.collection.service.ICcdiPurchaseTransactionService;
|
import com.ruoyi.info.collection.service.ICcdiPurchaseTransactionService;
|
||||||
import com.ruoyi.common.utils.SecurityUtils;
|
import com.ruoyi.common.utils.SecurityUtils;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -39,6 +49,9 @@ public class CcdiPurchaseTransactionServiceImpl implements ICcdiPurchaseTransact
|
|||||||
@Resource
|
@Resource
|
||||||
private ICcdiPurchaseTransactionImportService transactionImportService;
|
private ICcdiPurchaseTransactionImportService transactionImportService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CcdiPurchaseTransactionSupplierMapper supplierMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private RedisTemplate<String, Object> redisTemplate;
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
@@ -93,7 +106,14 @@ public class CcdiPurchaseTransactionServiceImpl implements ICcdiPurchaseTransact
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public CcdiPurchaseTransactionVO selectTransactionById(String purchaseId) {
|
public CcdiPurchaseTransactionVO selectTransactionById(String purchaseId) {
|
||||||
return transactionMapper.selectTransactionById(purchaseId);
|
CcdiPurchaseTransactionVO detail = transactionMapper.selectTransactionById(purchaseId);
|
||||||
|
if (detail == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<CcdiPurchaseTransactionSupplierVO> supplierList = selectSupplierListByPurchaseId(purchaseId);
|
||||||
|
detail.setSupplierList(supplierList);
|
||||||
|
detail.setSupplierCount(supplierList.size());
|
||||||
|
return detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -110,9 +130,12 @@ public class CcdiPurchaseTransactionServiceImpl implements ICcdiPurchaseTransact
|
|||||||
throw new RuntimeException("该采购事项ID已存在");
|
throw new RuntimeException("该采购事项ID已存在");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<CcdiPurchaseTransactionSupplier> supplierList = buildSupplierEntities(addDTO.getPurchaseId(), addDTO.getSupplierList());
|
||||||
CcdiPurchaseTransaction transaction = new CcdiPurchaseTransaction();
|
CcdiPurchaseTransaction transaction = new CcdiPurchaseTransaction();
|
||||||
BeanUtils.copyProperties(addDTO, transaction);
|
BeanUtils.copyProperties(addDTO, transaction);
|
||||||
|
fillWinnerSummary(transaction, supplierList);
|
||||||
int result = transactionMapper.insert(transaction);
|
int result = transactionMapper.insert(transaction);
|
||||||
|
saveSuppliers(supplierList);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -126,9 +149,13 @@ public class CcdiPurchaseTransactionServiceImpl implements ICcdiPurchaseTransact
|
|||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public int updateTransaction(CcdiPurchaseTransactionEditDTO editDTO) {
|
public int updateTransaction(CcdiPurchaseTransactionEditDTO editDTO) {
|
||||||
|
List<CcdiPurchaseTransactionSupplier> supplierList = buildSupplierEntities(editDTO.getPurchaseId(), editDTO.getSupplierList());
|
||||||
CcdiPurchaseTransaction transaction = new CcdiPurchaseTransaction();
|
CcdiPurchaseTransaction transaction = new CcdiPurchaseTransaction();
|
||||||
BeanUtils.copyProperties(editDTO, transaction);
|
BeanUtils.copyProperties(editDTO, transaction);
|
||||||
|
fillWinnerSummary(transaction, supplierList);
|
||||||
int result = transactionMapper.updateById(transaction);
|
int result = transactionMapper.updateById(transaction);
|
||||||
|
transactionMapper.deleteSuppliersByPurchaseIds(List.of(editDTO.getPurchaseId()));
|
||||||
|
saveSuppliers(supplierList);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -142,19 +169,24 @@ public class CcdiPurchaseTransactionServiceImpl implements ICcdiPurchaseTransact
|
|||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public int deleteTransactionByIds(String[] purchaseIds) {
|
public int deleteTransactionByIds(String[] purchaseIds) {
|
||||||
|
transactionMapper.deleteSuppliersByPurchaseIds(List.of(purchaseIds));
|
||||||
return transactionMapper.deleteBatchIds(java.util.List.of(purchaseIds));
|
return transactionMapper.deleteBatchIds(java.util.List.of(purchaseIds));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导入采购交易数据(异步)
|
* 导入采购交易数据(异步)
|
||||||
*
|
*
|
||||||
* @param excelList Excel实体列表
|
* @param mainExcelList 主信息Excel实体列表
|
||||||
|
* @param supplierExcelList 供应商明细Excel实体列表
|
||||||
* @return 任务ID
|
* @return 任务ID
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public String importTransaction(java.util.List<CcdiPurchaseTransactionExcel> excelList) {
|
public String importTransaction(
|
||||||
if (StringUtils.isNull(excelList) || excelList.isEmpty()) {
|
List<CcdiPurchaseTransactionExcel> mainExcelList,
|
||||||
|
List<CcdiPurchaseTransactionSupplierExcel> supplierExcelList
|
||||||
|
) {
|
||||||
|
if ((mainExcelList == null || mainExcelList.isEmpty()) && (supplierExcelList == null || supplierExcelList.isEmpty())) {
|
||||||
throw new RuntimeException("至少需要一条数据");
|
throw new RuntimeException("至少需要一条数据");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +202,7 @@ public class CcdiPurchaseTransactionServiceImpl implements ICcdiPurchaseTransact
|
|||||||
Map<String, Object> statusData = new HashMap<>();
|
Map<String, Object> statusData = new HashMap<>();
|
||||||
statusData.put("taskId", taskId);
|
statusData.put("taskId", taskId);
|
||||||
statusData.put("status", "PROCESSING");
|
statusData.put("status", "PROCESSING");
|
||||||
statusData.put("totalCount", excelList.size());
|
statusData.put("totalCount", countImportUnits(mainExcelList, supplierExcelList));
|
||||||
statusData.put("successCount", 0);
|
statusData.put("successCount", 0);
|
||||||
statusData.put("failureCount", 0);
|
statusData.put("failureCount", 0);
|
||||||
statusData.put("progress", 0);
|
statusData.put("progress", 0);
|
||||||
@@ -181,8 +213,134 @@ public class CcdiPurchaseTransactionServiceImpl implements ICcdiPurchaseTransact
|
|||||||
redisTemplate.expire(statusKey, 7, TimeUnit.DAYS);
|
redisTemplate.expire(statusKey, 7, TimeUnit.DAYS);
|
||||||
|
|
||||||
// 调用异步导入服务
|
// 调用异步导入服务
|
||||||
transactionImportService.importTransactionAsync(excelList, taskId, userName);
|
transactionImportService.importTransactionAsync(mainExcelList, supplierExcelList, taskId, userName);
|
||||||
|
|
||||||
return taskId;
|
return taskId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int countImportUnits(
|
||||||
|
List<CcdiPurchaseTransactionExcel> mainExcelList,
|
||||||
|
List<CcdiPurchaseTransactionSupplierExcel> supplierExcelList
|
||||||
|
) {
|
||||||
|
LinkedHashSet<String> purchaseIds = new LinkedHashSet<>();
|
||||||
|
if (mainExcelList != null) {
|
||||||
|
purchaseIds.addAll(
|
||||||
|
mainExcelList.stream()
|
||||||
|
.map(CcdiPurchaseTransactionExcel::getPurchaseId)
|
||||||
|
.filter(StringUtils::isNotEmpty)
|
||||||
|
.collect(Collectors.toCollection(LinkedHashSet::new))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (supplierExcelList != null) {
|
||||||
|
purchaseIds.addAll(
|
||||||
|
supplierExcelList.stream()
|
||||||
|
.map(CcdiPurchaseTransactionSupplierExcel::getPurchaseId)
|
||||||
|
.filter(StringUtils::isNotEmpty)
|
||||||
|
.collect(Collectors.toCollection(LinkedHashSet::new))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return purchaseIds.isEmpty() ? 0 : purchaseIds.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<CcdiPurchaseTransactionSupplier> buildSupplierEntities(
|
||||||
|
String purchaseId,
|
||||||
|
List<CcdiPurchaseTransactionSupplierDTO> supplierDTOList
|
||||||
|
) {
|
||||||
|
List<CcdiPurchaseTransactionSupplierDTO> normalizedList = normalizeSupplierList(supplierDTOList);
|
||||||
|
validateSupplierList(normalizedList);
|
||||||
|
|
||||||
|
List<CcdiPurchaseTransactionSupplier> supplierList = new ArrayList<>();
|
||||||
|
for (int i = 0; i < normalizedList.size(); i++) {
|
||||||
|
CcdiPurchaseTransactionSupplierDTO dto = normalizedList.get(i);
|
||||||
|
CcdiPurchaseTransactionSupplier supplier = new CcdiPurchaseTransactionSupplier();
|
||||||
|
BeanUtils.copyProperties(dto, supplier);
|
||||||
|
supplier.setPurchaseId(purchaseId);
|
||||||
|
supplier.setIsBidWinner(Objects.equals(dto.getIsBidWinner(), 1) ? 1 : 0);
|
||||||
|
supplier.setSortOrder(dto.getSortOrder() == null ? i + 1 : dto.getSortOrder());
|
||||||
|
supplierList.add(supplier);
|
||||||
|
}
|
||||||
|
return supplierList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<CcdiPurchaseTransactionSupplierDTO> normalizeSupplierList(
|
||||||
|
List<CcdiPurchaseTransactionSupplierDTO> supplierDTOList
|
||||||
|
) {
|
||||||
|
if (supplierDTOList == null) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
return supplierDTOList.stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.filter(this::hasAnySupplierValue)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasAnySupplierValue(CcdiPurchaseTransactionSupplierDTO supplierDTO) {
|
||||||
|
return StringUtils.isNotEmpty(supplierDTO.getSupplierName())
|
||||||
|
|| StringUtils.isNotEmpty(supplierDTO.getSupplierUscc())
|
||||||
|
|| StringUtils.isNotEmpty(supplierDTO.getContactPerson())
|
||||||
|
|| StringUtils.isNotEmpty(supplierDTO.getContactPhone())
|
||||||
|
|| StringUtils.isNotEmpty(supplierDTO.getSupplierBankAccount())
|
||||||
|
|| supplierDTO.getIsBidWinner() != null
|
||||||
|
|| supplierDTO.getSortOrder() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateSupplierList(List<CcdiPurchaseTransactionSupplierDTO> supplierList) {
|
||||||
|
long winnerCount = supplierList.stream()
|
||||||
|
.filter(item -> Objects.equals(item.getIsBidWinner(), 1))
|
||||||
|
.count();
|
||||||
|
if (winnerCount > 1) {
|
||||||
|
throw new RuntimeException("同一招投标事项仅允许维护一条中标供应商");
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkedHashSet<String> duplicateKeys = new LinkedHashSet<>();
|
||||||
|
for (CcdiPurchaseTransactionSupplierDTO supplier : supplierList) {
|
||||||
|
String duplicateKey = StringUtils.trimToEmpty(supplier.getSupplierName()) + "|"
|
||||||
|
+ StringUtils.trimToEmpty(supplier.getSupplierUscc());
|
||||||
|
if (!duplicateKeys.add(duplicateKey)) {
|
||||||
|
throw new RuntimeException("同一招投标事项存在重复供应商,请检查供应商名称和统一信用代码");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillWinnerSummary(
|
||||||
|
CcdiPurchaseTransaction transaction,
|
||||||
|
List<CcdiPurchaseTransactionSupplier> supplierList
|
||||||
|
) {
|
||||||
|
CcdiPurchaseTransactionSupplier winnerSupplier = supplierList.stream()
|
||||||
|
.filter(item -> Objects.equals(item.getIsBidWinner(), 1))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
if (winnerSupplier == null) {
|
||||||
|
transaction.setSupplierName(null);
|
||||||
|
transaction.setSupplierUscc(null);
|
||||||
|
transaction.setContactPerson(null);
|
||||||
|
transaction.setContactPhone(null);
|
||||||
|
transaction.setSupplierBankAccount(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
transaction.setSupplierName(winnerSupplier.getSupplierName());
|
||||||
|
transaction.setSupplierUscc(winnerSupplier.getSupplierUscc());
|
||||||
|
transaction.setContactPerson(winnerSupplier.getContactPerson());
|
||||||
|
transaction.setContactPhone(winnerSupplier.getContactPhone());
|
||||||
|
transaction.setSupplierBankAccount(winnerSupplier.getSupplierBankAccount());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveSuppliers(List<CcdiPurchaseTransactionSupplier> supplierList) {
|
||||||
|
for (CcdiPurchaseTransactionSupplier supplier : supplierList) {
|
||||||
|
supplierMapper.insert(supplier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<CcdiPurchaseTransactionSupplierVO> selectSupplierListByPurchaseId(String purchaseId) {
|
||||||
|
return supplierMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<CcdiPurchaseTransactionSupplier>()
|
||||||
|
.eq(CcdiPurchaseTransactionSupplier::getPurchaseId, purchaseId)
|
||||||
|
.orderByAsc(CcdiPurchaseTransactionSupplier::getSortOrder)
|
||||||
|
.orderByAsc(CcdiPurchaseTransactionSupplier::getId)
|
||||||
|
).stream().map(entity -> {
|
||||||
|
CcdiPurchaseTransactionSupplierVO vo = new CcdiPurchaseTransactionSupplierVO();
|
||||||
|
BeanUtils.copyProperties(entity, vo);
|
||||||
|
return vo;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.ruoyi.info.collection.utils;
|
package com.ruoyi.info.collection.utils;
|
||||||
|
|
||||||
import com.alibaba.excel.EasyExcel;
|
import com.alibaba.excel.EasyExcel;
|
||||||
|
import com.alibaba.excel.ExcelWriter;
|
||||||
|
import com.alibaba.excel.write.metadata.WriteSheet;
|
||||||
import com.alibaba.excel.write.handler.WriteHandler;
|
import com.alibaba.excel.write.handler.WriteHandler;
|
||||||
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
|
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
|
||||||
import com.ruoyi.info.collection.handler.DictDropdownWriteHandler;
|
import com.ruoyi.info.collection.handler.DictDropdownWriteHandler;
|
||||||
@@ -98,6 +100,23 @@ public class EasyExcelUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入Excel(按指定Sheet名称)
|
||||||
|
*
|
||||||
|
* @param inputStream 输入流
|
||||||
|
* @param clazz 实体类
|
||||||
|
* @param sheetName 工作表名称
|
||||||
|
* @param <T> 泛型
|
||||||
|
* @return 数据列表
|
||||||
|
*/
|
||||||
|
public static <T> List<T> importExcel(java.io.InputStream inputStream, Class<T> clazz, String sheetName) {
|
||||||
|
try {
|
||||||
|
return EasyExcel.read(inputStream).head(clazz).sheet(sheetName).doReadSync();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("导入Excel失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 下载导入模板
|
* 下载导入模板
|
||||||
*
|
*
|
||||||
@@ -210,6 +229,45 @@ public class EasyExcelUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载双Sheet导入模板(带字典下拉框)
|
||||||
|
*
|
||||||
|
* @param response 响应对象
|
||||||
|
* @param firstClazz 第一张Sheet实体类
|
||||||
|
* @param firstSheetName 第一张Sheet名称
|
||||||
|
* @param secondClazz 第二张Sheet实体类
|
||||||
|
* @param secondSheetName 第二张Sheet名称
|
||||||
|
* @param fileName 文件名称
|
||||||
|
* @param <T1> 第一张Sheet泛型
|
||||||
|
* @param <T2> 第二张Sheet泛型
|
||||||
|
*/
|
||||||
|
public static <T1, T2> void importTemplateWithDictDropdown(
|
||||||
|
HttpServletResponse response,
|
||||||
|
Class<T1> firstClazz,
|
||||||
|
String firstSheetName,
|
||||||
|
Class<T2> secondClazz,
|
||||||
|
String secondSheetName,
|
||||||
|
String fileName
|
||||||
|
) {
|
||||||
|
setResponseHeader(response, fileName);
|
||||||
|
try (ExcelWriter writer = EasyExcel.write(response.getOutputStream()).build()) {
|
||||||
|
writer.write(List.of(), buildTemplateSheet(0, firstClazz, firstSheetName));
|
||||||
|
writer.write(List.of(), buildTemplateSheet(1, secondClazz, secondSheetName));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("下载双Sheet导入模板失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> WriteSheet buildTemplateSheet(int sheetNo, Class<T> clazz, String sheetName) {
|
||||||
|
return EasyExcel.writerSheet(sheetNo, sheetName)
|
||||||
|
.head(clazz)
|
||||||
|
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
|
||||||
|
.registerWriteHandler(new DictDropdownWriteHandler(clazz))
|
||||||
|
.registerWriteHandler(new TextFormatWriteHandler(clazz))
|
||||||
|
.registerWriteHandler(new RequiredFieldWriteHandler(clazz))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导出Excel(带字典下拉框)
|
* 导出Excel(带字典下拉框)
|
||||||
* 导出的数据包含实际值,但模板中有下拉框供后续编辑使用
|
* 导出的数据包含实际值,但模板中有下拉框供后续编辑使用
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
<result property="contactPhone" column="contact_phone"/>
|
<result property="contactPhone" column="contact_phone"/>
|
||||||
<result property="supplierUscc" column="supplier_uscc"/>
|
<result property="supplierUscc" column="supplier_uscc"/>
|
||||||
<result property="supplierBankAccount" column="supplier_bank_account"/>
|
<result property="supplierBankAccount" column="supplier_bank_account"/>
|
||||||
|
<result property="supplierCount" column="supplier_count"/>
|
||||||
<result property="applyDate" column="apply_date"/>
|
<result property="applyDate" column="apply_date"/>
|
||||||
<result property="planApproveDate" column="plan_approve_date"/>
|
<result property="planApproveDate" column="plan_approve_date"/>
|
||||||
<result property="announceDate" column="announce_date"/>
|
<result property="announceDate" column="announce_date"/>
|
||||||
@@ -47,49 +48,61 @@
|
|||||||
<!-- 分页查询采购交易列表 -->
|
<!-- 分页查询采购交易列表 -->
|
||||||
<select id="selectTransactionPage" resultMap="CcdiPurchaseTransactionVOResult">
|
<select id="selectTransactionPage" resultMap="CcdiPurchaseTransactionVOResult">
|
||||||
SELECT
|
SELECT
|
||||||
purchase_id, purchase_category, project_name, subject_name, subject_desc,
|
t.purchase_id, t.purchase_category, t.project_name, t.subject_name, t.subject_desc,
|
||||||
purchase_qty, budget_amount, bid_amount, actual_amount, contract_amount, settlement_amount,
|
t.purchase_qty, t.budget_amount, t.bid_amount, t.actual_amount, t.contract_amount, t.settlement_amount,
|
||||||
purchase_method, supplier_name, contact_person, contact_phone, supplier_uscc, supplier_bank_account,
|
t.purchase_method, t.supplier_name, t.contact_person, t.contact_phone, t.supplier_uscc, t.supplier_bank_account,
|
||||||
apply_date, plan_approve_date, announce_date, bid_open_date, contract_sign_date,
|
IFNULL(supplier_stats.supplier_count, 0) AS supplier_count,
|
||||||
expected_delivery_date, actual_delivery_date, acceptance_date, settlement_date,
|
t.apply_date, t.plan_approve_date, t.announce_date, t.bid_open_date, t.contract_sign_date,
|
||||||
applicant_id, applicant_name, apply_department, purchase_leader_id, purchase_leader_name, purchase_department,
|
t.expected_delivery_date, t.actual_delivery_date, t.acceptance_date, t.settlement_date,
|
||||||
created_by, create_time, updated_by, update_time
|
t.applicant_id, t.applicant_name, t.apply_department, t.purchase_leader_id, t.purchase_leader_name, t.purchase_department,
|
||||||
FROM ccdi_purchase_transaction
|
t.created_by, t.create_time, t.updated_by, t.update_time
|
||||||
|
FROM ccdi_purchase_transaction t
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT purchase_id, COUNT(*) AS supplier_count
|
||||||
|
FROM ccdi_purchase_transaction_supplier
|
||||||
|
GROUP BY purchase_id
|
||||||
|
) supplier_stats ON supplier_stats.purchase_id = t.purchase_id
|
||||||
<where>
|
<where>
|
||||||
<if test="query.projectName != null and query.projectName != ''">
|
<if test="query.projectName != null and query.projectName != ''">
|
||||||
AND project_name LIKE CONCAT('%', #{query.projectName}, '%')
|
AND t.project_name LIKE CONCAT('%', #{query.projectName}, '%')
|
||||||
</if>
|
</if>
|
||||||
<if test="query.subjectName != null and query.subjectName != ''">
|
<if test="query.subjectName != null and query.subjectName != ''">
|
||||||
AND subject_name LIKE CONCAT('%', #{query.subjectName}, '%')
|
AND t.subject_name LIKE CONCAT('%', #{query.subjectName}, '%')
|
||||||
</if>
|
</if>
|
||||||
<if test="query.applicantName != null and query.applicantName != ''">
|
<if test="query.applicantName != null and query.applicantName != ''">
|
||||||
AND applicant_name LIKE CONCAT('%', #{query.applicantName}, '%')
|
AND t.applicant_name LIKE CONCAT('%', #{query.applicantName}, '%')
|
||||||
</if>
|
</if>
|
||||||
<if test="query.applicantId != null and query.applicantId != ''">
|
<if test="query.applicantId != null and query.applicantId != ''">
|
||||||
AND applicant_id = #{query.applicantId}
|
AND t.applicant_id = #{query.applicantId}
|
||||||
</if>
|
</if>
|
||||||
<if test="query.applyDateStart != null">
|
<if test="query.applyDateStart != null">
|
||||||
AND apply_date >= #{query.applyDateStart}
|
AND t.apply_date >= #{query.applyDateStart}
|
||||||
</if>
|
</if>
|
||||||
<if test="query.applyDateEnd != null">
|
<if test="query.applyDateEnd != null">
|
||||||
AND apply_date <= #{query.applyDateEnd}
|
AND t.apply_date <= #{query.applyDateEnd}
|
||||||
</if>
|
</if>
|
||||||
</where>
|
</where>
|
||||||
ORDER BY create_time DESC
|
ORDER BY t.create_time DESC
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 查询采购交易详情 -->
|
<!-- 查询采购交易详情 -->
|
||||||
<select id="selectTransactionById" resultMap="CcdiPurchaseTransactionVOResult">
|
<select id="selectTransactionById" resultMap="CcdiPurchaseTransactionVOResult">
|
||||||
SELECT
|
SELECT
|
||||||
purchase_id, purchase_category, project_name, subject_name, subject_desc,
|
t.purchase_id, t.purchase_category, t.project_name, t.subject_name, t.subject_desc,
|
||||||
purchase_qty, budget_amount, bid_amount, actual_amount, contract_amount, settlement_amount,
|
t.purchase_qty, t.budget_amount, t.bid_amount, t.actual_amount, t.contract_amount, t.settlement_amount,
|
||||||
purchase_method, supplier_name, contact_person, contact_phone, supplier_uscc, supplier_bank_account,
|
t.purchase_method, t.supplier_name, t.contact_person, t.contact_phone, t.supplier_uscc, t.supplier_bank_account,
|
||||||
apply_date, plan_approve_date, announce_date, bid_open_date, contract_sign_date,
|
IFNULL(supplier_stats.supplier_count, 0) AS supplier_count,
|
||||||
expected_delivery_date, actual_delivery_date, acceptance_date, settlement_date,
|
t.apply_date, t.plan_approve_date, t.announce_date, t.bid_open_date, t.contract_sign_date,
|
||||||
applicant_id, applicant_name, apply_department, purchase_leader_id, purchase_leader_name, purchase_department,
|
t.expected_delivery_date, t.actual_delivery_date, t.acceptance_date, t.settlement_date,
|
||||||
created_by, create_time, updated_by, update_time
|
t.applicant_id, t.applicant_name, t.apply_department, t.purchase_leader_id, t.purchase_leader_name, t.purchase_department,
|
||||||
FROM ccdi_purchase_transaction
|
t.created_by, t.create_time, t.updated_by, t.update_time
|
||||||
WHERE purchase_id = #{purchaseId}
|
FROM ccdi_purchase_transaction t
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT purchase_id, COUNT(*) AS supplier_count
|
||||||
|
FROM ccdi_purchase_transaction_supplier
|
||||||
|
GROUP BY purchase_id
|
||||||
|
) supplier_stats ON supplier_stats.purchase_id = t.purchase_id
|
||||||
|
WHERE t.purchase_id = #{purchaseId}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 批量插入采购交易数据 -->
|
<!-- 批量插入采购交易数据 -->
|
||||||
@@ -137,4 +150,12 @@
|
|||||||
</foreach>
|
</foreach>
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
|
<delete id="deleteSuppliersByPurchaseIds">
|
||||||
|
DELETE FROM ccdi_purchase_transaction_supplier
|
||||||
|
WHERE purchase_id IN
|
||||||
|
<foreach collection="purchaseIds" item="purchaseId" open="(" separator="," close=")">
|
||||||
|
#{purchaseId}
|
||||||
|
</foreach>
|
||||||
|
</delete>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.ruoyi.ccdi.project.domain.vo;
|
package com.ruoyi.ccdi.project.domain.vo;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,4 +81,6 @@ public class CcdiProjectExtendedPurchaseDetailVO {
|
|||||||
private String updatedBy;
|
private String updatedBy;
|
||||||
|
|
||||||
private String updateTime;
|
private String updateTime;
|
||||||
|
|
||||||
|
private List<CcdiProjectExtendedPurchaseSupplierVO> supplierList;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.ruoyi.ccdi.project.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 专项核查采购供应商明细
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CcdiProjectExtendedPurchaseSupplierVO {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String purchaseId;
|
||||||
|
|
||||||
|
private String supplierName;
|
||||||
|
|
||||||
|
private String supplierUscc;
|
||||||
|
|
||||||
|
private String contactPerson;
|
||||||
|
|
||||||
|
private String contactPhone;
|
||||||
|
|
||||||
|
private String supplierBankAccount;
|
||||||
|
|
||||||
|
private Integer isBidWinner;
|
||||||
|
|
||||||
|
private Integer sortOrder;
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import com.ruoyi.ccdi.project.domain.dto.CcdiProjectExtendedRecruitmentQueryDTO;
|
|||||||
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectExtendedTransferQueryDTO;
|
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectExtendedTransferQueryDTO;
|
||||||
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedPurchaseDetailVO;
|
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedPurchaseDetailVO;
|
||||||
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedPurchaseListItemVO;
|
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedPurchaseListItemVO;
|
||||||
|
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedPurchaseSupplierVO;
|
||||||
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedRecruitmentDetailVO;
|
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedRecruitmentDetailVO;
|
||||||
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedRecruitmentListItemVO;
|
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedRecruitmentListItemVO;
|
||||||
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedTransferDetailVO;
|
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedTransferDetailVO;
|
||||||
@@ -96,6 +97,18 @@ public interface CcdiProjectSpecialCheckMapper {
|
|||||||
@Param("purchaseId") String purchaseId
|
@Param("purchaseId") String purchaseId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询专项核查采购供应商明细
|
||||||
|
*
|
||||||
|
* @param projectId 项目ID
|
||||||
|
* @param purchaseId 采购事项ID
|
||||||
|
* @return 供应商明细
|
||||||
|
*/
|
||||||
|
List<CcdiProjectExtendedPurchaseSupplierVO> selectExtendedPurchaseSuppliers(
|
||||||
|
@Param("projectId") Long projectId,
|
||||||
|
@Param("purchaseId") String purchaseId
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询专项核查招聘拓展列表
|
* 查询专项核查招聘拓展列表
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -103,6 +103,9 @@ public class CcdiProjectSpecialCheckServiceImpl implements ICcdiProjectSpecialCh
|
|||||||
if (detail == null) {
|
if (detail == null) {
|
||||||
throw new ServiceException("当前记录不属于该项目专项核查范围");
|
throw new ServiceException("当前记录不属于该项目专项核查范围");
|
||||||
}
|
}
|
||||||
|
detail.setSupplierList(defaultList(
|
||||||
|
specialCheckMapper.selectExtendedPurchaseSuppliers(queryDTO.getProjectId(), queryDTO.getPurchaseId())
|
||||||
|
));
|
||||||
return detail;
|
return detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -574,6 +574,33 @@
|
|||||||
where p.purchase_id = #{purchaseId}
|
where p.purchase_id = #{purchaseId}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectExtendedPurchaseSuppliers"
|
||||||
|
resultType="com.ruoyi.ccdi.project.domain.vo.CcdiProjectExtendedPurchaseSupplierVO">
|
||||||
|
select
|
||||||
|
s.id,
|
||||||
|
s.purchase_id,
|
||||||
|
s.supplier_name,
|
||||||
|
s.supplier_uscc,
|
||||||
|
s.contact_person,
|
||||||
|
s.contact_phone,
|
||||||
|
s.supplier_bank_account,
|
||||||
|
s.is_bid_winner,
|
||||||
|
s.sort_order
|
||||||
|
from ccdi_purchase_transaction_supplier s
|
||||||
|
inner join ccdi_purchase_transaction p on p.purchase_id = s.purchase_id
|
||||||
|
inner join (
|
||||||
|
select distinct scope.staff_name
|
||||||
|
from (
|
||||||
|
<include refid="projectEmployeeScopeSql"/>
|
||||||
|
) scope
|
||||||
|
where scope.staff_name is not null
|
||||||
|
and scope.staff_name != ''
|
||||||
|
) scoped_staff
|
||||||
|
on scoped_staff.staff_name = p.applicant_name
|
||||||
|
where s.purchase_id = #{purchaseId}
|
||||||
|
order by s.sort_order asc, s.id asc
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="selectExtendedRecruitmentPage" resultMap="ExtendedRecruitmentListItemResultMap">
|
<select id="selectExtendedRecruitmentPage" resultMap="ExtendedRecruitmentListItemResultMap">
|
||||||
<bind name="projectId" value="query.projectId"/>
|
<bind name="projectId" value="query.projectId"/>
|
||||||
select distinct r.recruit_id,
|
select distinct r.recruit_id,
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# 招投标信息维护后端实施计划
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
- 将现有 `purchaseTransaction` 后端链路改造为“招投标主信息 + 供应商明细子表”结构。
|
||||||
|
- 保留原有 URL、权限前缀和内部类名,统一用户可见文案为“招投标信息维护”。
|
||||||
|
- 支持详情查询返回全部供应商明细,列表返回中标供应商摘要和参与供应商数。
|
||||||
|
- 支持双 Sheet 导入模板与按 `purchaseId` 聚合校验的异步导入。
|
||||||
|
|
||||||
|
## 实施内容
|
||||||
|
- 数据层
|
||||||
|
- 新增 `ccdi_purchase_transaction_supplier` 明细表初始化 SQL 与增量迁移脚本。
|
||||||
|
- 迁移脚本回填历史中标供应商数据,并将菜单名称更新为“招投标信息维护”。
|
||||||
|
- 领域模型
|
||||||
|
- 新增供应商 entity、DTO、VO、Excel 模型。
|
||||||
|
- 主 DTO/VO 增加 `supplierList`,主 VO 增加 `supplierCount`。
|
||||||
|
- 主 Excel 模板改为仅承载招投标主信息,供应商明细独立建模。
|
||||||
|
- 接口与服务
|
||||||
|
- 列表 SQL 增加供应商数聚合。
|
||||||
|
- 详情查询补充供应商明细列表。
|
||||||
|
- 新增/修改时由 `supplierList` 自动回填主表中标供应商摘要字段。
|
||||||
|
- 删除主记录时级联删除供应商明细。
|
||||||
|
- 导入链路改为“双 Sheet 读取 + 按事项聚合校验 + 主从同落库”。
|
||||||
|
- 项目专项核查
|
||||||
|
- 项目采购详情 VO、Mapper、Service 增加供应商明细查询能力,保持项目详情与信息维护详情口径一致。
|
||||||
|
|
||||||
|
## 验证
|
||||||
|
- `mvn -pl ccdi-info-collection,ccdi-project -am -DskipTests compile`
|
||||||
|
- `./bin/restart_java_backend.sh restart`
|
||||||
|
- 浏览器验证列表接口、详情接口与项目详情供应商明细展示。
|
||||||
|
|
||||||
|
## 产出文件
|
||||||
|
- `sql/ccdi_purchase_transaction.sql`
|
||||||
|
- `sql/ccdi_purchase_transaction_menu.sql`
|
||||||
|
- `sql/migration/2026-04-22-bidding-info-maintenance-supplier-detail.sql`
|
||||||
|
- `ccdi-info-collection` 与 `ccdi-project` 相关后端代码
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# 招投标信息维护弹窗宽度与供应商序号前端实施计划
|
||||||
|
|
||||||
|
## 保存路径确认
|
||||||
|
- 前端实施计划保存到 `docs/plans/frontend/`
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
- 新增、编辑弹窗宽度调整为页面宽度的 `80%`
|
||||||
|
- 供应商明细不再录入排序,改为页面按当前行顺序自动生成序号与提交顺序
|
||||||
|
|
||||||
|
## 实施范围
|
||||||
|
- 文件:`ruoyi-ui/src/views/ccdiPurchaseTransaction/index.vue`
|
||||||
|
|
||||||
|
## 实施步骤
|
||||||
|
1. 将新增/编辑共用弹窗宽度从固定像素改为 `80%`
|
||||||
|
2. 将供应商明细表中的“排序”输入列改为只读“序号”展示列
|
||||||
|
3. 调整供应商新增与提交逻辑,提交时按当前行顺序自动补齐 `sortOrder`
|
||||||
|
4. 清理空白供应商行判断,避免隐藏排序字段后把空白行误判为有效数据
|
||||||
|
5. 使用真实页面验证新增/编辑弹窗显示与供应商录入行为
|
||||||
|
|
||||||
|
## 验证点
|
||||||
|
- 新增/编辑弹窗宽度明显放大至页面宽度的 `80%`
|
||||||
|
- 供应商明细不再出现排序输入框
|
||||||
|
- 新增供应商后可正常录入供应商名称、统一信用代码、联系人、联系电话、银行账户
|
||||||
|
- 编辑已有数据时供应商顺序按当前表格行顺序提交
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# 招投标信息维护前端实施计划
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
- 将信息维护下“采购交易管理”页面改造为“招投标信息维护”。
|
||||||
|
- 列表页展示中标供应商和参与供应商数,新增/编辑弹窗支持维护全部供应商明细。
|
||||||
|
- 详情弹窗与项目详情采购弹窗统一展示供应商明细表。
|
||||||
|
- 导入入口文案和模板命名改为招投标信息维护语义。
|
||||||
|
|
||||||
|
## 实施内容
|
||||||
|
- 页面改造
|
||||||
|
- 重写 `ruoyi-ui/src/views/ccdiPurchaseTransaction/index.vue`。
|
||||||
|
- 将原单供应商表单替换为可增删行的供应商明细表格。
|
||||||
|
- 使用单选方式标记唯一中标供应商,并在提交时写回 `supplierList.isBidWinner`。
|
||||||
|
- 列表页新增“参与供应商数”列,保留“中标供应商”摘要列。
|
||||||
|
- 详情展示
|
||||||
|
- 页面详情弹窗改为供应商明细表展示。
|
||||||
|
- 项目专项核查采购详情弹窗同步改为供应商明细表展示。
|
||||||
|
- 导入交互
|
||||||
|
- 导入弹窗文案更新为“招投标信息导入”。
|
||||||
|
- 模板下载文件名与提示改为双 Sheet 模板。
|
||||||
|
|
||||||
|
## 验证
|
||||||
|
- `source ~/.nvm/nvm.sh && nvm use 14.21.3 >/dev/null && cd ruoyi-ui && npm run build:prod`
|
||||||
|
- `source ~/.nvm/nvm.sh && nvm use 14.21.3 >/dev/null && cd ruoyi-ui && npm run dev -- --port 8080`
|
||||||
|
- 使用 Playwright 打开真实页面:
|
||||||
|
- 验证菜单显示“招投标信息维护”
|
||||||
|
- 验证列表显示“中标供应商”“参与供应商数”
|
||||||
|
- 验证新增弹窗可添加供应商明细
|
||||||
|
- 验证详情弹窗展示供应商明细表
|
||||||
|
|
||||||
|
## 产出文件
|
||||||
|
- `ruoyi-ui/src/views/ccdiPurchaseTransaction/index.vue`
|
||||||
|
- `ruoyi-ui/src/views/ccdiProject/components/detail/ExtendedPurchaseDetailDialog.vue`
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# 招聘信息新增编辑弹窗宽度调整前端实施计划
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** 将招聘信息管理页“新增招聘信息”“修改招聘信息”共用弹窗的宽度从固定 `900px` 调整为页面宽度的 `80%`,提升表单内容展示空间。
|
||||||
|
|
||||||
|
**Architecture:** 本次仅调整 `ccdiStaffRecruitment` 页面新增/编辑弹窗的 `el-dialog` 宽度配置,不新增字段、不改动详情弹窗、不调整提交逻辑和接口交互。
|
||||||
|
|
||||||
|
**Tech Stack:** Vue 2, Element UI, JavaScript, Markdown
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 文件结构与职责
|
||||||
|
|
||||||
|
- `ruoyi-ui/src/views/ccdiStaffRecruitment/index.vue`
|
||||||
|
调整新增/编辑招聘信息弹窗宽度配置。
|
||||||
|
|
||||||
|
## 实施步骤
|
||||||
|
|
||||||
|
- [x] 定位招聘信息管理页新增/编辑弹窗的实际模板位置
|
||||||
|
- [x] 将新增/编辑弹窗宽度从固定像素改为 `80%`
|
||||||
|
- [x] 确认详情弹窗与其他弹窗保持原样,不扩大影响范围
|
||||||
|
- [x] 运行前端构建校验模板改动未引入语法问题
|
||||||
|
- [x] 使用浏览器实际打开新增/编辑弹窗,确认宽度按页面宽度 `80%` 展示
|
||||||
|
|
||||||
|
## 验证
|
||||||
|
|
||||||
|
```bash
|
||||||
|
source ~/.nvm/nvm.sh && nvm use 14.21.3 >/dev/null && cd ruoyi-ui && npm run build:prod
|
||||||
|
```
|
||||||
|
|
||||||
|
## 完成标准
|
||||||
|
|
||||||
|
- 招聘信息管理页新增/编辑弹窗宽度调整为页面宽度的 `80%`
|
||||||
|
- 招聘信息详情弹窗和页面其他交互保持不变
|
||||||
|
- 页面构建成功,且浏览器实测可正常打开新增/编辑弹窗
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# 招投标信息维护弹窗宽度与供应商序号实施记录
|
||||||
|
|
||||||
|
## 保存路径确认
|
||||||
|
- 实施记录保存到 `docs/reports/implementation/`
|
||||||
|
|
||||||
|
## 本次修改
|
||||||
|
- 将招投标信息新增/编辑弹窗宽度由固定 `1200px` 调整为 `80%`
|
||||||
|
- 将供应商明细中的“排序”录入列改为只读“序号”展示列
|
||||||
|
- 供应商新增行不再预填可编辑排序值
|
||||||
|
- 提交时按供应商当前行顺序自动回填 `sortOrder`
|
||||||
|
- 空白供应商行判定不再依赖 `sortOrder`
|
||||||
|
|
||||||
|
## 影响范围
|
||||||
|
- `ruoyi-ui/src/views/ccdiPurchaseTransaction/index.vue`
|
||||||
|
|
||||||
|
## 验证方式
|
||||||
|
- 启动前端开发服务进行页面热更新验证
|
||||||
|
- 使用 Playwright 打开真实页面 `http://localhost:8080/maintain/purchaseTransaction`
|
||||||
|
- 验证编辑弹窗宽度、供应商明细列展示与新增供应商录入行为
|
||||||
|
|
||||||
|
## 结果
|
||||||
|
- 弹窗宽度调整生效
|
||||||
|
- 供应商排序输入已移除
|
||||||
|
- 供应商录入功能正常
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# 招投标信息维护实施记录
|
||||||
|
|
||||||
|
## 本次改动
|
||||||
|
- 将信息维护下“采购交易管理”改为“招投标信息维护”,保留原有 `purchaseTransaction` 技术标识。
|
||||||
|
- 新增供应商明细子表 `ccdi_purchase_transaction_supplier`,支持维护全部参标供应商,并使用 `is_bid_winner` 标记中标方。
|
||||||
|
- 主表继续保留中标供应商摘要字段,新增/修改/导入时从供应商明细自动回填。
|
||||||
|
- 列表查询新增供应商数聚合;详情查询和项目专项核查采购详情新增供应商明细返回。
|
||||||
|
- 导入模板改为“招投标主信息 + 供应商明细”双 Sheet,并按 `purchaseId` 聚合校验。
|
||||||
|
- 前端页面改造为多供应商明细表单,详情弹窗与项目详情弹窗改为供应商明细表展示。
|
||||||
|
|
||||||
|
## 关键文件
|
||||||
|
- 后端
|
||||||
|
- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiPurchaseTransactionServiceImpl.java`
|
||||||
|
- `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiPurchaseTransactionImportServiceImpl.java`
|
||||||
|
- `ccdi-info-collection/src/main/resources/mapper/info/collection/CcdiPurchaseTransactionMapper.xml`
|
||||||
|
- `ccdi-project/src/main/resources/mapper/ccdi/project/CcdiProjectSpecialCheckMapper.xml`
|
||||||
|
- 前端
|
||||||
|
- `ruoyi-ui/src/views/ccdiPurchaseTransaction/index.vue`
|
||||||
|
- `ruoyi-ui/src/views/ccdiProject/components/detail/ExtendedPurchaseDetailDialog.vue`
|
||||||
|
- SQL
|
||||||
|
- `sql/ccdi_purchase_transaction.sql`
|
||||||
|
- `sql/ccdi_purchase_transaction_menu.sql`
|
||||||
|
- `sql/migration/2026-04-22-bidding-info-maintenance-supplier-detail.sql`
|
||||||
|
|
||||||
|
## 验证结果
|
||||||
|
- 后端编译
|
||||||
|
- 命令:`mvn -pl ccdi-info-collection,ccdi-project -am -DskipTests compile`
|
||||||
|
- 结果:通过。
|
||||||
|
- 前端构建
|
||||||
|
- 命令:`source ~/.nvm/nvm.sh && nvm use 14.21.3 >/dev/null && cd ruoyi-ui && npm run build:prod`
|
||||||
|
- 结果:通过,仅有既有产物体积 warning。
|
||||||
|
- 数据迁移
|
||||||
|
- 命令:`bin/mysql_utf8_exec.sh sql/migration/2026-04-22-bidding-info-maintenance-supplier-detail.sql`
|
||||||
|
- 结果:执行成功,本地联调库菜单名已更新为“招投标信息维护”。
|
||||||
|
- Playwright 实页验证
|
||||||
|
- 验证页面:`http://localhost:8080/maintain/purchaseTransaction`
|
||||||
|
- 结果:
|
||||||
|
- 菜单与面包屑显示“招投标信息维护”
|
||||||
|
- 列表显示“中标供应商”“参与供应商数”
|
||||||
|
- 新增弹窗显示供应商明细表,并可新增供应商行
|
||||||
|
- 详情弹窗显示供应商明细表与中标标识
|
||||||
|
- 联调过程中发现列表 SQL 因 join 后字段未加别名导致 `purchase_id is ambiguous`,已修复并复验通过。
|
||||||
|
|
||||||
|
## 测试进程清理
|
||||||
|
- 已关闭 Playwright 浏览器会话。
|
||||||
|
- 已停止前端 `npm run dev` 进程。
|
||||||
|
- 已停止测试期间启动的后端进程。
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# ruoyi-ui 添加 .nvmrc 实施记录
|
||||||
|
|
||||||
|
## 文档信息
|
||||||
|
|
||||||
|
- 保存路径:`docs/reports/implementation/2026-04-22-ruoyi-ui-nvmrc-implementation.md`
|
||||||
|
- 实施日期:2026-04-22
|
||||||
|
- 关联范围:`ruoyi-ui` 前端工程本地 Node 版本约束
|
||||||
|
|
||||||
|
## 本次修改内容
|
||||||
|
|
||||||
|
1. 确认 `docs/` 内近期前端实施计划与实施记录均使用 `nvm use 14.21.3` 作为 `ruoyi-ui` 的实际 Node 版本。
|
||||||
|
2. 在 `ruoyi-ui` 目录新增 `.nvmrc`,写入 `14.21.3`,统一本地开发、构建与测试时的 Node 版本入口。
|
||||||
|
3. 保持 `package.json` 现有 `engines` 配置不变,本次仅补充 `nvm` 版本声明文件,不扩展其他构建配置。
|
||||||
|
|
||||||
|
## 影响范围
|
||||||
|
|
||||||
|
- 前端:`ruoyi-ui/.nvmrc`
|
||||||
|
- 文档:本实施记录
|
||||||
|
|
||||||
|
## 验证情况
|
||||||
|
|
||||||
|
1. 版本依据核对:
|
||||||
|
- 已核对 `docs/plans/frontend/` 与 `docs/reports/implementation/` 中近期前端构建命令,当前统一使用 `nvm use 14.21.3`。
|
||||||
|
2. 本地命令校验:
|
||||||
|
- 执行命令:`source ~/.nvm/nvm.sh && cd ruoyi-ui && nvm use`
|
||||||
|
- 预期结果:自动读取 `.nvmrc` 并切换到 `v14.21.3`。
|
||||||
|
3. 说明:
|
||||||
|
- 本次为 Node 版本声明文件补充,不涉及业务代码、页面交互或接口行为变更,未执行额外前端构建与页面测试。
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# 招聘信息新增编辑弹窗宽度调整实施记录
|
||||||
|
|
||||||
|
## 文档信息
|
||||||
|
|
||||||
|
- 保存路径:`docs/reports/implementation/2026-04-22-staff-recruitment-dialog-width-implementation.md`
|
||||||
|
- 实施日期:2026-04-22
|
||||||
|
- 关联范围:招聘信息管理前端页面
|
||||||
|
|
||||||
|
## 本次修改内容
|
||||||
|
|
||||||
|
1. 定位到招聘信息管理页新增/编辑共用同一个 `el-dialog`,原宽度固定为 `900px`。
|
||||||
|
2. 将新增/编辑弹窗宽度改为 `80%`,使弹窗按页面可视宽度自适应放大。
|
||||||
|
3. 保持招聘信息详情弹窗宽度和原有表单提交流程不变,避免影响非本次需求范围的交互。
|
||||||
|
4. 新增本次前端实施计划与实施记录,沉淀改动背景、影响范围与验证结论。
|
||||||
|
|
||||||
|
## 影响范围
|
||||||
|
|
||||||
|
- 前端:`ruoyi-ui/src/views/ccdiStaffRecruitment/index.vue` 新增/编辑招聘信息弹窗。
|
||||||
|
- 文档:新增前端实施计划与实施记录。
|
||||||
|
|
||||||
|
## 验证情况
|
||||||
|
|
||||||
|
1. 前端构建校验:
|
||||||
|
- 执行命令:`source ~/.nvm/nvm.sh && nvm use 14.21.3 >/dev/null && cd ruoyi-ui && npm run build:prod`
|
||||||
|
- 结果:构建成功;存在项目原有的 bundle size warnings,本次改动未引入新的构建错误。
|
||||||
|
2. Playwright 浏览器实测:
|
||||||
|
- 执行方式:通过 `nvm use 25.9.0` 启动 `playwright-cli`,打开 `http://127.0.0.1:1025/prototype/staff-recruitment?preview=1&mode=add` 与 `http://127.0.0.1:1025/prototype/staff-recruitment?preview=1&mode=edit`,在真实浏览器中读取可见 `el-dialog` 的实际宽度。
|
||||||
|
- 结果:新增弹窗标题为“添加招聘信息”,页面宽度 `1280px`、弹窗宽度 `1024px`、宽度占比 `0.8`;编辑弹窗标题为“修改招聘信息”,页面宽度 `1280px`、弹窗宽度 `1024px`、宽度占比 `0.8`,与需求一致。
|
||||||
|
3. 测试进程清理:
|
||||||
|
- 已关闭本次测试过程中临时启动的 Playwright 浏览器与前端 dev server。
|
||||||
1
ruoyi-ui/.nvmrc
Normal file
1
ruoyi-ui/.nvmrc
Normal file
@@ -0,0 +1 @@
|
|||||||
|
14.21.3
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog title="采购记录详情" :visible.sync="visibleProxy" width="1000px" append-to-body>
|
<el-dialog title="招投标记录详情" :visible.sync="visibleProxy" width="1100px" append-to-body>
|
||||||
<div class="detail-container">
|
<div class="detail-container">
|
||||||
<el-divider content-position="left">基本信息</el-divider>
|
<el-divider content-position="left">基本信息</el-divider>
|
||||||
<el-descriptions :column="2" border>
|
<el-descriptions :column="2" border>
|
||||||
@@ -21,14 +21,27 @@
|
|||||||
<el-descriptions-item label="结算金额(元)">{{ detail.settlementAmount || "-" }}</el-descriptions-item>
|
<el-descriptions-item label="结算金额(元)">{{ detail.settlementAmount || "-" }}</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
|
|
||||||
<el-divider content-position="left">供应商信息</el-divider>
|
<el-divider content-position="left">供应商明细</el-divider>
|
||||||
<el-descriptions :column="2" border>
|
<el-empty
|
||||||
<el-descriptions-item label="中标供应商名称">{{ detail.supplierName || "-" }}</el-descriptions-item>
|
v-if="!supplierList.length"
|
||||||
<el-descriptions-item label="统一信用代码">{{ detail.supplierUscc || "-" }}</el-descriptions-item>
|
:image-size="72"
|
||||||
<el-descriptions-item label="供应商联系人">{{ detail.contactPerson || "-" }}</el-descriptions-item>
|
description="未录入供应商信息"
|
||||||
<el-descriptions-item label="供应商联系电话">{{ detail.contactPhone || "-" }}</el-descriptions-item>
|
/>
|
||||||
<el-descriptions-item label="供应商银行账户" :span="2">{{ detail.supplierBankAccount || "-" }}</el-descriptions-item>
|
<el-table v-else :data="supplierList" border size="small">
|
||||||
</el-descriptions>
|
<el-table-column label="排序" prop="sortOrder" width="90" align="center" />
|
||||||
|
<el-table-column label="中标结果" width="110" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-tag :type="scope.row.isBidWinner === 1 ? 'danger' : 'info'" size="mini">
|
||||||
|
{{ scope.row.isBidWinner === 1 ? "中标" : "参标" }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="供应商名称" prop="supplierName" min-width="220" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="统一信用代码" prop="supplierUscc" min-width="180" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="供应商联系人" prop="contactPerson" min-width="120" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="供应商联系电话" prop="contactPhone" min-width="150" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="供应商银行账户" prop="supplierBankAccount" min-width="180" :show-overflow-tooltip="true" />
|
||||||
|
</el-table>
|
||||||
|
|
||||||
<el-divider content-position="left">日期信息</el-divider>
|
<el-divider content-position="left">日期信息</el-divider>
|
||||||
<el-descriptions :column="3" border>
|
<el-descriptions :column="3" border>
|
||||||
@@ -77,12 +90,12 @@ export default {
|
|||||||
props: {
|
props: {
|
||||||
visible: {
|
visible: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false
|
||||||
},
|
},
|
||||||
detail: {
|
detail: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({}),
|
default: () => ({})
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
visibleProxy: {
|
visibleProxy: {
|
||||||
@@ -91,8 +104,11 @@ export default {
|
|||||||
},
|
},
|
||||||
set(value) {
|
set(value) {
|
||||||
this.$emit("update:visible", value);
|
this.$emit("update:visible", value);
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
},
|
supplierList() {
|
||||||
|
return Array.isArray(this.detail && this.detail.supplierList) ? this.detail.supplierList : [];
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -225,7 +225,7 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 添加或修改对话框 -->
|
<!-- 添加或修改对话框 -->
|
||||||
<el-dialog :title="title" :visible.sync="open" width="900px" append-to-body>
|
<el-dialog :title="title" :visible.sync="open" width="80%" append-to-body>
|
||||||
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
|
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
|
||||||
<el-divider content-position="left">招聘岗位信息</el-divider>
|
<el-divider content-position="left">招聘岗位信息</el-divider>
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
-- 员工采购交易信息表
|
-- 招投标主信息表
|
||||||
CREATE TABLE `ccdi_purchase_transaction` (
|
CREATE TABLE `ccdi_purchase_transaction` (
|
||||||
`purchase_id` VARCHAR(32) NOT NULL COMMENT '采购事项ID',
|
`purchase_id` VARCHAR(32) NOT NULL COMMENT '采购事项ID',
|
||||||
`purchase_category` VARCHAR(50) NOT NULL COMMENT '采购类别',
|
`purchase_category` VARCHAR(50) NOT NULL COMMENT '采购类别',
|
||||||
@@ -41,4 +41,24 @@ CREATE TABLE `ccdi_purchase_transaction` (
|
|||||||
KEY `idx_apply_date` (`apply_date`),
|
KEY `idx_apply_date` (`apply_date`),
|
||||||
KEY `idx_supplier_uscc` (`supplier_uscc`),
|
KEY `idx_supplier_uscc` (`supplier_uscc`),
|
||||||
KEY `idx_category_method` (`purchase_category`, `purchase_method`)
|
KEY `idx_category_method` (`purchase_category`, `purchase_method`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='员工采购交易信息表';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='招投标主信息表';
|
||||||
|
|
||||||
|
-- 招投标供应商明细表
|
||||||
|
CREATE TABLE `ccdi_purchase_transaction_supplier` (
|
||||||
|
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`purchase_id` VARCHAR(32) NOT NULL COMMENT '采购事项ID',
|
||||||
|
`supplier_name` VARCHAR(200) NOT NULL COMMENT '供应商名称',
|
||||||
|
`supplier_uscc` VARCHAR(18) DEFAULT NULL COMMENT '供应商统一信用代码',
|
||||||
|
`contact_person` VARCHAR(50) DEFAULT NULL COMMENT '供应商联系人',
|
||||||
|
`contact_phone` VARCHAR(20) DEFAULT NULL COMMENT '供应商联系电话',
|
||||||
|
`supplier_bank_account` VARCHAR(50) DEFAULT NULL COMMENT '供应商银行账户',
|
||||||
|
`is_bid_winner` TINYINT NOT NULL DEFAULT 0 COMMENT '是否中标:1-是,0-否',
|
||||||
|
`sort_order` INT NOT NULL DEFAULT 1 COMMENT '排序',
|
||||||
|
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
`created_by` VARCHAR(50) DEFAULT NULL COMMENT '创建人',
|
||||||
|
`updated_by` VARCHAR(50) DEFAULT NULL COMMENT '更新人',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_purchase_id` (`purchase_id`),
|
||||||
|
KEY `idx_purchase_bid_winner` (`purchase_id`, `is_bid_winner`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='招投标供应商明细表';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
-- 添加采购交易管理菜单
|
-- 添加招投标信息维护菜单
|
||||||
-- 注意: 执行前请确认已存在"信息维护"父菜单
|
-- 注意: 执行前请确认已存在"信息维护"父菜单
|
||||||
-- 如果不存在,请先执行以下语句创建父菜单:
|
-- 如果不存在,请先执行以下语句创建父菜单:
|
||||||
-- INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
-- INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||||
@@ -7,21 +7,21 @@
|
|||||||
-- 查询信息维护父菜单ID
|
-- 查询信息维护父菜单ID
|
||||||
SET @parent_menu_id = (SELECT menu_id FROM sys_menu WHERE menu_name='信息维护' AND parent_id=0 LIMIT 1);
|
SET @parent_menu_id = (SELECT menu_id FROM sys_menu WHERE menu_name='信息维护' AND parent_id=0 LIMIT 1);
|
||||||
|
|
||||||
-- 添加采购交易管理菜单
|
-- 添加招投标信息维护菜单
|
||||||
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
|
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
|
||||||
VALUES
|
VALUES
|
||||||
('采购交易管理', @parent_menu_id, 12, 'purchaseTransaction', 'ccdiPurchaseTransaction/index', 1, 0, 'C', '0', '0', 'ccdi:purchaseTransaction:list', 'shopping', 'admin', NOW(), '', NULL, '采购交易信息管理菜单');
|
('招投标信息维护', @parent_menu_id, 12, 'purchaseTransaction', 'ccdiPurchaseTransaction/index', 1, 0, 'C', '0', '0', 'ccdi:purchaseTransaction:list', 'shopping', 'admin', NOW(), '', NULL, '招投标信息维护菜单');
|
||||||
|
|
||||||
-- 获取刚插入的菜单ID
|
-- 获取刚插入的菜单ID
|
||||||
SET @menu_id = LAST_INSERT_ID();
|
SET @menu_id = LAST_INSERT_ID();
|
||||||
|
|
||||||
-- 添加按钮权限
|
-- 添加按钮权限
|
||||||
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) VALUES
|
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) VALUES
|
||||||
('采购交易查询', @menu_id, 1, '', '', 1, 0, 'F', '0', '0', 'ccdi:purchaseTransaction:query', '#', 'admin', NOW(), ''),
|
('招投标信息查询', @menu_id, 1, '', '', 1, 0, 'F', '0', '0', 'ccdi:purchaseTransaction:query', '#', 'admin', NOW(), ''),
|
||||||
('采购交易新增', @menu_id, 2, '', '', 1, 0, 'F', '0', '0', 'ccdi:purchaseTransaction:add', '#', 'admin', NOW(), ''),
|
('招投标信息新增', @menu_id, 2, '', '', 1, 0, 'F', '0', '0', 'ccdi:purchaseTransaction:add', '#', 'admin', NOW(), ''),
|
||||||
('采购交易修改', @menu_id, 3, '', '', 1, 0, 'F', '0', '0', 'ccdi:purchaseTransaction:edit', '#', 'admin', NOW(), ''),
|
('招投标信息修改', @menu_id, 3, '', '', 1, 0, 'F', '0', '0', 'ccdi:purchaseTransaction:edit', '#', 'admin', NOW(), ''),
|
||||||
('采购交易删除', @menu_id, 4, '', '', 1, 0, 'F', '0', '0', 'ccdi:purchaseTransaction:remove', '#', 'admin', NOW(), ''),
|
('招投标信息删除', @menu_id, 4, '', '', 1, 0, 'F', '0', '0', 'ccdi:purchaseTransaction:remove', '#', 'admin', NOW(), ''),
|
||||||
('采购交易导入', @menu_id, 5, '', '', 1, 0, 'F', '0', '0', 'ccdi:purchaseTransaction:import', '#', 'admin', NOW(), '');
|
('招投标信息导入', @menu_id, 5, '', '', 1, 0, 'F', '0', '0', 'ccdi:purchaseTransaction:import', '#', 'admin', NOW(), '');
|
||||||
|
|
||||||
-- 查询结果验证
|
-- 查询结果验证
|
||||||
SELECT
|
SELECT
|
||||||
@@ -40,5 +40,5 @@ SELECT
|
|||||||
m.create_time AS '创建时间'
|
m.create_time AS '创建时间'
|
||||||
FROM sys_menu m
|
FROM sys_menu m
|
||||||
LEFT JOIN sys_menu p ON m.parent_id = p.menu_id
|
LEFT JOIN sys_menu p ON m.parent_id = p.menu_id
|
||||||
WHERE m.menu_name = '采购交易管理' OR m.parent_id = @menu_id
|
WHERE m.menu_name = '招投标信息维护' OR m.parent_id = @menu_id
|
||||||
ORDER BY m.parent_id, m.order_num;
|
ORDER BY m.parent_id, m.order_num;
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
-- 招投标信息维护:供应商明细子表、历史数据回填与菜单改名
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `ccdi_purchase_transaction_supplier` (
|
||||||
|
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`purchase_id` VARCHAR(32) NOT NULL COMMENT '采购事项ID',
|
||||||
|
`supplier_name` VARCHAR(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '供应商名称',
|
||||||
|
`supplier_uscc` VARCHAR(18) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '供应商统一信用代码',
|
||||||
|
`contact_person` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '供应商联系人',
|
||||||
|
`contact_phone` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '供应商联系电话',
|
||||||
|
`supplier_bank_account` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '供应商银行账户',
|
||||||
|
`is_bid_winner` TINYINT NOT NULL DEFAULT 0 COMMENT '是否中标:1-是,0-否',
|
||||||
|
`sort_order` INT NOT NULL DEFAULT 1 COMMENT '排序',
|
||||||
|
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
`created_by` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
|
||||||
|
`updated_by` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_purchase_id` (`purchase_id`),
|
||||||
|
KEY `idx_purchase_bid_winner` (`purchase_id`, `is_bid_winner`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='招投标供应商明细表';
|
||||||
|
|
||||||
|
INSERT INTO ccdi_purchase_transaction_supplier (
|
||||||
|
purchase_id,
|
||||||
|
supplier_name,
|
||||||
|
supplier_uscc,
|
||||||
|
contact_person,
|
||||||
|
contact_phone,
|
||||||
|
supplier_bank_account,
|
||||||
|
is_bid_winner,
|
||||||
|
sort_order,
|
||||||
|
create_time,
|
||||||
|
update_time,
|
||||||
|
created_by,
|
||||||
|
updated_by
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
t.purchase_id,
|
||||||
|
t.supplier_name,
|
||||||
|
t.supplier_uscc,
|
||||||
|
t.contact_person,
|
||||||
|
t.contact_phone,
|
||||||
|
t.supplier_bank_account,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
IFNULL(t.create_time, NOW()),
|
||||||
|
IFNULL(t.update_time, NOW()),
|
||||||
|
t.created_by,
|
||||||
|
t.updated_by
|
||||||
|
FROM ccdi_purchase_transaction t
|
||||||
|
LEFT JOIN ccdi_purchase_transaction_supplier s
|
||||||
|
ON s.purchase_id = t.purchase_id
|
||||||
|
AND s.is_bid_winner = 1
|
||||||
|
WHERE IFNULL(t.supplier_name, '') <> ''
|
||||||
|
AND s.id IS NULL;
|
||||||
|
|
||||||
|
UPDATE sys_menu
|
||||||
|
SET menu_name = '招投标信息维护',
|
||||||
|
remark = '招投标信息维护菜单',
|
||||||
|
update_by = 'admin',
|
||||||
|
update_time = NOW()
|
||||||
|
WHERE perms = 'ccdi:purchaseTransaction:list'
|
||||||
|
OR path = 'purchaseTransaction';
|
||||||
|
|
||||||
|
UPDATE sys_menu
|
||||||
|
SET menu_name = CASE perms
|
||||||
|
WHEN 'ccdi:purchaseTransaction:query' THEN '招投标信息查询'
|
||||||
|
WHEN 'ccdi:purchaseTransaction:add' THEN '招投标信息新增'
|
||||||
|
WHEN 'ccdi:purchaseTransaction:edit' THEN '招投标信息修改'
|
||||||
|
WHEN 'ccdi:purchaseTransaction:remove' THEN '招投标信息删除'
|
||||||
|
WHEN 'ccdi:purchaseTransaction:import' THEN '招投标信息导入'
|
||||||
|
ELSE menu_name
|
||||||
|
END,
|
||||||
|
update_by = 'admin',
|
||||||
|
update_time = NOW()
|
||||||
|
WHERE perms IN (
|
||||||
|
'ccdi:purchaseTransaction:query',
|
||||||
|
'ccdi:purchaseTransaction:add',
|
||||||
|
'ccdi:purchaseTransaction:edit',
|
||||||
|
'ccdi:purchaseTransaction:remove',
|
||||||
|
'ccdi:purchaseTransaction:import'
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user