add项目售后信息

dev
Yangk 2 months ago
parent 05d13e3ac1
commit c9b98623cc

@ -0,0 +1,116 @@
package org.dromara.oa.erp.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.oa.erp.domain.vo.ErpAfterSalesVo;
import org.dromara.oa.erp.domain.bo.ErpAfterSalesBo;
import org.dromara.oa.erp.service.IErpAfterSalesService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
*
* 访:/oa/erp/afterSales
*
* @author Yangk
* @date 2025-11-21
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/erp/afterSales")
public class ErpAfterSalesController extends BaseController {
private final IErpAfterSalesService erpAfterSalesService;
/**
*
*/
@SaCheckPermission("oa/erp:afterSales:list")
@GetMapping("/list")
public TableDataInfo<ErpAfterSalesVo> list(ErpAfterSalesBo bo, PageQuery pageQuery) {
return erpAfterSalesService.queryPageList(bo, pageQuery);
}
/**
*
*/
@SaCheckPermission("oa/erp:afterSales:export")
@Log(title = "项目售后信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(ErpAfterSalesBo bo, HttpServletResponse response) {
List<ErpAfterSalesVo> list = erpAfterSalesService.queryList(bo);
ExcelUtil.exportExcel(list, "项目售后信息", ErpAfterSalesVo.class, response);
}
/**
*
*
* @param afterSalesId
*/
@SaCheckPermission("oa/erp:afterSales:query")
@GetMapping("/{afterSalesId}")
public R<ErpAfterSalesVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable("afterSalesId") Long afterSalesId) {
return R.ok(erpAfterSalesService.queryById(afterSalesId));
}
/**
*
*/
@SaCheckPermission("oa/erp:afterSales:add")
@Log(title = "项目售后信息", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody ErpAfterSalesBo bo) {
return toAjax(erpAfterSalesService.insertByBo(bo));
}
/**
*
*/
@SaCheckPermission("oa/erp:afterSales:edit")
@Log(title = "项目售后信息", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ErpAfterSalesBo bo) {
return toAjax(erpAfterSalesService.updateByBo(bo));
}
/**
*
*
* @param afterSalesIds
*/
@SaCheckPermission("oa/erp:afterSales:remove")
@Log(title = "项目售后信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{afterSalesIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable("afterSalesIds") Long[] afterSalesIds) {
return toAjax(erpAfterSalesService.deleteWithValidByIds(List.of(afterSalesIds), true));
}
/**
*
*/
@GetMapping("/getErpAfterSalesList")
public R<List<ErpAfterSalesVo>> getErpAfterSalesList(ErpAfterSalesBo bo) {
List<ErpAfterSalesVo> list = erpAfterSalesService.queryList(bo);
return R.ok(list);
}
}

@ -0,0 +1,116 @@
package org.dromara.oa.erp.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.oa.erp.domain.vo.ErpAfterSalesLaborCostsVo;
import org.dromara.oa.erp.domain.bo.ErpAfterSalesLaborCostsBo;
import org.dromara.oa.erp.service.IErpAfterSalesLaborCostsService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
*
* 访:/oa/erp/afterSalesLaborCosts
*
* @author Yangk
* @date 2025-11-21
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/erp/afterSalesLaborCosts")
public class ErpAfterSalesLaborCostsController extends BaseController {
private final IErpAfterSalesLaborCostsService erpAfterSalesLaborCostsService;
/**
*
*/
@SaCheckPermission("oa/erp:afterSalesLaborCosts:list")
@GetMapping("/list")
public TableDataInfo<ErpAfterSalesLaborCostsVo> list(ErpAfterSalesLaborCostsBo bo, PageQuery pageQuery) {
return erpAfterSalesLaborCostsService.queryPageList(bo, pageQuery);
}
/**
*
*/
@SaCheckPermission("oa/erp:afterSalesLaborCosts:export")
@Log(title = "售后人员费用明细", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(ErpAfterSalesLaborCostsBo bo, HttpServletResponse response) {
List<ErpAfterSalesLaborCostsVo> list = erpAfterSalesLaborCostsService.queryList(bo);
ExcelUtil.exportExcel(list, "售后人员费用明细", ErpAfterSalesLaborCostsVo.class, response);
}
/**
*
*
* @param laborCostsId
*/
@SaCheckPermission("oa/erp:afterSalesLaborCosts:query")
@GetMapping("/{laborCostsId}")
public R<ErpAfterSalesLaborCostsVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable("laborCostsId") Long laborCostsId) {
return R.ok(erpAfterSalesLaborCostsService.queryById(laborCostsId));
}
/**
*
*/
@SaCheckPermission("oa/erp:afterSalesLaborCosts:add")
@Log(title = "售后人员费用明细", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody ErpAfterSalesLaborCostsBo bo) {
return toAjax(erpAfterSalesLaborCostsService.insertByBo(bo));
}
/**
*
*/
@SaCheckPermission("oa/erp:afterSalesLaborCosts:edit")
@Log(title = "售后人员费用明细", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ErpAfterSalesLaborCostsBo bo) {
return toAjax(erpAfterSalesLaborCostsService.updateByBo(bo));
}
/**
*
*
* @param laborCostsIds
*/
@SaCheckPermission("oa/erp:afterSalesLaborCosts:remove")
@Log(title = "售后人员费用明细", businessType = BusinessType.DELETE)
@DeleteMapping("/{laborCostsIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable("laborCostsIds") Long[] laborCostsIds) {
return toAjax(erpAfterSalesLaborCostsService.deleteWithValidByIds(List.of(laborCostsIds), true));
}
/**
*
*/
@GetMapping("/getErpAfterSalesLaborCostsList")
public R<List<ErpAfterSalesLaborCostsVo>> getErpAfterSalesLaborCostsList(ErpAfterSalesLaborCostsBo bo) {
List<ErpAfterSalesLaborCostsVo> list = erpAfterSalesLaborCostsService.queryList(bo);
return R.ok(list);
}
}

@ -0,0 +1,116 @@
package org.dromara.oa.erp.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.oa.erp.domain.vo.ErpAfterSalesMaterialCostsVo;
import org.dromara.oa.erp.domain.bo.ErpAfterSalesMaterialCostsBo;
import org.dromara.oa.erp.service.IErpAfterSalesMaterialCostsService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
*
* 访:/oa/erp/afterSalesMaterialCosts
*
* @author Yangk
* @date 2025-11-21
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/erp/afterSalesMaterialCosts")
public class ErpAfterSalesMaterialCostsController extends BaseController {
private final IErpAfterSalesMaterialCostsService erpAfterSalesMaterialCostsService;
/**
*
*/
@SaCheckPermission("oa/erp:afterSalesMaterialCosts:list")
@GetMapping("/list")
public TableDataInfo<ErpAfterSalesMaterialCostsVo> list(ErpAfterSalesMaterialCostsBo bo, PageQuery pageQuery) {
return erpAfterSalesMaterialCostsService.queryPageList(bo, pageQuery);
}
/**
*
*/
@SaCheckPermission("oa/erp:afterSalesMaterialCosts:export")
@Log(title = "售后材料费用明细", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(ErpAfterSalesMaterialCostsBo bo, HttpServletResponse response) {
List<ErpAfterSalesMaterialCostsVo> list = erpAfterSalesMaterialCostsService.queryList(bo);
ExcelUtil.exportExcel(list, "售后材料费用明细", ErpAfterSalesMaterialCostsVo.class, response);
}
/**
*
*
* @param materialCostsId
*/
@SaCheckPermission("oa/erp:afterSalesMaterialCosts:query")
@GetMapping("/{materialCostsId}")
public R<ErpAfterSalesMaterialCostsVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable("materialCostsId") Long materialCostsId) {
return R.ok(erpAfterSalesMaterialCostsService.queryById(materialCostsId));
}
/**
*
*/
@SaCheckPermission("oa/erp:afterSalesMaterialCosts:add")
@Log(title = "售后材料费用明细", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody ErpAfterSalesMaterialCostsBo bo) {
return toAjax(erpAfterSalesMaterialCostsService.insertByBo(bo));
}
/**
*
*/
@SaCheckPermission("oa/erp:afterSalesMaterialCosts:edit")
@Log(title = "售后材料费用明细", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ErpAfterSalesMaterialCostsBo bo) {
return toAjax(erpAfterSalesMaterialCostsService.updateByBo(bo));
}
/**
*
*
* @param materialCostsIds
*/
@SaCheckPermission("oa/erp:afterSalesMaterialCosts:remove")
@Log(title = "售后材料费用明细", businessType = BusinessType.DELETE)
@DeleteMapping("/{materialCostsIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable("materialCostsIds") Long[] materialCostsIds) {
return toAjax(erpAfterSalesMaterialCostsService.deleteWithValidByIds(List.of(materialCostsIds), true));
}
/**
*
*/
@GetMapping("/getErpAfterSalesMaterialCostsList")
public R<List<ErpAfterSalesMaterialCostsVo>> getErpAfterSalesMaterialCostsList(ErpAfterSalesMaterialCostsBo bo) {
List<ErpAfterSalesMaterialCostsVo> list = erpAfterSalesMaterialCostsService.queryList(bo);
return R.ok(list);
}
}

@ -0,0 +1,169 @@
package org.dromara.oa.erp.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
/**
* erp_after_sales
*
* @author Yangk
* @date 2025-11-21
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("erp_after_sales")
public class ErpAfterSales extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@TableId(value = "after_sales_id", type = IdType.ASSIGN_ID)
private Long afterSalesId;
/**
*
*/
private String afterSalesCode;
/**
*
*/
private String afterSalesSubject;
/**
* ID
*/
private Long projectId;
/**
*
*/
private String projectCode;
/**
*
*/
private String projectName;
/**
* ID
*/
private Long customerId;
/**
*
*/
private String customerName;
/**
*
*/
private String contactPerson;
/**
*
*/
private String contactPhone;
/**
*
*/
private Date afterSalesDate;
/**
* ID
*/
private Long contractId;
/**
*
*/
private String contractCode;
/**
*
*/
private String afterSalesType;
/**
* ID
*/
private String stakeholderId;
/**
* ID
*/
private String handlerId;
/**
*
*/
private String problemDescription;
/**
*
*/
private Long totalWorkHours;
/**
*
*/
private Long totalCost;
/**
* 0 1 2
*/
private String solveStatus;
/**
*
*/
private Date completionDate;
/**
*
*/
private String processingResult;
/**
* 0 1 2
*/
private String afterSalesStatus;
/**
*
*/
private String flowStatus;
/**
* 1 0
*/
private String activeFlag;
/**
*
*/
private String remark;
/**
* 0 1
*/
@TableLogic
private String delFlag;
/**
* ID
*/
private String ossId;
}

@ -0,0 +1,73 @@
package org.dromara.oa.erp.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
import java.math.BigDecimal;
/**
* erp_after_sales_labor_costs
*
* @author Yangk
* @date 2025-11-21
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("erp_after_sales_labor_costs")
public class ErpAfterSalesLaborCosts extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@TableId(value = "labor_costs_id", type = IdType.ASSIGN_ID)
private Long laborCostsId;
/**
* ID
*/
private Long afterSalesId;
/**
* ID
*/
private Long laborId;
/**
*
*/
private String laborName;
/**
*
*/
private String expenseItem;
/**
*
*/
private BigDecimal cost;
/**
*
*/
private String remark;
/**
*
*/
private Long sortOrder;
/**
* 0 1
*/
@TableLogic
private String delFlag;
}

@ -0,0 +1,113 @@
package org.dromara.oa.erp.domain;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
import java.math.BigDecimal;
/**
* erp_after_sales_material_costs
*
* @author Yangk
* @date 2025-11-21
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("erp_after_sales_material_costs")
public class ErpAfterSalesMaterialCosts extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@TableId(value = "material_costs_id", type = IdType.ASSIGN_ID)
private Long materialCostsId;
/**
* ID
*/
private Long afterSalesId;
/**
* ID
*/
private Long materialId;
/**
*
*/
private String productCode;
/**
*
*/
private String productName;
/**
*
*/
private String specificationModel;
/**
* ID
*/
private String unitId;
/**
*
*/
private Long quantity;
/**
* %
*/
private Long taxRate;
/**
*
*/
private BigDecimal taxInclusivePrice;
/**
*
*/
private BigDecimal taxInclusiveAmount;
/**
*
*/
private BigDecimal taxExclusivePrice;
/**
*
*/
private BigDecimal taxExclusiveAmount;
/**
* 0 1
*/
private String giftFlag;
/**
*
*/
private String remark;
/**
*
*/
private Long sortOrder;
/**
* 0 1
*/
@TableLogic
private String delFlag;
}

@ -0,0 +1,184 @@
package org.dromara.oa.erp.domain.bo;
import org.dromara.oa.erp.domain.ErpAfterSales;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.List; // 1. 别忘了导包 List
// 2. 导入两个子表的 BO 对象,因为前端传的是子表的业务数据
import org.dromara.oa.erp.domain.bo.ErpAfterSalesLaborCostsBo;
import org.dromara.oa.erp.domain.bo.ErpAfterSalesMaterialCostsBo;
/**
* erp_after_sales
*
* @author Yangk
* @date 2025-11-21
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = ErpAfterSales.class, reverseConvertGenerate = false)
public class ErpAfterSalesBo extends BaseEntity {
/**
* ID
*/
@NotNull(message = "售后ID不能为空", groups = { EditGroup.class })
private Long afterSalesId;
/**
*
*/
private String afterSalesCode;
/**
*
*/
@NotBlank(message = "售后主题不能为空", groups = { AddGroup.class, EditGroup.class })
private String afterSalesSubject;
/**
* ID
*/
private Long projectId;
/**
*
*/
private String projectCode;
/**
*
*/
private String projectName;
/**
* ID
*/
private Long customerId;
/**
*
*/
private String customerName;
/**
*
*/
private String contactPerson;
/**
*
*/
private String contactPhone;
/**
*
*/
private Date afterSalesDate;
/**
* ID
*/
private Long contractId;
/**
*
*/
private String contractCode;
/**
*
*/
private String afterSalesType;
/**
* ID
*/
@NotBlank(message = "客户干系人ID关联客户联系人表不能为空", groups = { AddGroup.class, EditGroup.class })
private String stakeholderId;
/**
* ID
*/
@NotBlank(message = "处理人ID关联用户表不能为空", groups = { AddGroup.class, EditGroup.class })
private String handlerId;
/**
*
*/
private String problemDescription;
/**
*
*/
private Long totalWorkHours;
/**
*
*/
private Long totalCost;
/**
* 0 1 2
*/
private String solveStatus;
/**
*
*/
private Date completionDate;
/**
*
*/
private String processingResult;
/**
* 0 1 2
*/
private String afterSalesStatus;
/**
*
*/
private String flowStatus;
/**
* 1 0
*/
private String activeFlag;
/**
*
*/
private String remark;
/**
* ID
*/
private String ossId;
/**
*
* JSON "laborCostsList": [...]
*/
private List<ErpAfterSalesLaborCostsBo> laborCostsList;
/**
*
* JSON "materialCostsList": [...]
*/
private List<ErpAfterSalesMaterialCostsBo> materialCostsList;
}

@ -0,0 +1,68 @@
package org.dromara.oa.erp.domain.bo;
import org.dromara.oa.erp.domain.ErpAfterSalesLaborCosts;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
/**
* erp_after_sales_labor_costs
*
* @author Yangk
* @date 2025-11-21
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = ErpAfterSalesLaborCosts.class, reverseConvertGenerate = false)
public class ErpAfterSalesLaborCostsBo extends BaseEntity {
/**
* ID
*/
@NotNull(message = "人员费用ID不能为空", groups = { EditGroup.class })
private Long laborCostsId;
/**
* ID
*/
@NotNull(message = "售后ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long afterSalesId;
/**
* ID
*/
private Long laborId;
/**
*
*/
private String laborName;
/**
*
*/
private String expenseItem;
/**
*
*/
private BigDecimal cost;
/**
*
*/
private String remark;
/**
*
*/
private Long sortOrder;
}

@ -0,0 +1,109 @@
package org.dromara.oa.erp.domain.bo;
import org.dromara.oa.erp.domain.ErpAfterSalesMaterialCosts;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
/**
* erp_after_sales_material_costs
*
* @author Yangk
* @date 2025-11-21
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = ErpAfterSalesMaterialCosts.class, reverseConvertGenerate = false)
public class ErpAfterSalesMaterialCostsBo extends BaseEntity {
/**
* ID
*/
@NotNull(message = "材料费用ID不能为空", groups = { EditGroup.class })
private Long materialCostsId;
/**
* ID
*/
@NotNull(message = "售后ID不能为空", groups = { AddGroup.class, EditGroup.class })
private Long afterSalesId;
/**
* ID
*/
private Long materialId;
/**
*
*/
private String productCode;
/**
*
*/
private String productName;
/**
*
*/
private String specificationModel;
/**
* ID
*/
private String unitId;
/**
*
*/
private Long quantity;
/**
* %
*/
private Long taxRate;
/**
*
*/
private BigDecimal taxInclusivePrice;
/**
*
*/
private BigDecimal taxInclusiveAmount;
/**
*
*/
private BigDecimal taxExclusivePrice;
/**
*
*/
private BigDecimal taxExclusiveAmount;
/**
* 0 1
*/
private String giftFlag;
/**
*
*/
private String remark;
/**
*
*/
private Long sortOrder;
}

@ -0,0 +1,81 @@
package org.dromara.oa.erp.domain.vo;
import org.dromara.oa.erp.domain.ErpAfterSalesLaborCosts;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* erp_after_sales_labor_costs
*
* @author Yangk
* @date 2025-11-21
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = ErpAfterSalesLaborCosts.class)
public class ErpAfterSalesLaborCostsVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@ExcelProperty(value = "人员费用ID")
private Long laborCostsId;
/**
* ID
*/
@ExcelProperty(value = "售后ID")
private Long afterSalesId;
/**
* ID
*/
@ExcelProperty(value = "人员ID", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "关=联用户表")
private Long laborId;
/**
*
*/
@ExcelProperty(value = "人员姓名")
private String laborName;
/**
*
*/
@ExcelProperty(value = "费用科目")
private String expenseItem;
/**
*
*/
@ExcelProperty(value = "成本")
private Long cost;
/**
*
*/
@ExcelProperty(value = "备注")
private String remark;
/**
*
*/
@ExcelProperty(value = "排序号")
private Long sortOrder;
}

@ -0,0 +1,129 @@
package org.dromara.oa.erp.domain.vo;
import org.dromara.oa.erp.domain.ErpAfterSalesMaterialCosts;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* erp_after_sales_material_costs
*
* @author Yangk
* @date 2025-11-21
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = ErpAfterSalesMaterialCosts.class)
public class ErpAfterSalesMaterialCostsVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@ExcelProperty(value = "材料费用ID")
private Long materialCostsId;
/**
* ID
*/
@ExcelProperty(value = "售后ID")
private Long afterSalesId;
/**
* ID
*/
@ExcelProperty(value = "物料ID")
private Long materialId;
/**
*
*/
@ExcelProperty(value = "产品编码")
private String productCode;
/**
*
*/
@ExcelProperty(value = "产品名称")
private String productName;
/**
*
*/
@ExcelProperty(value = "规格型号")
private String specificationModel;
/**
* ID
*/
@ExcelProperty(value = "单位ID")
private String unitId;
/**
*
*/
@ExcelProperty(value = "数量")
private Long quantity;
/**
* %
*/
@ExcelProperty(value = "税率%")
private Long taxRate;
/**
*
*/
@ExcelProperty(value = "含税单价")
private Long taxInclusivePrice;
/**
*
*/
@ExcelProperty(value = "含税金额")
private Long taxInclusiveAmount;
/**
*
*/
@ExcelProperty(value = "不含税单价")
private Long taxExclusivePrice;
/**
*
*/
@ExcelProperty(value = "不含税金额")
private Long taxExclusiveAmount;
/**
* 0 1
*/
@ExcelProperty(value = "赠品", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "gift_flag")
private String giftFlag;
/**
*
*/
@ExcelProperty(value = "备注")
private String remark;
/**
*
*/
@ExcelProperty(value = "排序号")
private Long sortOrder;
}

@ -0,0 +1,215 @@
package org.dromara.oa.erp.domain.vo;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.dromara.oa.erp.domain.ErpAfterSales;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
import cn.idev.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.oa.erp.domain.vo.ErpAfterSalesLaborCostsVo;
import org.dromara.oa.erp.domain.vo.ErpAfterSalesMaterialCostsVo;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* erp_after_sales
*
* @author Yangk
* @date 2025-11-21
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = ErpAfterSales.class)
public class ErpAfterSalesVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@ExcelProperty(value = "售后ID")
private Long afterSalesId;
/**
*
*/
@ExcelProperty(value = "售后编号")
private String afterSalesCode;
/**
*
*/
@ExcelProperty(value = "售后主题")
private String afterSalesSubject;
/**
* ID
*/
@ExcelProperty(value = "项目ID")
private Long projectId;
/**
*
*/
@ExcelProperty(value = "项目编号")
private String projectCode;
/**
*
*/
@ExcelProperty(value = "项目名称")
private String projectName;
/**
* ID
*/
@ExcelProperty(value = "客户ID")
private Long customerId;
/**
*
*/
@ExcelProperty(value = "客户名称")
private String customerName;
/**
*
*/
@ExcelProperty(value = "联系人")
private String contactPerson;
/**
*
*/
@ExcelProperty(value = "联系电话")
private String contactPhone;
/**
*
*/
@ExcelProperty(value = "售后日期")
private Date afterSalesDate;
/**
* ID
*/
@ExcelProperty(value = "合同ID")
private Long contractId;
/**
*
*/
@ExcelProperty(value = "合同号")
private String contractCode;
/**
*
*/
@ExcelProperty(value = "售后类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "after_sales_type")
private String afterSalesType;
/**
* ID
*/
@ExcelProperty(value = "客户干系人ID", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "关=联客户联系人表")
private String stakeholderId;
/**
* ID
*/
@ExcelProperty(value = "处理人ID", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "关=联用户表")
private String handlerId;
/**
*
*/
@ExcelProperty(value = "问题描述")
private String problemDescription;
/**
*
*/
@ExcelProperty(value = "售后总工时")
private Long totalWorkHours;
/**
*
*/
@ExcelProperty(value = "售后总成本")
private Long totalCost;
/**
* 0 1 2
*/
@ExcelProperty(value = "售后问题是否解决", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "solve_status")
private String solveStatus;
/**
*
*/
@ExcelProperty(value = "完成日期")
private Date completionDate;
/**
*
*/
@ExcelProperty(value = "处理结果")
private String processingResult;
/**
* 0 1 2
*/
@ExcelProperty(value = "售后状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "after_sales_status")
private String afterSalesStatus;
/**
*
*/
@ExcelProperty(value = "流程状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "flow_status")
private String flowStatus;
/**
* 1 0
*/
@ExcelProperty(value = "激活标识", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "active_flag")
private String activeFlag;
/**
*
*/
@ExcelProperty(value = "备注")
private String remark;
/**
*
*/
private List<ErpAfterSalesLaborCostsVo> laborCostsList;
private List<ErpAfterSalesMaterialCostsVo> materialCostsList;
/**
*
*/
private String stakeholderName;
/**
*
*/
private String handlerName;
}

@ -0,0 +1,37 @@
package org.dromara.oa.erp.mapper;
import java.util.List;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.dromara.oa.erp.domain.ErpAfterSalesLaborCosts;
import org.dromara.oa.erp.domain.vo.ErpAfterSalesLaborCostsVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* Mapper
*
* @author Yangk
* @date 2025-11-21
*/
public interface ErpAfterSalesLaborCostsMapper extends BaseMapperPlus<ErpAfterSalesLaborCosts, ErpAfterSalesLaborCostsVo> {
/**
*
*
* @param page
* @param queryWrapper
* @return
*/
public Page<ErpAfterSalesLaborCostsVo> selectCustomErpAfterSalesLaborCostsVoList(@Param("page") Page<ErpAfterSalesLaborCostsVo> page, @Param(Constants.WRAPPER) MPJLambdaWrapper<ErpAfterSalesLaborCosts> queryWrapper);
/**
*
*
* @param queryWrapper
* @return
*/
public List<ErpAfterSalesLaborCostsVo> selectCustomErpAfterSalesLaborCostsVoList(@Param(Constants.WRAPPER) MPJLambdaWrapper<ErpAfterSalesLaborCosts> queryWrapper);
}

@ -0,0 +1,43 @@
package org.dromara.oa.erp.mapper;
import java.util.List;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.dromara.oa.erp.domain.ErpAfterSales;
import org.dromara.oa.erp.domain.vo.ErpAfterSalesVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* Mapper
*
* @author Yangk
* @date 2025-11-21
*/
public interface ErpAfterSalesMapper extends BaseMapperPlus<ErpAfterSales, ErpAfterSalesVo> {
/**
*
*
* @param page
* @param queryWrapper
* @return
*/
public Page<ErpAfterSalesVo> selectCustomErpAfterSalesVoList(@Param("page") Page<ErpAfterSalesVo> page, @Param(Constants.WRAPPER) MPJLambdaWrapper<ErpAfterSales> queryWrapper);
/**
*
*
* @param queryWrapper
* @return
*/
public List<ErpAfterSalesVo> selectCustomErpAfterSalesVoList(@Param(Constants.WRAPPER) MPJLambdaWrapper<ErpAfterSales> queryWrapper);
// 【新增】自定义分页查询,为了关联出多选的名字
Page<ErpAfterSalesVo> selectCustomVoPage(@Param("page") Page<ErpAfterSalesVo> page, @Param("ew") Wrapper<ErpAfterSales> wrapper);
}

@ -0,0 +1,37 @@
package org.dromara.oa.erp.mapper;
import java.util.List;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.dromara.oa.erp.domain.ErpAfterSalesMaterialCosts;
import org.dromara.oa.erp.domain.vo.ErpAfterSalesMaterialCostsVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* Mapper
*
* @author Yangk
* @date 2025-11-21
*/
public interface ErpAfterSalesMaterialCostsMapper extends BaseMapperPlus<ErpAfterSalesMaterialCosts, ErpAfterSalesMaterialCostsVo> {
/**
*
*
* @param page
* @param queryWrapper
* @return
*/
public Page<ErpAfterSalesMaterialCostsVo> selectCustomErpAfterSalesMaterialCostsVoList(@Param("page") Page<ErpAfterSalesMaterialCostsVo> page, @Param(Constants.WRAPPER) MPJLambdaWrapper<ErpAfterSalesMaterialCosts> queryWrapper);
/**
*
*
* @param queryWrapper
* @return
*/
public List<ErpAfterSalesMaterialCostsVo> selectCustomErpAfterSalesMaterialCostsVoList(@Param(Constants.WRAPPER) MPJLambdaWrapper<ErpAfterSalesMaterialCosts> queryWrapper);
}

@ -0,0 +1,70 @@
package org.dromara.oa.erp.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.oa.erp.domain.ErpAfterSalesLaborCosts;
import org.dromara.oa.erp.domain.vo.ErpAfterSalesLaborCostsVo;
import org.dromara.oa.erp.domain.bo.ErpAfterSalesLaborCostsBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* Service
*
* @author Yangk
* @date 2025-11-21
*/
public interface IErpAfterSalesLaborCostsService extends IService<ErpAfterSalesLaborCosts> {
/**
*
*
* @param laborCostsId
* @return
*/
ErpAfterSalesLaborCostsVo queryById(Long laborCostsId);
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
TableDataInfo<ErpAfterSalesLaborCostsVo> queryPageList(ErpAfterSalesLaborCostsBo bo, PageQuery pageQuery);
/**
*
*
* @param bo
* @return
*/
List<ErpAfterSalesLaborCostsVo> queryList(ErpAfterSalesLaborCostsBo bo);
/**
*
*
* @param bo
* @return
*/
Boolean insertByBo(ErpAfterSalesLaborCostsBo bo);
/**
*
*
* @param bo
* @return
*/
Boolean updateByBo(ErpAfterSalesLaborCostsBo bo);
/**
*
*
* @param ids
* @param isValid
* @return
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

@ -0,0 +1,70 @@
package org.dromara.oa.erp.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.oa.erp.domain.ErpAfterSalesMaterialCosts;
import org.dromara.oa.erp.domain.vo.ErpAfterSalesMaterialCostsVo;
import org.dromara.oa.erp.domain.bo.ErpAfterSalesMaterialCostsBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* Service
*
* @author Yangk
* @date 2025-11-21
*/
public interface IErpAfterSalesMaterialCostsService extends IService<ErpAfterSalesMaterialCosts> {
/**
*
*
* @param materialCostsId
* @return
*/
ErpAfterSalesMaterialCostsVo queryById(Long materialCostsId);
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
TableDataInfo<ErpAfterSalesMaterialCostsVo> queryPageList(ErpAfterSalesMaterialCostsBo bo, PageQuery pageQuery);
/**
*
*
* @param bo
* @return
*/
List<ErpAfterSalesMaterialCostsVo> queryList(ErpAfterSalesMaterialCostsBo bo);
/**
*
*
* @param bo
* @return
*/
Boolean insertByBo(ErpAfterSalesMaterialCostsBo bo);
/**
*
*
* @param bo
* @return
*/
Boolean updateByBo(ErpAfterSalesMaterialCostsBo bo);
/**
*
*
* @param ids
* @param isValid
* @return
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

@ -0,0 +1,69 @@
package org.dromara.oa.erp.service;
import org.dromara.oa.erp.domain.ErpAfterSales;
import org.dromara.oa.erp.domain.vo.ErpAfterSalesVo;
import org.dromara.oa.erp.domain.bo.ErpAfterSalesBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* Service
*
* @author Yangk
* @date 2025-11-21
*/
public interface IErpAfterSalesService {
/**
*
*
* @param afterSalesId
* @return
*/
ErpAfterSalesVo queryById(Long afterSalesId);
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
TableDataInfo<ErpAfterSalesVo> queryPageList(ErpAfterSalesBo bo, PageQuery pageQuery);
/**
*
*
* @param bo
* @return
*/
List<ErpAfterSalesVo> queryList(ErpAfterSalesBo bo);
/**
*
*
* @param bo
* @return
*/
Boolean insertByBo(ErpAfterSalesBo bo);
/**
*
*
* @param bo
* @return
*/
Boolean updateByBo(ErpAfterSalesBo bo);
/**
*
*
* @param ids
* @param isValid
* @return
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

@ -0,0 +1,142 @@
package org.dromara.oa.erp.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.dromara.oa.erp.domain.bo.ErpAfterSalesLaborCostsBo;
import org.dromara.oa.erp.domain.vo.ErpAfterSalesLaborCostsVo;
import org.dromara.oa.erp.domain.ErpAfterSalesLaborCosts;
import org.dromara.oa.erp.mapper.ErpAfterSalesLaborCostsMapper;
import org.dromara.oa.erp.service.IErpAfterSalesLaborCostsService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* Service
*
* @author Yangk
* @date 2025-11-21
*/
@RequiredArgsConstructor
@Service
public class ErpAfterSalesLaborCostsServiceImpl
extends ServiceImpl<ErpAfterSalesLaborCostsMapper, ErpAfterSalesLaborCosts>
implements IErpAfterSalesLaborCostsService {
private final ErpAfterSalesLaborCostsMapper baseMapper;
/**
*
*
* @param laborCostsId
* @return
*/
@Override
public ErpAfterSalesLaborCostsVo queryById(Long laborCostsId){
return baseMapper.selectVoById(laborCostsId);
}
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
@Override
public TableDataInfo<ErpAfterSalesLaborCostsVo> queryPageList(ErpAfterSalesLaborCostsBo bo, PageQuery pageQuery) {
MPJLambdaWrapper<ErpAfterSalesLaborCosts> lqw = buildQueryWrapper(bo);
Page<ErpAfterSalesLaborCostsVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
*
*
* @param bo
* @return
*/
@Override
public List<ErpAfterSalesLaborCostsVo> queryList(ErpAfterSalesLaborCostsBo bo) {
MPJLambdaWrapper<ErpAfterSalesLaborCosts> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private MPJLambdaWrapper<ErpAfterSalesLaborCosts> buildQueryWrapper(ErpAfterSalesLaborCostsBo bo) {
Map<String, Object> params = bo.getParams();
MPJLambdaWrapper<ErpAfterSalesLaborCosts> lqw = JoinWrappers.lambda(ErpAfterSalesLaborCosts.class)
.selectAll(ErpAfterSalesLaborCosts.class)
.eq(ErpAfterSalesLaborCosts::getDelFlag, "0")
.eq(bo.getAfterSalesId() != null, ErpAfterSalesLaborCosts::getAfterSalesId, bo.getAfterSalesId())
.eq(bo.getLaborId() != null, ErpAfterSalesLaborCosts::getLaborId, bo.getLaborId())
.like(StringUtils.isNotBlank(bo.getLaborName()), ErpAfterSalesLaborCosts::getLaborName, bo.getLaborName())
.eq(StringUtils.isNotBlank(bo.getExpenseItem()), ErpAfterSalesLaborCosts::getExpenseItem, bo.getExpenseItem())
.eq(bo.getCost() != null, ErpAfterSalesLaborCosts::getCost, bo.getCost())
.eq(bo.getSortOrder() != null, ErpAfterSalesLaborCosts::getSortOrder, bo.getSortOrder())
;
return lqw;
}
/**
*
*
* @param bo
* @return
*/
@Override
public Boolean insertByBo(ErpAfterSalesLaborCostsBo bo) {
ErpAfterSalesLaborCosts add = MapstructUtils.convert(bo, ErpAfterSalesLaborCosts.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setLaborCostsId(add.getLaborCostsId());
}
return flag;
}
/**
*
*
* @param bo
* @return
*/
@Override
public Boolean updateByBo(ErpAfterSalesLaborCostsBo bo) {
ErpAfterSalesLaborCosts update = MapstructUtils.convert(bo, ErpAfterSalesLaborCosts.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
*
*/
private void validEntityBeforeSave(ErpAfterSalesLaborCosts entity){
//TODO 做一些数据校验,如唯一约束
}
/**
*
*
* @param ids
* @param isValid
* @return
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
}

@ -0,0 +1,150 @@
package org.dromara.oa.erp.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.dromara.oa.erp.domain.bo.ErpAfterSalesMaterialCostsBo;
import org.dromara.oa.erp.domain.vo.ErpAfterSalesMaterialCostsVo;
import org.dromara.oa.erp.domain.ErpAfterSalesMaterialCosts;
import org.dromara.oa.erp.mapper.ErpAfterSalesMaterialCostsMapper;
import org.dromara.oa.erp.service.IErpAfterSalesMaterialCostsService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* Service
*
* @author Yangk
* @date 2025-11-21
*/
@RequiredArgsConstructor
@Service
public class ErpAfterSalesMaterialCostsServiceImpl
extends ServiceImpl<ErpAfterSalesMaterialCostsMapper, ErpAfterSalesMaterialCosts>
implements IErpAfterSalesMaterialCostsService {
private final ErpAfterSalesMaterialCostsMapper baseMapper;
/**
*
*
* @param materialCostsId
* @return
*/
@Override
public ErpAfterSalesMaterialCostsVo queryById(Long materialCostsId){
return baseMapper.selectVoById(materialCostsId);
}
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
@Override
public TableDataInfo<ErpAfterSalesMaterialCostsVo> queryPageList(ErpAfterSalesMaterialCostsBo bo, PageQuery pageQuery) {
MPJLambdaWrapper<ErpAfterSalesMaterialCosts> lqw = buildQueryWrapper(bo);
Page<ErpAfterSalesMaterialCostsVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
*
*
* @param bo
* @return
*/
@Override
public List<ErpAfterSalesMaterialCostsVo> queryList(ErpAfterSalesMaterialCostsBo bo) {
MPJLambdaWrapper<ErpAfterSalesMaterialCosts> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private MPJLambdaWrapper<ErpAfterSalesMaterialCosts> buildQueryWrapper(ErpAfterSalesMaterialCostsBo bo) {
Map<String, Object> params = bo.getParams();
MPJLambdaWrapper<ErpAfterSalesMaterialCosts> lqw = JoinWrappers.lambda(ErpAfterSalesMaterialCosts.class)
.selectAll(ErpAfterSalesMaterialCosts.class)
.eq(ErpAfterSalesMaterialCosts::getDelFlag, "0")
.eq(bo.getAfterSalesId() != null, ErpAfterSalesMaterialCosts::getAfterSalesId, bo.getAfterSalesId())
.eq(bo.getMaterialId() != null, ErpAfterSalesMaterialCosts::getMaterialId, bo.getMaterialId())
.eq(StringUtils.isNotBlank(bo.getProductCode()), ErpAfterSalesMaterialCosts::getProductCode, bo.getProductCode())
.like(StringUtils.isNotBlank(bo.getProductName()), ErpAfterSalesMaterialCosts::getProductName, bo.getProductName())
.eq(StringUtils.isNotBlank(bo.getSpecificationModel()), ErpAfterSalesMaterialCosts::getSpecificationModel, bo.getSpecificationModel())
.eq(StringUtils.isNotBlank(bo.getUnitId()), ErpAfterSalesMaterialCosts::getUnitId, bo.getUnitId())
.eq(bo.getQuantity() != null, ErpAfterSalesMaterialCosts::getQuantity, bo.getQuantity())
.eq(bo.getTaxRate() != null, ErpAfterSalesMaterialCosts::getTaxRate, bo.getTaxRate())
.eq(bo.getTaxInclusivePrice() != null, ErpAfterSalesMaterialCosts::getTaxInclusivePrice, bo.getTaxInclusivePrice())
.eq(bo.getTaxInclusiveAmount() != null, ErpAfterSalesMaterialCosts::getTaxInclusiveAmount, bo.getTaxInclusiveAmount())
.eq(bo.getTaxExclusivePrice() != null, ErpAfterSalesMaterialCosts::getTaxExclusivePrice, bo.getTaxExclusivePrice())
.eq(bo.getTaxExclusiveAmount() != null, ErpAfterSalesMaterialCosts::getTaxExclusiveAmount, bo.getTaxExclusiveAmount())
.eq(StringUtils.isNotBlank(bo.getGiftFlag()), ErpAfterSalesMaterialCosts::getGiftFlag, bo.getGiftFlag())
.eq(bo.getSortOrder() != null, ErpAfterSalesMaterialCosts::getSortOrder, bo.getSortOrder())
;
return lqw;
}
/**
*
*
* @param bo
* @return
*/
@Override
public Boolean insertByBo(ErpAfterSalesMaterialCostsBo bo) {
ErpAfterSalesMaterialCosts add = MapstructUtils.convert(bo, ErpAfterSalesMaterialCosts.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setMaterialCostsId(add.getMaterialCostsId());
}
return flag;
}
/**
*
*
* @param bo
* @return
*/
@Override
public Boolean updateByBo(ErpAfterSalesMaterialCostsBo bo) {
ErpAfterSalesMaterialCosts update = MapstructUtils.convert(bo, ErpAfterSalesMaterialCosts.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
*
*/
private void validEntityBeforeSave(ErpAfterSalesMaterialCosts entity){
//TODO 做一些数据校验,如唯一约束
}
/**
*
*
* @param ids
* @param isValid
* @return
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
}

@ -0,0 +1,278 @@
package org.dromara.oa.erp.service.impl;
import cn.hutool.core.collection.CollUtil;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.oa.erp.domain.ErpAfterSalesLaborCosts;
import org.dromara.oa.erp.domain.ErpAfterSalesMaterialCosts;
import org.dromara.oa.erp.domain.bo.ErpAfterSalesLaborCostsBo;
import org.dromara.oa.erp.domain.bo.ErpAfterSalesMaterialCostsBo;
import org.dromara.oa.erp.domain.vo.ErpAfterSalesLaborCostsVo;
import org.dromara.oa.erp.domain.vo.ErpAfterSalesMaterialCostsVo;
import org.dromara.oa.erp.service.IErpAfterSalesLaborCostsService;
import org.dromara.oa.erp.service.IErpAfterSalesMaterialCostsService;
import org.springframework.stereotype.Service;
import org.dromara.oa.erp.domain.bo.ErpAfterSalesBo;
import org.dromara.oa.erp.domain.vo.ErpAfterSalesVo;
import org.dromara.oa.erp.domain.ErpAfterSales;
import org.dromara.oa.erp.mapper.ErpAfterSalesMapper;
import org.dromara.oa.erp.service.IErpAfterSalesService;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* Service
*
* @author Yangk
* @date 2025-11-21
*/
@RequiredArgsConstructor
@Service
public class ErpAfterSalesServiceImpl implements IErpAfterSalesService {
private final ErpAfterSalesMapper baseMapper;
// 【修改点 1】注入两个子表的 Service
// 注意:这里必须加 final配合 @RequiredArgsConstructor 使用
private final IErpAfterSalesLaborCostsService laborCostsService;
private final IErpAfterSalesMaterialCostsService materialCostsService;
/**
*
*
* @param afterSalesId
* @return
*/
@Override
public ErpAfterSalesVo queryById(Long afterSalesId){
// 1. 查询主表 VO
ErpAfterSalesVo vo = baseMapper.selectVoById(afterSalesId);
// 2. 如果主表存在,继续查询子表
if (vo != null) {
// ============ 处理人工费 ============
// 2.1 使用 list 方法查询出 Entity 列表
List<ErpAfterSalesLaborCosts> laborEntities = laborCostsService.list(
new LambdaQueryWrapper<ErpAfterSalesLaborCosts>()
.eq(ErpAfterSalesLaborCosts::getAfterSalesId, afterSalesId)
);
// 2.2 将 Entity 列表转换为 VO 列表 (核心修复点)
List<ErpAfterSalesLaborCostsVo> laborVos = MapstructUtils.convert(laborEntities, ErpAfterSalesLaborCostsVo.class);
// 2.3 塞入主表对象
vo.setLaborCostsList(laborVos);
// ============ 处理材料费 ============
// 3.1 使用 list 方法查询出 Entity 列表
List<ErpAfterSalesMaterialCosts> materialEntities = materialCostsService.list(
new LambdaQueryWrapper<ErpAfterSalesMaterialCosts>()
.eq(ErpAfterSalesMaterialCosts::getAfterSalesId, afterSalesId)
);
// 3.2 将 Entity 列表转换为 VO 列表
List<ErpAfterSalesMaterialCostsVo> materialVos = MapstructUtils.convert(materialEntities, ErpAfterSalesMaterialCostsVo.class);
// 3.3 塞入主表对象
vo.setMaterialCostsList(materialVos);
}
return vo;
}
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
@Override
public TableDataInfo<ErpAfterSalesVo> queryPageList(ErpAfterSalesBo bo, PageQuery pageQuery) {
MPJLambdaWrapper<ErpAfterSales> lqw = buildQueryWrapper(bo);
// Page<ErpAfterSalesVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
Page<ErpAfterSalesVo> result = baseMapper.selectCustomVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
*
*
* @param bo
* @return
*/
@Override
public List<ErpAfterSalesVo> queryList(ErpAfterSalesBo bo) {
MPJLambdaWrapper<ErpAfterSales> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private MPJLambdaWrapper<ErpAfterSales> buildQueryWrapper(ErpAfterSalesBo bo) {
Map<String, Object> params = bo.getParams();
MPJLambdaWrapper<ErpAfterSales> lqw = JoinWrappers.lambda(ErpAfterSales.class)
.selectAll(ErpAfterSales.class)
.eq(ErpAfterSales::getDelFlag, "0")
.eq(StringUtils.isNotBlank(bo.getAfterSalesCode()), ErpAfterSales::getAfterSalesCode, bo.getAfterSalesCode())
.eq(StringUtils.isNotBlank(bo.getAfterSalesSubject()), ErpAfterSales::getAfterSalesSubject, bo.getAfterSalesSubject())
.eq(bo.getProjectId() != null, ErpAfterSales::getProjectId, bo.getProjectId())
.eq(StringUtils.isNotBlank(bo.getProjectCode()), ErpAfterSales::getProjectCode, bo.getProjectCode())
.like(StringUtils.isNotBlank(bo.getProjectName()), ErpAfterSales::getProjectName, bo.getProjectName())
.eq(bo.getCustomerId() != null, ErpAfterSales::getCustomerId, bo.getCustomerId())
.like(StringUtils.isNotBlank(bo.getCustomerName()), ErpAfterSales::getCustomerName, bo.getCustomerName())
.eq(StringUtils.isNotBlank(bo.getContactPerson()), ErpAfterSales::getContactPerson, bo.getContactPerson())
.eq(StringUtils.isNotBlank(bo.getContactPhone()), ErpAfterSales::getContactPhone, bo.getContactPhone())
.eq(bo.getAfterSalesDate() != null, ErpAfterSales::getAfterSalesDate, bo.getAfterSalesDate())
.eq(bo.getContractId() != null, ErpAfterSales::getContractId, bo.getContractId())
.eq(StringUtils.isNotBlank(bo.getContractCode()), ErpAfterSales::getContractCode, bo.getContractCode())
.eq(StringUtils.isNotBlank(bo.getAfterSalesType()), ErpAfterSales::getAfterSalesType, bo.getAfterSalesType())
.eq(StringUtils.isNotBlank(bo.getStakeholderId()), ErpAfterSales::getStakeholderId, bo.getStakeholderId())
.eq(StringUtils.isNotBlank(bo.getHandlerId()), ErpAfterSales::getHandlerId, bo.getHandlerId())
.eq(StringUtils.isNotBlank(bo.getProblemDescription()), ErpAfterSales::getProblemDescription, bo.getProblemDescription())
.eq(bo.getTotalWorkHours() != null, ErpAfterSales::getTotalWorkHours, bo.getTotalWorkHours())
.eq(bo.getTotalCost() != null, ErpAfterSales::getTotalCost, bo.getTotalCost())
.eq(StringUtils.isNotBlank(bo.getSolveStatus()), ErpAfterSales::getSolveStatus, bo.getSolveStatus())
.eq(bo.getCompletionDate() != null, ErpAfterSales::getCompletionDate, bo.getCompletionDate())
.eq(StringUtils.isNotBlank(bo.getProcessingResult()), ErpAfterSales::getProcessingResult, bo.getProcessingResult())
.eq(StringUtils.isNotBlank(bo.getAfterSalesStatus()), ErpAfterSales::getAfterSalesStatus, bo.getAfterSalesStatus())
.eq(StringUtils.isNotBlank(bo.getFlowStatus()), ErpAfterSales::getFlowStatus, bo.getFlowStatus())
.eq(StringUtils.isNotBlank(bo.getActiveFlag()), ErpAfterSales::getActiveFlag, bo.getActiveFlag())
;
return lqw;
}
/**
*
*
* @param bo
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class) // 【重要】开启事务!如果子表保存失败,主表也要回滚,防止数据不一致
public Boolean insertByBo(ErpAfterSalesBo bo) {
// 1. 将 BO (业务对象) 转换为 Entity (数据库实体)
// MapstructUtils 是 Plus 封装的高性能 Bean 拷贝工具
ErpAfterSales add = MapstructUtils.convert(bo, ErpAfterSales.class);
// 2. 校验数据(这是生成的代码自带的)
validEntityBeforeSave(add);
// 3. 保存主表
// baseMapper.insert(add) 返回受影响行数大于0表示成功
// 成功后MyBatis 会自动把生成的 ID 回填到 add 对象中
boolean flag = baseMapper.insert(add) > 0;
// 4. 如果主表保存成功,开始处理子表
if (flag) {
Long afterSalesId = add.getAfterSalesId(); // 拿到主表刚才生成的 ID
// --- 处理子表 A人员费用 ---
List<ErpAfterSalesLaborCostsBo> laborBoList = bo.getLaborCostsList();
// 使用 CollUtil.isNotEmpty 判断列表不为空
if (CollUtil.isNotEmpty(laborBoList)) {
// 将 BO 列表转为 Entity 列表
List<ErpAfterSalesLaborCosts> laborList = MapstructUtils.convert(laborBoList, ErpAfterSalesLaborCosts.class);
// 遍历每个子对象,把主表 ID 填进去,建立外键关联
laborList.forEach(item -> item.setAfterSalesId(afterSalesId));
// 批量保存
laborCostsService.saveBatch(laborList);
}
// --- 处理子表 B材料费用 ---
List<ErpAfterSalesMaterialCostsBo> materialBoList = bo.getMaterialCostsList();
if (CollUtil.isNotEmpty(materialBoList)) {
List<ErpAfterSalesMaterialCosts> materialList = MapstructUtils.convert(materialBoList, ErpAfterSalesMaterialCosts.class);
materialList.forEach(item -> item.setAfterSalesId(afterSalesId));
materialCostsService.saveBatch(materialList);
}
}
return flag;
}
/**
*
*
* @param bo
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class) // 【重要】开启事务
public Boolean updateByBo(ErpAfterSalesBo bo) {
// 1. 更新主表数据
ErpAfterSales update = MapstructUtils.convert(bo, ErpAfterSales.class);
validEntityBeforeSave(update);
// updateById 会根据主键 ID 更新其他字段
int row = baseMapper.updateById(update);
// 2. 如果主表更新成功,开始处理子表
if (row > 0) {
Long afterSalesId = bo.getAfterSalesId();
// ================== 1. 处理人员费用 ==================
// 先删除旧的
laborCostsService.remove(new LambdaQueryWrapper<ErpAfterSalesLaborCosts>()
.eq(ErpAfterSalesLaborCosts::getAfterSalesId, afterSalesId));
// 后新增新的
List<ErpAfterSalesLaborCostsBo> laborBoList = bo.getLaborCostsList();
if (CollUtil.isNotEmpty(laborBoList)) {
List<ErpAfterSalesLaborCosts> laborList = MapstructUtils.convert(laborBoList, ErpAfterSalesLaborCosts.class);
// 【核心修改点 👇】遍历列表,清空 ID
laborList.forEach(item -> {
item.setLaborCostsId(null); // 关键清空ID让MP重新生成雪花ID避免和逻辑删除的数据冲突
item.setAfterSalesId(afterSalesId);
});
laborCostsService.saveBatch(laborList);
}
// ================== 2. 处理材料费用 ==================
// 先删除旧的
materialCostsService.remove(new LambdaQueryWrapper<ErpAfterSalesMaterialCosts>()
.eq(ErpAfterSalesMaterialCosts::getAfterSalesId, afterSalesId));
// 后新增新的
List<ErpAfterSalesMaterialCostsBo> materialBoList = bo.getMaterialCostsList();
if (CollUtil.isNotEmpty(materialBoList)) {
List<ErpAfterSalesMaterialCosts> materialList = MapstructUtils.convert(materialBoList, ErpAfterSalesMaterialCosts.class);
// 【核心修改点 👇】遍历列表,清空 ID
materialList.forEach(item -> {
item.setMaterialCostsId(null); // 关键清空ID
item.setAfterSalesId(afterSalesId);
});
materialCostsService.saveBatch(materialList);
}
}
return row > 0;
}
/**
*
*/
private void validEntityBeforeSave(ErpAfterSales entity){
//TODO 做一些数据校验,如唯一约束
}
/**
*
*
* @param ids
* @param isValid
* @return
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
}

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.oa.erp.mapper.ErpAfterSalesLaborCostsMapper">
<resultMap type="org.dromara.oa.erp.domain.vo.ErpAfterSalesLaborCostsVo" id="ErpAfterSalesLaborCostsResult">
</resultMap>
<select id="selectCustomErpAfterSalesLaborCostsVoList" resultMap="ErpAfterSalesLaborCostsResult">
select labor_costs_id, tenant_id, after_sales_id, labor_id, labor_name, expense_item, cost, remark, sort_order, del_flag, create_dept, create_by, create_time, update_by, update_time from erp_after_sales_labor_costs t
${ew.getCustomSqlSegment}
</select>
</mapper>

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.oa.erp.mapper.ErpAfterSalesMapper">
<resultMap type="org.dromara.oa.erp.domain.vo.ErpAfterSalesVo" id="ErpAfterSalesResult">
</resultMap>
<select id="selectCustomErpAfterSalesVoList" resultMap="ErpAfterSalesResult">
select after_sales_id, tenant_id, after_sales_code, after_sales_subject, project_id, project_code, project_name, customer_id, customer_name, contact_person, contact_phone, after_sales_date, contract_id, contract_code, after_sales_type, stakeholder_id, handler_id, problem_description, total_work_hours, total_cost, solve_status, completion_date, processing_result, after_sales_status, flow_status, active_flag, remark, del_flag, create_dept, create_by, create_time, update_by, update_time from erp_after_sales t
${ew.getCustomSqlSegment}
</select>
<select id="selectCustomVoPage" resultType="org.dromara.oa.erp.domain.vo.ErpAfterSalesVo">
SELECT
t.*,
-- 1. 翻译客户干系人 (crm_customer_contact 表)
(
SELECT GROUP_CONCAT(c.contact_name SEPARATOR ', ')
FROM crm_customer_contact c
WHERE FIND_IN_SET(c.contact_id, t.stakeholder_id)
) AS stakeholderName,
-- 2. 翻译处理人 (sys_user 表)
(
SELECT GROUP_CONCAT(u.nick_name SEPARATOR ', ')
FROM sys_user u
WHERE FIND_IN_SET(u.user_id, t.handler_id)
) AS handlerName,
c.contract_code AS contractCode
FROM erp_after_sales t
left join erp_contract_info c on t.contract_id = c.contract_id
${ew.customSqlSegment}
</select>
</mapper>

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.oa.erp.mapper.ErpAfterSalesMaterialCostsMapper">
<resultMap type="org.dromara.oa.erp.domain.vo.ErpAfterSalesMaterialCostsVo" id="ErpAfterSalesMaterialCostsResult">
</resultMap>
<select id="selectCustomErpAfterSalesMaterialCostsVoList" resultMap="ErpAfterSalesMaterialCostsResult">
select material_costs_id, tenant_id, after_sales_id, material_id, product_code, product_name, specification_model, unit_id, quantity, tax_rate, tax_inclusive_price, tax_inclusive_amount, tax_exclusive_price, tax_exclusive_amount, gift_flag, remark, sort_order, del_flag, create_dept, create_by, create_time, update_by, update_time from erp_after_sales_material_costs t
${ew.getCustomSqlSegment}
</select>
</mapper>
Loading…
Cancel
Save