seatonwan9
2025-08-24 5fd8f535ef44ef055d91673740491b9c9177aa89
交易管理
10个文件已添加
5个文件已修改
1587 ■■■■■ 已修改文件
src/main/java/com/webmanage/controller/FileController.java 82 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/controller/OrderController.java 122 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/controller/ProductController.java 184 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/dto/FileCheckDTO.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/dto/OrderApprovalDTO.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/dto/UpdateOrderDetailDTO.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/entity/OrderApproval.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/entity/Product.java 143 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/mapper/OrderApprovalMapper.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/mapper/ProductMapper.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/service/OrderInfoService.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/service/ProductService.java 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/service/impl/OrderInfoServiceImpl.java 535 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/service/impl/ProductServiceImpl.java 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/OrderInfoMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/controller/FileController.java
@@ -61,11 +61,11 @@
    }
    /**
     * 下载文件
     * 下载文件(路径参数方式)
     */
    @GetMapping("/download/{fileName}")
    @ApiOperation("下载文件")
    public ResponseEntity<InputStreamResource> downloadFile(
    @ApiOperation("下载文件(路径参数)")
    public ResponseEntity<InputStreamResource> downloadFileByPath(
            @ApiParam("文件名") @PathVariable String fileName,
            @ApiParam("原始文件名") @RequestParam(required = false) String originalName) {
        try {
@@ -95,11 +95,60 @@
    }
    /**
     * 获取文件预览URL
     * 下载文件(查询参数方式)
     */
    @GetMapping("/download")
    @ApiOperation("下载文件(查询参数)")
    public ResponseEntity<InputStreamResource> downloadFile(
            @ApiParam("文件名") @RequestParam String fileName,
            @ApiParam("原始文件名") @RequestParam(required = false) String originalName) {
        try {
            InputStream inputStream = minioService.downloadFile(fileName);
            // 如果没有提供原始文件名,从路径中提取
            if (originalName == null || originalName.isEmpty()) {
                String[] parts = fileName.split("/");
                originalName = parts[parts.length - 1];
            }
            // 设置响应头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            headers.setContentDispositionFormData("attachment",
                    URLEncoder.encode(originalName, StandardCharsets.UTF_8.toString()));
            InputStreamResource resource = new InputStreamResource(inputStream);
            return ResponseEntity.ok()
                    .headers(headers)
                    .body(resource);
        } catch (Exception e) {
            log.error("文件下载失败: ", e);
            return ResponseEntity.notFound().build();
        }
    }
    /**
     * 获取文件预览URL(路径参数方式)
     */
    @GetMapping("/preview/{fileName}")
    @ApiOperation("获取文件预览URL")
    public Result<String> getPreviewUrl(@ApiParam("文件名") @PathVariable String fileName) {
    @ApiOperation("获取文件预览URL(路径参数)")
    public Result<String> getPreviewUrlByPath(@ApiParam("文件名") @PathVariable String fileName) {
        try {
            String previewUrl = minioService.getPreviewUrl(fileName);
            return Result.success("获取预览URL成功", previewUrl);
        } catch (Exception e) {
            log.error("获取预览URL失败: ", e);
            return Result.error("获取预览URL失败: " + e.getMessage());
        }
    }
    /**
     * 获取文件预览URL(查询参数方式)
     */
    @GetMapping("/preview")
    @ApiOperation("获取文件预览URL(查询参数)")
    public Result<String> getPreviewUrl(@ApiParam("文件名") @RequestParam String fileName) {
        try {
            String previewUrl = minioService.getPreviewUrl(fileName);
            return Result.success("获取预览URL成功", previewUrl);
@@ -125,11 +174,26 @@
    }
 
    /**
     * 删除文件
     * 删除文件(路径参数方式)
     */
    @DeleteMapping("/delete/{fileName}")
    @ApiOperation("删除文件")
    public Result<Boolean> deleteFile(@ApiParam("文件名") @PathVariable String fileName) {
    @ApiOperation("删除文件(路径参数)")
    public Result<Boolean> deleteFileByPath(@ApiParam("文件名") @PathVariable String fileName) {
        try {
            minioService.deleteFile(fileName);
            return Result.success("文件删除成功", true);
        } catch (Exception e) {
            log.error("文件删除失败: ", e);
            return Result.error("文件删除失败: " + e.getMessage());
        }
    }
    /**
     * 删除文件(查询参数方式)
     */
    @DeleteMapping("/delete")
    @ApiOperation("删除文件(查询参数)")
    public Result<Boolean> deleteFile(@ApiParam("文件名") @RequestParam String fileName) {
        try {
            minioService.deleteFile(fileName);
            return Result.success("文件删除成功", true);
src/main/java/com/webmanage/controller/OrderController.java
@@ -2,8 +2,10 @@
import com.webmanage.common.Result;
import com.webmanage.dto.CreateOrderDTO;
import com.webmanage.dto.FileCheckDTO;
import com.webmanage.dto.OrderQueryDTO;
import com.webmanage.entity.OrderInfo;
import com.webmanage.dto.UpdateOrderDetailDTO;
import com.webmanage.service.OrderInfoService;
import com.webmanage.service.TokenService;
import com.webmanage.service.OrderNoService;
@@ -19,6 +21,7 @@
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import com.webmanage.dto.OrderApprovalDTO;
/**
 * 订单管理Controller
@@ -80,6 +83,34 @@
        }
    }
    @PostMapping("/status/next")
    @ApiOperation("更新订单状态到下一个状态")
    public Result<Object> updateOrderStatusToNext(
            @ApiParam("订单ID") @RequestParam @NotBlank String orderId) {
        try {
            boolean success = orderInfoService.updateOrderStatusToNext(orderId);
            return success ? Result.success("订单状态更新到下一个状态成功") : Result.error("订单状态更新失败");
        } catch (Exception e) {
            log.error("更新订单状态到下一个状态失败", e);
            return Result.error("更新订单状态到下一个状态失败:" + e.getMessage());
        }
    }
    @PostMapping("/status/previous")
    @ApiOperation("更新订单状态到上一个状态")
    public Result<Object> updateOrderStatusToPrevious(
            @ApiParam("订单ID") @RequestParam @NotBlank String orderId) {
        try {
            boolean success = orderInfoService.updateOrderStatusToPrevious(orderId);
            return success ? Result.success("订单状态更新到上一个状态成功") : Result.error("订单状态更新失败");
        } catch (Exception e) {
            log.error("更新订单状态到上一个状态失败", e);
            return Result.error("更新订单状态到上一个状态失败:" + e.getMessage());
        }
    }
    @PostMapping("/seller/page")
    @ApiOperation("分页查询卖家订单列表")
    public Result<Object> getSellerOrderPage(@Valid @RequestBody OrderQueryDTO queryDTO) {
@@ -120,7 +151,7 @@
    @PostMapping("/attachment/upload")
    @ApiOperation("上传订单附件")
    public Result<Boolean> uploadOrderAttachment(
    public Result<Long> uploadOrderAttachment(
            @ApiParam("订单ID") @RequestParam @NotBlank String orderId,
            @ApiParam("文件名") @RequestParam @NotBlank String fileName,
            @ApiParam("原始文件名") @RequestParam String originalName,
@@ -134,11 +165,11 @@
            @ApiParam("附件类型") @RequestParam String attachmentType,
            @ApiParam("附件描述") @RequestParam String description) {
        try {
            boolean result = orderInfoService.uploadOrderAttachment(
            Long attachmentId = orderInfoService.uploadOrderAttachment(
                orderId, fileName, originalName, fileType, fileSize, fileUrl,
                bucketName, objectName, uploadUserId, uploadUserName, attachmentType, description
            );
            return result ? Result.success(true) : Result.error("上传订单附件失败");
            return Result.success("上传订单附件成功", attachmentId);
        } catch (Exception e) {
            log.error("上传订单附件失败,订单ID: {}", orderId, e);
            return Result.error("上传订单附件失败:" + e.getMessage());
@@ -198,4 +229,89 @@
            return Result.error("回复评价失败:" + e.getMessage());
        }
    }
    @PostMapping("/detail/update")
    @ApiOperation("更新订单详情")
    public Result<Boolean> updateOrderDetail(@Valid @RequestBody UpdateOrderDetailDTO updateOrderDetailDTO) {
        try {
            boolean result = orderInfoService.updateOrderDetail(updateOrderDetailDTO);
            return result ? Result.success(true) : Result.error("更新订单详情失败");
        } catch (Exception e) {
            log.error("更新订单详情失败,订单ID: {}", updateOrderDetailDTO.getOrderId(), e);
            return Result.error("更新订单详情失败:" + e.getMessage());
        }
    }
    @PostMapping("/detail/remarks/update")
    @ApiOperation("只更新订单详情的备注信息")
    public Result<Boolean> updateOrderDetailRemarksOnly(@Valid @RequestBody UpdateOrderDetailDTO.UpdateOrderDetailRemarksOnlyDTO updateOrderDetailDTO) {
        try {
            boolean result = orderInfoService.updateOrderDetailRemarksOnly(updateOrderDetailDTO);
            return result ? Result.success(true) : Result.error("更新订单详情备注失败");
        } catch (Exception e) {
            log.error("更新订单详情备注失败,订单ID: {}", updateOrderDetailDTO.getOrderId(), e);
            return Result.error("更新订单详情备注失败:" + e.getMessage());
        }
    }
    @PostMapping("/trade/checkFiles")
    @ApiOperation("文件核查")
    public Result<Boolean> checkFiles(@Valid @RequestBody FileCheckDTO fileCheckDTO) {
        try {
            boolean result = orderInfoService.checkFiles(fileCheckDTO);
            return result ? Result.success(true) : Result.error("文件核查失败");
        } catch (Exception e) {
            log.error("文件核查失败,订单ID: {}", fileCheckDTO.getOrderId(), e);
            return Result.error("文件核查失败:" + e.getMessage());
        }
    }
    @DeleteMapping("/attachment/delete/{attachmentId}")
    @ApiOperation("删除订单附件")
    public Result<Boolean> deleteOrderAttachment(@ApiParam("附件ID") @PathVariable @NotNull Long attachmentId) {
        try {
            boolean result = orderInfoService.deleteOrderAttachment(attachmentId);
            return result ? Result.success(true) : Result.error("删除订单附件失败");
        } catch (Exception e) {
            log.error("删除订单附件失败,附件ID: {}", attachmentId, e);
            return Result.error("删除订单附件失败:" + e.getMessage());
        }
    }
    @PostMapping("/trade/approve")
    @ApiOperation("审批通过")
    public Result<Boolean> approveOrder(@Valid @RequestBody OrderApprovalDTO orderApprovalDTO) {
        try {
            boolean result = orderInfoService.approveOrder(orderApprovalDTO);
            return result ? Result.success(true) : Result.error("审批通过失败");
        } catch (Exception e) {
            log.error("审批通过失败,订单ID: {}", orderApprovalDTO.getOrderId(), e);
            return Result.error("审批通过失败:" + e.getMessage());
        }
    }
    @GetMapping("/agreement/check/{orderId}")
    @ApiOperation("检查订单是否包含协议类型的子订单")
    public Result<Boolean> checkAgreementPriceType(
            @ApiParam("订单ID") @PathVariable @NotBlank String orderId) {
        try {
            boolean hasAgreement = orderInfoService.hasAgreementPriceType(orderId);
            return Result.success(hasAgreement);
        } catch (Exception e) {
            log.error("检查订单协议类型失败,订单ID: {}", orderId, e);
            return Result.error("检查订单协议类型失败:" + e.getMessage());
        }
    }
    @DeleteMapping("/cancel/{orderId}")
    @ApiOperation("取消订单")
    public Result<Boolean> cancelOrder(@ApiParam("订单ID") @PathVariable @NotBlank String orderId) {
        try {
            boolean result = orderInfoService.cancelOrder(orderId);
            return result ? Result.success(true) : Result.error("取消订单失败");
        } catch (Exception e) {
            log.error("取消订单失败,订单ID: {}", orderId, e);
            return Result.error("取消订单失败:" + e.getMessage());
        }
    }
}
src/main/java/com/webmanage/controller/ProductController.java
New file
@@ -0,0 +1,184 @@
package com.webmanage.controller;
import com.webmanage.common.Result;
import com.webmanage.entity.Product;
import com.webmanage.service.ProductService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
 * 产品管理控制器
 *
 * @author webmanage
 * @date 2024-08-07
 */
@Slf4j
@RestController
@RequestMapping("/product")
@Api(tags = "产品管理")
public class ProductController {
    @Autowired
    private ProductService productService;
    /**
     * 获取产品列表
     */
    @GetMapping("/list")
    @ApiOperation("获取产品列表")
    public Result<List<Product>> getProductList(
            @ApiParam("产品名称") @RequestParam(required = false) String productName,
            @ApiParam("产品类型") @RequestParam(required = false) String productType,
            @ApiParam("产品状态") @RequestParam(required = false) String status,
            @ApiParam("提供者ID") @RequestParam(required = false) Long providerId) {
        try {
            List<Product> productList = productService.getProductList(productName, productType, status, providerId);
            return Result.success(productList);
        } catch (Exception e) {
            log.error("获取产品列表失败", e);
            return Result.error("获取产品列表失败: " + e.getMessage());
        }
    }
    /**
     * 根据ID获取产品详情
     */
    @GetMapping("/{id}")
    @ApiOperation("根据ID获取产品详情")
    public Result<Product> getProductById(@ApiParam("产品ID") @PathVariable Long id) {
        try {
            Product product = productService.getProductById(id);
            if (product == null) {
                return Result.error("产品不存在");
            }
            return Result.success(product);
        } catch (Exception e) {
            log.error("获取产品详情失败", e);
            return Result.error("获取产品详情失败: " + e.getMessage());
        }
    }
    /**
     * 创建产品
     */
    @PostMapping
    @ApiOperation("创建产品")
    public Result<Boolean> createProduct(@RequestBody Product product) {
        try {
            boolean result = productService.createProduct(product);
            if (result) {
                return Result.success("产品创建成功", true);
            } else {
                return Result.error("产品创建失败");
            }
        } catch (Exception e) {
            log.error("创建产品失败", e);
            return Result.error("创建产品失败: " + e.getMessage());
        }
    }
    /**
     * 更新产品信息
     */
    @PutMapping("/{id}")
    @ApiOperation("更新产品信息")
    public Result<Boolean> updateProduct(@ApiParam("产品ID") @PathVariable Long id, @RequestBody Product product) {
        try {
            product.setId(id);
            boolean result = productService.updateProduct(product);
            if (result) {
                return Result.success("产品更新成功", true);
            } else {
                return Result.error("产品更新失败");
            }
        } catch (Exception e) {
            log.error("更新产品失败", e);
            return Result.error("更新产品失败: " + e.getMessage());
        }
    }
    /**
     * 删除产品
     */
    @DeleteMapping("/{id}")
    @ApiOperation("删除产品")
    public Result<Boolean> deleteProduct(@ApiParam("产品ID") @PathVariable Long id) {
        try {
            boolean result = productService.deleteProduct(id);
            if (result) {
                return Result.success("产品删除成功", true);
            } else {
                return Result.error("产品删除失败");
            }
        } catch (Exception e) {
            log.error("删除产品失败", e);
            return Result.error("删除产品失败: " + e.getMessage());
        }
    }
    /**
     * 更新产品状态
     */
    @PutMapping("/{id}/status")
    @ApiOperation("更新产品状态")
    public Result<Boolean> updateProductStatus(
            @ApiParam("产品ID") @PathVariable Long id,
            @ApiParam("产品状态") @RequestParam String status) {
        try {
            boolean result = productService.updateProductStatus(id, status);
            if (result) {
                return Result.success("产品状态更新成功", true);
            } else {
                return Result.error("产品状态更新失败");
            }
        } catch (Exception e) {
            log.error("更新产品状态失败", e);
            return Result.error("更新产品状态失败: " + e.getMessage());
        }
    }
    /**
     * 更新产品审核状态
     */
    @PutMapping("/{id}/audit-status")
    @ApiOperation("更新产品审核状态")
    public Result<Boolean> updateProductAuditStatus(
            @ApiParam("产品ID") @PathVariable Long id,
            @ApiParam("审核状态") @RequestParam String auditStatus) {
        try {
            boolean result = productService.updateProductAuditStatus(id, auditStatus);
            if (result) {
                return Result.success("产品审核状态更新成功", true);
            } else {
                return Result.error("产品审核状态更新失败");
            }
        } catch (Exception e) {
            log.error("更新产品审核状态失败", e);
            return Result.error("更新产品审核状态失败: " + e.getMessage());
        }
    }
    /**
     * 检查产品编码是否存在
     */
    @GetMapping("/check-code")
    @ApiOperation("检查产品编码是否存在")
    public Result<Boolean> checkProductCodeExists(
            @ApiParam("产品编码") @RequestParam String productCode,
            @ApiParam("排除的产品ID") @RequestParam(required = false) Long excludeId) {
        try {
            boolean exists = productService.checkProductCodeExists(productCode, excludeId);
            return Result.success(exists);
        } catch (Exception e) {
            log.error("检查产品编码失败", e);
            return Result.error("检查产品编码失败: " + e.getMessage());
        }
    }
}
src/main/java/com/webmanage/dto/FileCheckDTO.java
New file
@@ -0,0 +1,35 @@
package com.webmanage.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
 * 文件核查DTO
 */
@Data
@ApiModel(value = "FileCheckDTO", description = "文件核查")
public class FileCheckDTO {
    @ApiModelProperty("订单ID")
    @NotBlank(message = "订单ID不能为空")
    private String orderId;
    @ApiModelProperty("是否通过")
    @NotNull(message = "审批结果不能为空")
    private Boolean isApprove;
    @ApiModelProperty("审批意见")
    private String approvalOpinion;
    @ApiModelProperty("审批人ID")
    @NotNull(message = "审批人ID不能为空")
    private Long approverId;
    @ApiModelProperty("审批人姓名")
    @NotBlank(message = "审批人姓名不能为空")
    private String approverName;
}
src/main/java/com/webmanage/dto/OrderApprovalDTO.java
New file
@@ -0,0 +1,37 @@
package com.webmanage.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
@ApiModel("订单审批DTO")
public class OrderApprovalDTO {
    @ApiModelProperty("订单ID")
    @NotBlank(message = "订单ID不能为空")
    private String orderId;
    @ApiModelProperty("审批意见")
    @NotBlank(message = "审批意见不能为空")
    private String approvalOpinion;
    @ApiModelProperty("审批人ID")
    @NotNull(message = "审批人ID不能为空")
    private Long approverId;
    @ApiModelProperty("审批人姓名")
    @NotBlank(message = "审批人姓名不能为空")
    private String approverName;
    @ApiModelProperty("审批类型:审批/授权")
    @NotBlank(message = "审批类型不能为空")
    private String approvalType;
    @ApiModelProperty("审批结果:通过/驳回")
    @NotBlank(message = "审批结果不能为空")
    private String approvalResult;
}
src/main/java/com/webmanage/dto/UpdateOrderDetailDTO.java
New file
@@ -0,0 +1,56 @@
package com.webmanage.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
 * 更新订单详情DTO
 */
@Data
@ApiModel(value = "UpdateOrderDetailDTO", description = "更新订单详情")
public class UpdateOrderDetailDTO {
    @ApiModelProperty("订单ID")
    @NotBlank(message = "订单ID不能为空")
    private String orderId;
    @ApiModelProperty("订单状态")
    @NotBlank(message = "订单状态不能为空")
    private String orderStatus;
    @ApiModelProperty("订单详情列表")
    @NotNull(message = "订单详情列表不能为空")
    private List<UpdateOrderDetailItemDTO> orderDetails;
    @Data
    @ApiModel(value = "UpdateOrderDetailItemDTO", description = "更新订单详情项")
    public static class UpdateOrderDetailItemDTO {
        @ApiModelProperty("订单详情ID")
        @NotNull(message = "订单详情ID不能为空")
        private Long id;
        @ApiModelProperty("备注")
        private String remarks;
    }
    /**
     * 只更新订单详情备注的DTO(不更新订单状态)
     */
    @Data
    @ApiModel(value = "UpdateOrderDetailRemarksOnlyDTO", description = "只更新订单详情备注")
    public static class UpdateOrderDetailRemarksOnlyDTO {
        @ApiModelProperty("订单ID")
        @NotBlank(message = "订单ID不能为空")
        private String orderId;
        @ApiModelProperty("订单详情列表")
        @NotNull(message = "订单详情列表不能为空")
        private List<UpdateOrderDetailItemDTO> orderDetails;
    }
}
src/main/java/com/webmanage/entity/OrderApproval.java
New file
@@ -0,0 +1,68 @@
package com.webmanage.entity;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
/**
 * 订单审批记录实体类
 */
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("order_approval")
@ApiModel(value = "OrderApproval", description = "订单审批记录")
public class OrderApproval {
    @ApiModelProperty("主键ID")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    @ApiModelProperty("关联订单ID")
    @TableField("order_id")
    private String orderId;
    @ApiModelProperty("审批步骤")
    @TableField("approval_step")
    private String approvalStep;
    @ApiModelProperty("审批类型:审批/授权")
    @TableField("approval_type")
    private String approvalType;
    @ApiModelProperty("审批结果:通过/驳回")
    @TableField("approval_result")
    private String approvalResult;
    @ApiModelProperty("审批人ID")
    @TableField("approver_id")
    private Long approverId;
    @ApiModelProperty("审批人姓名")
    @TableField("approver_name")
    private String approverName;
    @ApiModelProperty("审批意见")
    @TableField("approval_opinion")
    private String approvalOpinion;
    @ApiModelProperty("审批时间")
    @TableField("approval_time")
    private LocalDateTime approvalTime;
    @ApiModelProperty("创建时间")
    @TableField(value = "created_at", fill = FieldFill.INSERT)
    private LocalDateTime createdAt;
    @ApiModelProperty("更新时间")
    @TableField(value = "updated_at", fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updatedAt;
    @ApiModelProperty("逻辑删除:1-已删除,0-未删除")
    @TableLogic
    @TableField("deleted")
    private Integer deleted;
}
src/main/java/com/webmanage/entity/Product.java
New file
@@ -0,0 +1,143 @@
package com.webmanage.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
 * 产品实体
 *
 * @author webmanage
 * @date 2024-08-07
 */
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("product")
public class Product implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 主键ID
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * 产品名称
     */
    @TableField("product_name")
    private String productName;
    /**
     * 产品编码
     */
    @TableField("product_code")
    private String productCode;
    /**
     * 产品类型
     */
    @TableField("product_type")
    private String productType;
    /**
     * 产品分类
     */
    @TableField("category")
    private String category;
    /**
     * 产品描述
     */
    @TableField("description")
    private String description;
    /**
     * 提供者ID
     */
    @TableField("provider_id")
    private Long providerId;
    /**
     * 提供者名称
     */
    @TableField("provider_name")
    private String providerName;
    /**
     * 提供者类型
     */
    @TableField("provider_type")
    private String providerType;
    /**
     * 产品状态
     */
    @TableField("status")
    private String status;
    /**
     * 审核状态
     */
    @TableField("audit_status")
    private String auditStatus;
    /**
     * 产品标签
     */
    @TableField("tags")
    private String tags;
    /**
     * 封面图片
     */
    @TableField("cover_image")
    private String coverImage;
    /**
     * 演示地址
     */
    @TableField("demo_url")
    private String demoUrl;
    /**
     * 文档地址
     */
    @TableField("doc_url")
    private String docUrl;
    /**
     * 创建时间
     */
    @TableField(value = "created_at", fill = FieldFill.INSERT)
    private LocalDateTime createdAt;
    /**
     * 更新时间
     */
    @TableField(value = "updated_at", fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updatedAt;
    /**
     * 创建人ID
     */
    @TableField("created_by")
    private Long createdBy;
    /**
     * 更新人ID
     */
    @TableField("updated_by")
    private Long updatedBy;
    /**
     * 逻辑删除
     */
    @TableLogic
    @TableField("deleted")
    private Integer deleted;
}
src/main/java/com/webmanage/mapper/OrderApprovalMapper.java
New file
@@ -0,0 +1,12 @@
package com.webmanage.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.webmanage.entity.OrderApproval;
import org.apache.ibatis.annotations.Mapper;
/**
 * 订单审批记录Mapper接口
 */
@Mapper
public interface OrderApprovalMapper extends BaseMapper<OrderApproval> {
}
src/main/java/com/webmanage/mapper/ProductMapper.java
New file
@@ -0,0 +1,58 @@
package com.webmanage.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.webmanage.entity.Product;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * 产品Mapper接口
 *
 * @author webmanage
 * @date 2024-08-07
 */
@Mapper
public interface ProductMapper extends BaseMapper<Product> {
    /**
     * 根据条件查询产品列表
     *
     * @param productName 产品名称(模糊查询)
     * @param productType 产品类型
     * @param status 产品状态
     * @param providerId 提供者ID
     * @return 产品列表
     */
    List<Product> selectProductList(@Param("productName") String productName,
                                   @Param("productType") String productType,
                                   @Param("status") String status,
                                   @Param("providerId") Long providerId);
    /**
     * 根据ID查询产品详情
     *
     * @param id 产品ID
     * @return 产品详情
     */
    Product selectProductById(@Param("id") Long id);
    /**
     * 更新产品状态
     *
     * @param id 产品ID
     * @param status 新状态
     * @return 更新结果
     */
    int updateProductStatus(@Param("id") Long id, @Param("status") String status);
    /**
     * 更新产品审核状态
     *
     * @param id 产品ID
     * @param auditStatus 新审核状态
     * @return 更新结果
     */
    int updateProductAuditStatus(@Param("id") Long id, @Param("auditStatus") String auditStatus);
}
src/main/java/com/webmanage/service/OrderInfoService.java
@@ -3,9 +3,12 @@
import com.baomidou.mybatisplus.extension.service.IService;
import com.webmanage.common.PageResult;
import com.webmanage.dto.CreateOrderDTO;
import com.webmanage.dto.FileCheckDTO;
import com.webmanage.dto.OrderQueryDTO;
import com.webmanage.dto.UpdateOrderDetailDTO;
import com.webmanage.entity.OrderInfo;
import com.webmanage.vo.OrderDetailVO;
import com.webmanage.dto.OrderApprovalDTO;
/**
 * 订单信息Service接口
@@ -40,7 +43,7 @@
    /**
     * 上传订单附件
     */
    boolean uploadOrderAttachment(String orderId, String fileName, String originalName,
    Long uploadOrderAttachment(String orderId, String fileName, String originalName,
                                String fileType, Long fileSize, String fileUrl, 
                                String bucketName, String objectName, Long uploadUserId, 
                                String uploadUserName, String attachmentType, String description);
@@ -54,6 +57,27 @@
                             Boolean isAnonymous);
    /**
     * 更新订单状态到下一个状态
     * @param orderId 订单ID
     * @return 是否更新成功
     */
    boolean updateOrderStatusToNext(String orderId);
    /**
     * 删除订单附件
     * @param attachmentId 附件ID
     * @return 是否删除成功
     */
    boolean deleteOrderAttachment(Long attachmentId);
    /**
     * 更新订单状态到上一个状态
     * @param orderId 订单ID
     * @return 是否更新成功
     */
    boolean updateOrderStatusToPrevious(String orderId);
    /**
     * 交易确认
     */
    boolean confirmTransaction(String orderId, Long userId);
@@ -62,4 +86,40 @@
     * 回复评价
     */
    boolean replyEvaluation(Long evaluationId, String replyContent, Long replyUserId);
    /**
     * 更新订单详情(包含订单状态和详情备注)
     */
    boolean updateOrderDetail(UpdateOrderDetailDTO updateOrderDetailDTO);
    /**
     * 文件核查
     */
    boolean checkFiles(FileCheckDTO fileCheckDTO);
    /**
     * 审批通过
     */
    boolean approveOrder(OrderApprovalDTO orderApprovalDTO);
    /**
     * 检查订单是否包含协议类型的子订单
     * @param orderId 订单ID
     * @return 是否包含协议类型子订单
     */
    boolean hasAgreementPriceType(String orderId);
    /**
     * 只更新订单详情的备注信息(不更新订单状态)
     * @param updateOrderDetailDTO 更新订单详情DTO
     * @return 是否更新成功
     */
    boolean updateOrderDetailRemarksOnly(UpdateOrderDetailDTO.UpdateOrderDetailRemarksOnlyDTO updateOrderDetailDTO);
    /**
     * 取消订单
     * @param orderId 订单ID
     * @return 是否取消成功
     */
    boolean cancelOrder(String orderId);
}
src/main/java/com/webmanage/service/ProductService.java
New file
@@ -0,0 +1,85 @@
package com.webmanage.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.webmanage.entity.Product;
import java.util.List;
/**
 * 产品服务接口
 *
 * @author webmanage
 * @date 2024-08-07
 */
public interface ProductService extends IService<Product> {
    /**
     * 获取产品列表
     *
     * @param productName 产品名称(模糊查询)
     * @param productType 产品类型
     * @param status 产品状态
     * @param providerId 提供者ID
     * @return 产品列表
     */
    List<Product> getProductList(String productName, String productType, String status, Long providerId);
    /**
     * 根据ID获取产品详情
     *
     * @param id 产品ID
     * @return 产品详情
     */
    Product getProductById(Long id);
    /**
     * 创建产品
     *
     * @param product 产品信息
     * @return 创建结果
     */
    boolean createProduct(Product product);
    /**
     * 更新产品信息
     *
     * @param product 产品信息
     * @return 更新结果
     */
    boolean updateProduct(Product product);
    /**
     * 删除产品
     *
     * @param id 产品ID
     * @return 删除结果
     */
    boolean deleteProduct(Long id);
    /**
     * 更新产品状态
     *
     * @param id 产品ID
     * @param status 新状态
     * @return 更新结果
     */
    boolean updateProductStatus(Long id, String status);
    /**
     * 更新产品审核状态
     *
     * @param id 产品ID
     * @param auditStatus 新审核状态
     * @return 更新结果
     */
    boolean updateProductAuditStatus(Long id, String auditStatus);
    /**
     * 检查产品编码是否存在
     *
     * @param productCode 产品编码
     * @param excludeId 排除的产品ID(用于更新时检查)
     * @return 是否存在
     */
    boolean checkProductCodeExists(String productCode, Long excludeId);
}
src/main/java/com/webmanage/service/impl/OrderInfoServiceImpl.java
@@ -8,17 +8,23 @@
import com.webmanage.common.PageResult;
import com.webmanage.dto.CreateOrderDTO;
import com.webmanage.dto.CreateOrderItemDTO;
import com.webmanage.dto.FileCheckDTO;
import com.webmanage.dto.OrderApprovalDTO;
import com.webmanage.dto.OrderQueryDTO;
import com.webmanage.dto.UpdateOrderDetailDTO;
import com.webmanage.entity.OrderApproval;
import com.webmanage.entity.OrderAttachment;
import com.webmanage.entity.OrderDetail;
import com.webmanage.entity.OrderEvaluation;
import com.webmanage.entity.OrderInfo;
import com.webmanage.mapper.OrderApprovalMapper;
import com.webmanage.mapper.OrderAttachmentMapper;
import com.webmanage.mapper.OrderDetailMapper;
import com.webmanage.mapper.OrderEvaluationMapper;
import com.webmanage.mapper.OrderInfoMapper;
import com.webmanage.service.OrderInfoService;
import com.webmanage.service.OrderNoService;
import com.webmanage.service.MinioService;
import com.webmanage.vo.OrderAttachmentVO;
import com.webmanage.vo.OrderDetailItemVO;
import com.webmanage.vo.OrderDetailVO;
@@ -53,7 +59,13 @@
    private OrderEvaluationMapper orderEvaluationMapper;
    @Resource
    private OrderApprovalMapper orderApprovalMapper;
    @Resource
    private OrderNoService orderNoService;
    @Resource
    private MinioService minioService;
    @Override
    public PageResult<OrderInfo> getBuyerOrderPage(OrderQueryDTO queryDTO) {
@@ -90,8 +102,8 @@
    @Override
    public PageResult<OrderInfo> getSellerOrderPage(OrderQueryDTO queryDTO) {
        // 参数校验
        if (queryDTO.getUserId() == null) {
            throw new BusinessException("用户ID不能为空");
        if (queryDTO.getProviderId() == null) {
            throw new BusinessException("提供者ID不能为空");
        }
        // 创建分页对象
@@ -99,7 +111,7 @@
        // 执行分页查询
        IPage<OrderInfo> result = baseMapper.selectSellerOrderPage(
            page, queryDTO.getUserId(), queryDTO.getOrderStatus(), queryDTO.getPaymentStatus(),
            page, queryDTO.getProviderId(), queryDTO.getOrderStatus(), queryDTO.getPaymentStatus(),
            queryDTO.getProductName(), queryDTO.getOrderId(),
            queryDTO.getApplyTimeStart() != null ? queryDTO.getApplyTimeStart().toString() : null,
            queryDTO.getApplyTimeEnd() != null ? queryDTO.getApplyTimeEnd().toString() : null,
@@ -219,7 +231,11 @@
        orderInfo.setUserId(createOrderDTO.getUserId());
        orderInfo.setUnitId(createOrderDTO.getUnitId());
        orderInfo.setApplyTime(LocalDateTime.now());
        orderInfo.setOrderStatus("待审批");
        // 根据订单明细中是否包含协议价格类型来决定初始状态
        String initialStatus = determineInitialOrderStatus(createOrderDTO.getItems());
        orderInfo.setOrderStatus(initialStatus);
        orderInfo.setTotalAmount(createOrderDTO.getTotalAmount() != null ? createOrderDTO.getTotalAmount() : totalAmount);
        orderInfo.setPaymentType(createOrderDTO.getPaymentType());
        orderInfo.setPaymentStatus("未支付");
@@ -263,7 +279,7 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean uploadOrderAttachment(String orderId, String fileName, String originalName,
    public Long uploadOrderAttachment(String orderId, String fileName, String originalName,
                                      String fileType, Long fileSize, String fileUrl, 
                                      String bucketName, String objectName, Long uploadUserId, 
                                      String uploadUserName, String attachmentType, String description) {
@@ -296,8 +312,13 @@
        attachment.setAttachmentType(attachmentType);
        attachment.setDescription(description);
        // 保存附件
        return orderAttachmentMapper.insert(attachment) > 0;
        // 保存附件并返回附件ID
        int result = orderAttachmentMapper.insert(attachment);
        if (result > 0) {
            return attachment.getId();
        } else {
            throw new BusinessException("保存附件失败");
        }
    }
    @Override
@@ -419,4 +440,504 @@
        // 保存评价
        return orderEvaluationMapper.updateById(evaluation) > 0;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOrderDetail(UpdateOrderDetailDTO updateOrderDetailDTO) {
        // 参数校验
        if (updateOrderDetailDTO == null) {
            throw new BusinessException("更新参数不能为空");
        }
        if (!StringUtils.hasText(updateOrderDetailDTO.getOrderId())) {
            throw new BusinessException("订单ID不能为空");
        }
        if (!StringUtils.hasText(updateOrderDetailDTO.getOrderStatus())) {
            throw new BusinessException("订单状态不能为空");
        }
        if (CollectionUtils.isEmpty(updateOrderDetailDTO.getOrderDetails())) {
            throw new BusinessException("订单详情列表不能为空");
        }
        // 查询订单信息
        OrderInfo orderInfo = this.getById(updateOrderDetailDTO.getOrderId());
        if (orderInfo == null) {
            throw new BusinessException("订单不存在");
        }
        // 更新订单状态
        orderInfo.setOrderStatus(updateOrderDetailDTO.getOrderStatus());
        orderInfo.setUpdatedAt(LocalDateTime.now());
        int orderUpdated = this.baseMapper.updateById(orderInfo);
        if (orderUpdated <= 0) {
            throw new BusinessException("更新订单状态失败");
        }
        // 更新订单详情备注
        for (UpdateOrderDetailDTO.UpdateOrderDetailItemDTO itemDTO : updateOrderDetailDTO.getOrderDetails()) {
            if (itemDTO.getId() == null) {
                continue;
            }
            OrderDetail orderDetail = orderDetailMapper.selectById(itemDTO.getId());
            if (orderDetail == null) {
                log.warn("订单详情不存在,ID: {}", itemDTO.getId());
                continue;
            }
            // 更新备注
            orderDetail.setRemarks(itemDTO.getRemarks());
            orderDetail.setUpdatedAt(LocalDateTime.now());
            int detailUpdated = orderDetailMapper.updateById(orderDetail);
            if (detailUpdated <= 0) {
                log.warn("更新订单详情失败,ID: {}", itemDTO.getId());
            }
        }
        return true;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean checkFiles(FileCheckDTO fileCheckDTO) {
        // 参数校验
        if (fileCheckDTO == null) {
            throw new BusinessException("文件核查参数不能为空");
        }
        if (!StringUtils.hasText(fileCheckDTO.getOrderId())) {
            throw new BusinessException("订单ID不能为空");
        }
        if (fileCheckDTO.getIsApprove() == null) {
            throw new BusinessException("审批结果不能为空");
        }
        if (fileCheckDTO.getApproverId() == null) {
            throw new BusinessException("审批人ID不能为空");
        }
        if (!StringUtils.hasText(fileCheckDTO.getApproverName())) {
            throw new BusinessException("审批人姓名不能为空");
        }
        // 查询订单信息
        OrderInfo orderInfo = this.getById(fileCheckDTO.getOrderId());
        if (orderInfo == null) {
            throw new BusinessException("订单不存在");
        }
        // 检查订单状态是否为"待授权"
        if (!"待授权".equals(orderInfo.getOrderStatus())) {
            throw new BusinessException("订单状态不正确,当前状态为:" + orderInfo.getOrderStatus());
        }
        // 更新订单状态
        if (fileCheckDTO.getIsApprove()) {
            // 通过:更新为"待交易确认"
            orderInfo.setOrderStatus("待交易确认");
        } else {
            // 驳回:更新为"待上传文件"(需要重新上传)
            orderInfo.setOrderStatus("待上传文件");
        }
        orderInfo.setUpdatedAt(LocalDateTime.now());
        // 保存订单
        int updated = this.baseMapper.updateById(orderInfo);
        if (updated <= 0) {
            throw new BusinessException("更新订单状态失败");
        }
        log.info("文件核查完成,订单ID: {}, 审批结果: {}, 审批人: {}, 审批意见: {}",
                fileCheckDTO.getOrderId(),
                fileCheckDTO.getIsApprove() ? "通过" : "驳回",
                fileCheckDTO.getApproverName(),
                fileCheckDTO.getApprovalOpinion());
        return true;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean approveOrder(OrderApprovalDTO orderApprovalDTO) {
        // 参数校验
        if (orderApprovalDTO == null) {
            throw new BusinessException("审批参数不能为空");
        }
        if (!StringUtils.hasText(orderApprovalDTO.getOrderId())) {
            throw new BusinessException("订单ID不能为空");
        }
        if (!StringUtils.hasText(orderApprovalDTO.getApprovalOpinion())) {
            throw new BusinessException("审批意见不能为空");
        }
        if (orderApprovalDTO.getApproverId() == null) {
            throw new BusinessException("审批人ID不能为空");
        }
        if (!StringUtils.hasText(orderApprovalDTO.getApproverName())) {
            throw new BusinessException("审批人姓名不能为空");
        }
        if (!StringUtils.hasText(orderApprovalDTO.getApprovalType())) {
            throw new BusinessException("审批类型不能为空");
        }
        if (!StringUtils.hasText(orderApprovalDTO.getApprovalResult())) {
            throw new BusinessException("审批结果不能为空");
        }
        // 查询订单信息
        OrderInfo orderInfo = this.getById(orderApprovalDTO.getOrderId());
        if (orderInfo == null) {
            throw new BusinessException("订单不存在");
        }
        // 创建审批记录
        OrderApproval orderApproval = new OrderApproval();
        orderApproval.setOrderId(orderApprovalDTO.getOrderId());
        orderApproval.setApprovalStep("审批授权");
        orderApproval.setApprovalType(orderApprovalDTO.getApprovalType());
        orderApproval.setApprovalResult(orderApprovalDTO.getApprovalResult());
        orderApproval.setApproverId(orderApprovalDTO.getApproverId());
        orderApproval.setApproverName(orderApprovalDTO.getApproverName());
        orderApproval.setApprovalOpinion(orderApprovalDTO.getApprovalOpinion());
        orderApproval.setApprovalTime(LocalDateTime.now());
        // 插入审批记录
        int insertResult = orderApprovalMapper.insert(orderApproval);
        if (insertResult <= 0) {
            throw new BusinessException("插入审批记录失败");
        }
        log.info("审批记录添加成功,订单ID: {}, 审批类型: {}, 审批结果: {}, 审批人: {}, 审批意见: {}",
                orderApprovalDTO.getOrderId(),
                orderApprovalDTO.getApprovalType(),
                orderApprovalDTO.getApprovalResult(),
                orderApprovalDTO.getApproverName(),
                orderApprovalDTO.getApprovalOpinion());
        return true;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOrderStatusToNext(String orderId) {
        // 参数校验
        if (!StringUtils.hasText(orderId)) {
            throw new BusinessException("订单ID不能为空");
        }
        // 查询订单信息
        OrderInfo orderInfo = this.getById(orderId);
        if (orderInfo == null) {
            throw new BusinessException("订单不存在");
        }
        // 获取当前状态
        String currentStatus = orderInfo.getOrderStatus();
        if (!StringUtils.hasText(currentStatus)) {
            throw new BusinessException("订单当前状态为空");
        }
        // 获取下一个状态
        String nextStatus = getNextOrderStatus(currentStatus);
        if (nextStatus == null) {
            throw new BusinessException("当前状态 " + currentStatus + " 已是最终状态,无法继续流转");
        }
        // 更新订单状态
        orderInfo.setOrderStatus(nextStatus);
        orderInfo.setUpdatedAt(LocalDateTime.now());
        int updated = this.baseMapper.updateById(orderInfo);
        if (updated <= 0) {
            throw new BusinessException("更新订单状态失败");
        }
        log.info("订单状态更新成功,订单ID: {}, 从 {} 更新为 {}", orderId, currentStatus, nextStatus);
        return true;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOrderStatusToPrevious(String orderId) {
        // 参数校验
        if (!StringUtils.hasText(orderId)) {
            throw new BusinessException("订单ID不能为空");
        }
        // 查询订单信息
        OrderInfo orderInfo = this.getById(orderId);
        if (orderInfo == null) {
            throw new BusinessException("订单不存在");
        }
        // 获取当前状态
        String currentStatus = orderInfo.getOrderStatus();
        if (!StringUtils.hasText(currentStatus)) {
            throw new BusinessException("订单当前状态为空");
        }
        // 获取上一个状态
        String previousStatus = getPreviousOrderStatus(currentStatus);
        if (previousStatus == null) {
            throw new BusinessException("当前状态 " + currentStatus + " 已是初始状态,无法回退");
        }
        // 更新订单状态
        orderInfo.setOrderStatus(previousStatus);
        orderInfo.setUpdatedAt(LocalDateTime.now());
        int updated = this.baseMapper.updateById(orderInfo);
        if (updated <= 0) {
            throw new BusinessException("更新订单状态失败");
        }
        log.info("订单状态更新成功,订单ID: {}, 从 {} 回退为 {}", orderId, currentStatus, previousStatus);
        return true;
    }
    /**
     * 根据订单明细确定初始订单状态
     * @param items 订单明细列表
     * @return 初始状态
     */
    private String determineInitialOrderStatus(List<CreateOrderItemDTO> items) {
        // 检查是否有价格类型为"协议"的明细项
        boolean hasAgreementPrice = items.stream()
                .anyMatch(item -> "协议".equals(item.getPriceType()));
        // 如果有协议价格,从"待上传文件"开始,否则从"待授权"开始
        String initialStatus = hasAgreementPrice ? "待上传文件" : "待授权";
        log.info("订单初始状态确定为: {}, 是否包含协议价格: {}", initialStatus, hasAgreementPrice);
        return initialStatus;
    }
    /**
     * 获取下一个订单状态
     * @param currentStatus 当前状态
     * @return 下一个状态,如果是最终状态则返回null
     */
    private String getNextOrderStatus(String currentStatus) {
        switch (currentStatus) {
            case "待上传文件":
                return "待授权";
            case "待授权":
                return "待交易确认";
            case "待交易确认":
                return "已完成";
            case "已完成":
                return "已评价";
            case "已评价":
                return null; // 最终状态
            default:
                throw new BusinessException("未知的订单状态:" + currentStatus);
        }
    }
    /**
     * 获取上一个订单状态
     * @param currentStatus 当前状态
     * @return 上一个状态,如果是初始状态则返回null
     */
    private String getPreviousOrderStatus(String currentStatus) {
        switch (currentStatus) {
            case "待上传文件":
                return null; // 初始状态
            case "待授权":
                return "待上传文件";
            case "待交易确认":
                return "待授权";
            case "已完成":
                return "待交易确认";
            case "已评价":
                return "已完成";
            default:
                throw new BusinessException("未知的订单状态:" + currentStatus);
        }
    }
    @Override
    public boolean hasAgreementPriceType(String orderId) {
        // 参数校验
        if (!StringUtils.hasText(orderId)) {
            throw new BusinessException("订单ID不能为空");
        }
        // 查询订单详情,检查是否有价格类型为"协议"的子订单
        QueryWrapper<OrderDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_id", orderId);
        queryWrapper.eq("price_type", "协议");
        queryWrapper.eq("deleted", 0);
        List<OrderDetail> agreementDetails = orderDetailMapper.selectList(queryWrapper);
        boolean hasAgreement = !CollectionUtils.isEmpty(agreementDetails);
        log.info("检查订单协议类型,订单ID: {}, 是否包含协议类型: {}", orderId, hasAgreement);
        return hasAgreement;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOrderDetailRemarksOnly(UpdateOrderDetailDTO.UpdateOrderDetailRemarksOnlyDTO updateOrderDetailDTO) {
        // 参数校验
        if (updateOrderDetailDTO == null) {
            throw new BusinessException("更新参数不能为空");
        }
        if (!StringUtils.hasText(updateOrderDetailDTO.getOrderId())) {
            throw new BusinessException("订单ID不能为空");
        }
        if (CollectionUtils.isEmpty(updateOrderDetailDTO.getOrderDetails())) {
            throw new BusinessException("订单详情列表不能为空");
        }
        // 查询订单信息(验证订单存在)
        OrderInfo orderInfo = this.getById(updateOrderDetailDTO.getOrderId());
        if (orderInfo == null) {
            throw new BusinessException("订单不存在");
        }
        // 只更新订单详情备注,不更新订单状态
        for (UpdateOrderDetailDTO.UpdateOrderDetailItemDTO itemDTO : updateOrderDetailDTO.getOrderDetails()) {
            if (itemDTO.getId() == null) {
                continue;
            }
            OrderDetail orderDetail = orderDetailMapper.selectById(itemDTO.getId());
            if (orderDetail == null) {
                log.warn("订单详情不存在,ID: {}", itemDTO.getId());
                continue;
            }
            // 更新备注
            orderDetail.setRemarks(itemDTO.getRemarks());
            orderDetail.setUpdatedAt(LocalDateTime.now());
            int detailUpdated = orderDetailMapper.updateById(orderDetail);
            if (detailUpdated <= 0) {
                log.warn("更新订单详情失败,ID: {}", itemDTO.getId());
            }
        }
        log.info("订单详情备注更新成功,订单ID: {}", updateOrderDetailDTO.getOrderId());
        return true;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteOrderAttachment(Long attachmentId) {
        // 参数校验
        if (attachmentId == null) {
            throw new BusinessException("附件ID不能为空");
        }
        log.info("开始删除订单附件,附件ID: {}", attachmentId);
        // 查询附件信息
        OrderAttachment attachment = orderAttachmentMapper.selectById(attachmentId);
        if (attachment == null) {
            log.error("附件不存在,附件ID: {}", attachmentId);
            throw new BusinessException("附件不存在");
        }
        log.info("查询到附件信息: ID={}, 文件名={}, 对象名称={}, 当前删除状态={}",
                attachment.getId(), attachment.getFileName(), attachment.getObjectName(), attachment.getDeleted());
        try {
            // 1. 删除MinIO中的文件
            if (StringUtils.hasText(attachment.getObjectName())) {
                log.info("开始删除MinIO文件,对象名称: {}", attachment.getObjectName());
                minioService.deleteFile(attachment.getObjectName());
                log.info("MinIO文件删除成功,对象名称: {}", attachment.getObjectName());
            } else {
                log.warn("附件对象名称为空,跳过MinIO文件删除");
            }
            // 2. 删除数据库中的附件记录(逻辑删除)
            log.info("开始逻辑删除数据库记录,附件ID: {}", attachmentId);
            // 使用MyBatis-Plus的逻辑删除方法
            int result = orderAttachmentMapper.deleteById(attachmentId);
            log.info("数据库逻辑删除结果: 影响行数={}", result);
            if (result > 0) {
                log.info("订单附件删除成功,附件ID: {}, 文件名: {}", attachmentId, attachment.getFileName());
                return true;
            } else {
                log.error("数据库更新失败,影响行数为0,附件ID: {}", attachmentId);
                throw new BusinessException("删除附件记录失败");
            }
        } catch (Exception e) {
            log.error("删除订单附件失败,附件ID: {}", attachmentId, e);
            throw new BusinessException("删除订单附件失败:" + e.getMessage());
        }
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelOrder(String orderId) {
        // 参数校验
        if (!StringUtils.hasText(orderId)) {
            throw new BusinessException("订单ID不能为空");
        }
        log.info("开始取消订单,订单ID: {}", orderId);
        // 查询订单信息
        OrderInfo orderInfo = this.getById(orderId);
        if (orderInfo == null) {
            throw new BusinessException("订单不存在");
        }
        // 检查订单状态,只有"已完成"状态前的订单才能取消
        String currentStatus = orderInfo.getOrderStatus();
        if ("已完成".equals(currentStatus) || "已评价".equals(currentStatus)) {
            throw new BusinessException("已完成或已评价的订单不能取消");
        }
        try {
            // 1. 删除订单附件(包括MinIO文件和数据库记录)
            log.info("开始删除订单附件,订单ID: {}", orderId);
            List<OrderAttachment> attachments = orderAttachmentMapper.selectByOrderId(orderId);
            for (OrderAttachment attachment : attachments) {
                try {
                    // 删除MinIO中的文件
                    if (StringUtils.hasText(attachment.getObjectName())) {
                        log.info("删除MinIO文件,对象名称: {}", attachment.getObjectName());
                        minioService.deleteFile(attachment.getObjectName());
                    }
                    // 删除数据库记录
                    orderAttachmentMapper.deleteById(attachment.getId());
                    log.info("删除附件记录成功,附件ID: {}", attachment.getId());
                } catch (Exception e) {
                    log.error("删除附件失败,附件ID: {}, 错误: {}", attachment.getId(), e.getMessage());
                    // 继续删除其他附件,不中断整个流程
                }
            }
            // 2. 逻辑删除订单详情
            log.info("开始逻辑删除订单详情,订单ID: {}", orderId);
            // 先查询订单详情列表,然后逐个逻辑删除
            List<OrderDetail> orderDetails = orderDetailMapper.selectByOrderId(orderId);
            int detailDeleted = 0;
            for (OrderDetail detail : orderDetails) {
                int result = orderDetailMapper.deleteById(detail.getId());
                if (result > 0) {
                    detailDeleted++;
                }
            }
            log.info("逻辑删除订单详情完成,影响行数: {}", detailDeleted);
            // 3. 删除订单信息(逻辑删除)
            log.info("开始删除订单信息,订单ID: {}", orderId);
            int orderDeleted = this.baseMapper.deleteById(orderId);
            log.info("删除订单信息完成,影响行数: {}", orderDeleted);
            if (orderDeleted > 0) {
                log.info("订单取消成功,订单ID: {}", orderId);
                return true;
            } else {
                log.error("删除订单信息失败,影响行数为0,订单ID: {}", orderId);
                throw new BusinessException("删除订单信息失败");
            }
        } catch (Exception e) {
            log.error("取消订单失败,订单ID: {}", orderId, e);
            throw new BusinessException("取消订单失败:" + e.getMessage());
        }
    }
}
src/main/java/com/webmanage/service/impl/ProductServiceImpl.java
New file
@@ -0,0 +1,106 @@
package com.webmanage.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.webmanage.entity.Product;
import com.webmanage.mapper.ProductMapper;
import com.webmanage.service.ProductService;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.List;
/**
 * 产品服务实现类
 *
 * @author webmanage
 * @date 2024-08-07
 */
@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {
    @Override
    public List<Product> getProductList(String productName, String productType, String status, Long providerId) {
        LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>();
        // 添加查询条件
        if (StringUtils.hasText(productName)) {
            queryWrapper.like(Product::getProductName, productName);
        }
        if (StringUtils.hasText(productType)) {
            queryWrapper.eq(Product::getProductType, productType);
        }
        if (StringUtils.hasText(status)) {
            queryWrapper.eq(Product::getStatus, status);
        }
        if (providerId != null) {
            queryWrapper.eq(Product::getProviderId, providerId);
        }
        // 按创建时间倒序排列
        queryWrapper.orderByDesc(Product::getCreatedAt);
        return this.list(queryWrapper);
    }
    @Override
    public Product getProductById(Long id) {
        return this.getById(id);
    }
    @Override
    public boolean createProduct(Product product) {
        // 检查产品编码是否已存在
        if (checkProductCodeExists(product.getProductCode(), null)) {
            throw new RuntimeException("产品编码已存在");
        }
        return this.save(product);
    }
    @Override
    public boolean updateProduct(Product product) {
        // 检查产品编码是否已存在(排除当前产品)
        if (checkProductCodeExists(product.getProductCode(), product.getId())) {
            throw new RuntimeException("产品编码已存在");
        }
        return this.updateById(product);
    }
    @Override
    public boolean deleteProduct(Long id) {
        return this.removeById(id);
    }
    @Override
    public boolean updateProductStatus(Long id, String status) {
        LambdaUpdateWrapper<Product> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Product::getId, id)
                    .set(Product::getStatus, status);
        return this.update(updateWrapper);
    }
    @Override
    public boolean updateProductAuditStatus(Long id, String auditStatus) {
        LambdaUpdateWrapper<Product> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Product::getId, id)
                    .set(Product::getAuditStatus, auditStatus);
        return this.update(updateWrapper);
    }
    @Override
    public boolean checkProductCodeExists(String productCode, Long excludeId) {
        LambdaQueryWrapper<Product> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Product::getProductCode, productCode);
        if (excludeId != null) {
            queryWrapper.ne(Product::getId, excludeId);
        }
        return this.count(queryWrapper) > 0;
    }
}
src/main/resources/mapper/OrderInfoMapper.xml
@@ -152,7 +152,7 @@
        <include refid="Base_Column_List"/>
        FROM order_info
        WHERE deleted = 0
        AND order_status IN ('待审批', '待审批授权', '待授权')
        AND order_status IN ('待上传文件', '待授权', '待交易确认', '已完成', '已评价')
        <if test="orderStatus != null and orderStatus != ''">
            AND order_status = #{orderStatus}
        </if>