seatonwan9
2025-08-24 5fd8f535ef44ef055d91673740491b9c9177aa89
交易管理
10个文件已添加
5个文件已修改
1599 ■■■■■ 已修改文件
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 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/service/ProductService.java 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/service/impl/OrderInfoServiceImpl.java 541 ●●●●● 补丁 | 查看 | 原始文档 | 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,10 +43,10 @@
    /**
     * 上传订单附件
     */
    boolean 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);
    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,10 +279,10 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean 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) {
    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) {
        // 参数校验
        if (!StringUtils.hasText(orderId)) {
            throw new BusinessException("订单ID不能为空");
@@ -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>