From 15e54c5984e51d5c065737804f9934fc22e11161 Mon Sep 17 00:00:00 2001 From: xyc <3422692813@qq.com> Date: Wed, 13 Aug 2025 17:29:22 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E6=9B=B4=E6=96=B00813?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iocoder/yudao/common/RecordTypeEnum.java | 5 +- .../admin/DlRepairTicketsController.java | 15 ++++++ .../tickets/entity/DlRepairTickets.java | 2 + .../service/DlRepairTicketsService.java | 10 ++++ .../impl/DlRepairTicketsServiceImpl.java | 20 +++++++ .../tickets/vo/DlRepairTicketsReqVO.java | 3 ++ .../mapper/tickets/DlRepairTicketsMapper.xml | 54 +++++++++++++++---- 7 files changed, 97 insertions(+), 12 deletions(-) diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/common/RecordTypeEnum.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/common/RecordTypeEnum.java index e5babda7..df353a01 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/common/RecordTypeEnum.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/common/RecordTypeEnum.java @@ -88,7 +88,10 @@ public enum RecordTypeEnum { JC("jc", "交车"), /** 内返派工 */ - NFPG("nfpg", "内返派工"); + NFPG("nfpg", "内返派工"), + /** 收款*/ + SK("sk", "收款"), + PICKCAR("pickcar", "接车"); /** * code diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/controller/admin/DlRepairTicketsController.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/controller/admin/DlRepairTicketsController.java index dcf83fc4..3d0291a5 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/controller/admin/DlRepairTicketsController.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/controller/admin/DlRepairTicketsController.java @@ -603,5 +603,20 @@ public class DlRepairTicketsController { } ExcelUtils.write(response, name, "数据", TicketExportByStatusVO.class, list); } + + /** + * @Author 许 + * @Description //TODO 接车 + * @Date 14:06 2025/8/13 + * @Param [id, image, remark] + * @return cn.iocoder.yudao.framework.common.pojo.CommonResult + **/ + @GetMapping("/pickCar") + public CommonResult pickCar(@RequestParam("id") String id, + @RequestParam(value="image",required = false) String image, + @RequestParam(value="remark",required = false) String remark){ + dlRepairTicketsService.pickCar(id,image,remark); + return CommonResult.ok(); + } } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTickets.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTickets.java index 1ae5ef98..68e7181a 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTickets.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTickets.java @@ -202,6 +202,8 @@ public class DlRepairTickets extends TenantBaseDO { private String isFinish; /** 是否交车(0未交车|1已交车) */ private String isHandover; + /** 是否接车(0未接车|1已接车) */ + private String isPickCar; /** 工单当前施工人id */ private Long nowRepairId; diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/DlRepairTicketsService.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/DlRepairTicketsService.java index b7de9700..d8ba8f39 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/DlRepairTicketsService.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/DlRepairTicketsService.java @@ -271,4 +271,14 @@ public interface DlRepairTicketsService extends IService { * @param id 工单ID **/ void refreshUpdateTime(String id); + + /** + * @Author 许 + * @Description //TODO 接车 + * @Date 14:07 2025/8/13 + * @Param [id, image, remark] + * @return void + **/ + + void pickCar(String id, String image, String remark); } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java index 6425e52d..8f4cd24f 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java @@ -68,6 +68,7 @@ import com.baomidou.dynamic.datasource.annotation.DSTransactional; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.deepoove.poi.XWPFTemplate; @@ -2171,6 +2172,25 @@ public class DlRepairTicketsServiceImpl extends ServiceImpllambdaUpdate() + .eq(DlRepairTickets::getId, id) + .set(DlRepairTickets::getIsPickCar, 1)); + + /* 2.步骤表里添加接车*/ + repairRecordsService.saveRepairRecord(id, null, RecordTypeEnum.PICKCAR.getCode(), "接车", image); + } } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/DlRepairTicketsReqVO.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/DlRepairTicketsReqVO.java index f9861143..07fa1ec8 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/DlRepairTicketsReqVO.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/DlRepairTicketsReqVO.java @@ -52,4 +52,7 @@ public class DlRepairTicketsReqVO extends DlRepairTickets { private List statusList; /** 工单id集和 */ private List idList; + + /** 统计参数 wxz:维修中 wjs:未结算 zc:在厂*/ + private String statisticsType; } diff --git a/dl-module-repair/src/main/resources/mapper/tickets/DlRepairTicketsMapper.xml b/dl-module-repair/src/main/resources/mapper/tickets/DlRepairTicketsMapper.xml index 95076eb0..0ac6bdfe 100644 --- a/dl-module-repair/src/main/resources/mapper/tickets/DlRepairTicketsMapper.xml +++ b/dl-module-repair/src/main/resources/mapper/tickets/DlRepairTicketsMapper.xml @@ -102,6 +102,7 @@ + @@ -237,10 +238,10 @@ From d85b0d802843b9732bed3bcf330c44a06e363a74 Mon Sep 17 00:00:00 2001 From: xyc <3422692813@qq.com> Date: Fri, 15 Aug 2025 13:06:16 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E6=9B=B4=E6=96=B00815?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/DlRepairSoServiceImpl.java | 102 ++++-- .../module/tickets/entity/DlRepairTitem.java | 12 +- .../impl/DlRepairTicketsServiceImpl.java | 317 +++++++++--------- .../tickets/utils/TicketsOperateUtil.java | 67 +++- .../tickets/vo/DlRepairTicketsRespVO.java | 7 + 5 files changed, 310 insertions(+), 195 deletions(-) diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/stockOperate/service/impl/DlRepairSoServiceImpl.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/stockOperate/service/impl/DlRepairSoServiceImpl.java index 89470bff..a38c2e65 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/stockOperate/service/impl/DlRepairSoServiceImpl.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/stockOperate/service/impl/DlRepairSoServiceImpl.java @@ -31,6 +31,7 @@ import cn.iocoder.yudao.module.tickets.service.DlRepairTicketsService; import cn.iocoder.yudao.module.tickets.service.DlRepairTitemService; import cn.iocoder.yudao.module.tickets.service.DlTicketWaresService; import cn.iocoder.yudao.module.tickets.service.DlTwItemService; +import cn.iocoder.yudao.module.tickets.utils.TicketsOperateUtil; import cn.iocoder.yudao.module.tickets.vo.AppWaresGroupVO; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; @@ -44,6 +45,7 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -53,7 +55,6 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU /** * 针对表【dl_repair_so(采购单领料单)】的数据库操作Service实现 - * * @author 小李 * @date 9:11 2024/9/13 **/ @@ -108,9 +109,11 @@ public class DlRepairSoServiceImpl extends ServiceImpl sois = repairSoiService.list(new LambdaQueryWrapper().in(DlRepairSoi::getSoId, so.getId())); @@ -272,7 +273,6 @@ public class DlRepairSoServiceImpl extends ServiceImpl sois = repairSoiService.list(new LambdaQueryWrapper().eq(DlRepairSoi::getSoId, id)); @@ -414,7 +412,7 @@ public class DlRepairSoServiceImpl extends ServiceImpl sois,List repairWares){ + **/ + private void dealWareItem(Boolean ifGet, String applyId, List sois, List repairWares) { //配件申请单 DlTicketWares dlTicketWares = ticketWaresService.getById(applyId); //工单现有的配件 List titems = titemService.list(new LambdaQueryWrapper().and(i -> { - i.eq(DlRepairTitem::getTicketId,dlTicketWares.getTicketId()) + i.eq(DlRepairTitem::getTicketId, dlTicketWares.getTicketId()) .eq(DlRepairTitem::getItemType, "02"); })); //更新或插入的数据集合 @@ -461,37 +459,64 @@ public class DlRepairSoServiceImpl extends ServiceImpl delIdList = new ArrayList<>(); //工单现有配件转MAP - Map itemMap = titems.stream().collect(Collectors.toMap(DlRepairTitem::getPartId,Function.identity())); + Map itemMap = titems.stream().collect(Collectors.toMap(DlRepairTitem::getPartId, Function.identity())); //配件库的数据集合转MAP - Map repairWaresMap = repairWares.stream().collect(Collectors.toMap(RepairWares::getId,Function.identity())); + Map repairWaresMap = repairWares.stream().collect(Collectors.toMap(RepairWares::getId, Function.identity())); //遍历本次领料/退料的所有配件 - for (DlRepairSoi repairSoi:sois){ - if(itemMap.containsKey(repairSoi.getGoodsId())){ + for (DlRepairSoi repairSoi : sois) { + if (itemMap.containsKey(repairSoi.getGoodsId())) { //工单中有这个配件 - if(ifGet){ + if (ifGet) { //领料 //工单现有配件中就有这个领取的配件,需要更新这个配件的数量、价格 DlRepairTitem item = itemMap.get(repairSoi.getGoodsId()); item.setItemCount(item.getItemCount() + repairSoi.getGoodsCount()); item.setItemMoney(item.getItemPrice().multiply(BigDecimal.valueOf(item.getItemCount())).multiply(item.getItemDiscount())); item.setItemStatus(TicketsItemStatusEnum.RECEIVED.getCode()); + + + // 获取配件的售价和进价 + BigDecimal salePrice = repairWaresMap.get(repairSoi.getGoodsId()).getPrice(); // 售价 + BigDecimal purchasePrice = repairWaresMap.get(repairSoi.getGoodsId()).getPurPrice(); // 进价 + + //计算利润 + BigDecimal profit = operateUtil.calcProfit(salePrice, purchasePrice, item.getItemCount()); + // 计算毛利率 + BigDecimal profitRate = operateUtil.calcProfitRate(salePrice, purchasePrice, item.getItemCount()); + + item.setItemProfit(profit); + item.setItemProfitRate(profitRate); + saveOrUpdateList.add(item); - }else{ + } else { //退料 //工单现有配件中就有这个领取的配件,需要更新这个配件的数量、价格 DlRepairTitem item = itemMap.get(repairSoi.getGoodsId()); - if(item.getItemCount()>repairSoi.getGoodsCount()){ + if (item.getItemCount() > repairSoi.getGoodsCount()) { //现有数量大于要退的数量,扣掉 item.setItemCount(item.getItemCount() - repairSoi.getGoodsCount()); item.setItemMoney(item.getItemPrice().multiply(BigDecimal.valueOf(item.getItemCount())).multiply(item.getItemDiscount())); item.setItemStatus(TicketsItemStatusEnum.RECEIVED.getCode()); + + // 重新计算利润和利润率 + BigDecimal salePrice = repairWaresMap.get(repairSoi.getGoodsId()).getPrice(); // 售价 + BigDecimal purchasePrice = repairWaresMap.get(repairSoi.getGoodsId()).getPurPrice(); // 进价 + + //计算利润 + BigDecimal profit = operateUtil.calcProfit(salePrice, purchasePrice, item.getItemCount()); + // 计算毛利率 + BigDecimal profitRate = operateUtil.calcProfitRate(salePrice, purchasePrice, item.getItemCount()); + + item.setItemProfit(profit); + item.setItemProfitRate(profitRate); + saveOrUpdateList.add(item); - }else{ + } else { //现有数量小于或等于要退的数量,直接将这个配件删掉 delIdList.add(item.getId()); } } - }else{ + } else { //工单中没有这个配件 if (ifGet) { //领料,需要把这个配件添加到工单子表中 @@ -515,25 +540,37 @@ public class DlRepairSoServiceImpl extends ServiceImpl * @author vinjor-M diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTitem.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTitem.java index b00c5337..ab123328 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTitem.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTitem.java @@ -61,6 +61,16 @@ public class DlRepairTitem extends TenantBaseDO { */ private BigDecimal itemMoney; + /** + * 利润 + */ + private BigDecimal itemProfit; + + /** + * 毛利率 + */ + private BigDecimal itemProfitRate; + /** * 维修人员ID(system_users表的ID) */ @@ -115,4 +125,4 @@ public class DlRepairTitem extends TenantBaseDO { * 备注 */ private String remark; -} \ No newline at end of file +} diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java index 8f4cd24f..3ac919ee 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java @@ -86,6 +86,7 @@ import javax.servlet.http.HttpServletResponse; import java.io.FileOutputStream; import java.io.InputStream; import java.math.BigDecimal; +import java.math.RoundingMode; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; @@ -100,7 +101,6 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU /** * 针对表【dl_repair_tickets(维修工单表)】的数据库操作Service实现 - * * @author 小李 * @date 18:19 2024/9/13 **/ @@ -202,7 +202,6 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl repairTypeList = dictDataApi.getDictDataList(DICT_REPAIR_TYPE); - Map repairTypeMap = repairTypeList.stream().collect(Collectors.toMap(DictDataRespDTO::getValue,DictDataRespDTO::getLabel)); + Map repairTypeMap = repairTypeList.stream().collect(Collectors.toMap(DictDataRespDTO::getValue, DictDataRespDTO::getLabel)); DlRepairTicketsRespVO result = BeanUtil.toBean(dlRepairTickets, DlRepairTicketsRespVO.class); - result.setRepairTypeText(repairTypeMap.getOrDefault(dlRepairTickets.getRepairType(),"")); + result.setRepairTypeText(repairTypeMap.getOrDefault(dlRepairTickets.getRepairType(), "")); //查是否存在总检完成的记录,取出他的时间 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() - .eq(RepairRecords::getTicketId,id) - .eq(RepairRecords::getType,RecordTypeEnum.ZJ.getCode()) + .eq(RepairRecords::getTicketId, id) + .eq(RepairRecords::getType, RecordTypeEnum.ZJ.getCode()) .orderByDesc(BaseDO::getCreateTime); List repairRecords = repairRecordsService.list(queryWrapper); - if(!repairRecords.isEmpty()){ + if (!repairRecords.isEmpty()) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); String formattedString = repairRecords.get(0).getCreateTime().format(formatter); result.setRealOverDate(formattedString); @@ -427,13 +424,13 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl dataFromList = dictDataApi.getDictDataList(DICT_CUS_DATA_FROM); - Map dataFromMap = dataFromList.stream().collect(Collectors.toMap(DictDataRespDTO::getValue,DictDataRespDTO::getLabel)); + Map dataFromMap = dataFromList.stream().collect(Collectors.toMap(DictDataRespDTO::getValue, DictDataRespDTO::getLabel)); customerInfo.setDataFromText(dataFromMap.get(customerInfo.getDataFrom())); } result.setCustomerInfo(customerInfo); @@ -464,15 +461,15 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl repairProjects.stream().filter(i -> i.getId().equals(item.getProjectId())).findFirst().ifPresent(item::setProject)); } result.setProjects(projects); - if(ifApp){ + if (ifApp) { //app新增逻辑 if (CollectionUtil.isNotEmpty(projects)) { List projectList = new ArrayList<>(); //查所有服务分类(项目分类) List baseTypeList = baseTypeService.list(); - Map baseTypeMap = baseTypeList.stream().collect(Collectors.toMap(BaseType::getId,BaseType::getName)); + Map baseTypeMap = baseTypeList.stream().collect(Collectors.toMap(BaseType::getId, BaseType::getName)); //先过滤出itenTypeId为null或空为单独一个组 - List nullList = projects.stream().filter(item->StringUtils.isEmpty(item.getItemTypeId())).collect(Collectors.toList()); + List nullList = projects.stream().filter(item -> StringUtils.isEmpty(item.getItemTypeId())).collect(Collectors.toList()); if (CollectionUtil.isNotEmpty(nullList)) { AppWaresGroupVO waresGroupVO = new AppWaresGroupVO(); waresGroupVO.setWares(nullList); @@ -484,8 +481,8 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl> groupListMap = projects.stream().filter(item->StringUtils.isNotEmpty(item.getItemTypeId())).collect(Collectors.groupingBy(DlRepairTitem::getItemTypeId)); - for (String key:groupListMap.keySet()){ + Map> groupListMap = projects.stream().filter(item -> StringUtils.isNotEmpty(item.getItemTypeId())).collect(Collectors.groupingBy(DlRepairTitem::getItemTypeId)); + for (String key : groupListMap.keySet()) { AppWaresGroupVO waresGroupVO = new AppWaresGroupVO(); waresGroupVO.setWares(groupListMap.get(key)); waresGroupVO.setGroupName(baseTypeMap.get(key)); @@ -501,44 +498,44 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl waresGroupList = new ArrayList<>(); //查这个工单的配件 List waresList = repairTitemMapper.selectByTicketId(id); if (CollectionUtil.isNotEmpty(waresList)) { //先过滤出itenTypeId为null或空,或者itemTypeName为null或空的,为单独一个组 - List nullList = waresList.stream().filter(item->StringUtils.isEmpty(item.getItemTypeId()) || StringUtils.isEmpty(item.getItemTypeName())).collect(Collectors.toList()); + List nullList = waresList.stream().filter(item -> StringUtils.isEmpty(item.getItemTypeId()) || StringUtils.isEmpty(item.getItemTypeName())).collect(Collectors.toList()); if (CollectionUtil.isNotEmpty(nullList)) { AppWaresGroupVO waresGroupVO = new AppWaresGroupVO(); waresGroupVO.setWares(nullList); waresGroupVO.setGroupName("未知分组"); waresGroupVO.setNums(nullList.size()); - waresGroupVO.setTotalAmount(nullList.stream().peek(item->{ - if(null==item.getItemMoney()){ + waresGroupVO.setTotalAmount(nullList.stream().peek(item -> { + if (null == item.getItemMoney()) { item.setItemMoney(new BigDecimal(0)); } - }).map(DlRepairTitem::getItemMoney).reduce(BigDecimal.ZERO,BigDecimal::add)); + }).map(DlRepairTitem::getItemMoney).reduce(BigDecimal.ZERO, BigDecimal::add)); waresGroupList.add(waresGroupVO); } //过滤出有分类的进行分组 - Map> groupListMap = waresList.stream().filter(item->StringUtils.isNotEmpty(item.getItemTypeId()) && StringUtils.isNotEmpty(item.getItemTypeName())).collect(Collectors.groupingBy(DlRepairTitem::getItemTypeId)); - for (String key:groupListMap.keySet()){ + Map> groupListMap = waresList.stream().filter(item -> StringUtils.isNotEmpty(item.getItemTypeId()) && StringUtils.isNotEmpty(item.getItemTypeName())).collect(Collectors.groupingBy(DlRepairTitem::getItemTypeId)); + for (String key : groupListMap.keySet()) { AppWaresGroupVO waresGroupVO = new AppWaresGroupVO(); waresGroupVO.setWares(groupListMap.get(key)); waresGroupVO.setGroupName(groupListMap.get(key).get(0).getItemTypeName()); waresGroupVO.setGroupId(key); waresGroupVO.setNums(groupListMap.get(key).size()); - waresGroupVO.setTotalAmount(groupListMap.get(key).stream().peek(item->{ - if(null==item.getItemMoney()){ + waresGroupVO.setTotalAmount(groupListMap.get(key).stream().peek(item -> { + if (null == item.getItemMoney()) { item.setItemMoney(new BigDecimal(0)); } - }).map(DlRepairTitem::getItemMoney).reduce(BigDecimal.ZERO,BigDecimal::add)); + }).map(DlRepairTitem::getItemMoney).reduce(BigDecimal.ZERO, BigDecimal::add)); waresGroupList.add(waresGroupVO); } } result.setWaresGroupList(waresGroupList); - }else{ + } else { // 取配件----原有逻辑-电脑端 List wares = items.stream().filter(item -> item.getItemType().equals("02")).collect(Collectors.toList()); if (CollectionUtil.isNotEmpty(wares)) { @@ -570,13 +567,45 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl recordTypeList = dictDataApi.getDictDataList(DICT_REPAIR_RECORDS_TYPE); Map typeMap = recordTypeList.stream().collect(Collectors.toMap(DictDataRespDTO::getValue, DictDataRespDTO::getLabel)); result.setRecords(records.stream().peek(item -> item.setType(typeMap.get(item.getType()))).collect(Collectors.toList())); + + //配件总利润 + BigDecimal waresProfit = BigDecimal.ZERO; + if (CollectionUtil.isNotEmpty(items)) { + for (DlRepairTitemReqVO item : items) { + if ("02".equals(item.getItemType())) { + // 获取配件利润 加到总利润中 + BigDecimal itemProfit = item.getItemProfit() != null ? item.getItemProfit() : BigDecimal.ZERO; + waresProfit = waresProfit.add(itemProfit); + System.out.println("配件利润:" + itemProfit); + } + } + } + + + //计算含工时项目毛利率 + //配件总利润除以工单总价 + BigDecimal profitRate = new BigDecimal(0); + if (ObjectUtil.isNotEmpty(dlRepairTickets.getTotalPrice())) { + if (dlRepairTickets.getTotalPrice().compareTo(BigDecimal.ZERO) != 0) { + profitRate = waresProfit.divide(dlRepairTickets.getTotalPrice(), 2, RoundingMode.HALF_UP); + } + result.setProfitRate(profitRate); + } + //计算不含工时项目毛利率 + if (ObjectUtil.isNotEmpty(dlRepairTickets.getPartPrice())) { + BigDecimal profitRateNo = new BigDecimal(0); + if (dlRepairTickets.getPartPrice().compareTo(BigDecimal.ZERO) != 0) { + profitRateNo = waresProfit.divide(dlRepairTickets.getPartPrice(), 2, RoundingMode.HALF_UP); + } + result.setProfitRateNo(profitRateNo); + } + return result; } /** * 维修工单表 作废 * 传对象是因为需要有作废备注 - * * @param repairTicketsReqVO 工单对象 * @author 小李 * @date 19:46 2024/9/22 @@ -600,7 +629,6 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl - **/ - private IPage dealDictText(IPage dlRepairTicketsIPage){ + * @author vinjor-M + * @date 16:25 2025/1/9 + **/ + private IPage dealDictText(IPage dlRepairTicketsIPage) { //维修类型 List repairTypeList = dictDataApi.getDictDataList(DICT_REPAIR_TYPE); - Map repairTypeMap = repairTypeList.stream().collect(Collectors.toMap(DictDataRespDTO::getValue,DictDataRespDTO::getLabel)); + Map repairTypeMap = repairTypeList.stream().collect(Collectors.toMap(DictDataRespDTO::getValue, DictDataRespDTO::getLabel)); //支付方式 List payTypeList = dictDataApi.getDictDataList(DICT_REPAIR_PAY_TYPE); - dlRepairTicketsIPage.getRecords().forEach(item->{ - if(StringUtils.isNotEmpty(item.getRepairType())){ + dlRepairTicketsIPage.getRecords().forEach(item -> { + if (StringUtils.isNotEmpty(item.getRepairType())) { item.setRepairTypeText(repairTypeMap.get(item.getRepairType())); } - if(StringUtils.isNotEmpty(item.getPayType())){ - payTypeList.forEach(payType->{ - if(item.getPayType().contains(payType.getValue())){ - if(StringUtils.isEmpty(item.getPayTypeText())){ + if (StringUtils.isNotEmpty(item.getPayType())) { + payTypeList.forEach(payType -> { + if (item.getPayType().contains(payType.getValue())) { + if (StringUtils.isEmpty(item.getPayTypeText())) { item.setPayTypeText(payType.getLabel()); - }else{ - item.setPayTypeText(item.getPayTypeText()+","+payType.getLabel()); + } else { + item.setPayTypeText(item.getPayTypeText() + "," + payType.getLabel()); } } }); @@ -1065,7 +1091,6 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl getPageType(DlRepairTicketsReqVO repairTicketsReqVO, Page page) { String userRoleCode = getUserRole(); - if(null!=repairTicketsReqVO.getIdList() && repairTicketsReqVO.getIdList().size()>0){ + if (null != repairTicketsReqVO.getIdList() && repairTicketsReqVO.getIdList().size() > 0) { //根据id集和查询 DlRepairTicketsReqVO queryObj = new DlRepairTicketsReqVO(); queryObj.setIdList(repairTicketsReqVO.getIdList()); @@ -1127,54 +1152,54 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl idList = new ArrayList<>(); - if("yijungong".equals(repairTicketsReqVO.getTicketsStatus())){ + if ("yijungong".equals(repairTicketsReqVO.getTicketsStatus())) { //已竣工 - idList = repairTicketsMapper.selectTicketIdByParams(null,RecordTypeEnum.ZJ.getCode(),startDate,endDate); - }else if("yijiaoche".equals(repairTicketsReqVO.getTicketsStatus())){ + idList = repairTicketsMapper.selectTicketIdByParams(null, RecordTypeEnum.ZJ.getCode(), startDate, endDate); + } else if ("yijiaoche".equals(repairTicketsReqVO.getTicketsStatus())) { //已交车 - idList = repairTicketsMapper.selectTicketIdByParams(null,RecordTypeEnum.JC.getCode(),startDate,endDate); - }else { + idList = repairTicketsMapper.selectTicketIdByParams(null, RecordTypeEnum.JC.getCode(), startDate, endDate); + } else { //进厂 repairTicketsReqVO.setStartDate(startDate); repairTicketsReqVO.setEndDate(endDate); } - if(null!=idList && !idList.isEmpty()){ + if (null != idList && !idList.isEmpty()) { repairTicketsReqVO.setIdList(idList); //时间查询条件置空 repairTicketsReqVO.setStartDate(null); repairTicketsReqVO.setEndDate(null); } - }else { + } else { //否则查询时间不生效,按维修状态查 List statusList = new ArrayList<>(); - if("weixiuzhong".equals(repairTicketsReqVO.getTicketsStatus())){ + if ("weixiuzhong".equals(repairTicketsReqVO.getTicketsStatus())) { //维修中 statusList.add(TicketsStatusEnum.WORKING.getCode()); - }else if("weijiesuan".equals(repairTicketsReqVO.getTicketsStatus())){ + } else if ("weijiesuan".equals(repairTicketsReqVO.getTicketsStatus())) { //未结算 - statusList = Arrays.asList("04","05","07","01"); - }else if("zaichang".equals(repairTicketsReqVO.getTicketsStatus())){ + statusList = Arrays.asList("04", "05", "07", "01"); + } else if ("zaichang".equals(repairTicketsReqVO.getTicketsStatus())) { //在厂,就是没交车的,且不能是已作废和已完成的 repairTicketsReqVO.setIsHandover("0"); - statusList = Arrays.asList("04","05","07","01","06","02"); - }else if("jinchang".equals(repairTicketsReqVO.getTicketsStatus())){ + statusList = Arrays.asList("04", "05", "07", "01", "06", "02"); + } else if ("jinchang".equals(repairTicketsReqVO.getTicketsStatus())) { //进厂 statusList.add(TicketsStatusEnum.NO_WORK.getCode()); - }else if("yijungong".equals(repairTicketsReqVO.getTicketsStatus())){ + } else if ("yijungong".equals(repairTicketsReqVO.getTicketsStatus())) { //已竣工 - statusList = Arrays.asList("07","01","06","02","08"); - }else if("yijiaoche".equals(repairTicketsReqVO.getTicketsStatus())){ + statusList = Arrays.asList("07", "01", "06", "02", "08"); + } else if ("yijiaoche".equals(repairTicketsReqVO.getTicketsStatus())) { //已交车 repairTicketsReqVO.setIsHandover("1"); } - if(!statusList.isEmpty()){ + if (!statusList.isEmpty()) { repairTicketsReqVO.setStatusList(statusList); } } @@ -1184,7 +1209,6 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl dataList = dictDataApi.getDictDataList("repair_work_type"); DictDataRespDTO dictDataRespDTO = dataList.stream().filter(item -> item.getValue().equals(worker.getWorkType())).findFirst().orElse(null); String message = String.format("您的爱车%s已由%s %s接单了", tickets.getCarNo(), (dictDataRespDTO != null ? dictDataRespDTO.getLabel() : "维修工"), worker.getUserName()); - repairWorkerService.sentMessageToCus(SystemEnum.REPAIR.getCode(),id, message, false); + repairWorkerService.sentMessageToCus(SystemEnum.REPAIR.getCode(), id, message, false); // 更新工单主表时间 refreshUpdateTime(id); @@ -1265,7 +1288,6 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl() .setSql("now_repair_id = adviser_id") @@ -1428,7 +1448,7 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl { - repairWorkerService.sentMessage(SystemEnum.REPAIR.getCode(),id, message); + repairWorkerService.sentMessage(SystemEnum.REPAIR.getCode(), id, message); }); } @@ -1466,7 +1486,7 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl * @author vinjor-M * @date 11:30 2024/10/24 **/ @Override - public Map getBossNum(String selectType,String startDate,String endDate) { + public Map getBossNum(String selectType, String startDate, String endDate) { Map rtnMap = new HashMap<>(); //维修中---当前这一时刻 long workingNum = 0; @@ -1712,16 +1726,16 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl inCompanyIdList = new ArrayList<>(); //进场数 - long newOrderNum=0; + long newOrderNum = 0; List newOrderIdList = new ArrayList<>(); //已完成 - long overNum=0; + long overNum = 0; List overIdList = new ArrayList<>(); //已交车 - long giveCusNum=0; + long giveCusNum = 0; List giveCusIdList = new ArrayList<>(); //未结算 - long noPayNum=0; + long noPayNum = 0; List noPayIdList = new ArrayList<>(); List repairTickets = this.list(); if (!repairTickets.isEmpty()) { @@ -1729,46 +1743,46 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl TicketsStatusEnum.WORKING.getCode().equals(item.getTicketsStatus())).map(DlRepairTickets::getId).collect(Collectors.toList()); workingNum = workingIdList.size(); //只要没交车都算在厂 - inCompanyIdList = repairTickets.stream().filter(item -> "0".equals(item.getIsHandover())).filter(item->!"03".equals(item.getTicketsStatus())).map(DlRepairTickets::getId).collect(Collectors.toList()); + inCompanyIdList = repairTickets.stream().filter(item -> "0".equals(item.getIsHandover())).filter(item -> !"03".equals(item.getTicketsStatus())).map(DlRepairTickets::getId).collect(Collectors.toList()); inCompanyNum = inCompanyIdList.size(); //只要没结算,都是未结算 - List noPayCodeList = Arrays.asList("04","05","07","01"); + List noPayCodeList = Arrays.asList("04", "05", "07", "01"); noPayIdList = repairTickets.stream().filter(item -> noPayCodeList.contains(item.getTicketsStatus())).map(DlRepairTickets::getId).collect(Collectors.toList()); noPayNum = noPayIdList.size(); LocalDateTime currentTime = LocalDateTime.now(); - if("today".equals(selectType)){ + if ("today".equals(selectType)) { String nowDayStr = DateUtil.formatDate(new Date()); //查当日进厂数、已完成、已交车 newOrderIdList = repairTickets.stream().filter(item -> item.getCreateTime().toLocalDate().equals(currentTime.toLocalDate())).map(DlRepairTickets::getId).collect(Collectors.toList()); newOrderNum = newOrderIdList.size(); //查当日已完成的(总检完成的) - overIdList = repairTicketsMapper.selectTicketIdByParams(nowDayStr,RecordTypeEnum.ZJ.getCode(),null,null); + overIdList = repairTicketsMapper.selectTicketIdByParams(nowDayStr, RecordTypeEnum.ZJ.getCode(), null, null); overNum = overIdList.size(); //查当日已交车的 - giveCusIdList = repairTicketsMapper.selectTicketIdByParams(nowDayStr,RecordTypeEnum.JC.getCode(),null,null); + giveCusIdList = repairTicketsMapper.selectTicketIdByParams(nowDayStr, RecordTypeEnum.JC.getCode(), null, null); giveCusNum = giveCusIdList.size(); - }else if("all".equals(selectType)){ + } else if ("all".equals(selectType)) { //查累计进厂数、已完成、已交车 newOrderIdList = repairTickets.stream().map(DlRepairTickets::getId).collect(Collectors.toList()); newOrderNum = repairTickets.size(); //查累计已完成的(总检完成的) - List overCodeList = Arrays.asList("07","01","06","02","08"); + List overCodeList = Arrays.asList("07", "01", "06", "02", "08"); overIdList = repairTickets.stream().filter(item -> overCodeList.contains(item.getTicketsStatus())).map(DlRepairTickets::getId).collect(Collectors.toList()); overNum = overIdList.size(); //查累计已交车的 giveCusIdList = repairTickets.stream().filter(item -> "1".equals(item.getIsHandover())).map(DlRepairTickets::getId).collect(Collectors.toList()); giveCusNum = giveCusIdList.size(); - }else { + } else { //查某个时间范围内进厂数、已完成、已交车 - LocalDateTime startTime = LocalDateTime.parse(startDate+" 00:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); - LocalDateTime endTime = LocalDateTime.parse(endDate+" 23:59:59", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + LocalDateTime startTime = LocalDateTime.parse(startDate + " 00:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + LocalDateTime endTime = LocalDateTime.parse(endDate + " 23:59:59", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); newOrderIdList = repairTickets.stream().filter(item -> item.getCreateTime().isAfter(startTime) && item.getCreateTime().isBefore(endTime)).map(DlRepairTickets::getId).collect(Collectors.toList()); newOrderNum = newOrderIdList.size(); //查某区间范围内已完成的(总检完成的) - overIdList = repairTicketsMapper.selectTicketIdByParams(null,RecordTypeEnum.ZJ.getCode(), startDate+" 00:00:00", endDate+" 23:59:59"); + overIdList = repairTicketsMapper.selectTicketIdByParams(null, RecordTypeEnum.ZJ.getCode(), startDate + " 00:00:00", endDate + " 23:59:59"); overNum = overIdList.size(); //查某区间范围内已交车的 - giveCusIdList = repairTicketsMapper.selectTicketIdByParams(null,RecordTypeEnum.JC.getCode(), startDate+" 00:00:00", endDate+" 23:59:59"); + giveCusIdList = repairTicketsMapper.selectTicketIdByParams(null, RecordTypeEnum.JC.getCode(), startDate + " 00:00:00", endDate + " 23:59:59"); giveCusNum = giveCusIdList.size(); } } @@ -1789,7 +1803,6 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl { - repairWorkerService.sentMessage(SystemEnum.REPAIR.getCode(),id, "待总检车牌为:" + item.getCarNo() + "工单已经超时,但无法自动总检,请手动处理"); + repairWorkerService.sentMessage(SystemEnum.REPAIR.getCode(), id, "待总检车牌为:" + item.getCarNo() + "工单已经超时,但无法自动总检,请手动处理"); }); } return flag; @@ -2058,9 +2067,9 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl { - repairWorkerService.sentMessage(SystemEnum.REPAIR.getCode(),Long.valueOf(item.getAdviserId()), "您有新的工单可以出厂检验"); + repairWorkerService.sentMessage(SystemEnum.REPAIR.getCode(), Long.valueOf(item.getAdviserId()), "您有新的工单可以出厂检验"); ids.forEach(id -> { - repairWorkerService.sentMessage(SystemEnum.REPAIR.getCode(),id, "车牌为:" + item.getCarNo() + "工单已由系统自动总检并移交服务顾问"); + repairWorkerService.sentMessage(SystemEnum.REPAIR.getCode(), id, "车牌为:" + item.getCarNo() + "工单已由系统自动总检并移交服务顾问"); }); // 记录日志 repairRecordsService.saveRepairRecord(item.getId(), null, RecordTypeEnum.ZJ.getCode(), "该工单由系统自动总检完成", null); @@ -2069,7 +2078,6 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl() .set(DlRepairTickets::getUpdateTime, LocalDateTime.now()) .eq(DlRepairTickets::getId, id) diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/utils/TicketsOperateUtil.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/utils/TicketsOperateUtil.java index 3eb78601..2484ccf2 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/utils/TicketsOperateUtil.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/utils/TicketsOperateUtil.java @@ -3,26 +3,85 @@ package cn.iocoder.yudao.module.tickets.utils; import cn.hutool.core.date.DateUtil; import org.springframework.stereotype.Component; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.Date; /** * 工单操作常用util * @author vinjor-M * @date 16:15 2024/10/18 -**/ + **/ @Component public class TicketsOperateUtil { /** * 计算车龄 + * @param registerDate 车辆注册日期 + * @return java.lang.Double * @author vinjor-M * @date 14:47 2025/1/9 - * @param registerDate 车辆注册日期 - * @return java.lang.Double **/ - public Double computeCarYear(Date registerDate){ + public Double computeCarYear(Date registerDate) { long betweenMonth = DateUtil.betweenMonth(registerDate, new Date(), true); String carYear = String.format("%.2f", (double) betweenMonth / 12); return Double.parseDouble(carYear); } + + /** + * 计算利润 + * @param salePrice 单个售价(不含折扣) + * @param purchasePrice 单个进价(采购价格) + * @param count 数量 + * @return 利润金额 + */ + public BigDecimal calcProfit(BigDecimal salePrice, BigDecimal purchasePrice, int count) { + if (salePrice == null || purchasePrice == null) { + return BigDecimal.ZERO; + } + BigDecimal c = BigDecimal.valueOf(count); + return salePrice.multiply(c).subtract(purchasePrice.multiply(c)); + } + + /** + * 计算利润率 + * @param salePrice 单个售价(不含折扣) + * @param purchasePrice 单个进价(采购价格) + * @param count 数量 + * @return 利润率(0-1之间的小数,保留2位) + */ + public BigDecimal calcProfitRate(BigDecimal salePrice, BigDecimal purchasePrice, int count) { + if (salePrice == null || purchasePrice == null || count <= 0) { + return BigDecimal.ZERO; + } + + BigDecimal c = BigDecimal.valueOf(count); + BigDecimal saleTotal = salePrice.multiply(c); + if (saleTotal.compareTo(BigDecimal.ZERO) == 0) { + return BigDecimal.ZERO; + } + + BigDecimal profit = saleTotal.subtract(purchasePrice.multiply(c)); + return profit.divide(saleTotal, 2, RoundingMode.HALF_UP); + } + + /** + * 计算利润 + * @param salePrice 单个售价(不含折扣) + * @param purchasePrice 单个进价(采购价格) + * @return 利润金额 + */ + public BigDecimal calcProfit(BigDecimal salePrice, BigDecimal purchasePrice) { + return calcProfit(salePrice, purchasePrice, 1); + } + + /** + * 计算利润率 + * @param salePrice 售价(不含折扣) + * @param purchasePrice 进价(采购价格) + * @return 利润率(0-1之间的小数,保留2位) + */ + public BigDecimal calcProfitRate(BigDecimal salePrice, BigDecimal purchasePrice) { + return calcProfitRate(salePrice, purchasePrice, 1); + } } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/DlRepairTicketsRespVO.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/DlRepairTicketsRespVO.java index f2db5780..761b4e1c 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/DlRepairTicketsRespVO.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/DlRepairTicketsRespVO.java @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.tickets.entity.DlRepairTickets; import cn.iocoder.yudao.module.tickets.entity.DlRepairTitem; import lombok.Data; +import java.math.BigDecimal; import java.util.List; /** @@ -75,4 +76,10 @@ public class DlRepairTicketsRespVO extends DlRepairTickets { /** 客户来源 */ private String cusFrom; + + /** 含工时项目毛利率*/ + private BigDecimal profitRate; + + /** 不含工时项目毛利率*/ + private BigDecimal profitRateNo; } From 6788c0c1fd9a15ea456ac102ef034d028250b5da Mon Sep 17 00:00:00 2001 From: xyc <3422692813@qq.com> Date: Wed, 20 Aug 2025 09:22:17 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E6=9B=B4=E6=96=B00820?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/RepairWorkerServiceImpl.java | 11 +- .../admin/DlRepairTicketsController.java | 82 ++++++- .../module/tickets/dto/JobTypeProfitDTO.java | 28 +++ .../module/tickets/entity/DlRepairTitem.java | 174 +++++++------- .../tickets/mapper/DlRepairTicketsMapper.java | 11 + .../service/DlRepairTicketsService.java | 10 + .../impl/DlRepairTicketsServiceImpl.java | 108 ++++++++- .../tickets/vo/DlRepairTicketsReqVO.java | 7 +- .../tickets/vo/DlRepairTicketsRespVO.java | 4 + .../mapper/tickets/DlRepairTicketsMapper.xml | 223 ++++++++++++++---- .../excel/core/util/ExcelExtraHelper.java | 104 ++++++++ .../framework/excel/core/util/ExcelUtils.java | 45 ++++ 12 files changed, 663 insertions(+), 144 deletions(-) create mode 100644 dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/dto/JobTypeProfitDTO.java create mode 100644 yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelExtraHelper.java diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairWorkerServiceImpl.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairWorkerServiceImpl.java index 59b33182..f872e5e7 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairWorkerServiceImpl.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairWorkerServiceImpl.java @@ -32,6 +32,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; @@ -177,7 +178,15 @@ public class RepairWorkerServiceImpl extends ServiceImpl ids = titems.stream().flatMap(item -> Arrays.stream(item.getRepairIds().split(","))).collect(Collectors.toSet()); + // 取所有的员工ID + Set ids = titems.stream() + .filter(item -> item.getRepairIds() != null) // 过滤掉repairIds为null的项 + .flatMap(item -> Arrays.stream(item.getRepairIds().split(","))) + .filter(StringUtils::hasText) // 过滤掉空字符串 + .collect(Collectors.toSet()); + if (ids.isEmpty()) { + return Collections.emptyList(); + } List repairWorkerList = baseMapper.selectList(new LambdaQueryWrapper().in(RepairWorker::getUserId, ids)); if (!repairWorkerList.isEmpty()) { // 单位字典 diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/controller/admin/DlRepairTicketsController.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/controller/admin/DlRepairTicketsController.java index 3d0291a5..d857314c 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/controller/admin/DlRepairTicketsController.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/controller/admin/DlRepairTicketsController.java @@ -5,6 +5,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; import cn.iocoder.yudao.common.RecordTypeEnum; import cn.iocoder.yudao.common.RepairCons; +import cn.iocoder.yudao.common.RepairDictConstants; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; @@ -13,19 +14,30 @@ import cn.iocoder.yudao.module.custom.entity.CarMain; import cn.iocoder.yudao.module.custom.entity.CustomerMain; import cn.iocoder.yudao.module.custom.service.CarMainService; import cn.iocoder.yudao.module.custom.service.CustomerMainService; +import cn.iocoder.yudao.module.system.api.dict.DictDataApi; +import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; import cn.iocoder.yudao.module.tickets.entity.DlRepairTickets; import cn.iocoder.yudao.module.tickets.service.DlRepairTicketsService; import cn.iocoder.yudao.module.tickets.vo.*; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import io.swagger.v3.oas.annotations.Operation; import org.apache.commons.lang3.StringUtils; +import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.net.URLEncoder; +import java.time.LocalDateTime; import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; @@ -53,6 +65,9 @@ public class DlRepairTicketsController { @Resource private RepairRecordsService repairRecordsService; + @Resource + private DictDataApi dictDataApi; + /** * 维修工单表 新增 @@ -528,6 +543,18 @@ public class DlRepairTicketsController { return success(dlRepairTicketsService.getCusAndCarById(id)); } + /** + * @Author 许 + * @Description 工单统计 + * @Date 15:53 2025/8/19 + * @Param [repairTicketsReqVO] + * @return cn.iocoder.yudao.framework.common.pojo.CommonResult + **/ + @GetMapping("/getStatistics") + public CommonResult getStatistics(DlRepairTicketsReqVO repairTicketsReqVO) { + return success(dlRepairTicketsService.getStatistics(repairTicketsReqVO)); + } + /** * 导出数据 * @@ -559,9 +586,48 @@ public class DlRepairTicketsController { if (CollUtil.isEmpty(list)){ throw exception0(500, "没有数据可以导出"); } - ExcelUtils.write(response, "工单数据.xls", "数据", TicketsExportVO.class, list); + + Map statistics = dlRepairTicketsService.getStatistics(repairTicketsReqVO); + + List dictDataList = dictDataApi.getDictDataList(RepairDictConstants.REPAIR_TYPE); + // 转换map + Map repairTypeMap = dictDataList.stream().collect(Collectors.toMap(DictDataRespDTO::getValue, DictDataRespDTO::getLabel)); + + List> rows = new ArrayList<>(); + + // 第一行可以写汇总信息或标题行 + String totalLaborPartsMoney = statistics.get("totalLaborPartsMoney") != null ? statistics.get("totalLaborPartsMoney").toString() : "0"; + String totalProfit = statistics.get("totalProfit") != null ? statistics.get("totalProfit").toString() : "0"; + String profitRateWithLabor = statistics.get("profitRateWithLabor") != null ? formatPercentage(statistics.get("profitRateWithLabor").toString()) : "0%"; + String profitRateWithoutLabor = statistics.get("profitRateWithoutLabor") != null ? formatPercentage(statistics.get("profitRateWithoutLabor").toString()) : "0%"; + + rows.add(CollUtil.newArrayList( + "产值:", totalLaborPartsMoney, + "毛利:", totalProfit, + "含工时毛利率:", profitRateWithLabor, + "不含工时毛利率:", profitRateWithoutLabor)); + + // 第二行写表头 + rows.add(CollUtil.newArrayList("订单编号","维修类别", "客户名称", "车牌号", "车系", "手机号", "经办人姓名", "经办人电话")); + + // 后面循环写数据 + for (TicketsExportVO item : list) { + rows.add(CollUtil.newArrayList( + item.getTicketNo(), + repairTypeMap.get(item.getRepairType()), + item.getUserName(), + item.getCarNo(), + item.getCarBrandName(), + item.getUserMobile(), + item.getHandleName(), + item.getHandleMobile() + )); + } + + ExcelUtils.exportExcel("维修工单", rows, CollUtil.newArrayList(3), response); } + /** * 导出数据 根据工单状态 * @@ -618,5 +684,19 @@ public class DlRepairTicketsController { dlRepairTicketsService.pickCar(id,image,remark); return CommonResult.ok(); } + + /** + * 格式化为百分比字符串 + * @param value 值 + * @return 百分比格式字符串 + */ + private String formatPercentage(String value) { + try { + double rate = Double.parseDouble(value); + return String.format("%.2f%%", rate * 100); + } catch (NumberFormatException e) { + return "0.00%"; + } + } } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/dto/JobTypeProfitDTO.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/dto/JobTypeProfitDTO.java new file mode 100644 index 00000000..54ef3d40 --- /dev/null +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/dto/JobTypeProfitDTO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.tickets.dto; + +import lombok.Data; + +import java.math.BigDecimal; + +/** + * @BelongsProject: lanan-system + * @BelongsPackage: cn.iocoder.yudao.module.tickets.dto + * @Author: 许 + * @CreateTime: 2025-08-18 14:51 + * @Description: 工种利润 + * @Version: 1.0 + */ +@Data +public class JobTypeProfitDTO { + private String jobTypeCode; // 工种编码 + private String jobTypeName; // 工种名称 + private BigDecimal profit; // 毛利 + private BigDecimal money; // 金额 + private BigDecimal profitRate;// 毛利率 + private BigDecimal cost; //成本 + private BigDecimal profitRateWithoutWork; // 不含工时毛利率 + private BigDecimal profitRateWithWork; // 含工时毛利率 + private BigDecimal workMoney; // 工时金额(分母用) + +} + diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTitem.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTitem.java index ab123328..fcd6c127 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTitem.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTitem.java @@ -19,110 +19,110 @@ import lombok.EqualsAndHashCode; @TableName(value ="dl_repair_titem") @Data @EqualsAndHashCode(callSuper = true) -public class DlRepairTitem extends TenantBaseDO { - /** - * 主键标识 - */ - @TableId(type = IdType.ASSIGN_ID) - private String id; + public class DlRepairTitem extends TenantBaseDO { + /** + * 主键标识 + */ + @TableId(type = IdType.ASSIGN_ID) + private String id; - /** - * 工单ID(dl_repair_tickets表的ID) - */ - private String ticketId; + /** + * 工单ID(dl_repair_tickets表的ID) + */ + private String ticketId; - /** - * 名称;计划前端写的时候可以监听一下,动态查一下历史的记录推荐给使用者选 - */ - private String itemName; + /** + * 名称;计划前端写的时候可以监听一下,动态查一下历史的记录推荐给使用者选 + */ + private String itemName; - /** - * 数量 - */ - private Integer itemCount; + /** + * 数量 + */ + private Integer itemCount; - /** - * 单位;计划前端写的时候可以监听一下,动态查一下历史的记录推荐给使用者选 - */ - private String itemUnit; + /** + * 单位;计划前端写的时候可以监听一下,动态查一下历史的记录推荐给使用者选 + */ + private String itemUnit; - /** - * 单价 - */ - private BigDecimal itemPrice; + /** + * 单价 + */ + private BigDecimal itemPrice; - /** - * 折扣 - */ - private BigDecimal itemDiscount; + /** + * 折扣 + */ + private BigDecimal itemDiscount; - /** - * 金额;正常是自动计算 - */ - private BigDecimal itemMoney; + /** + * 金额;正常是自动计算 + */ + private BigDecimal itemMoney; - /** - * 利润 - */ - private BigDecimal itemProfit; + /** + * 利润 + */ + private BigDecimal itemProfit; - /** - * 毛利率 - */ - private BigDecimal itemProfitRate; + /** + * 毛利率 + */ + private BigDecimal itemProfitRate; - /** - * 维修人员ID(system_users表的ID) - */ - private String repairIds; + /** + * 维修人员ID(system_users表的ID) + */ + private String repairIds; - /** - * 维修人员名字(company_staff表的name) - */ - private String repairNames; + /** + * 维修人员名字(company_staff表的name) + */ + private String repairNames; - /** - * 销售人员ID(system_users表的ID) - */ - private Long saleId; + /** + * 销售人员ID(system_users表的ID) + */ + private Long saleId; - /** - * 销售人员名字(company_staff表的name) - */ - private String saleName; + /** + * 销售人员名字(company_staff表的name) + */ + private String saleName; - /** - * 子项类型(字典repair_item_type) - */ - private String itemType; + /** + * 子项类型(字典repair_item_type) + */ + private String itemType; - /** - * 项目ID(dl_repair_project表的ID) - */ - private String projectId; + /** + * 项目ID(dl_repair_project表的ID) + */ + private String projectId; - /** - * 配件ID(dl_base_type表的ID) - */ - private String partId; + /** + * 配件ID(dl_base_type表的ID) + */ + private String partId; - /** - * 其他ID(dl_base_type表的ID) - */ - private String otherId; + /** + * 其他ID(dl_base_type表的ID) + */ + private String otherId; - /** - * 子项类型ID(dl_base_type表的ID) - */ - private String itemTypeId; + /** + * 子项类型ID(dl_base_type表的ID) + */ + private String itemTypeId; - /** - * 状态(字典repair_item_status) - */ - private String itemStatus; + /** + * 状态(字典repair_item_status) + */ + private String itemStatus; - /** - * 备注 - */ - private String remark; -} + /** + * 备注 + */ + private String remark; + } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/mapper/DlRepairTicketsMapper.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/mapper/DlRepairTicketsMapper.java index ba318aed..c97cc4a3 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/mapper/DlRepairTicketsMapper.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/mapper/DlRepairTicketsMapper.java @@ -9,6 +9,7 @@ import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import java.util.List; +import java.util.Map; /** * 针对表【dl_repair_tickets(维修工单表)】的数据库操作Mapper @@ -55,6 +56,16 @@ public interface DlRepairTicketsMapper extends BaseMapper { * @return java.lang.Long **/ List selectTicketIdByParams(@Param("nowDate")String dayDate, @Param("recordCode")String recordCode, @Param("startTime")String startTime, @Param("endTime")String endTime); + + /** + * @Author 许 + * @Description 统计工单 + * @Date 15:54 2025/8/19 + * @Param [repairTicketsReqVO] + * @return java.util.Map + **/ + + Map getStatistics(@Param("map") DlRepairTicketsReqVO repairTicketsReqVO); } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/DlRepairTicketsService.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/DlRepairTicketsService.java index d8ba8f39..e3d2fb24 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/DlRepairTicketsService.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/DlRepairTicketsService.java @@ -281,4 +281,14 @@ public interface DlRepairTicketsService extends IService { **/ void pickCar(String id, String image, String remark); + + /** + * @Author 许 + * @Description 工单统计 + * @Date 15:54 2025/8/19 + * @Param [repairTicketsReqVO] + * @return java.util.Map + **/ + + Map getStatistics(DlRepairTicketsReqVO repairTicketsReqVO); } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java index 3ac919ee..4b29b4dd 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java @@ -49,6 +49,7 @@ import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import cn.iocoder.yudao.module.system.api.user.dto.UserDTO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import cn.iocoder.yudao.module.tickets.dto.JobTypeProfitDTO; import cn.iocoder.yudao.module.tickets.entity.DlRepairTickets; import cn.iocoder.yudao.module.tickets.entity.DlRepairTitem; import cn.iocoder.yudao.module.tickets.entity.DlTicketWares; @@ -96,6 +97,7 @@ import java.util.stream.Collectors; import static cn.iocoder.yudao.common.BaseConstants.ORDER_TENANT_NAME; import static cn.iocoder.yudao.common.RepairCons.*; +import static cn.iocoder.yudao.common.RepairDictConstants.REPAIR_WORK_TYPE; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; @@ -568,19 +570,98 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl typeMap = recordTypeList.stream().collect(Collectors.toMap(DictDataRespDTO::getValue, DictDataRespDTO::getLabel)); result.setRecords(records.stream().peek(item -> item.setType(typeMap.get(item.getType()))).collect(Collectors.toList())); + //查询维修工人表 + List workers = repairWorkerService.listByTicketId(id); + //转成map + Map workerMap = workers.stream().collect(Collectors.toMap(RepairWorker::getUserId, item -> item)); + + //配件总利润 BigDecimal waresProfit = BigDecimal.ZERO; + List resultList = new ArrayList<>(); + if (CollectionUtil.isNotEmpty(items)) { for (DlRepairTitemReqVO item : items) { - if ("02".equals(item.getItemType())) { - // 获取配件利润 加到总利润中 - BigDecimal itemProfit = item.getItemProfit() != null ? item.getItemProfit() : BigDecimal.ZERO; - waresProfit = waresProfit.add(itemProfit); - System.out.println("配件利润:" + itemProfit); + BigDecimal itemProfit = item.getItemProfit() != null ? item.getItemProfit() : BigDecimal.ZERO; + waresProfit = waresProfit.add(itemProfit); + BigDecimal itemMoney = item.getItemMoney() != null ? item.getItemMoney() : BigDecimal.ZERO; + // 成本 = 售价 - 利润(也可以直接从 item.getItemCost() 取,如果有字段) + BigDecimal itemCost = itemMoney.subtract(itemProfit); + + if (StringUtils.isNotEmpty(item.getRepairIds())) { + if (StringUtils.isNotEmpty(item.getRepairIds())) { + String[] repairIdArr = item.getRepairIds().split(","); + for (String repairIdStr : repairIdArr) { + if (StringUtils.isNotEmpty(repairIdStr)) { + RepairWorker repairWorker = workerMap.get(Long.valueOf(repairIdStr)); + if (repairWorker != null) { + String jobType = repairWorker.getWorkType(); + + JobTypeProfitDTO dto = resultList.stream() + .filter(r -> r.getJobTypeCode().equals(jobType)) + .findFirst() + .orElseGet(() -> { + JobTypeProfitDTO newDto = new JobTypeProfitDTO(); + newDto.setJobTypeCode(jobType); + newDto.setJobTypeName(dictDataApi.getDictDataLabel(REPAIR_WORK_TYPE, jobType)); + newDto.setProfit(BigDecimal.ZERO); + newDto.setMoney(BigDecimal.ZERO); + newDto.setWorkMoney(BigDecimal.ZERO); + newDto.setCost(BigDecimal.ZERO); // 新增成本字段 + resultList.add(newDto); + return newDto; + }); + + if ("02".equals(item.getItemType())) { // 配件 + // 多人平摊利润/金额/成本 + int numWorkers = repairIdArr.length; + BigDecimal profitPerWorker = itemProfit.divide(BigDecimal.valueOf(numWorkers), 4, RoundingMode.HALF_UP); + BigDecimal moneyPerWorker = itemMoney.divide(BigDecimal.valueOf(numWorkers), 4, RoundingMode.HALF_UP); + BigDecimal costPerWorker = itemCost.divide(BigDecimal.valueOf(numWorkers), 4, RoundingMode.HALF_UP); + + dto.setProfit(dto.getProfit().add(profitPerWorker)); + dto.setMoney(dto.getMoney().add(moneyPerWorker)); + dto.setCost(dto.getCost().add(costPerWorker)); + } else if ("01".equals(item.getItemType())) { // 工时 + dto.setWorkMoney(dto.getWorkMoney().add(itemMoney)); + } + } + } + } + } + } + } } + // ====== 计算分组毛利率 ====== + for (JobTypeProfitDTO dto : resultList) { + BigDecimal partsProfit = dto.getProfit(); // 配件利润 + BigDecimal partsMoney = dto.getMoney(); // 配件售价 + BigDecimal workMoney = dto.getWorkMoney(); // 工时售价 + + // 不含工时 + BigDecimal profitRateWithoutWork = BigDecimal.ZERO; + if (partsMoney.compareTo(BigDecimal.ZERO) > 0) { + profitRateWithoutWork = partsProfit.divide(partsMoney, 4, RoundingMode.HALF_UP); + } + + // 含工时 + BigDecimal profitRateWithWork = BigDecimal.ZERO; + BigDecimal totalMoney = partsMoney.add(workMoney); + if (totalMoney.compareTo(BigDecimal.ZERO) > 0) { + profitRateWithWork = partsProfit.divide(totalMoney, 4, RoundingMode.HALF_UP); + } + + dto.setProfitRateWithoutWork(profitRateWithoutWork); + dto.setProfitRateWithWork(profitRateWithWork); + } + + + // 最终返回 list + result.setGroupByJobType(resultList); + //计算含工时项目毛利率 //配件总利润除以工单总价 @@ -590,6 +671,9 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl + * @Author 许 + * @Description 工单统计 + * @Date 15:54 2025/8/19 + * @Param [repairTicketsReqVO] + */ + @Override + public Map getStatistics(DlRepairTicketsReqVO repairTicketsReqVO) { + return baseMapper.getStatistics(repairTicketsReqVO); + } } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/DlRepairTicketsReqVO.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/DlRepairTicketsReqVO.java index 07fa1ec8..a6550a94 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/DlRepairTicketsReqVO.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/DlRepairTicketsReqVO.java @@ -8,6 +8,7 @@ import org.springframework.format.annotation.DateTimeFormat; import java.util.Date; import java.util.List; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; /** @@ -20,8 +21,7 @@ public class DlRepairTicketsReqVO extends DlRepairTickets { /** 时间区间 */ @Schema(pattern = "时间区间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date[] searchTimeArray; + private String[] searchTimeArray; /** 工单中项目指定的施工人员的ids */ private List userIds; @@ -55,4 +55,7 @@ public class DlRepairTicketsReqVO extends DlRepairTickets { /** 统计参数 wxz:维修中 wjs:未结算 zc:在厂*/ private String statisticsType; + + /** 工种 */ + private String workType; } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/DlRepairTicketsRespVO.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/DlRepairTicketsRespVO.java index 761b4e1c..298e15c0 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/DlRepairTicketsRespVO.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/DlRepairTicketsRespVO.java @@ -4,12 +4,14 @@ import cn.iocoder.yudao.module.base.vo.RepairRecordsRespVO; import cn.iocoder.yudao.module.booking.entity.DlRepairBooking; import cn.iocoder.yudao.module.custom.entity.CustomerMain; import cn.iocoder.yudao.module.custom.vo.CarMainRespVO; +import cn.iocoder.yudao.module.tickets.dto.JobTypeProfitDTO; import cn.iocoder.yudao.module.tickets.entity.DlRepairTickets; import cn.iocoder.yudao.module.tickets.entity.DlRepairTitem; import lombok.Data; import java.math.BigDecimal; import java.util.List; +import java.util.Map; /** * 维修工单表 响应VO @@ -82,4 +84,6 @@ public class DlRepairTicketsRespVO extends DlRepairTickets { /** 不含工时项目毛利率*/ private BigDecimal profitRateNo; + + private List groupByJobType; } diff --git a/dl-module-repair/src/main/resources/mapper/tickets/DlRepairTicketsMapper.xml b/dl-module-repair/src/main/resources/mapper/tickets/DlRepairTicketsMapper.xml index 0ac6bdfe..a761c29c 100644 --- a/dl-module-repair/src/main/resources/mapper/tickets/DlRepairTicketsMapper.xml +++ b/dl-module-repair/src/main/resources/mapper/tickets/DlRepairTicketsMapper.xml @@ -218,7 +218,7 @@ ) - and drt.create_time between #{map.searchTimeArray[0]} and #{map.searchTimeArray[1]} + AND (drt.create_time BETWEEN CONCAT(#{map.searchTimeArray[0]}, ' 00:00:00') AND CONCAT(#{map.searchTimeArray[1]}, ' 23:59:59')) and drt.repair_type = #{map.repairType} @@ -268,7 +268,7 @@ ) - and (drt.create_time between #{map.searchTimeArray[0]} and #{map.searchTimeArray[1]}) + AND (drt.create_time BETWEEN CONCAT(#{map.searchTimeArray[0]}, ' 00:00:00') AND CONCAT(#{map.searchTimeArray[1]}, ' 23:59:59')) AND (drt.repair_type=#{map.repairType}) @@ -389,96 +389,108 @@ + + diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelExtraHelper.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelExtraHelper.java new file mode 100644 index 00000000..99b9bc1c --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelExtraHelper.java @@ -0,0 +1,104 @@ +package cn.iocoder.yudao.framework.excel.core.util; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.poi.excel.ExcelWriter; +import org.apache.poi.ss.usermodel.*; + +import java.util.List; + +public class ExcelExtraHelper { + + /** + * 根据内容自动设置列宽,并设置样式 + * @param writer ExcelWriter + * @param rows 所有行(含表头) + * @param timeColumnIndexList 哪些列是时间列(索引从0开始) + * @param numberColumnIndexList 哪些列是数字列(右对齐) + */ + public static void enhanceExcel(ExcelWriter writer, List> rows, + List timeColumnIndexList, List numberColumnIndexList) { + if (CollUtil.isEmpty(rows)) return; + + // ============ 1. 表头样式 ============ + CellStyle headStyle = writer.getHeadCellStyle(); + Font headFont = writer.getWorkbook().createFont(); + headFont.setBold(true); + headFont.setFontHeightInPoints((short) 12); + headStyle.setFont(headFont); + // 设置背景色 + headStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + headStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + + // ============ 2. 内容样式 ============ + CellStyle contentStyle = writer.getCellStyle(); + contentStyle.setAlignment(HorizontalAlignment.LEFT); + contentStyle.setVerticalAlignment(VerticalAlignment.CENTER); + + // ============ 3. 时间列样式 ============ + CellStyle timeStyle = writer.getWorkbook().createCellStyle(); + timeStyle.cloneStyleFrom(contentStyle); + timeStyle.setDataFormat(writer.getWorkbook().createDataFormat().getFormat("yyyy-MM-dd HH:mm")); + + // ============ 4. 数字列样式 ============ + CellStyle numberStyle = writer.getWorkbook().createCellStyle(); + numberStyle.cloneStyleFrom(contentStyle); + numberStyle.setAlignment(HorizontalAlignment.RIGHT); + + // ============ 5. 根据内容自动调节列宽 ============ + int colSize = rows.get(0).size(); + int[] maxLength = new int[colSize]; + + for (List row : rows) { + for (int colIndex = 0; colIndex < colSize; colIndex++) { + if (row.size() > colIndex && row.get(colIndex) != null) { + String cell = row.get(colIndex); + int length = getStringDisplayLength(cell); + if (length > maxLength[colIndex]) { + maxLength[colIndex] = length; + } + } + } + } + for (int i = 0; i < colSize; i++) { + writer.setColumnWidth(i, maxLength[i] + 2); + } + + // ============ 6. 设置时间列 & 数字列格式 ============ + Sheet sheet = writer.getSheet(); + int rowCount = rows.size(); + + for (int rowIdx = 1; rowIdx < rowCount; rowIdx++) { // 第0行是表头 + Row row = sheet.getRow(rowIdx); + if (row == null) continue; + if (timeColumnIndexList != null) + for (Integer colIdx : timeColumnIndexList) { + Cell cell = row.getCell(colIdx); + if (cell != null) { + cell.setCellStyle(timeStyle); + } + } + if (numberColumnIndexList != null) + for (Integer colIdx : numberColumnIndexList) { + Cell cell = row.getCell(colIdx); + if (cell != null) { + cell.setCellStyle(numberStyle); + } + } + } + } + + /** + * 中文算2长度,英文算1 + */ + private static int getStringDisplayLength(String str) { + int length = 0; + for (char c : str.toCharArray()) { + if (c >= 0x4E00 && c <= 0x9FA5) { + length += 2; + } else { + length += 1; + } + } + return length; + } +} diff --git a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java index 964506bc..421d7732 100644 --- a/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java @@ -1,5 +1,8 @@ package cn.iocoder.yudao.framework.excel.core.util; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.poi.excel.ExcelUtil; +import cn.hutool.poi.excel.ExcelWriter; import cn.iocoder.yudao.framework.excel.core.handler.CellTextWrapHandler; import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler; import cn.iocoder.yudao.framework.excel.core.handler.SetColumnWidthHandler; @@ -212,4 +215,46 @@ public class ExcelUtils { } } + /** + * 通用 Excel 导出方法 + * + * @param title Excel标题 + * @param rows 数据行 + * @param mergeCols 需要增强或特殊处理的列索引(可选) + * @param response HttpServletResponse + * @throws IOException + */ + public static void exportExcel(String title, List> rows, List mergeCols, HttpServletResponse response) throws IOException { + if (CollUtil.isEmpty(rows)) { + throw new IllegalArgumentException("导出数据为空!"); + } + + // 创建 ExcelWriter + ExcelWriter writer = ExcelUtil.getWriter(); + + // ====== 合并单元格写标题 ====== + writer.merge(rows.get(0).size() - 1, title); // 根据第一行列数合并单元格 + writer.setRowHeight(0, 30); // 设置标题行高 + + // 写入数据,true 表示包含表头 + writer.write(rows, true); + + // 如果有需要增强的列 + if (mergeCols != null && !mergeCols.isEmpty()) { + ExcelExtraHelper.enhanceExcel(writer, rows, mergeCols, null); + } + + // 设置响应头 + response.setContentType("application/vnd.ms-excel;charset=utf-8"); + response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(title + ".xls", "UTF-8")); + + try (ServletOutputStream out = response.getOutputStream()) { + writer.flush(out, true); + } finally { + writer.close(); // 释放资源 + } + + } + + } From 06560969c097d1505035d03a416360bb2566c8bb Mon Sep 17 00:00:00 2001 From: xyc <3422692813@qq.com> Date: Wed, 20 Aug 2025 16:14:44 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=B4=A2=E5=8A=A1?= =?UTF-8?q?=E7=BB=93=E7=AE=97=E6=94=B6=E6=AC=BE=E7=9B=B8=E5=85=B3=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iocoder/yudao/common/RecordTypeEnum.java | 4 +- .../yudao/common/RepairDictConstants.java | 3 + .../module/base/entity/RepairRecords.java | 5 + .../base/service/RepairRecordsService.java | 10 ++ .../impl/RepairRecordsServiceImpl.java | 27 ++++ .../admin/DlRepairTicketsController.java | 64 ++++++++- .../tickets/entity/DlRepairTickets.java | 8 ++ .../service/DlRepairTicketsService.java | 35 ++++- .../impl/DlRepairTicketsServiceImpl.java | 136 ++++++++++++++++-- .../tickets/vo/TicketsSettlementVO.java | 40 ++++++ .../mapper/tickets/DlRepairTicketsMapper.xml | 23 ++- 11 files changed, 331 insertions(+), 24 deletions(-) create mode 100644 dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/TicketsSettlementVO.java diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/common/RecordTypeEnum.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/common/RecordTypeEnum.java index df353a01..59134dcb 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/common/RecordTypeEnum.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/common/RecordTypeEnum.java @@ -91,7 +91,9 @@ public enum RecordTypeEnum { NFPG("nfpg", "内返派工"), /** 收款*/ SK("sk", "收款"), - PICKCAR("pickcar", "接车"); + PICKCAR("pickcar", "接车"), + JSSQ("jssq", "结算申请"), + JSSP("jssp", "结算审批"); /** * code diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/common/RepairDictConstants.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/common/RepairDictConstants.java index c541d183..e72ba81b 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/common/RepairDictConstants.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/common/RepairDictConstants.java @@ -34,4 +34,7 @@ public interface RepairDictConstants { /** 调拨状态 */ String REPAIR_ST_STATUS = "repair_st_status"; + + /** 基础业务配置 */ + String BASE_BUSINESS_CONFIG = "base_business_config"; } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/entity/RepairRecords.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/entity/RepairRecords.java index 6b9e0de5..0ac425f0 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/entity/RepairRecords.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/entity/RepairRecords.java @@ -50,4 +50,9 @@ public class RepairRecords extends TenantBaseDO { */ private Long dealUserId; + /** + * 冗余字段 + */ + private String otherData; + } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/RepairRecordsService.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/RepairRecordsService.java index 73d7589a..5c9e2899 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/RepairRecordsService.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/RepairRecordsService.java @@ -28,6 +28,16 @@ public interface RepairRecordsService extends IService { **/ void saveRepairRecord(String ticketId, String repairItemId, String type, String remark, String images); + /** + * @Author 许 + * @Description 保存维修记录 + * @Date 13:38 2025/8/20 + * @Param [ticketId, repairItemId, type, remark, images, otherData] + * @return void + **/ + + void saveRepairRecord(String ticketId, String repairItemId, String type, String remark, String images, String otherData); + /** * 根据条件查询维修记录 * @author PQZ diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairRecordsServiceImpl.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairRecordsServiceImpl.java index fde8d479..d36fbab5 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairRecordsServiceImpl.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairRecordsServiceImpl.java @@ -76,6 +76,33 @@ public class RepairRecordsServiceImpl extends ServiceImpl setTicketsPaid(@RequestBody DlRepairTicketsRespVO repairTicketsRespVO) { dlRepairTicketsService.setTicketsPaid(repairTicketsRespVO); return CommonResult.ok(); } + /** + * 维修工单表 结算 + * + * @param vo 工单 + * @author 小李 + * @date 8:50 2024/9/23 + **/ + @PostMapping("/settlement") + @Operation(summary = "维修工单表 结算") + public CommonResult setTicketsSettlement(@RequestBody TicketsSettlementVO vo) { + dlRepairTicketsService.setTicketsSettlement(vo); + return CommonResult.ok(); + } + + /** + * @Author 许 + * @Description 结算审批 + * @Date 13:43 2025/8/20 + * @Param [vo] + * @return cn.iocoder.yudao.framework.common.pojo.CommonResult + **/ + + @PostMapping("/settlementReview") + @Operation(summary = "维修工单表 结算") + public CommonResult settlementReview(@RequestBody TicketsSettlementVO vo) { + dlRepairTicketsService.settlementReview(vo); + return CommonResult.ok(); + } + + /** + * @Author 许 + * @Description 查询审批金额 + * @Date 14:20 2025/8/20 + * @Param [repairTicketsReqVO] + * @return cn.iocoder.yudao.framework.common.pojo.CommonResult + **/ + @GetMapping("/getSettlement") + public CommonResult getSettlement(DlRepairTicketsReqVO repairTicketsReqVO) { + return CommonResult.success(dlRepairTicketsService.getSettlement(repairTicketsReqVO)); + } + // /** // * 维修工单表 导出 // * @@ -601,11 +647,15 @@ public class DlRepairTicketsController { String profitRateWithLabor = statistics.get("profitRateWithLabor") != null ? formatPercentage(statistics.get("profitRateWithLabor").toString()) : "0%"; String profitRateWithoutLabor = statistics.get("profitRateWithoutLabor") != null ? formatPercentage(statistics.get("profitRateWithoutLabor").toString()) : "0%"; - rows.add(CollUtil.newArrayList( - "产值:", totalLaborPartsMoney, - "毛利:", totalProfit, - "含工时毛利率:", profitRateWithLabor, - "不含工时毛利率:", profitRateWithoutLabor)); + + boolean hasAnyPermissions = permissionApi.hasAnyPermissions(SecurityFrameworkUtils.getLoginUserId(), "repair:tick:profit"); + if (hasAnyPermissions) { + rows.add(CollUtil.newArrayList( + "产值:", totalLaborPartsMoney, + "毛利:", totalProfit, + "含工时毛利率:", profitRateWithLabor, + "不含工时毛利率:", profitRateWithoutLabor)); + } // 第二行写表头 rows.add(CollUtil.newArrayList("订单编号","维修类别", "客户名称", "车牌号", "车系", "手机号", "经办人姓名", "经办人电话")); diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTickets.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTickets.java index 68e7181a..72b11781 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTickets.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTickets.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.tickets.entity; import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; +import cn.iocoder.yudao.module.tickets.vo.TicketsSettlementVO; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; @@ -249,6 +250,9 @@ public class DlRepairTickets extends TenantBaseDO { /** 商业险保费 */ private BigDecimal shangye; + /** 支付状态 字典(repair_pat_status) */ + private String payStatus; + /** 更新时上传的图片 */ @TableField(exist = false) private String image; @@ -258,4 +262,8 @@ public class DlRepairTickets extends TenantBaseDO { /** 支付方式文本 */ @TableField(exist = false) private String payTypeText; + @TableField(exist = false) + private String settlementStr; + @TableField(exist = false) + private TicketsSettlementVO settlement; } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/DlRepairTicketsService.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/DlRepairTicketsService.java index e3d2fb24..4a9f62da 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/DlRepairTicketsService.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/DlRepairTicketsService.java @@ -1,10 +1,7 @@ package cn.iocoder.yudao.module.tickets.service; import cn.iocoder.yudao.module.tickets.entity.DlRepairTickets; -import cn.iocoder.yudao.module.tickets.vo.CustomerAndCarVO; -import cn.iocoder.yudao.module.tickets.vo.DlRepairTicketsReqVO; -import cn.iocoder.yudao.module.tickets.vo.DlRepairTicketsRespVO; -import cn.iocoder.yudao.module.tickets.vo.NoticeCusVO; +import cn.iocoder.yudao.module.tickets.vo.*; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; @@ -291,4 +288,34 @@ public interface DlRepairTicketsService extends IService { **/ Map getStatistics(DlRepairTicketsReqVO repairTicketsReqVO); + + /** + * @Author 许 + * @Description 结算申请 + * @Date 10:12 2025/8/20 + * @Param [repairTicketsRespVO] + * @return void + **/ + + void setTicketsSettlement(TicketsSettlementVO repairTicketsRespVO); + + /** + * @Author 许 + * @Description 结算审批 + * @Date 13:41 2025/8/20 + * @Param [vo] + * @return void + **/ + + void settlementReview(TicketsSettlementVO vo); + + /** + * @Author 许 + * @Description 查询审批金额 + * @Date 14:20 2025/8/20 + * @Param [repairTicketsReqVO] + * @return cn.iocoder.yudao.module.tickets.vo.TicketsSettlementVO + **/ + + TicketsSettlementVO getSettlement(DlRepairTicketsReqVO repairTicketsReqVO); } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java index 4b29b4dd..729aa381 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java @@ -65,6 +65,7 @@ import cn.iocoder.yudao.module.tickets.utils.TicketsOperateUtil; import cn.iocoder.yudao.module.tickets.vo.*; import cn.iocoder.yudao.util.CreateQRCodeUtil; import cn.iocoder.yudao.util.SendSmsUtil; +import com.alibaba.fastjson.JSON; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; @@ -97,6 +98,7 @@ import java.util.stream.Collectors; import static cn.iocoder.yudao.common.BaseConstants.ORDER_TENANT_NAME; import static cn.iocoder.yudao.common.RepairCons.*; +import static cn.iocoder.yudao.common.RepairDictConstants.BASE_BUSINESS_CONFIG; import static cn.iocoder.yudao.common.RepairDictConstants.REPAIR_WORK_TYPE; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; @@ -389,7 +391,14 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl getTicketsPage(DlRepairTicketsReqVO repairTicketsReqVO, Page page) { - return baseMapper.getTicketsPage(repairTicketsReqVO, page); + IPage ticketsPage = baseMapper.getTicketsPage(repairTicketsReqVO, page); + ticketsPage.getRecords().forEach(item -> { + if (ObjectUtil.isNotEmpty(item.getSettlementStr())) { + // 将json字符串转换成对象 + item.setSettlement(JSON.parseObject(item.getSettlementStr(), TicketsSettlementVO.class)); + } + }); + return ticketsPage; } /** @@ -685,7 +694,6 @@ public class DlRepairTicketsServiceImpl extends ServiceImpllambdaQuery() + .eq(RepairRecords::getTicketId, repairTicketsRespVO.getId()) + .eq(RepairRecords::getType, RecordTypeEnum.JSSP) + .orderByDesc(RepairRecords::getCreateTime) + .last("limit 1")); + + // 提取冗余字段 + String otherData = record.getOtherData(); + // 将json 转为对象 + TicketsSettlementVO approvalVO = JSON.parseObject(otherData, TicketsSettlementVO.class); + + // 设置订单金额信息 + repairOrderInfo.setPayMoney(approvalVO.getActualMoney()); + repairOrderInfo.setGoodsPrice(approvalVO.getMoney()); + + //判断优惠类型 + if (approvalVO.getDiscountType().equals("1")) { + repairOrderInfo.setReduceMoney(BigDecimal.valueOf(approvalVO.getDiscount())); + } else if (approvalVO.getDiscountType().equals("2")) { + // 折扣计算 + repairOrderInfo.setReduceMoney(repairOrderInfo.getGoodsPrice().multiply(BigDecimal.valueOf(approvalVO.getDiscount() / 10))); + } + // 设置订单支付时间和支付结果 repairOrderInfo.setPayTime(LocalDateTime.now()); repairOrderInfo.setOrderStatus("1"); - } +// } // 更新工单 baseMapper.updateById(repairTicketsRespVO); //更新订单 repairOrderInfoService.updateById(repairOrderInfo); // 记录日志 - repairRecordsService.saveRepairRecord(one.getGoodsId(), null, RecordTypeEnum.JS.getCode(), "线下支付结算", null); + repairRecordsService.saveRepairRecord(one.getGoodsId(), null, RecordTypeEnum.SK.getCode(), "线下支付结算", null); // 更新工单主表时间 refreshUpdateTime(repairTicketsRespVO.getId()); } + /** + * @return void + * @Author 许 + * @Description 结算申请 + * @Date 10:13 2025/8/20 + * @Param [repairTicketsRespVO] + **/ + public void setTicketsSettlement(TicketsSettlementVO vo) { + /*添加结算数据*/ + // 将vo转为json + String json = JSON.toJSONString(vo); + + //添加维修记录 + repairRecordsService.saveRepairRecord(vo.getTicketId(), null, RecordTypeEnum.JSSQ.getCode(), "结算申请", null, json); + + /*获取字典 判断是否自动审核通过该结算申请*/ + DictDataRespDTO repairSettlementReview = dictDataApi.getDictData(BASE_BUSINESS_CONFIG, "repair_settlement_review"); + boolean ifReview = false; + if (ObjectUtil.isNotEmpty(repairSettlementReview)) { + ifReview = repairSettlementReview.getRemark().equals("1"); + } + + // 如果是自动审核直接修改支付状态 + if (ifReview) { + //添加维修记录 + repairRecordsService.saveRepairRecord(vo.getTicketId(), null, RecordTypeEnum.JSSP.getCode(), "自动结算审批", null, json); + + // 修改工单支付状态为待收款 + update(Wrappers.lambdaUpdate() + .eq(DlRepairTickets::getId, vo.getTicketId()) + .set(DlRepairTickets::getPayStatus, "02")); + // 修改工单支付状态为待收款 + update(Wrappers.lambdaUpdate() + .eq(DlRepairTickets::getId, vo.getTicketId()) + .set(DlRepairTickets::getPayStatus, "02")); + } + } + + /** + * @return void + * @Author 许 + * @Description 结算审批 + * @Date 13:41 2025/8/20 + * @Param [vo] + */ + @Override + public void settlementReview(TicketsSettlementVO vo) { + /*添加结算审核记录*/ + // 将vo转为json + String json = JSON.toJSONString(vo); + + //添加维修记录 + repairRecordsService.saveRepairRecord(vo.getTicketId(), null, RecordTypeEnum.JSSP.getCode(), "结算审批", null, json); + + // 修改工单支付状态为待收款 + update(Wrappers.lambdaUpdate() + .eq(DlRepairTickets::getId, vo.getTicketId()) + .set(DlRepairTickets::getPayStatus, "02")); + } + + /** + * @return cn.iocoder.yudao.module.tickets.vo.TicketsSettlementVO + * @Author 许 + * @Description 查询审批金额 + * @Date 14:20 2025/8/20 + * @Param [repairTicketsReqVO] + */ + @Override + public TicketsSettlementVO getSettlement(DlRepairTicketsReqVO repairTicketsReqVO) { + // 根据工单id 查询工单记录中的审批记录 + RepairRecords record = repairRecordsService.getOne(Wrappers.lambdaQuery() + .eq(RepairRecords::getTicketId, repairTicketsReqVO.getId()) + .eq(RepairRecords::getType, RecordTypeEnum.JSSP) + .orderByDesc(RepairRecords::getCreateTime) + .last("limit 1")); + + // 提取冗余字段 + if (record == null) + return null; + String otherData = record.getOtherData(); + // 将json 转为对象 + TicketsSettlementVO approvalVO = JSON.parseObject(otherData, TicketsSettlementVO.class); + return approvalVO; + } + /** * 客户信息和车辆信息 新增、修改 * @param customerAndCarVO 用户信息和车辆信息 diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/TicketsSettlementVO.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/TicketsSettlementVO.java new file mode 100644 index 00000000..be58cfbe --- /dev/null +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/TicketsSettlementVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.tickets.vo; + +import lombok.Data; + +import java.math.BigDecimal; + +/** + * @BelongsProject: lanan-system + * @BelongsPackage: cn.iocoder.yudao.module.tickets.vo + * @Author: 许 + * @CreateTime: 2025-08-20 12:47 + * @Description: TODO + * @Version: 1.0 + */ +@Data +public class TicketsSettlementVO { + /** + * 工单ID + */ + private String ticketId; + /** + * 实际金额 + */ + private BigDecimal actualMoney; + + /** + * 金额 + */ + private BigDecimal money; + + /** + * 优惠类型 + */ + private String discountType; + + /** + * 优惠金额|折扣 + */ + private Integer discount; +} diff --git a/dl-module-repair/src/main/resources/mapper/tickets/DlRepairTicketsMapper.xml b/dl-module-repair/src/main/resources/mapper/tickets/DlRepairTicketsMapper.xml index a761c29c..b1cdcc1a 100644 --- a/dl-module-repair/src/main/resources/mapper/tickets/DlRepairTicketsMapper.xml +++ b/dl-module-repair/src/main/resources/mapper/tickets/DlRepairTicketsMapper.xml @@ -60,6 +60,8 @@ + + @@ -191,19 +193,31 @@ SELECT * FROM dl_repair_booking WHERE tickets_id = #{id} From 6e3997af97cb5d7fd81afe1024c1bf725f8131c0 Mon Sep 17 00:00:00 2001 From: xyc <3422692813@qq.com> Date: Fri, 22 Aug 2025 11:09:11 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E6=9B=B4=E6=96=B00822?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapper/staff/CompanyStaffMapper.xml | 4 + .../admin/RepairStaffController.java | 25 +++++ .../yudao/module/base/entity/RepairStaff.java | 10 ++ .../module/base/entity/RepairStaffSaveVo.java | 1 + .../base/service/RepairStaffService.java | 18 ++++ .../service/impl/RepairStaffServiceImpl.java | 95 +++++++++++++++++++ .../module/system/api/user/dto/UserDTO.java | 13 +++ 7 files changed, 166 insertions(+) diff --git a/dl-module-company/src/main/resources/mapper/staff/CompanyStaffMapper.xml b/dl-module-company/src/main/resources/mapper/staff/CompanyStaffMapper.xml index 9dfdb225..8367b096 100644 --- a/dl-module-company/src/main/resources/mapper/staff/CompanyStaffMapper.xml +++ b/dl-module-company/src/main/resources/mapper/staff/CompanyStaffMapper.xml @@ -132,6 +132,10 @@ su.status, su.avatar AS avatar, dsc.folder_id AS folderId, + dsc.safe_date AS safeDate, + dsc.formal_date AS formalDate, + dsc.address AS address, + dsc.id_number AS idNumber, GROUP_CONCAT(DISTINCT sr2.name SEPARATOR ',') AS roleNames FROM system_users su diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/controller/admin/RepairStaffController.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/controller/admin/RepairStaffController.java index 35455714..3d19710c 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/controller/admin/RepairStaffController.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/controller/admin/RepairStaffController.java @@ -90,6 +90,31 @@ public class RepairStaffController { return CommonResult.ok(); } + /** + * 新增员工 + * + * @param repairStaff 员工信息 + * @return + */ + @PostMapping("/insert") + public CommonResult insert(@RequestBody RepairStaffSaveVo repairStaff) { + repairStaffService.insert(repairStaff); + return CommonResult.ok(); + } + + /** + * @Author 许 + * @Description 更新员工 + * @Date 10:38 2025/8/21 + * @Param [repairStaff] + * @return cn.iocoder.yudao.framework.common.pojo.CommonResult + **/ + @PostMapping("/updateStaff") + public CommonResult updateStaff(@RequestBody RepairStaffSaveVo repairStaff) { + repairStaffService.updateStaff(repairStaff); + return CommonResult.ok(); + } + @GetMapping("/listSelectUser") public CommonResult listSelectUser(@Valid UserPageReqVO pageReqVO) { // 查询目前所有的userId diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/entity/RepairStaff.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/entity/RepairStaff.java index e262a904..d30c223d 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/entity/RepairStaff.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/entity/RepairStaff.java @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.system.api.user.dto.UserDTO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; import lombok.Data; +import java.util.Date; import java.util.List; @Data @@ -60,4 +61,13 @@ public class RepairStaff { * 文件夹id */ private String folderId; + + /** 家庭住址 */ + private String address; + + private String IdNumber; + + private Date safeDate; + + private Date formalDate; } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/entity/RepairStaffSaveVo.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/entity/RepairStaffSaveVo.java index b689d532..352d6616 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/entity/RepairStaffSaveVo.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/entity/RepairStaffSaveVo.java @@ -14,6 +14,7 @@ public class RepairStaffSaveVo { * 选择的员工 */ public List repairStaffs; + public UserDTO repairStaff; /** * 角色id */ diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/RepairStaffService.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/RepairStaffService.java index 7b30bfe3..e2303dab 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/RepairStaffService.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/RepairStaffService.java @@ -40,4 +40,22 @@ public interface RepairStaffService { * @date: 2025/8/11 13:22 */ UserDTO getStaff(Long id); + + /** + * @Author 许 + * @Description 新增员工 + * @Date 16:17 2025/8/20 + * @Param [repairStaff] + * @return void + **/ + void insert(RepairStaffSaveVo repairStaff); + + /** + * @Author 许 + * @Description + * @Date 10:44 2025/8/21 + * @Param [repairStaff] + * @return void + **/ + void updateStaff(RepairStaffSaveVo repairStaff); } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairStaffServiceImpl.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairStaffServiceImpl.java index ff3005ef..936bdc43 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairStaffServiceImpl.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairStaffServiceImpl.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.base.service.impl; +import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.common.CommonErrorCodeConstants; @@ -154,6 +155,100 @@ public class RepairStaffServiceImpl implements RepairStaffService { return companyStaffService.getStaff(id); } + /** + * @return void + * @Author 许 + * @Description 新增员工 + * @Date 16:17 2025/8/20 + * @Param [repairStaff] + */ + @Override + public void insert(RepairStaffSaveVo repairStaff) { + // 获取当前登录用户的详细信息 + AdminUserRespDTO loginUser = getLoginUser(); + + // 判断用户是否存在 + AdminUserRespDTO checkUserName = adminUserApi.getUserByUsername(repairStaff.getRepairStaffs().get(0).getUsername()); + + if (ObjectUtil.isEmpty(checkUserName)) { + // 新增 + Long user = adminUserApi.createUser(repairStaff.getRepairStaffs().get(0)); + repairStaff.getRepairStaffs().get(0).setId(user); + } + + // 1. 分配角色 + repairStaff.getRepairStaffs().forEach(item -> { + permissionService.assignUserRoleByServicePackageId(item.getId(), repairStaff.getRoleIds(), SystemEnum.REPAIR.getCode()); + }); + // 2. 查看员工表中是否存在 + List oldIds = repairStaff.getRepairStaffs().stream().map(UserDTO::getId).collect(Collectors.toList()); + List staffList = companyStaffService.list(Wrappers.lambdaQuery() + .in(CompanyStaff::getUserId, oldIds)); + + // 获取员工表中已有的用户ID集合 + Set existUserIds = staffList.stream() + .map(CompanyStaff::getUserId) + .collect(Collectors.toSet()); + + // 找出不存在于员工表中的用户ID + List notExistUsers = repairStaff.getRepairStaffs().stream() + .filter(user -> !existUserIds.contains(user.getId())) + .collect(Collectors.toList()); + + /* 插入员工库 */ + DeptRespDTO loginDept = getLoginDept(loginUser.getDeptId()); + + // 添加员工 + if (CollectionUtil.isNotEmpty(notExistUsers)) { + List companyStaffs = new ArrayList<>(); + for (UserDTO notExistUser : notExistUsers) { + CompanyStaff companyStaff = new CompanyStaff(); + BeanUtil.copyProperties(notExistUser, companyStaff); + companyStaff.setId(null); + companyStaff.setCreateTime(null); + companyStaff.setUpdateTime(null); + companyStaff.setCreator(null); + companyStaff.setUpdater(null); + + // 1 获取当前登录用户的企业信息给添加的员工 + // 2 生成唯一推广码 + String uniqueCode = uniqueCodeService.createUniqueCode(); + if (!ObjectUtil.isNotEmpty(uniqueCode)) { + throw exception(CommonErrorCodeConstants.UNIQUE_CODE_CREATE_REPEAT); + } + companyStaff.setCorpId(loginDept.getCorpId()); + companyStaff.setUserId(notExistUser.getId()); + companyStaff.setName(notExistUser.getNickname()); + companyStaff.setTel(notExistUser.getUsername()); + companyStaff.setUniqueCode(uniqueCode); + + companyStaffs.add(companyStaff); + } + companyStaffService.saveBatch(companyStaffs); + } + } + + /** + * @return void + * @Author 许 + * @Description + * @Date 10:44 2025/8/21 + * @Param [repairStaff] + */ + @Override + public void updateStaff(RepairStaffSaveVo repairStaff) { + UserDTO staff = repairStaff.getRepairStaff(); + CompanyStaff companyStaff = BeanUtil.copyProperties(staff, CompanyStaff.class); + companyStaff.setCreator(null); + companyStaff.setUpdater(null); + companyStaff.setUpdateTime(null); + companyStaff.setCreateTime(null); + companyStaff.setDeptId(null); + companyStaff.setId(null); + companyStaffService.update(companyStaff, Wrappers.lambdaUpdate() + .eq(CompanyStaff::getUserId, staff.getId())); + } + /** * 获取当前登录用户的部门详细信息 * diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/dto/UserDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/dto/UserDTO.java index 8cd045a1..91b31f66 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/dto/UserDTO.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/dto/UserDTO.java @@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.system.api.user.dto; import lombok.Data; +import java.util.Date; + @Data public class UserDTO { /** @@ -68,4 +70,15 @@ public class UserDTO { */ private String folderId; + + // ================== 员工字段 ================== + /** 家庭住址 */ + private String address; + + private String IdNumber; + + private Date safeDate; + + private Date formalDate; + } From 8691f9e94a3c704f0a0e218083c00f623cf3f098 Mon Sep 17 00:00:00 2001 From: xyc <3422692813@qq.com> Date: Tue, 26 Aug 2025 16:51:36 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E6=9B=B4=E6=96=B00826?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/RepairStatisticsController.java | 21 +- .../yudao/module/base/entity/RepairStaff.java | 7 +- .../base/mapper/RepairStatisticsMapper.java | 22 +++ .../base/service/RepairStatisticsService.java | 12 ++ .../impl/RepairStatisticsServiceImpl.java | 23 +++ .../module/base/vo/QueryBusinessReqVO.java | 30 +++ .../module/base/vo/QueryBusinessResp.java | 58 ++++++ .../tickets/entity/DlRepairTickets.java | 2 + .../impl/DlRepairTicketsServiceImpl.java | 181 +++++++++--------- .../mapper/base/RepairStatisticsMapper.xml | 109 +++++++++++ .../mapper/tickets/DlRepairTicketsMapper.xml | 7 + .../module/system/api/user/dto/UserDTO.java | 9 +- 12 files changed, 390 insertions(+), 91 deletions(-) create mode 100644 dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/vo/QueryBusinessReqVO.java create mode 100644 dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/vo/QueryBusinessResp.java diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/controller/admin/RepairStatisticsController.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/controller/admin/RepairStatisticsController.java index bedb10de..96d2fd52 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/controller/admin/RepairStatisticsController.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/controller/admin/RepairStatisticsController.java @@ -2,11 +2,15 @@ package cn.iocoder.yudao.module.base.controller.admin; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.base.service.RepairStatisticsService; +import cn.iocoder.yudao.module.base.vo.QueryBusinessReqVO; +import cn.iocoder.yudao.module.base.vo.QueryBusinessResp; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @@ -136,4 +140,19 @@ public class RepairStatisticsController { return CommonResult.success(statisticsService.listWorks()); } -} \ No newline at end of file + /** + * @Author 许 + * @Description 统计最近业务(车辆或客户) + * @Date 11:16 2025/8/22 + * @Param [reqVO] + * @return cn.iocoder.yudao.framework.common.pojo.CommonResult + **/ + @GetMapping("/listBusiness") + public CommonResult listBusinessByCustomerOrCar(QueryBusinessReqVO reqVO, + @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, + @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) { + Page page = new Page<>(pageNo, pageSize); + return CommonResult.success(statisticsService.listBusinessByCustomerOrCar(reqVO,page)); + } + +} diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/entity/RepairStaff.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/entity/RepairStaff.java index d30c223d..12f78890 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/entity/RepairStaff.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/entity/RepairStaff.java @@ -3,7 +3,10 @@ package cn.iocoder.yudao.module.base.entity; import cn.iocoder.yudao.module.system.api.user.dto.UserDTO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; +import com.alibaba.fastjson.annotation.JSONField; +import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; import java.util.Date; import java.util.List; @@ -65,9 +68,11 @@ public class RepairStaff { /** 家庭住址 */ private String address; - private String IdNumber; + private String idNumber; + @JsonFormat(pattern = "yyyy-MM-dd") private Date safeDate; + @JsonFormat(pattern = "yyyy-MM-dd") private Date formalDate; } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/mapper/RepairStatisticsMapper.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/mapper/RepairStatisticsMapper.java index bd4e7cbb..4eea9f9e 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/mapper/RepairStatisticsMapper.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/mapper/RepairStatisticsMapper.java @@ -1,9 +1,14 @@ package cn.iocoder.yudao.module.base.mapper; +import cn.iocoder.yudao.module.base.vo.QueryBusinessReqVO; +import cn.iocoder.yudao.module.base.vo.QueryBusinessResp; import cn.iocoder.yudao.module.base.vo.RepairStatisticsVO; import cn.iocoder.yudao.module.base.vo.RepairTicketStatisticsVO; import cn.iocoder.yudao.module.tickets.vo.DlRepairTicketsRespVO; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; import java.util.List; @@ -96,4 +101,21 @@ public interface RepairStatisticsMapper { **/ List listWorks(); + /** + * @Author 许 + * @Description 统计最近业务 + * @Date 11:24 2025/8/22 + * @Param [reqVO] + * @return java.util.List + **/ + IPage listBusinessByCustomer(@Param("reqVO") QueryBusinessReqVO reqVO,@Param("page") Page page); + + /** + * @Author 许 + * @Description 统计最近业务 + * @Date 11:24 2025/8/22 + * @Param [reqVO] + * @return java.util.List + **/ + IPage listBusinessByCar(@Param("reqVO") QueryBusinessReqVO reqVO,@Param("page") Page page); } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/RepairStatisticsService.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/RepairStatisticsService.java index dde50d36..8847875b 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/RepairStatisticsService.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/RepairStatisticsService.java @@ -1,8 +1,12 @@ package cn.iocoder.yudao.module.base.service; +import cn.iocoder.yudao.module.base.vo.QueryBusinessReqVO; +import cn.iocoder.yudao.module.base.vo.QueryBusinessResp; import cn.iocoder.yudao.module.base.vo.RepairStatisticsVO; import cn.iocoder.yudao.module.base.vo.RepairTicketStatisticsVO; import cn.iocoder.yudao.module.tickets.vo.DlRepairTicketsRespVO; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import java.util.List; import java.util.Map; @@ -82,4 +86,12 @@ public interface RepairStatisticsService { List listWorks(); + /** + * @Author 许 + * @Description 统计最近业务(车辆或客户) + * @Date 15:04 2025/8/25 + * @Param [reqVO, page] + * @return com.baomidou.mybatisplus.core.metadata.IPage + **/ + IPage listBusinessByCustomerOrCar(QueryBusinessReqVO reqVO, Page page); } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairStatisticsServiceImpl.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairStatisticsServiceImpl.java index 816ecd96..46302482 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairStatisticsServiceImpl.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/service/impl/RepairStatisticsServiceImpl.java @@ -2,13 +2,18 @@ package cn.iocoder.yudao.module.base.service.impl; import cn.iocoder.yudao.module.base.mapper.RepairStatisticsMapper; import cn.iocoder.yudao.module.base.service.RepairStatisticsService; +import cn.iocoder.yudao.module.base.vo.QueryBusinessReqVO; +import cn.iocoder.yudao.module.base.vo.QueryBusinessResp; import cn.iocoder.yudao.module.base.vo.RepairStatisticsVO; import cn.iocoder.yudao.module.base.vo.RepairTicketStatisticsVO; import cn.iocoder.yudao.module.tickets.vo.DlRepairTicketsRespVO; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -128,4 +133,22 @@ public class RepairStatisticsServiceImpl implements RepairStatisticsService { public List listWorks() { return statisticsMapper.listWorks(); } + + /** + * @Author 许 + * @Description 统计最近业务(车辆或客户) + * @Date 15:03 2025/8/25 + * @Param [reqVO, page] + * @return com.baomidou.mybatisplus.core.metadata.IPage + **/ + @Override + public IPage listBusinessByCustomerOrCar(QueryBusinessReqVO reqVO, Page page) { + IPage queryBusinessResps = null; + if ("customer".equals(reqVO.getType())) { + queryBusinessResps = statisticsMapper.listBusinessByCustomer(reqVO,page); + }else if ("car".equals(reqVO.getType())) { + queryBusinessResps = statisticsMapper.listBusinessByCar(reqVO,page); + } + return queryBusinessResps; + } } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/vo/QueryBusinessReqVO.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/vo/QueryBusinessReqVO.java new file mode 100644 index 00000000..5f2de25b --- /dev/null +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/vo/QueryBusinessReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.base.vo; + +import lombok.Data; + +/** + *@BelongsProject: lanan-system + *@BelongsPackage: cn.iocoder.yudao.module.base.vo + *@Author: 许 + *@CreateTime: 2025-08-22 11:14 + *@Description: 业务统计请求参数 + *@Version: 1.0 + */ +@Data +public class QueryBusinessReqVO { + + /** + * 时间范围 + */ + private String[] dateRange; + + /** + * 类型 car: 车辆 customer: 客户 + */ + private String type; + + /** + * 搜索 + */ + private String search; +} diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/vo/QueryBusinessResp.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/vo/QueryBusinessResp.java new file mode 100644 index 00000000..2aa46cac --- /dev/null +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/base/vo/QueryBusinessResp.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.base.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.util.Date; + +/** + *@BelongsProject: lanan-system + *@BelongsPackage: cn.iocoder.yudao.module.base.vo + *@Author: 许 + *@CreateTime: 2025-08-22 14:04 + *@Description: TODO + *@Version: 1.0 + */ +@Data +public class QueryBusinessResp { + /** + * 客户id + */ + private String customerId; + + /** + * 客户名称 + */ + private String customerName; + + /** + * 客户手机号 + */ + private String customerPhone; + + /** + * 业务id + */ + private String bizId; + + /** + * 业务编号 + */ + private String bizNo; + + /** + * 业务时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date bizTime; + + /** + * 业务来源 + */ + private String source; + + /** + * 车牌号 + */ + private String carNum; +} diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTickets.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTickets.java index 72b11781..fd2d8a03 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTickets.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/entity/DlRepairTickets.java @@ -266,4 +266,6 @@ public class DlRepairTickets extends TenantBaseDO { private String settlementStr; @TableField(exist = false) private TicketsSettlementVO settlement; + @TableField(exist = false) + private boolean ifShow = false; } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java index 729aa381..f192db10 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java @@ -579,118 +579,123 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl typeMap = recordTypeList.stream().collect(Collectors.toMap(DictDataRespDTO::getValue, DictDataRespDTO::getLabel)); result.setRecords(records.stream().peek(item -> item.setType(typeMap.get(item.getType()))).collect(Collectors.toList())); - //查询维修工人表 - List workers = repairWorkerService.listByTicketId(id); - //转成map - Map workerMap = workers.stream().collect(Collectors.toMap(RepairWorker::getUserId, item -> item)); + + if (!ifApp) { + //查询维修工人表 + List workers = repairWorkerService.listByTicketId(id); + //转成map + Map workerMap = workers.stream().collect(Collectors.toMap(RepairWorker::getUserId, item -> item)); - //配件总利润 - BigDecimal waresProfit = BigDecimal.ZERO; - List resultList = new ArrayList<>(); + //配件总利润 + BigDecimal waresProfit = BigDecimal.ZERO; + List resultList = new ArrayList<>(); - if (CollectionUtil.isNotEmpty(items)) { - for (DlRepairTitemReqVO item : items) { - BigDecimal itemProfit = item.getItemProfit() != null ? item.getItemProfit() : BigDecimal.ZERO; - waresProfit = waresProfit.add(itemProfit); - BigDecimal itemMoney = item.getItemMoney() != null ? item.getItemMoney() : BigDecimal.ZERO; - // 成本 = 售价 - 利润(也可以直接从 item.getItemCost() 取,如果有字段) - BigDecimal itemCost = itemMoney.subtract(itemProfit); + if (CollectionUtil.isNotEmpty(items)) { + for (DlRepairTitemReqVO item : items) { + BigDecimal itemProfit = item.getItemProfit() != null ? item.getItemProfit() : BigDecimal.ZERO; + waresProfit = waresProfit.add(itemProfit); + BigDecimal itemMoney = item.getItemMoney() != null ? item.getItemMoney() : BigDecimal.ZERO; + // 成本 = 售价 - 利润(也可以直接从 item.getItemCost() 取,如果有字段) + BigDecimal itemCost = itemMoney.subtract(itemProfit); - if (StringUtils.isNotEmpty(item.getRepairIds())) { if (StringUtils.isNotEmpty(item.getRepairIds())) { - String[] repairIdArr = item.getRepairIds().split(","); - for (String repairIdStr : repairIdArr) { - if (StringUtils.isNotEmpty(repairIdStr)) { - RepairWorker repairWorker = workerMap.get(Long.valueOf(repairIdStr)); - if (repairWorker != null) { - String jobType = repairWorker.getWorkType(); + if (StringUtils.isNotEmpty(item.getRepairIds())) { + String[] repairIdArr = item.getRepairIds().split(","); + for (String repairIdStr : repairIdArr) { + if (StringUtils.isNotEmpty(repairIdStr)) { + RepairWorker repairWorker = workerMap.get(Long.valueOf(repairIdStr)); + if (repairWorker != null) { + String jobType = repairWorker.getWorkType(); + if (jobType == null) { + } - JobTypeProfitDTO dto = resultList.stream() - .filter(r -> r.getJobTypeCode().equals(jobType)) - .findFirst() - .orElseGet(() -> { - JobTypeProfitDTO newDto = new JobTypeProfitDTO(); - newDto.setJobTypeCode(jobType); - newDto.setJobTypeName(dictDataApi.getDictDataLabel(REPAIR_WORK_TYPE, jobType)); - newDto.setProfit(BigDecimal.ZERO); - newDto.setMoney(BigDecimal.ZERO); - newDto.setWorkMoney(BigDecimal.ZERO); - newDto.setCost(BigDecimal.ZERO); // 新增成本字段 - resultList.add(newDto); - return newDto; - }); + JobTypeProfitDTO dto = resultList.stream() + .filter(r -> r.getJobTypeCode().equals(jobType)) + .findFirst() + .orElseGet(() -> { + JobTypeProfitDTO newDto = new JobTypeProfitDTO(); + newDto.setJobTypeCode(jobType); + newDto.setJobTypeName(dictDataApi.getDictDataLabel(REPAIR_WORK_TYPE, jobType)); + newDto.setProfit(BigDecimal.ZERO); + newDto.setMoney(BigDecimal.ZERO); + newDto.setWorkMoney(BigDecimal.ZERO); + newDto.setCost(BigDecimal.ZERO); // 新增成本字段 + resultList.add(newDto); + return newDto; + }); - if ("02".equals(item.getItemType())) { // 配件 - // 多人平摊利润/金额/成本 - int numWorkers = repairIdArr.length; - BigDecimal profitPerWorker = itemProfit.divide(BigDecimal.valueOf(numWorkers), 4, RoundingMode.HALF_UP); - BigDecimal moneyPerWorker = itemMoney.divide(BigDecimal.valueOf(numWorkers), 4, RoundingMode.HALF_UP); - BigDecimal costPerWorker = itemCost.divide(BigDecimal.valueOf(numWorkers), 4, RoundingMode.HALF_UP); + if ("02".equals(item.getItemType())) { // 配件 + // 多人平摊利润/金额/成本 + int numWorkers = repairIdArr.length; + BigDecimal profitPerWorker = itemProfit.divide(BigDecimal.valueOf(numWorkers), 4, RoundingMode.HALF_UP); + BigDecimal moneyPerWorker = itemMoney.divide(BigDecimal.valueOf(numWorkers), 4, RoundingMode.HALF_UP); + BigDecimal costPerWorker = itemCost.divide(BigDecimal.valueOf(numWorkers), 4, RoundingMode.HALF_UP); - dto.setProfit(dto.getProfit().add(profitPerWorker)); - dto.setMoney(dto.getMoney().add(moneyPerWorker)); - dto.setCost(dto.getCost().add(costPerWorker)); - } else if ("01".equals(item.getItemType())) { // 工时 - dto.setWorkMoney(dto.getWorkMoney().add(itemMoney)); + dto.setProfit(dto.getProfit().add(profitPerWorker)); + dto.setMoney(dto.getMoney().add(moneyPerWorker)); + dto.setCost(dto.getCost().add(costPerWorker)); + } else if ("01".equals(item.getItemType())) { // 工时 + dto.setWorkMoney(dto.getWorkMoney().add(itemMoney)); + } } } } } + } } - - } - } - - // ====== 计算分组毛利率 ====== - for (JobTypeProfitDTO dto : resultList) { - BigDecimal partsProfit = dto.getProfit(); // 配件利润 - BigDecimal partsMoney = dto.getMoney(); // 配件售价 - BigDecimal workMoney = dto.getWorkMoney(); // 工时售价 - - // 不含工时 - BigDecimal profitRateWithoutWork = BigDecimal.ZERO; - if (partsMoney.compareTo(BigDecimal.ZERO) > 0) { - profitRateWithoutWork = partsProfit.divide(partsMoney, 4, RoundingMode.HALF_UP); } - // 含工时 - BigDecimal profitRateWithWork = BigDecimal.ZERO; - BigDecimal totalMoney = partsMoney.add(workMoney); - if (totalMoney.compareTo(BigDecimal.ZERO) > 0) { - profitRateWithWork = partsProfit.divide(totalMoney, 4, RoundingMode.HALF_UP); + // ====== 计算分组毛利率 ====== + for (JobTypeProfitDTO dto : resultList) { + BigDecimal partsProfit = dto.getProfit(); // 配件利润 + BigDecimal partsMoney = dto.getMoney(); // 配件售价 + BigDecimal workMoney = dto.getWorkMoney(); // 工时售价 + + // 不含工时 + BigDecimal profitRateWithoutWork = BigDecimal.ZERO; + if (partsMoney.compareTo(BigDecimal.ZERO) > 0) { + profitRateWithoutWork = partsProfit.divide(partsMoney, 4, RoundingMode.HALF_UP); + } + + // 含工时 + BigDecimal profitRateWithWork = BigDecimal.ZERO; + BigDecimal totalMoney = partsMoney.add(workMoney); + if (totalMoney.compareTo(BigDecimal.ZERO) > 0) { + profitRateWithWork = partsProfit.divide(totalMoney, 4, RoundingMode.HALF_UP); + } + + dto.setProfitRateWithoutWork(profitRateWithoutWork); + dto.setProfitRateWithWork(profitRateWithWork); } - dto.setProfitRateWithoutWork(profitRateWithoutWork); - dto.setProfitRateWithWork(profitRateWithWork); - } + + // 最终返回 list + result.setGroupByJobType(resultList); - // 最终返回 list - result.setGroupByJobType(resultList); + //计算含工时项目毛利率 + //配件总利润除以工单总价 + BigDecimal profitRate = new BigDecimal(0); + if (ObjectUtil.isNotEmpty(dlRepairTickets.getTotalPrice())) { + if (dlRepairTickets.getTotalPrice().compareTo(BigDecimal.ZERO) != 0) { + profitRate = waresProfit.divide(dlRepairTickets.getTotalPrice(), 2, RoundingMode.HALF_UP); + } + result.setProfitRate(profitRate); - - //计算含工时项目毛利率 - //配件总利润除以工单总价 - BigDecimal profitRate = new BigDecimal(0); - if (ObjectUtil.isNotEmpty(dlRepairTickets.getTotalPrice())) { - if (dlRepairTickets.getTotalPrice().compareTo(BigDecimal.ZERO) != 0) { - profitRate = waresProfit.divide(dlRepairTickets.getTotalPrice(), 2, RoundingMode.HALF_UP); + // 工单成本 售价 - 利润 + result.setCost(dlRepairTickets.getTotalPrice().subtract(waresProfit)); } - result.setProfitRate(profitRate); - - // 工单成本 售价 - 利润 - result.setCost(dlRepairTickets.getTotalPrice().subtract(waresProfit)); - } - //计算不含工时项目毛利率 - if (ObjectUtil.isNotEmpty(dlRepairTickets.getPartPrice())) { - BigDecimal profitRateNo = new BigDecimal(0); - if (dlRepairTickets.getPartPrice().compareTo(BigDecimal.ZERO) != 0) { - profitRateNo = waresProfit.divide(dlRepairTickets.getPartPrice(), 2, RoundingMode.HALF_UP); + //计算不含工时项目毛利率 + if (ObjectUtil.isNotEmpty(dlRepairTickets.getPartPrice())) { + BigDecimal profitRateNo = new BigDecimal(0); + if (dlRepairTickets.getPartPrice().compareTo(BigDecimal.ZERO) != 0) { + profitRateNo = waresProfit.divide(dlRepairTickets.getPartPrice(), 2, RoundingMode.HALF_UP); + } + result.setProfitRateNo(profitRateNo); } - result.setProfitRateNo(profitRateNo); } diff --git a/dl-module-repair/src/main/resources/mapper/base/RepairStatisticsMapper.xml b/dl-module-repair/src/main/resources/mapper/base/RepairStatisticsMapper.xml index 287db120..36cdd0f3 100644 --- a/dl-module-repair/src/main/resources/mapper/base/RepairStatisticsMapper.xml +++ b/dl-module-repair/src/main/resources/mapper/base/RepairStatisticsMapper.xml @@ -123,4 +123,113 @@ GROUP BY drw.user_id,drr.ticket_id ORDER BY value DESC + + diff --git a/dl-module-repair/src/main/resources/mapper/tickets/DlRepairTicketsMapper.xml b/dl-module-repair/src/main/resources/mapper/tickets/DlRepairTicketsMapper.xml index b1cdcc1a..937ed74a 100644 --- a/dl-module-repair/src/main/resources/mapper/tickets/DlRepairTicketsMapper.xml +++ b/dl-module-repair/src/main/resources/mapper/tickets/DlRepairTicketsMapper.xml @@ -266,6 +266,10 @@ -- 维修工需要关联操作记录,查没有总检记录的工单 -- left join dl_repair_records drr ON drt.id = drr.ticket_id AND drr.type='zj' + + -- 维修工需要关联操作记录,查没有总检记录的工单 -- + inner join dl_repair_records drr ON drt.id = drr.ticket_id AND drr.type='zj' + left join dl_repair_titem drti on drt.id = drti.ticket_id AND drti.deleted = '0' where (drt.deleted = '0') AND drt.tickets_status IN ('04','05','01','07','06','02') @@ -306,6 +310,9 @@ -- 在厂 -- AND drt.is_handover = '0' AND drt.tickets_status != '03' + + -- 已竣工 -- + diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/dto/UserDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/dto/UserDTO.java index 91b31f66..ae62ec3b 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/dto/UserDTO.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/user/dto/UserDTO.java @@ -1,6 +1,9 @@ package cn.iocoder.yudao.module.system.api.user.dto; +import com.alibaba.fastjson.annotation.JSONField; +import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; import java.util.Date; @@ -75,10 +78,14 @@ public class UserDTO { /** 家庭住址 */ private String address; - private String IdNumber; + private String idNumber; + @JSONField(format = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") private Date safeDate; + @JSONField(format = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") private Date formalDate; }