zhouhui.jiang

update 基础数据添加

Showing 32 changed files with 2134 additions and 14 deletions
This diff is collapsed. Click to expand it.
package com.apple.erp.controller;
import com.apple.erp.dto.DealerAddReq;
import com.apple.erp.dto.DealerQueryReq;
import com.apple.erp.dto.DealerUpdateReq;
import com.apple.erp.entity.DealerInfo;
import com.apple.erp.service.DealerInfoService;
import com.apple.erp.dto.response.ApiRes;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import javax.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Tag(name = "经销商管理", description = "经销商信息管理接口")
@RestController
@RequestMapping("/api/dealer")
@RequiredArgsConstructor
public class DealerInfoController {
private final DealerInfoService dealerInfoService;
@Operation(summary = "获取经销商列表", description = "分页查询经销商信息列表")
@GetMapping("/list")
@PreAuthorize("hasAuthority('dealer:list')")
public ApiRes<IPage<DealerInfo>> getDealerList(@Valid DealerQueryReq queryReq) {
IPage<DealerInfo> page = dealerInfoService.getDealerList(queryReq);
return ApiRes.success(page);
}
@Operation(summary = "获取经销商详情", description = "根据经销商ID获取经销商详细信息")
@GetMapping("/{dealerId}")
@PreAuthorize("hasAuthority('dealer:detail')")
public ApiRes<DealerInfo> getDealerDetail(@Parameter(description = "经销商ID") @PathVariable Long dealerId) {
DealerInfo dealerInfo = dealerInfoService.getDealerDetail(dealerId);
if (dealerInfo != null) {
return ApiRes.success(dealerInfo);
} else {
return ApiRes.error("经销商不存在");
}
}
@Operation(summary = "新增经销商", description = "新增一个经销商信息")
@PostMapping
@PreAuthorize("hasAuthority('dealer:add')")
public ApiRes<String> addDealer(@Parameter(description = "经销商新增请求") @Valid @RequestBody DealerAddReq addReq) {
try {
boolean success = dealerInfoService.addDealer(addReq);
return success ? ApiRes.success("经销商新增成功", null) : ApiRes.error("经销商新增失败");
} catch (IllegalArgumentException e) {
return ApiRes.error(e.getMessage());
}
}
@Operation(summary = "修改经销商", description = "修改一个经销商信息")
@PostMapping("/update")
@PreAuthorize("hasAuthority('dealer:update')")
public ApiRes<String> updateDealer(@Parameter(description = "经销商修改请求") @Valid @RequestBody DealerUpdateReq updateReq) {
try {
boolean success = dealerInfoService.updateDealer(updateReq);
return success ? ApiRes.success("经销商修改成功", null) : ApiRes.error("经销商修改失败");
} catch (IllegalArgumentException e) {
return ApiRes.error(e.getMessage());
}
}
@Operation(summary = "删除经销商", description = "根据经销商ID删除经销商信息(软删除)")
@DeleteMapping("/{dealerId}")
@PreAuthorize("hasAuthority('dealer:delete')")
public ApiRes<String> deleteDealer(@Parameter(description = "经销商ID") @PathVariable Long dealerId) {
try {
boolean success = dealerInfoService.deleteDealer(dealerId);
return success ? ApiRes.success("经销商删除成功", null) : ApiRes.error("经销商删除失败");
} catch (IllegalArgumentException e) {
return ApiRes.error(e.getMessage());
}
}
@Operation(summary = "批量删除经销商", description = "根据经销商ID列表批量删除经销商信息(软删除)")
@DeleteMapping("/batch")
@PreAuthorize("hasAuthority('dealer:batchDelete')")
public ApiRes<String> batchDeleteDealers(@Parameter(description = "经销商ID列表") @RequestBody List<Long> dealerIds) {
boolean success = dealerInfoService.batchDeleteDealers(dealerIds);
return success ? ApiRes.success("经销商批量删除成功", null) : ApiRes.error("经销商批量删除失败");
}
@Operation(summary = "修改经销商合作状态", description = "修改经销商的合作状态")
@PostMapping("/{dealerId}/cooperateStatus/{cooperateStatus}")
@PreAuthorize("hasAuthority('dealer:updateStatus')")
public ApiRes<String> updateDealerCooperateStatus(
@Parameter(description = "经销商ID") @PathVariable Long dealerId,
@Parameter(description = "合作状态(1-正常合作/2-暂停合作/3-终止合作)") @PathVariable Integer cooperateStatus) {
try {
boolean success = dealerInfoService.updateDealerCooperateStatus(dealerId, cooperateStatus);
return success ? ApiRes.success("经销商合作状态修改成功", null) : ApiRes.error("经销商合作状态修改失败");
} catch (IllegalArgumentException e) {
return ApiRes.error(e.getMessage());
}
}
@Operation(summary = "修改经销商资质审核状态", description = "修改经销商的资质审核状态")
@PostMapping("/{dealerId}/auditStatus")
@PreAuthorize("hasAuthority('dealer:audit')")
public ApiRes<String> updateDealerAuditStatus(
@Parameter(description = "经销商ID") @PathVariable Long dealerId,
@Parameter(description = "资质审核状态(1-待审核/2-审核通过/3-审核不通过)") @RequestParam Integer qualificationAuditStatus,
@Parameter(description = "审核意见") @RequestParam(required = false) String auditOpinion) {
try {
boolean success = dealerInfoService.updateDealerAuditStatus(dealerId, qualificationAuditStatus, auditOpinion);
return success ? ApiRes.success("经销商资质审核状态修改成功", null) : ApiRes.error("经销商资质审核状态修改失败");
} catch (IllegalArgumentException e) {
return ApiRes.error(e.getMessage());
}
}
}
package com.apple.erp.controller;
import com.apple.erp.dto.ProductAddReq;
import com.apple.erp.dto.ProductQueryReq;
import com.apple.erp.dto.ProductUpdateReq;
import com.apple.erp.entity.ProductInfo;
import com.apple.erp.service.ProductInfoService;
import com.apple.erp.dto.response.ApiRes;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
/**
* 产品信息管理控制器
*
* @author Apple ERP Team
* @since 2025-01-27
*/
@Tag(name = "产品信息管理", description = "产品信息的增删改查等操作")
@RestController
@RequestMapping("/api/product")
@RequiredArgsConstructor
@Validated
public class ProductInfoController {
private final ProductInfoService productInfoService;
@Operation(summary = "分页查询产品列表", description = "根据条件分页查询产品列表")
@GetMapping("/list")
@PreAuthorize("hasAuthority('product:list')")
public ApiRes<IPage<ProductInfo>> getProductList(@Valid ProductQueryReq queryReq) {
try {
IPage<ProductInfo> result = productInfoService.getProductPage(queryReq);
return ApiRes.success(result);
} catch (Exception e) {
return ApiRes.error("查询产品列表失败:" + e.getMessage());
}
}
@Operation(summary = "获取产品详情", description = "根据产品ID获取产品详情")
@GetMapping("/{productId}")
@PreAuthorize("hasAuthority('product:detail')")
public ApiRes<ProductInfo> getProductDetail(
@Parameter(description = "产品ID", required = true)
@PathVariable Long productId) {
try {
ProductInfo productInfo = productInfoService.getProductById(productId);
if (productInfo == null) {
return ApiRes.error("产品不存在");
}
return ApiRes.success(productInfo);
} catch (Exception e) {
return ApiRes.error("获取产品详情失败:" + e.getMessage());
}
}
@Operation(summary = "新增产品", description = "新增产品信息")
@PostMapping
@PreAuthorize("hasAuthority('product:add')")
public ApiRes<String> addProduct(@Valid @RequestBody ProductAddReq addReq) {
try {
boolean success = productInfoService.addProduct(addReq);
if (success) {
return ApiRes.success("新增产品成功");
} else {
return ApiRes.error("新增产品失败");
}
} catch (RuntimeException e) {
return ApiRes.error(e.getMessage());
} catch (Exception e) {
return ApiRes.error("新增产品失败:" + e.getMessage());
}
}
@Operation(summary = "修改产品", description = "修改产品信息")
@PostMapping("/update")
@PreAuthorize("hasAuthority('product:edit')")
public ApiRes<String> updateProduct(@Valid @RequestBody ProductUpdateReq updateReq) {
try {
boolean success = productInfoService.updateProduct(updateReq);
if (success) {
return ApiRes.success("修改产品成功");
} else {
return ApiRes.error("修改产品失败");
}
} catch (RuntimeException e) {
return ApiRes.error(e.getMessage());
} catch (Exception e) {
return ApiRes.error("修改产品失败:" + e.getMessage());
}
}
@Operation(summary = "删除产品", description = "根据产品ID删除产品")
@DeleteMapping("/{productId}")
@PreAuthorize("hasAuthority('product:delete')")
public ApiRes<String> deleteProduct(
@Parameter(description = "产品ID", required = true)
@PathVariable Long productId) {
try {
boolean success = productInfoService.deleteProduct(productId);
if (success) {
return ApiRes.success("删除产品成功");
} else {
return ApiRes.error("删除产品失败");
}
} catch (Exception e) {
return ApiRes.error("删除产品失败:" + e.getMessage());
}
}
@Operation(summary = "批量删除产品", description = "批量删除产品")
@PostMapping("/batchDelete")
@PreAuthorize("hasAuthority('product:delete')")
public ApiRes<String> batchDeleteProducts(@RequestBody List<Long> productIds) {
try {
if (productIds == null || productIds.isEmpty()) {
return ApiRes.error("请选择要删除的产品");
}
boolean success = productInfoService.batchDeleteProducts(productIds);
if (success) {
return ApiRes.success("批量删除产品成功");
} else {
return ApiRes.error("批量删除产品失败");
}
} catch (Exception e) {
return ApiRes.error("批量删除产品失败:" + e.getMessage());
}
}
@Operation(summary = "修改产品状态", description = "修改产品销售状态")
@PostMapping("/{productId}/status")
@PreAuthorize("hasAuthority('product:edit')")
public ApiRes<String> updateProductStatus(
@Parameter(description = "产品ID", required = true)
@PathVariable Long productId,
@Parameter(description = "销售状态", required = true)
@RequestParam Integer saleStatus) {
try {
boolean success = productInfoService.updateProductStatus(productId, saleStatus);
if (success) {
return ApiRes.success("修改产品状态成功");
} else {
return ApiRes.error("修改产品状态失败");
}
} catch (Exception e) {
return ApiRes.error("修改产品状态失败:" + e.getMessage());
}
}
@Operation(summary = "修改返利标识", description = "修改产品返利标识")
@PostMapping("/{productId}/rebate")
@PreAuthorize("hasAuthority('product:edit')")
public ApiRes<String> updateRebateFlag(
@Parameter(description = "产品ID", required = true)
@PathVariable Long productId,
@Parameter(description = "返利标识", required = true)
@RequestParam Integer rebateFlag) {
try {
boolean success = productInfoService.updateRebateFlag(productId, rebateFlag);
if (success) {
return ApiRes.success("修改返利标识成功");
} else {
return ApiRes.error("修改返利标识失败");
}
} catch (Exception e) {
return ApiRes.error("修改返利标识失败:" + e.getMessage());
}
}
}
package com.apple.erp.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
@Data
@Schema(description = "经销商新增请求DTO")
public class DealerAddReq {
@NotBlank(message = "经销商编码不能为空")
@Pattern(regexp = "^[A-Z0-9]{6,20}$", message = "经销商编码格式不正确,应为6-20位大写字母和数字")
@Schema(description = "经销商编码", required = true)
private String dealerCode;
@NotBlank(message = "经销商名称不能为空")
@Schema(description = "经销商名称", required = true)
private String dealerName;
@NotBlank(message = "统一社会信用代码不能为空")
@Pattern(regexp = "^[0-9A-HJ-NPQRTUWXY]{2}[0-9]{6}[0-9A-HJ-NPQRTUWXY]{10}$", message = "统一社会信用代码格式不正确")
@Schema(description = "统一社会信用代码", required = true)
private String creditCode;
@NotNull(message = "经销商等级不能为空")
@Schema(description = "经销商等级(1-一级经销商/2-二级经销商)", required = true)
private Integer dealerLevel;
@NotBlank(message = "所在区域不能为空")
@Schema(description = "所在区域", required = true)
private String region;
@Schema(description = "联系人")
private String contactPerson;
@Schema(description = "联系电话")
private String contactPhone;
@NotNull(message = "合作起始日期不能为空")
@Schema(description = "合作起始日期", required = true)
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate cooperateStartDate;
@Schema(description = "合作状态(1-正常合作/2-暂停合作/3-终止合作)")
private Integer cooperateStatus = 1;
@Schema(description = "营业执照URL")
private String businessLicenseUrl;
@Schema(description = "合作协议URL")
private String cooperationAgreementUrl;
@Schema(description = "资质审核状态(1-待审核/2-审核通过/3-审核不通过)")
private Integer qualificationAuditStatus = 1;
@Schema(description = "审核意见")
private String auditOpinion;
}
package com.apple.erp.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
@Data
@Schema(description = "经销商查询请求DTO")
public class DealerQueryReq {
@Schema(description = "经销商编码")
private String dealerCode;
@Schema(description = "经销商名称")
private String dealerName;
@Schema(description = "统一社会信用代码")
private String creditCode;
@Schema(description = "经销商等级(1-一级经销商/2-二级经销商)")
private Integer dealerLevel;
@Schema(description = "所在区域")
private String region;
@Schema(description = "联系人")
private String contactPerson;
@Schema(description = "联系电话")
private String contactPhone;
@Schema(description = "合作状态(1-正常合作/2-暂停合作/3-终止合作)")
private Integer cooperateStatus;
@Schema(description = "资质审核状态(1-待审核/2-审核通过/3-审核不通过)")
private Integer qualificationAuditStatus;
@Schema(description = "合作起始日期开始")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate cooperateStartDateStart;
@Schema(description = "合作起始日期结束")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate cooperateStartDateEnd;
@Schema(description = "当前页码")
private Long pageNum = 1L;
@Schema(description = "每页大小")
private Long pageSize = 10L;
}
package com.apple.erp.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
@Data
@Schema(description = "经销商修改请求DTO")
public class DealerUpdateReq {
@NotNull(message = "经销商ID不能为空")
@Schema(description = "经销商ID", required = true)
private Long dealerId;
@NotBlank(message = "经销商编码不能为空")
@Pattern(regexp = "^[A-Z0-9]{6,20}$", message = "经销商编码格式不正确,应为6-20位大写字母和数字")
@Schema(description = "经销商编码", required = true)
private String dealerCode;
@NotBlank(message = "经销商名称不能为空")
@Schema(description = "经销商名称", required = true)
private String dealerName;
@NotBlank(message = "统一社会信用代码不能为空")
@Pattern(regexp = "^[0-9A-HJ-NPQRTUWXY]{2}[0-9]{6}[0-9A-HJ-NPQRTUWXY]{10}$", message = "统一社会信用代码格式不正确")
@Schema(description = "统一社会信用代码", required = true)
private String creditCode;
@NotNull(message = "经销商等级不能为空")
@Schema(description = "经销商等级(1-一级经销商/2-二级经销商)", required = true)
private Integer dealerLevel;
@NotBlank(message = "所在区域不能为空")
@Schema(description = "所在区域", required = true)
private String region;
@Schema(description = "联系人")
private String contactPerson;
@Schema(description = "联系电话")
private String contactPhone;
@NotNull(message = "合作起始日期不能为空")
@Schema(description = "合作起始日期", required = true)
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate cooperateStartDate;
@Schema(description = "合作状态(1-正常合作/2-暂停合作/3-终止合作)")
private Integer cooperateStatus;
@Schema(description = "营业执照URL")
private String businessLicenseUrl;
@Schema(description = "合作协议URL")
private String cooperationAgreementUrl;
@Schema(description = "资质审核状态(1-待审核/2-审核通过/3-审核不通过)")
private Integer qualificationAuditStatus;
@Schema(description = "审核意见")
private String auditOpinion;
}
package com.apple.erp.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* 产品新增请求DTO
*
* @author Apple ERP Team
* @since 2025-01-27
*/
@Data
@Schema(description = "产品新增请求")
public class ProductAddReq {
@Schema(description = "产品编码", required = true)
@NotBlank(message = "产品编码不能为空")
private String productCode;
@Schema(description = "产品名称", required = true)
@NotBlank(message = "产品名称不能为空")
private String productName;
@Schema(description = "产品型号", required = true)
@NotBlank(message = "产品型号不能为空")
private String productModel;
@Schema(description = "产品类别", required = true)
@NotBlank(message = "产品类别不能为空")
private String productType;
@Schema(description = "存储容量")
private String storageCapacity;
@Schema(description = "产品颜色")
private String color;
@Schema(description = "产品图片URL")
private String productImgUrl;
@Schema(description = "官方指导价")
private BigDecimal officialPrice;
@Schema(description = "销售状态(0-下架/1-在售/2-预售)", required = true)
@NotNull(message = "销售状态不能为空")
private Integer saleStatus;
@Schema(description = "是否参与返利(0-否/1-是)", required = true)
@NotNull(message = "返利标识不能为空")
private Integer rebateFlag;
@Schema(description = "销售起始日期")
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate saleStartDate;
@Schema(description = "销售终止日期")
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate saleEndDate;
@Schema(description = "产品备注")
private String remark;
}
package com.apple.erp.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* 产品查询请求DTO
*
* @author Apple ERP Team
* @since 2025-01-27
*/
@Data
@Schema(description = "产品查询请求")
public class ProductQueryReq {
@Schema(description = "产品编码")
private String productCode;
@Schema(description = "产品名称")
private String productName;
@Schema(description = "产品型号")
private String productModel;
@Schema(description = "产品类别")
private String productType;
@Schema(description = "存储容量")
private String storageCapacity;
@Schema(description = "产品颜色")
private String color;
@Schema(description = "销售状态(0-下架/1-在售/2-预售)")
private Integer saleStatus;
@Schema(description = "是否参与返利(0-否/1-是)")
private Integer rebateFlag;
@Schema(description = "最低价格")
private BigDecimal minPrice;
@Schema(description = "最高价格")
private BigDecimal maxPrice;
@Schema(description = "销售起始日期开始")
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate saleStartDateBegin;
@Schema(description = "销售起始日期结束")
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate saleStartDateEnd;
@Schema(description = "销售终止日期开始")
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate saleEndDateBegin;
@Schema(description = "销售终止日期结束")
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate saleEndDateEnd;
@Schema(description = "页码", example = "1")
private Integer pageNum = 1;
@Schema(description = "每页大小", example = "10")
private Integer pageSize = 10;
}
package com.apple.erp.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* 产品修改请求DTO
*
* @author Apple ERP Team
* @since 2025-01-27
*/
@Data
@Schema(description = "产品修改请求")
public class ProductUpdateReq {
@Schema(description = "产品ID", required = true)
@NotNull(message = "产品ID不能为空")
private Long productId;
@Schema(description = "产品编码", required = true)
@NotBlank(message = "产品编码不能为空")
private String productCode;
@Schema(description = "产品名称", required = true)
@NotBlank(message = "产品名称不能为空")
private String productName;
@Schema(description = "产品型号", required = true)
@NotBlank(message = "产品型号不能为空")
private String productModel;
@Schema(description = "产品类别", required = true)
@NotBlank(message = "产品类别不能为空")
private String productType;
@Schema(description = "存储容量")
private String storageCapacity;
@Schema(description = "产品颜色")
private String color;
@Schema(description = "产品图片URL")
private String productImgUrl;
@Schema(description = "官方指导价")
private BigDecimal officialPrice;
@Schema(description = "销售状态(0-下架/1-在售/2-预售)", required = true)
@NotNull(message = "销售状态不能为空")
private Integer saleStatus;
@Schema(description = "是否参与返利(0-否/1-是)", required = true)
@NotNull(message = "返利标识不能为空")
private Integer rebateFlag;
@Schema(description = "销售起始日期")
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate saleStartDate;
@Schema(description = "销售终止日期")
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate saleEndDate;
@Schema(description = "产品备注")
private String remark;
}
package com.apple.erp.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
@TableName("t_dealer_info")
@Schema(description = "经销商信息实体")
public class DealerInfo {
@TableId(type = IdType.AUTO)
@Schema(description = "经销商ID")
private Long dealerId;
@Schema(description = "经销商编码")
private String dealerCode;
@Schema(description = "经销商名称")
private String dealerName;
@Schema(description = "统一社会信用代码")
private String creditCode;
@Schema(description = "经销商等级(1-一级经销商/2-二级经销商)")
private Integer dealerLevel;
@Schema(description = "所在区域")
private String region;
@Schema(description = "联系人")
private String contactPerson;
@Schema(description = "联系电话")
private String contactPhone;
@Schema(description = "合作起始日期")
private LocalDate cooperateStartDate;
@Schema(description = "合作状态(1-正常合作/2-暂停合作/3-终止合作)")
private Integer cooperateStatus;
@Schema(description = "营业执照URL")
private String businessLicenseUrl;
@Schema(description = "合作协议URL")
private String cooperationAgreementUrl;
@Schema(description = "资质审核状态(1-待审核/2-审核通过/3-审核不通过)")
private Integer qualificationAuditStatus;
@Schema(description = "审核意见")
private String auditOpinion;
@Schema(description = "累计应返金额")
private BigDecimal totalRebateAmount;
@Schema(description = "累计已返金额")
private BigDecimal usedRebateAmount;
@Schema(description = "待返利总金额")
private BigDecimal pendingRebateAmount;
@Schema(description = "最后返利更新时间")
private LocalDateTime lastRebateUpdateTime;
@Schema(description = "创建者")
private String createBy;
@Schema(description = "创建时间")
private LocalDateTime createTime;
@Schema(description = "更新者")
private String updateBy;
@Schema(description = "更新时间")
private LocalDateTime updateTime;
@Schema(description = "删除标志(0代表存在 2代表删除)")
private String delFlag;
}
package com.apple.erp.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* 产品信息表
*
* @author Apple ERP Team
* @since 2025-01-27
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("t_product_info")
public class ProductInfo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 产品ID
*/
@TableId(value = "product_id", type = IdType.AUTO)
private Long productId;
/**
* 产品编码
*/
private String productCode;
/**
* 产品名称
*/
private String productName;
/**
* 产品型号
*/
private String productModel;
/**
* 产品类别
*/
private String productType;
/**
* 存储容量
*/
private String storageCapacity;
/**
* 产品颜色
*/
private String color;
/**
* 产品图片URL
*/
private String productImgUrl;
/**
* 官方指导价
*/
private BigDecimal officialPrice;
/**
* 销售状态(0-下架/1-在售/2-预售)
*/
private Integer saleStatus;
/**
* 是否参与返利(0-否/1-是)
*/
private Integer rebateFlag;
/**
* 销售起始日期
*/
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate saleStartDate;
/**
* 销售终止日期
*/
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate saleEndDate;
/**
* 产品备注
*/
private String remark;
/**
* 创建者
*/
private String createBy;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
/**
* 更新者
*/
private String updateBy;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
/**
* 删除标志(0代表存在 2代表删除)
*/
private String delFlag;
}
package com.apple.erp.mapper;
import com.apple.erp.entity.DealerInfo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface DealerInfoMapper extends BaseMapper<DealerInfo> {
}
package com.apple.erp.mapper;
import com.apple.erp.entity.ProductInfo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* 产品信息表 Mapper 接口
*
* @author Apple ERP Team
* @since 2025-01-27
*/
@Mapper
public interface ProductInfoMapper extends BaseMapper<ProductInfo> {
}
package com.apple.erp.service;
import com.apple.erp.dto.DealerAddReq;
import com.apple.erp.dto.DealerQueryReq;
import com.apple.erp.dto.DealerUpdateReq;
import com.apple.erp.entity.DealerInfo;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
public interface DealerInfoService extends IService<DealerInfo> {
/**
* 分页查询经销商列表
* @param queryReq 查询条件
* @return 经销商分页数据
*/
IPage<DealerInfo> getDealerList(DealerQueryReq queryReq);
/**
* 根据ID获取经销商详情
* @param dealerId 经销商ID
* @return 经销商详情
*/
DealerInfo getDealerDetail(Long dealerId);
/**
* 新增经销商
* @param addReq 新增请求
* @return 是否成功
*/
boolean addDealer(DealerAddReq addReq);
/**
* 修改经销商
* @param updateReq 修改请求
* @return 是否成功
*/
boolean updateDealer(DealerUpdateReq updateReq);
/**
* 删除经销商
* @param dealerId 经销商ID
* @return 是否成功
*/
boolean deleteDealer(Long dealerId);
/**
* 批量删除经销商
* @param dealerIds 经销商ID列表
* @return 是否成功
*/
boolean batchDeleteDealers(List<Long> dealerIds);
/**
* 修改经销商合作状态
* @param dealerId 经销商ID
* @param cooperateStatus 合作状态
* @return 是否成功
*/
boolean updateDealerCooperateStatus(Long dealerId, Integer cooperateStatus);
/**
* 修改经销商资质审核状态
* @param dealerId 经销商ID
* @param qualificationAuditStatus 资质审核状态
* @param auditOpinion 审核意见
* @return 是否成功
*/
boolean updateDealerAuditStatus(Long dealerId, Integer qualificationAuditStatus, String auditOpinion);
}
package com.apple.erp.service;
import com.apple.erp.dto.ProductAddReq;
import com.apple.erp.dto.ProductQueryReq;
import com.apple.erp.dto.ProductUpdateReq;
import com.apple.erp.entity.ProductInfo;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* 产品信息表 服务类
*
* @author Apple ERP Team
* @since 2025-01-27
*/
public interface ProductInfoService extends IService<ProductInfo> {
/**
* 分页查询产品列表
*
* @param queryReq 查询条件
* @return 产品分页列表
*/
IPage<ProductInfo> getProductPage(ProductQueryReq queryReq);
/**
* 根据产品ID获取产品详情
*
* @param productId 产品ID
* @return 产品详情
*/
ProductInfo getProductById(Long productId);
/**
* 新增产品
*
* @param addReq 新增请求
* @return 是否成功
*/
boolean addProduct(ProductAddReq addReq);
/**
* 修改产品
*
* @param updateReq 修改请求
* @return 是否成功
*/
boolean updateProduct(ProductUpdateReq updateReq);
/**
* 删除产品
*
* @param productId 产品ID
* @return 是否成功
*/
boolean deleteProduct(Long productId);
/**
* 批量删除产品
*
* @param productIds 产品ID列表
* @return 是否成功
*/
boolean batchDeleteProducts(List<Long> productIds);
/**
* 修改产品状态
*
* @param productId 产品ID
* @param saleStatus 销售状态
* @return 是否成功
*/
boolean updateProductStatus(Long productId, Integer saleStatus);
/**
* 修改返利标识
*
* @param productId 产品ID
* @param rebateFlag 返利标识
* @return 是否成功
*/
boolean updateRebateFlag(Long productId, Integer rebateFlag);
/**
* 检查产品编码是否存在
*
* @param productCode 产品编码
* @param productId 产品ID(修改时排除自己)
* @return 是否存在
*/
boolean checkProductCodeExists(String productCode, Long productId);
}
package com.apple.erp.service.impl;
import com.apple.erp.dto.ProductAddReq;
import com.apple.erp.dto.ProductQueryReq;
import com.apple.erp.dto.ProductUpdateReq;
import com.apple.erp.entity.ProductInfo;
import com.apple.erp.mapper.ProductInfoMapper;
import com.apple.erp.service.ProductInfoService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.util.List;
/**
* 产品信息表 服务实现类
*
* @author Apple ERP Team
* @since 2025-01-27
*/
@Service
public class ProductInfoServiceImpl extends ServiceImpl<ProductInfoMapper, ProductInfo> implements ProductInfoService {
@Override
public IPage<ProductInfo> getProductPage(ProductQueryReq queryReq) {
Page<ProductInfo> page = new Page<>(queryReq.getPageNum(), queryReq.getPageSize());
LambdaQueryWrapper<ProductInfo> queryWrapper = getQueryWrapper(queryReq);
return this.page(page, queryWrapper);
}
@Override
public ProductInfo getProductById(Long productId) {
return this.getById(productId);
}
@Override
public boolean addProduct(ProductAddReq addReq) {
// 检查产品编码是否已存在
if (checkProductCodeExists(addReq.getProductCode(), null)) {
throw new RuntimeException("产品编码已存在");
}
ProductInfo productInfo = new ProductInfo();
BeanUtils.copyProperties(addReq, productInfo);
productInfo.setCreateTime(LocalDateTime.now());
productInfo.setDelFlag("0");
return this.save(productInfo);
}
@Override
public boolean updateProduct(ProductUpdateReq updateReq) {
// 检查产品编码是否已存在(排除自己)
if (checkProductCodeExists(updateReq.getProductCode(), updateReq.getProductId())) {
throw new RuntimeException("产品编码已存在");
}
ProductInfo productInfo = new ProductInfo();
BeanUtils.copyProperties(updateReq, productInfo);
productInfo.setUpdateTime(LocalDateTime.now());
return this.updateById(productInfo);
}
@Override
public boolean deleteProduct(Long productId) {
ProductInfo productInfo = new ProductInfo();
productInfo.setProductId(productId);
productInfo.setDelFlag("2");
productInfo.setUpdateTime(LocalDateTime.now());
return this.updateById(productInfo);
}
@Override
public boolean batchDeleteProducts(List<Long> productIds) {
for (Long productId : productIds) {
deleteProduct(productId);
}
return true;
}
@Override
public boolean updateProductStatus(Long productId, Integer saleStatus) {
ProductInfo productInfo = new ProductInfo();
productInfo.setProductId(productId);
productInfo.setSaleStatus(saleStatus);
productInfo.setUpdateTime(LocalDateTime.now());
return this.updateById(productInfo);
}
@Override
public boolean updateRebateFlag(Long productId, Integer rebateFlag) {
ProductInfo productInfo = new ProductInfo();
productInfo.setProductId(productId);
productInfo.setRebateFlag(rebateFlag);
productInfo.setUpdateTime(LocalDateTime.now());
return this.updateById(productInfo);
}
@Override
public boolean checkProductCodeExists(String productCode, Long productId) {
LambdaQueryWrapper<ProductInfo> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ProductInfo::getProductCode, productCode)
.eq(ProductInfo::getDelFlag, "0");
if (productId != null) {
queryWrapper.ne(ProductInfo::getProductId, productId);
}
return this.count(queryWrapper) > 0;
}
/**
* 构建查询条件
*
* @param queryReq 查询请求
* @return 查询条件
*/
private LambdaQueryWrapper<ProductInfo> getQueryWrapper(ProductQueryReq queryReq) {
LambdaQueryWrapper<ProductInfo> queryWrapper = new LambdaQueryWrapper<>();
// 基础查询条件
queryWrapper.eq(ProductInfo::getDelFlag, "0");
// 产品编码
if (StringUtils.hasText(queryReq.getProductCode())) {
queryWrapper.like(ProductInfo::getProductCode, queryReq.getProductCode());
}
// 产品名称
if (StringUtils.hasText(queryReq.getProductName())) {
queryWrapper.like(ProductInfo::getProductName, queryReq.getProductName());
}
// 产品型号
if (StringUtils.hasText(queryReq.getProductModel())) {
queryWrapper.like(ProductInfo::getProductModel, queryReq.getProductModel());
}
// 产品类别
if (StringUtils.hasText(queryReq.getProductType())) {
queryWrapper.eq(ProductInfo::getProductType, queryReq.getProductType());
}
// 存储容量
if (StringUtils.hasText(queryReq.getStorageCapacity())) {
queryWrapper.eq(ProductInfo::getStorageCapacity, queryReq.getStorageCapacity());
}
// 产品颜色
if (StringUtils.hasText(queryReq.getColor())) {
queryWrapper.eq(ProductInfo::getColor, queryReq.getColor());
}
// 销售状态
if (queryReq.getSaleStatus() != null) {
queryWrapper.eq(ProductInfo::getSaleStatus, queryReq.getSaleStatus());
}
// 返利标识
if (queryReq.getRebateFlag() != null) {
queryWrapper.eq(ProductInfo::getRebateFlag, queryReq.getRebateFlag());
}
// 价格范围
if (queryReq.getMinPrice() != null) {
queryWrapper.ge(ProductInfo::getOfficialPrice, queryReq.getMinPrice());
}
if (queryReq.getMaxPrice() != null) {
queryWrapper.le(ProductInfo::getOfficialPrice, queryReq.getMaxPrice());
}
// 销售起始日期范围
if (queryReq.getSaleStartDateBegin() != null) {
queryWrapper.ge(ProductInfo::getSaleStartDate, queryReq.getSaleStartDateBegin());
}
if (queryReq.getSaleStartDateEnd() != null) {
queryWrapper.le(ProductInfo::getSaleStartDate, queryReq.getSaleStartDateEnd());
}
// 销售终止日期范围
if (queryReq.getSaleEndDateBegin() != null) {
queryWrapper.ge(ProductInfo::getSaleEndDate, queryReq.getSaleEndDateBegin());
}
if (queryReq.getSaleEndDateEnd() != null) {
queryWrapper.le(ProductInfo::getSaleEndDate, queryReq.getSaleEndDateEnd());
}
// 排序
queryWrapper.orderByDesc(ProductInfo::getCreateTime);
return queryWrapper;
}
}
-- Apple经销商ERP系统 - 业务数据库初始化脚本
-- 按顺序执行所有业务数据库脚本
-- 1. 创建业务表
SOURCE 01_create_business_tables.sql;
-- 2. 创建业务索引
SOURCE 02_create_business_indexes.sql;
-- 3. 插入业务测试数据
SOURCE 03_insert_business_data.sql;
-- 4. 插入产品管理和经销商管理权限
SOURCE 06_insert_product_dealer_permissions.sql;
-- 完成业务数据库初始化
SELECT 'Apple经销商ERP系统业务数据库初始化完成!' AS message;
This diff is collapsed. Click to expand it.
-- Apple经销商ERP系统 - 业务表索引创建脚本
-- 按照数据库设计文档创建索引
-- =============================================
-- 订单主表索引
-- =============================================
-- 业务唯一索引
CREATE UNIQUE INDEX uk_order_no ON t_order_main(order_no);
-- 查询优化索引
CREATE INDEX idx_order_dealer_code ON t_order_main(dealer_code);
CREATE INDEX idx_order_date ON t_order_main(order_date);
CREATE INDEX idx_order_status ON t_order_main(delivery_status, invoice_status);
CREATE INDEX idx_order_verify ON t_order_main(verify_status);
CREATE INDEX idx_order_upload_time ON t_order_main(upload_time);
-- =============================================
-- 订单商品明细表索引
-- =============================================
-- 外键索引
CREATE INDEX idx_item_order_id ON t_order_item(order_id);
CREATE INDEX idx_item_order_no ON t_order_item(order_no);
CREATE INDEX idx_item_product_code ON t_order_item(product_code);
-- =============================================
-- 出库主表索引
-- =============================================
-- 业务唯一索引
CREATE UNIQUE INDEX uk_delivery_no ON t_delivery_main(delivery_no);
-- 查询优化索引
CREATE INDEX idx_delivery_dealer_code ON t_delivery_main(dealer_code);
CREATE INDEX idx_delivery_order_no ON t_delivery_main(order_no);
CREATE INDEX idx_delivery_date ON t_delivery_main(delivery_date);
CREATE INDEX idx_delivery_status ON t_delivery_main(delivery_status);
-- =============================================
-- 出库商品明细表索引
-- =============================================
-- 外键索引
CREATE INDEX idx_delivery_item_delivery_id ON t_delivery_item(delivery_id);
CREATE INDEX idx_delivery_item_delivery_no ON t_delivery_item(delivery_no);
CREATE INDEX idx_delivery_item_order_no ON t_delivery_item(order_no);
CREATE INDEX idx_delivery_item_product_code ON t_delivery_item(product_code);
-- =============================================
-- 发票主表索引
-- =============================================
-- 业务唯一索引
CREATE UNIQUE INDEX uk_invoice_no ON t_invoice_main(invoice_no);
-- 查询优化索引
CREATE INDEX idx_invoice_dealer_code ON t_invoice_main(dealer_code);
CREATE INDEX idx_invoice_order_no ON t_invoice_main(order_no);
CREATE INDEX idx_invoice_delivery_no ON t_invoice_main(delivery_no);
CREATE INDEX idx_invoice_date ON t_invoice_main(invoice_date);
CREATE INDEX idx_invoice_status ON t_invoice_main(invoice_status);
-- =============================================
-- 发票商品明细表索引
-- =============================================
-- 外键索引
CREATE INDEX idx_invoice_item_invoice_id ON t_invoice_item(invoice_id);
CREATE INDEX idx_invoice_item_invoice_no ON t_invoice_item(invoice_no);
CREATE INDEX idx_invoice_item_order_no ON t_invoice_item(order_no);
CREATE INDEX idx_invoice_item_product_code ON t_invoice_item(product_code);
-- =============================================
-- 返利台账明细表索引
-- =============================================
-- 业务唯一索引
CREATE UNIQUE INDEX uk_rebate_no ON t_rebate_detail(rebate_no);
-- 查询优化索引
CREATE INDEX idx_rebate_dealer_code ON t_rebate_detail(dealer_code);
CREATE INDEX idx_rebate_order_no ON t_rebate_detail(order_no);
CREATE INDEX idx_rebate_product_code ON t_rebate_detail(product_code);
CREATE INDEX idx_rebate_date ON t_rebate_detail(rebate_date);
CREATE INDEX idx_rebate_operate_type ON t_rebate_detail(operate_type);
CREATE INDEX idx_rebate_calc_flag ON t_rebate_detail(calc_flag);
-- =============================================
-- 异常工单表索引
-- =============================================
-- 业务唯一索引
CREATE UNIQUE INDEX uk_workorder_no ON t_exception_workorder(workorder_no);
-- 查询优化索引
CREATE INDEX idx_workorder_dealer_code ON t_exception_workorder(dealer_code);
CREATE INDEX idx_workorder_order_no ON t_exception_workorder(order_no);
CREATE INDEX idx_workorder_exception_type ON t_exception_workorder(exception_type);
CREATE INDEX idx_workorder_severity_level ON t_exception_workorder(severity_level);
CREATE INDEX idx_workorder_status ON t_exception_workorder(workorder_status);
CREATE INDEX idx_workorder_create_time ON t_exception_workorder(create_time);
CREATE INDEX idx_workorder_handler_user ON t_exception_workorder(handler_user);
-- =============================================
-- 异常工单处理日志表索引
-- =============================================
-- 外键索引
CREATE INDEX idx_workorder_log_workorder_id ON t_exception_workorder_log(workorder_id);
CREATE INDEX idx_workorder_log_workorder_no ON t_exception_workorder_log(workorder_no);
CREATE INDEX idx_workorder_log_handle_user ON t_exception_workorder_log(handle_user);
CREATE INDEX idx_workorder_log_handle_time ON t_exception_workorder_log(handle_time);
-- =============================================
-- 经销商信息表索引
-- =============================================
-- 业务唯一索引(已在表定义中创建)
-- UNIQUE INDEX uk_dealer_code ON t_dealer_info(dealer_code);
-- UNIQUE INDEX uk_credit_code ON t_dealer_info(credit_code);
-- 查询优化索引
CREATE INDEX idx_dealer_name ON t_dealer_info(dealer_name);
CREATE INDEX idx_dealer_level ON t_dealer_info(dealer_level);
CREATE INDEX idx_dealer_region ON t_dealer_info(region);
CREATE INDEX idx_dealer_cooperate_status ON t_dealer_info(cooperate_status);
CREATE INDEX idx_dealer_qualification_audit_status ON t_dealer_info(qualification_audit_status);
CREATE INDEX idx_dealer_cooperate_start_date ON t_dealer_info(cooperate_start_date);
-- =============================================
-- 产品信息表索引
-- =============================================
-- 业务唯一索引(已在表定义中创建)
-- UNIQUE INDEX uk_product_code ON t_product_info(product_code);
-- 查询优化索引
CREATE INDEX idx_product_name ON t_product_info(product_name);
CREATE INDEX idx_product_model ON t_product_info(product_model);
CREATE INDEX idx_product_type ON t_product_info(product_type);
CREATE INDEX idx_product_sale_status ON t_product_info(sale_status);
CREATE INDEX idx_product_rebate_flag ON t_product_info(rebate_flag);
CREATE INDEX idx_product_sale_start_date ON t_product_info(sale_start_date);
CREATE INDEX idx_product_sale_end_date ON t_product_info(sale_end_date);
-- =============================================
-- 复合索引优化查询性能
-- =============================================
-- 订单查询优化
CREATE INDEX idx_order_complex_query ON t_order_main(dealer_code, order_date, delivery_status, invoice_status);
-- 出库查询优化
CREATE INDEX idx_delivery_complex_query ON t_delivery_main(dealer_code, delivery_date, delivery_status);
-- 发票查询优化
CREATE INDEX idx_invoice_complex_query ON t_invoice_main(dealer_code, invoice_date, invoice_status);
-- 返利查询优化
CREATE INDEX idx_rebate_complex_query ON t_rebate_detail(dealer_code, rebate_date, operate_type);
-- 异常工单查询优化
CREATE INDEX idx_workorder_complex_query ON t_exception_workorder(workorder_status, severity_level, create_time);
-- 经销商查询优化
CREATE INDEX idx_dealer_complex_query ON t_dealer_info(dealer_level, cooperate_status, region);
-- 产品查询优化
CREATE INDEX idx_product_complex_query ON t_product_info(product_type, sale_status, rebate_flag);
This diff is collapsed. Click to expand it.
-- Apple经销商ERP系统对接项目 - 产品管理和经销商管理权限配置脚本
-- 创建时间: 2025-01-27
-- 版本: v1.0
-- 设置数据库和字符集
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- 使用数据库
USE apple_erp;
-- =========================================
-- 1. 插入产品管理相关按钮权限
-- =========================================
-- 获取产品管理主菜单ID(menu_id = 8)
SET @product_menu_id = (SELECT menu_id FROM t_sys_menu WHERE menu_name = '产品管理' AND del_flag = '0' LIMIT 1);
-- 产品管理按钮权限
INSERT INTO t_sys_menu (parent_id, menu_name, menu_type, path, icon, sort, status, perms, create_by, create_time, update_by, update_time, del_flag)
VALUES
(@product_menu_id, '产品查询', '2', '', '', 1, '1', 'product:list', 'admin', NOW(), 'admin', NOW(), '0'),
(@product_menu_id, '产品新增', '2', '', '', 2, '1', 'product:add', 'admin', NOW(), 'admin', NOW(), '0'),
(@product_menu_id, '产品修改', '2', '', '', 3, '1', 'product:edit', 'admin', NOW(), 'admin', NOW(), '0'),
(@product_menu_id, '产品删除', '2', '', '', 4, '1', 'product:delete', 'admin', NOW(), 'admin', NOW(), '0'),
(@product_menu_id, '产品详情', '2', '', '', 5, '1', 'product:detail', 'admin', NOW(), 'admin', NOW(), '0'),
(@product_menu_id, '产品批量删除', '2', '', '', 6, '1', 'product:batchDelete', 'admin', NOW(), 'admin', NOW(), '0'),
(@product_menu_id, '产品状态修改', '2', '', '', 7, '1', 'product:updateStatus', 'admin', NOW(), 'admin', NOW(), '0'),
(@product_menu_id, '产品返利标识修改', '2', '', '', 8, '1', 'product:updateRebateFlag', 'admin', NOW(), 'admin', NOW(), '0');
-- =========================================
-- 2. 插入经销商管理相关按钮权限
-- =========================================
-- 获取经销商管理主菜单ID(menu_id = 9)
SET @dealer_menu_id = (SELECT menu_id FROM t_sys_menu WHERE menu_name = '经销商管理' AND del_flag = '0' LIMIT 1);
-- 经销商管理按钮权限
INSERT INTO t_sys_menu (parent_id, menu_name, menu_type, path, icon, sort, status, perms, create_by, create_time, update_by, update_time, del_flag)
VALUES
(@dealer_menu_id, '经销商查询', '2', '', '', 1, '1', 'dealer:list', 'admin', NOW(), 'admin', NOW(), '0'),
(@dealer_menu_id, '经销商新增', '2', '', '', 2, '1', 'dealer:add', 'admin', NOW(), 'admin', NOW(), '0'),
(@dealer_menu_id, '经销商修改', '2', '', '', 3, '1', 'dealer:update', 'admin', NOW(), 'admin', NOW(), '0'),
(@dealer_menu_id, '经销商删除', '2', '', '', 4, '1', 'dealer:delete', 'admin', NOW(), 'admin', NOW(), '0'),
(@dealer_menu_id, '经销商详情', '2', '', '', 5, '1', 'dealer:detail', 'admin', NOW(), 'admin', NOW(), '0'),
(@dealer_menu_id, '经销商批量删除', '2', '', '', 6, '1', 'dealer:batchDelete', 'admin', NOW(), 'admin', NOW(), '0'),
(@dealer_menu_id, '经销商合作状态修改', '2', '', '', 7, '1', 'dealer:updateStatus', 'admin', NOW(), 'admin', NOW(), '0'),
(@dealer_menu_id, '经销商资质审核', '2', '', '', 8, '1', 'dealer:audit', 'admin', NOW(), 'admin', NOW(), '0');
SET FOREIGN_KEY_CHECKS = 1;
SELECT 'Apple经销商ERP系统产品管理和经销商管理权限配置完成!' AS message;
This diff is collapsed. Click to expand it.
import { request } from '@/utils/request'
import axios from 'axios'
import type { LoginForm, LoginResponse, User } from '@/types'
// 创建axios实例
const api = axios.create({
baseURL: 'http://localhost:8083/api',
timeout: 10000
})
// 请求拦截器
api.interceptors.request.use(
config => {
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
error => {
return Promise.reject(error)
}
)
// 响应拦截器
api.interceptors.response.use(
response => {
return response.data
},
error => {
if (error.response?.status === 401) {
localStorage.removeItem('token')
localStorage.removeItem('userInfo')
window.location.href = '/login'
}
return Promise.reject(error)
}
)
// 登录
export function loginApi(data: LoginForm): Promise<LoginResponse> {
return request.post('/api/auth/login', data)
return api.post('/auth/login', data)
}
// 登出
export function logoutApi(): Promise<void> {
return request.post('/api/auth/logout')
return api.post('/auth/logout')
}
// 获取用户信息
export function getUserInfoApi(): Promise<User> {
return request.get('/api/auth/userInfo')
return api.get('/auth/userInfo')
}
// 刷新Token
export function refreshTokenApi(): Promise<{ token: string }> {
return request.post('/api/auth/refresh')
return api.post('/auth/refresh')
}
// 修改密码
......@@ -26,10 +61,10 @@ export function changePasswordApi(data: {
oldPassword: string
newPassword: string
}): Promise<void> {
return request.post('/api/auth/changePassword', data)
return api.post('/auth/changePassword', data)
}
// 获取验证码
export function getCaptchaApi(): Promise<{ captchaId: string; captchaImage: string }> {
return request.get('/api/auth/captcha')
return api.get('/auth/captcha')
}
......
import axios from 'axios'
// 创建axios实例
const api = axios.create({
baseURL: 'http://localhost:8083/api',
timeout: 10000
})
// 请求拦截器
api.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
(error) => {
return Promise.reject(error)
}
)
// 响应拦截器
api.interceptors.response.use(
(response) => {
return response.data
},
(error) => {
if (error.response?.status === 401) {
localStorage.removeItem('token')
localStorage.removeItem('userInfo')
window.location.href = '/login'
}
return Promise.reject(error)
}
)
// 经销商信息接口
export interface DealerInfo {
dealerId: number
dealerCode: string
dealerName: string
creditCode: string
dealerLevel: number
region: string
contactPerson: string
contactPhone: string
cooperateStartDate: string
cooperateStatus: number
businessLicenseUrl: string
cooperationAgreementUrl: string
qualificationAuditStatus: number
auditOpinion: string
createTime: string
updateTime: string
}
// 经销商查询请求参数
export interface DealerQueryReq {
dealerCode?: string
dealerName?: string
creditCode?: string
dealerLevel?: number
region?: string
contactPerson?: string
contactPhone?: string
cooperateStatus?: number
qualificationAuditStatus?: number
pageNum: number
pageSize: number
}
// 经销商新增请求参数
export interface DealerAddReq {
dealerCode: string
dealerName: string
creditCode: string
dealerLevel: number
region: string
contactPerson?: string
contactPhone?: string
cooperateStartDate: string
cooperateStatus?: number
businessLicenseUrl?: string
cooperationAgreementUrl?: string
qualificationAuditStatus?: number
auditOpinion?: string
}
// 经销商修改请求参数
export interface DealerUpdateReq {
dealerId: number
dealerCode: string
dealerName: string
creditCode: string
dealerLevel: number
region: string
contactPerson?: string
contactPhone?: string
cooperateStartDate: string
cooperateStatus?: number
businessLicenseUrl?: string
cooperationAgreementUrl?: string
qualificationAuditStatus?: number
auditOpinion?: string
}
// 分页数据接口
export interface PageData<T> {
records: T[]
total: number
pageNum: number
pageSize: number
}
// API响应接口
export interface ApiResponse<T = any> {
code: number
message: string
data: T
}
// 经销商管理API
export const dealerApi = {
// 分页查询经销商列表
getDealerList: (params: DealerQueryReq) => {
return api.get<ApiResponse<PageData<DealerInfo>>>('/dealer/list', { params })
},
// 获取经销商详情
getDealerDetail: (dealerId: number) => {
return api.get<ApiResponse<DealerInfo>>(`/dealer/${dealerId}`)
},
// 新增经销商
addDealer: (data: DealerAddReq) => {
return api.post<ApiResponse>('/dealer', data)
},
// 修改经销商
updateDealer: (data: DealerUpdateReq) => {
return api.post<ApiResponse>('/dealer/update', data)
},
// 删除经销商
deleteDealer: (dealerId: number) => {
return api.delete<ApiResponse>(`/dealer/${dealerId}`)
},
// 批量删除经销商
batchDeleteDealer: (dealerIds: number[]) => {
return api.delete<ApiResponse>('/dealer/batch', { data: dealerIds })
},
// 修改经销商合作状态
updateCooperateStatus: (dealerId: number, cooperateStatus: number) => {
return api.post<ApiResponse>(`/dealer/${dealerId}/cooperateStatus/${cooperateStatus}`)
},
// 修改经销商资质审核状态
updateAuditStatus: (dealerId: number, qualificationAuditStatus: number, auditOpinion?: string) => {
return api.post<ApiResponse>(`/dealer/${dealerId}/auditStatus`, null, {
params: { qualificationAuditStatus, auditOpinion }
})
}
}
import axios from 'axios'
// 创建axios实例
const api = axios.create({
baseURL: 'http://localhost:8083/api',
timeout: 10000
})
// 请求拦截器
api.interceptors.request.use(
config => {
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
error => {
return Promise.reject(error)
}
)
// 响应拦截器
api.interceptors.response.use(
response => {
return response.data
},
error => {
if (error.response?.status === 401) {
localStorage.removeItem('token')
localStorage.removeItem('userInfo')
window.location.href = '/login'
}
return Promise.reject(error)
}
)
// 产品信息接口
export interface ProductInfo {
productId: number
productCode: string
productName: string
productModel: string
productType: string
storageCapacity: string
color: string
officialPrice: number
saleStatus: number
rebateFlag: number
saleStartDate: string
saleEndDate: string
imageUrl: string
remark: string
createTime: string
updateTime: string
}
// 产品查询请求参数
export interface ProductQueryReq {
productCode?: string
productName?: string
productModel?: string
saleStatus?: number
rebateFlag?: number
pageNum: number
pageSize: number
}
// 产品新增请求参数
export interface ProductAddReq {
productCode: string
productName: string
productModel: string
productType: string
storageCapacity: string
color: string
officialPrice: number
saleStatus: number
rebateFlag: number
saleStartDate: string
saleEndDate: string
imageUrl?: string
remark?: string
}
// 产品修改请求参数
export interface ProductUpdateReq {
productId: number
productCode: string
productName: string
productModel: string
productType: string
storageCapacity: string
color: string
officialPrice: number
saleStatus: number
rebateFlag: number
saleStartDate: string
saleEndDate: string
imageUrl?: string
remark?: string
}
// 分页数据接口
export interface PageData<T> {
records: T[]
total: number
current: number
size: number
pages: number
}
// API响应接口
export interface ApiResponse<T> {
code: number
message: string
data: T
}
// API接口
export const productApi = {
// 获取产品列表
getProductList: (params: ProductQueryReq) => {
return api.get<ApiResponse<PageData<ProductInfo>>>('/product/list', { params })
},
// 获取产品详情
getProductDetail: (productId: number) => {
return api.get<ProductInfo>(`/product/${productId}`)
},
// 新增产品
addProduct: (data: ProductAddReq) => {
return api.post('/product', data)
},
// 修改产品
updateProduct: (data: ProductUpdateReq) => {
return api.post('/product/update', data)
},
// 删除产品
deleteProduct: (productId: number) => {
return api.delete(`/product/${productId}`)
},
// 批量删除产品
batchDeleteProduct: (productIds: number[]) => {
return api.post('/product/batchDelete', productIds)
},
// 修改销售状态
updateSaleStatus: (productId: number, saleStatus: number) => {
return api.post(`/product/${productId}/status`, null, { params: { saleStatus } })
},
// 修改返利标识
updateRebateFlag: (productId: number, rebateFlag: number) => {
return api.post(`/product/${productId}/rebate`, null, { params: { rebateFlag } })
}
}
......@@ -124,6 +124,7 @@
<script setup lang="ts">
import { ref, computed, onMounted, watch, nextTick } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { logoutApi } from '../api/auth'
const router = useRouter()
const route = useRoute()
......@@ -140,6 +141,8 @@ const tabContainer = ref<HTMLElement>()
// 菜单项配置
const menuItems = ref([
{ name: '首页', path: '/main/dashboard', icon: '🏠' },
{ name: '产品管理', path: '/main/product', icon: '📦' },
{ name: '经销商管理', path: '/main/dealer', icon: '🏢' },
{
name: '系统设置',
icon: '⚙️',
......@@ -314,14 +317,21 @@ const toggleSidebar = () => {
}
// 退出登录
const handleLogout = () => {
const handleLogout = async () => {
if (confirm('确定要退出登录吗?')) {
// 清除本地存储
localStorage.removeItem('token')
localStorage.removeItem('userInfo')
// 跳转到登录页
router.push('/')
try {
// 调用后端退出登录接口
await logoutApi()
} catch (error) {
console.error('退出登录接口调用失败:', error)
} finally {
// 无论接口调用成功与否,都清除本地存储
localStorage.removeItem('token')
localStorage.removeItem('userInfo')
// 跳转到登录页
router.push('/')
}
}
}
......
......@@ -45,6 +45,15 @@ const staticRoutes: RouteRecordRaw[] = [
}
},
{
path: 'product',
name: 'Product',
component: () => import('@/views/product/index.vue'),
meta: {
title: '产品管理',
requiresAuth: true
}
},
{
path: 'sys/role',
name: 'Role',
component: () => import('@/views/sys/role/index.vue'),
......@@ -108,6 +117,24 @@ const staticRoutes: RouteRecordRaw[] = [
}
},
{
path: 'product',
name: 'Product',
component: () => import('@/views/product/index.vue'),
meta: {
title: '产品管理',
requiresAuth: true
}
},
{
path: 'dealer',
name: 'Dealer',
component: () => import('@/views/dealer/index.vue'),
meta: {
title: '经销商管理',
requiresAuth: true
}
},
{
path: 'settings',
name: 'Settings',
component: () => import('@/views/settings/index.vue'),
......
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
<template>
<div class="users-container">
<!-- 搜索筛选区域 -->
<div class="search-section">
<div class="search-row">
<div class="search-item">
<label>登录名称:</label>
<input
v-model="searchForm.username"
type="text"
class="search-input"
placeholder="请输入登录名称"
/>
</div>
<div class="search-item">
<label>用户状态:</label>
<select v-model="searchForm.status" class="search-select">
<option value="">所有</option>
<option value="1">正常</option>
<option value="0">停用</option>
</select>
</div>
<div class="search-item">
<label>创建时间:</label>
<div class="date-range">
<div class="date-picker-container">
<input
v-model="searchForm.startTime"
type="text"
class="date-input"
placeholder="开始时间"
readonly
@click="toggleStartDatePicker"
@mouseenter="showStartDateOptions = true"
@mouseleave="hideStartDateOptions"
/>
<div v-if="showStartDateOptions" class="date-options" @mouseenter="showStartDateOptions = true" @mouseleave="hideStartDateOptions">
<div class="date-option" @click="selectStartDate('today')">今天</div>
<div class="date-option" @click="selectStartDate('yesterday')">昨天</div>
<div class="date-option" @click="selectStartDate('thisWeek')">本周</div>
<div class="date-option" @click="selectStartDate('lastWeek')">上周</div>
<div class="date-option" @click="selectStartDate('thisMonth')">本月</div>
<div class="date-option" @click="selectStartDate('lastMonth')">上月</div>
<div class="date-option" @click="selectStartDate('custom')">自定义</div>
</div>
<!-- 自定义日期选择器 -->
<div v-if="showStartDatePicker" class="custom-date-picker">
<input
type="date"
v-model="searchForm.startTime"
@change="showStartDatePicker = false"
class="date-input"
/>
</div>
</div>
<span class="date-separator">-</span>
<div class="date-picker-container">
<input
v-model="searchForm.endTime"
type="text"
class="date-input"
placeholder="结束时间"
readonly
@click="toggleEndDatePicker"
@mouseenter="showEndDateOptions = true"
@mouseleave="hideEndDateOptions"
/>
<div v-if="showEndDateOptions" class="date-options" @mouseenter="showEndDateOptions = true" @mouseleave="hideEndDateOptions">
<div class="date-option" @click="selectEndDate('today')">今天</div>
<div class="date-option" @click="selectEndDate('yesterday')">昨天</div>
<div class="date-option" @click="selectEndDate('thisWeek')">本周</div>
<div class="date-option" @click="selectEndDate('lastWeek')">上周</div>
<div class="date-option" @click="selectEndDate('thisMonth')">本月</div>
<div class="date-option" @click="selectEndDate('lastMonth')">上月</div>
<div class="date-option" @click="selectEndDate('custom')">自定义</div>
</div>
<!-- 自定义日期选择器 -->
<div v-if="showEndDatePicker" class="custom-date-picker">
<input
type="date"
v-model="searchForm.endTime"
@change="showEndDatePicker = false"
class="date-input"
/>
</div>
</div>
</div>
</div>
<div class="search-actions">
<button @click="handleSearch" class="search-btn">🔍 搜索</button>
<button @click="handleReset" class="reset-btn">🔄 重置</button>
</div>
</div>
</div>
<!-- 操作按钮区域 -->
<div class="action-section">
<div class="action-buttons">
<button @click="handleAdd" class="action-btn primary">✨ 新增</button>
<button @click="handleBatchDelete" class="action-btn danger">🗑️ 删除</button>
</div>
</div>
<!-- 数据表格 -->
<div class="table-section">
<div class="table-header">
<div class="table-controls">
<button @click="handleTableSearch" class="control-btn" title="搜索">🔍</button>
<button @click="handleTableRefresh" class="control-btn" title="刷新">🔄</button>
<button @click="handleTableExport" class="control-btn" title="导出">📋</button>
<button @click="handleTableViewToggle" class="control-btn" title="视图切换">⊞</button>
</div>
</div>
<div class="table-container">
<div v-if="loading" class="loading-overlay">
<div class="loading-spinner">加载中...</div>
</div>
<table class="data-table">
<thead>
<tr>
<th>
<input
type="checkbox"
class="select-all"
v-model="selectAll"
@change="handleSelectAll"
/>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="user in users" :key="user.userId">
<td>
<button @click="handleEdit(user)" class="table-btn edit">✏️ 编辑</button>
<button @click="handleDelete(user)" class="table-btn delete">🗑️ 删除</button>
</td>
</tr>
</tbody>
</table>
</div>
<!-- 分页信息 -->
<div class="table-footer">
<div class="pagination-left">
<div class="pagination-info">
共 {{ total }} 条记录,第 {{ currentPage }} / {{ totalPages }} 页
</div>
<div class="page-size-selector">
<label>每页显示:</label>
<select v-model="pageSize" @change="handlePageSizeChange" class="page-size-select">
<option value="10">10条</option>
<option value="20">20条</option>
<option value="50">50条</option>
<option value="100">100条</option>
</select>
</div>
</div>
<div class="pagination-container">
<button
@click="handlePageChange(currentPage - 1)"
:disabled="currentPage <= 1"
class="pagination-btn prev-btn"
>
上一页
</button>
<div class="pagination-pages">
<button
v-for="page in getPageNumbers()"
:key="page"
@click="handlePageChange(page)"
:class="['page-number', { active: page === currentPage }]"
>
{{ page }}
</button>
</div>
<button
@click="handlePageChange(currentPage + 1)"
:disabled="currentPage >= totalPages"
class="pagination-btn next-btn"
>
下一页
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
\ No newline at end of file