From 7b8b2456bb15aa733b8599fce2ada5d9549ba881 Mon Sep 17 00:00:00 2001
From: huminmin <mac@MacBook-Pro.local>
Date: 星期四, 11 六月 2026 13:21:20 +0800
Subject: [PATCH] 销售台账,工艺路线配置设置是否完成;导出工艺路线
---
src/main/java/com/ruoyi/sales/mapper/SalesLedgerProcessRouteRecordMapper.java | 10 +
src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java | 69 +++++++
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProcessRouteRecordServiceImpl.java | 15 +
src/main/java/com/ruoyi/sales/service/ISalesLedgerProcessRouteRecordService.java | 10 +
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java | 304 +++++++++++++++++++++++++++++++++
src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java | 11 +
doc/sales_ledger_process_route_record.sql | 17 +
src/main/java/com/ruoyi/sales/dto/SalesLedgerProcessRouteDto.java | 4
src/main/java/com/ruoyi/sales/pojo/SalesLedgerProcessRouteRecord.java | 57 ++++++
9 files changed, 488 insertions(+), 9 deletions(-)
diff --git a/doc/sales_ledger_process_route_record.sql b/doc/sales_ledger_process_route_record.sql
new file mode 100644
index 0000000..47fe7f7
--- /dev/null
+++ b/doc/sales_ledger_process_route_record.sql
@@ -0,0 +1,17 @@
+-- 閿�鍞彴璐﹀伐鑹鸿矾绾垮畬鎴愯褰曡〃
+CREATE TABLE IF NOT EXISTS `sales_ledger_process_route_record` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `sales_ledger_id` bigint NOT NULL COMMENT '閿�鍞彴璐D',
+ `sales_ledger_process_route_id` bigint NOT NULL COMMENT '閿�鍞彴璐﹀伐鑹鸿矾绾縄D',
+ `is_completed` int DEFAULT 0 COMMENT '鏄惁瀹屾垚(0-鍚�,1-鏄�)',
+ `completed_time` datetime DEFAULT NULL COMMENT '瀹屾垚鏃堕棿',
+ `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+ `tenant_id` bigint DEFAULT NULL COMMENT '绉熸埛ID',
+ PRIMARY KEY (`id`),
+ KEY `idx_slprr_sales_ledger_id` (`sales_ledger_id`),
+ KEY `idx_slprr_sales_ledger_process_route_id` (`sales_ledger_process_route_id`),
+ KEY `idx_slprr_completed_time` (`completed_time`),
+ CONSTRAINT `fk_slprr_sales_ledger_process_route_id`
+ FOREIGN KEY (`sales_ledger_process_route_id`) REFERENCES `sales_ledger_process_route` (`id`)
+ ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='閿�鍞彴璐﹀伐鑹鸿矾绾垮畬鎴愯褰�';
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java b/src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java
index f74c85c..8b374f5 100644
--- a/src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java
+++ b/src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java
@@ -23,9 +23,11 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
+import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -171,6 +173,20 @@
}
/**
+ * 瀵煎嚭鍞悗鍙拌处宸ヨ壓璺嚎
+ */
+ @Log(title = "閿�鍞彴璐﹀伐鑹鸿矾绾�", businessType = BusinessType.EXPORT)
+ @PostMapping("/exportProcessRoute")
+ @ApiOperation("瀵煎嚭鍞悗鍙拌处宸ヨ壓璺嚎")
+ public void exportProcessRoute(HttpServletResponse response,
+ HttpServletRequest request,
+ @RequestParam(value = "completedTimeStart", required = false) String completedTimeStart,
+ @RequestParam(value = "completedTimeEnd", required = false) String completedTimeEnd) {
+ List<Long> salesLedgerIds = parseSalesLedgerIds(request);
+ salesLedgerService.exportProcessRoute(response, salesLedgerIds, completedTimeStart, completedTimeEnd);
+ }
+
+ /**
* 瀵煎嚭寮�绁ㄧ櫥璁板垪琛�
*/
@Log(title = "瀵煎嚭寮�绁ㄧ櫥璁板垪琛�", businessType = BusinessType.EXPORT)
@@ -198,8 +214,8 @@
*/
@PostMapping("/saleProcessBind")
@ApiOperation("閿�鍞鍗曠粦瀹氬伐鑹鸿矾绾�")
- public AjaxResult saleProcessBind(@RequestBody SalesLedgerProcessRoute salesLedgerProcessRoute) {
- salesLedgerService.saleProcessBind(salesLedgerProcessRoute);
+ public AjaxResult saleProcessBind(@RequestBody SalesLedgerProcessRouteDto salesLedgerProcessRouteDto) {
+ salesLedgerService.saleProcessBind(salesLedgerProcessRouteDto);
return AjaxResult.success();
}
@@ -443,4 +459,53 @@
excelUtil.importTemplateExcel(response, "鏈嚭搴撳鍏ユā鏉夸笅杞�");
}
+ private List<Long> parseSalesLedgerIds(HttpServletRequest request) {
+ if (request == null) {
+ return Collections.emptyList();
+ }
+
+ List<Long> ids = new ArrayList<>();
+ Map<String, String[]> parameterMap = request.getParameterMap();
+ if (parameterMap == null || parameterMap.isEmpty()) {
+ return ids;
+ }
+
+ String directValue = request.getParameter("salesLedgerIds");
+ if (StringUtils.hasText(directValue)) {
+ for (String value : directValue.split(",")) {
+ addParsedLong(ids, value);
+ }
+ }
+
+ for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
+ String key = entry.getKey();
+ if (!StringUtils.hasText(key)) {
+ continue;
+ }
+ if (!"salesLedgerIds".equals(key) && !key.startsWith("salesLedgerIds[")) {
+ continue;
+ }
+ String[] values = entry.getValue();
+ if (values == null) {
+ continue;
+ }
+ for (String value : values) {
+ addParsedLong(ids, value);
+ }
+ }
+
+ return ids.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList());
+ }
+
+ private void addParsedLong(List<Long> target, String value) {
+ if (target == null || !StringUtils.hasText(value)) {
+ return;
+ }
+ try {
+ target.add(Long.valueOf(value.trim()));
+ } catch (Exception ignored) {
+ // ignore invalid id values
+ }
+ }
+
}
diff --git a/src/main/java/com/ruoyi/sales/dto/SalesLedgerProcessRouteDto.java b/src/main/java/com/ruoyi/sales/dto/SalesLedgerProcessRouteDto.java
index 37be557..c4566b4 100644
--- a/src/main/java/com/ruoyi/sales/dto/SalesLedgerProcessRouteDto.java
+++ b/src/main/java/com/ruoyi/sales/dto/SalesLedgerProcessRouteDto.java
@@ -1,6 +1,7 @@
package com.ruoyi.sales.dto;
import com.ruoyi.sales.pojo.SalesLedgerProcessRoute;
+import com.ruoyi.sales.pojo.SalesLedgerProcessRouteRecord;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -29,4 +30,7 @@
@ApiModelProperty("閿�鍞鍗曠粦瀹氱殑宸ヨ壓璺嚎")
List<SalesLedgerProcessRoute> list;
+ @ApiModelProperty("閿�鍞鍗曞伐搴忓畬鎴愯褰�")
+ List<SalesLedgerProcessRouteRecord> recordList;
+
}
diff --git a/src/main/java/com/ruoyi/sales/mapper/SalesLedgerProcessRouteRecordMapper.java b/src/main/java/com/ruoyi/sales/mapper/SalesLedgerProcessRouteRecordMapper.java
new file mode 100644
index 0000000..7a5e016
--- /dev/null
+++ b/src/main/java/com/ruoyi/sales/mapper/SalesLedgerProcessRouteRecordMapper.java
@@ -0,0 +1,10 @@
+package com.ruoyi.sales.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.sales.pojo.SalesLedgerProcessRouteRecord;
+
+/**
+ * 閿�鍞彴璐﹀伐鑹鸿矾绾垮畬鎴愯褰� Mapper
+ */
+public interface SalesLedgerProcessRouteRecordMapper extends BaseMapper<SalesLedgerProcessRouteRecord> {
+}
diff --git a/src/main/java/com/ruoyi/sales/pojo/SalesLedgerProcessRouteRecord.java b/src/main/java/com/ruoyi/sales/pojo/SalesLedgerProcessRouteRecord.java
new file mode 100644
index 0000000..c4ad88d
--- /dev/null
+++ b/src/main/java/com/ruoyi/sales/pojo/SalesLedgerProcessRouteRecord.java
@@ -0,0 +1,57 @@
+package com.ruoyi.sales.pojo;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 閿�鍞彴璐﹀伐鑹鸿矾绾垮畬鎴愯褰�
+ */
+@Data
+@TableName("sales_ledger_process_route_record")
+@ApiModel(value = "SalesLedgerProcessRouteRecord瀵硅薄", description = "閿�鍞彴璐﹀伐鑹鸿矾绾垮畬鎴愯褰�")
+public class SalesLedgerProcessRouteRecord implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @TableId(value = "id", type = IdType.AUTO)
+ @ApiModelProperty(value = "涓婚敭")
+ private Long id;
+
+ @ApiModelProperty(value = "閿�鍞彴璐D")
+ private Long salesLedgerId;
+
+ @ApiModelProperty(value = "閿�鍞彴璐﹀伐鑹鸿矾绾縄D")
+ private Long salesLedgerProcessRouteId;
+
+ @TableField(exist = false)
+ @ApiModelProperty(value = "宸ヨ壓璺嚎鑺傜偣ID")
+ private Long processRouteItemId;
+
+ @ApiModelProperty(value = "鏄惁瀹屾垚(0-鍚�,1-鏄�)")
+ private Integer isCompleted;
+
+ @ApiModelProperty(value = "瀹屾垚鏃堕棿")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime completedTime;
+
+ @TableField(fill = FieldFill.INSERT)
+ @ApiModelProperty(value = "鍒涘缓鏃堕棿")
+ private LocalDateTime createTime;
+
+ @TableField(fill = FieldFill.INSERT)
+ @ApiModelProperty(value = "绉熸埛ID")
+ private Long tenantId;
+}
diff --git a/src/main/java/com/ruoyi/sales/service/ISalesLedgerProcessRouteRecordService.java b/src/main/java/com/ruoyi/sales/service/ISalesLedgerProcessRouteRecordService.java
new file mode 100644
index 0000000..7264b56
--- /dev/null
+++ b/src/main/java/com/ruoyi/sales/service/ISalesLedgerProcessRouteRecordService.java
@@ -0,0 +1,10 @@
+package com.ruoyi.sales.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.sales.pojo.SalesLedgerProcessRouteRecord;
+
+/**
+ * 閿�鍞彴璐﹀伐鑹鸿矾绾垮畬鎴愯褰� Service
+ */
+public interface ISalesLedgerProcessRouteRecordService extends IService<SalesLedgerProcessRouteRecord> {
+}
diff --git a/src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java b/src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java
index bfa28aa..751856d 100644
--- a/src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java
+++ b/src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java
@@ -57,7 +57,7 @@
IPage<SalesLedgerDto> listSalesLedger(SalesLedgerDto salesLedgerDto, Page page);
- void saleProcessBind(SalesLedgerProcessRoute salesLedgerProcessRoute);
+ void saleProcessBind(SalesLedgerProcessRouteDto salesLedgerProcessRouteDto);
SalesProcessCardDto processCard(Long salesLedgerId);
@@ -126,4 +126,13 @@
* @param salesLedgerDto 鏌ヨ鏉′欢
*/
void exportWithProducts(HttpServletResponse response, SalesLedgerDto salesLedgerDto);
+
+ /**
+ * 瀵煎嚭鍞悗鍙拌处宸ヨ壓璺嚎
+ * @param response HttpServletResponse
+ * @param salesLedgerIds 閿�鍞彴璐D鍒楄〃
+ * @param completedTimeStart 瀹屾垚鏃堕棿寮�濮�
+ * @param completedTimeEnd 瀹屾垚鏃堕棿缁撴潫
+ */
+ void exportProcessRoute(HttpServletResponse response, List<Long> salesLedgerIds, String completedTimeStart, String completedTimeEnd);
}
diff --git a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProcessRouteRecordServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProcessRouteRecordServiceImpl.java
new file mode 100644
index 0000000..e0ea01f
--- /dev/null
+++ b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProcessRouteRecordServiceImpl.java
@@ -0,0 +1,15 @@
+package com.ruoyi.sales.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.sales.mapper.SalesLedgerProcessRouteRecordMapper;
+import com.ruoyi.sales.pojo.SalesLedgerProcessRouteRecord;
+import com.ruoyi.sales.service.ISalesLedgerProcessRouteRecordService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 閿�鍞彴璐﹀伐鑹鸿矾绾垮畬鎴愯褰� Service 瀹炵幇
+ */
+@Service
+public class SalesLedgerProcessRouteRecordServiceImpl extends ServiceImpl<SalesLedgerProcessRouteRecordMapper, SalesLedgerProcessRouteRecord>
+ implements ISalesLedgerProcessRouteRecordService {
+}
diff --git a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
index e209855..7fdb825 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -53,6 +53,7 @@
import com.ruoyi.sales.mapper.*;
import com.ruoyi.sales.pojo.*;
import com.ruoyi.sales.service.ISalesLedgerProcessRouteService;
+import com.ruoyi.sales.service.ISalesLedgerProcessRouteRecordService;
import com.ruoyi.sales.service.ISalesLedgerProductProcessBindService;
import com.ruoyi.sales.service.ISalesLedgerProductProcessService;
import com.ruoyi.sales.service.ISalesLedgerService;
@@ -152,6 +153,7 @@
private final ISalesLedgerProductProcessBindService salesLedgerProductProcessBindService;
private final ISalesLedgerProcessRouteService salesLedgerProcessRouteService;
+ private final ISalesLedgerProcessRouteRecordService salesLedgerProcessRouteRecordService;
private final StockInventoryService stockInventoryService;
private final StockInRecordMapper stockInRecordMapper;
@@ -754,21 +756,22 @@
@Override
@Transactional(rollbackFor = Exception.class)
- public void saleProcessBind(SalesLedgerProcessRoute salesLedgerProcessRoute) {
- if (salesLedgerProcessRoute == null) {
+ public void saleProcessBind(SalesLedgerProcessRouteDto salesLedgerProcessRouteDto) {
+ if (salesLedgerProcessRouteDto == null) {
throw new ServiceException("缁戝畾澶辫触,鏁版嵁涓嶈兘涓虹┖");
}
- SalesLedger salesLedger = baseMapper.selectById(salesLedgerProcessRoute.getSalesLedgerId());
+ SalesLedger salesLedger = baseMapper.selectById(salesLedgerProcessRouteDto.getSalesLedgerId());
if (salesLedger == null) {
throw new ServiceException("缁戝畾澶辫触,閿�鍞鍗曚笉瀛樺湪");
}
- ProcessRoute processRoute = processRouteMapper.selectById(salesLedgerProcessRoute.getProcessRouteId());
+ ProcessRoute processRoute = processRouteMapper.selectById(salesLedgerProcessRouteDto.getProcessRouteId());
if (processRoute == null) {
throw new ServiceException("缁戝畾澶辫触,宸ヨ壓璺嚎涓嶅瓨鍦�");
}
// 娓呴櫎宸茬粦瀹氱殑鏁版嵁
salesLedgerProcessRouteService.remove(new LambdaQueryWrapper<SalesLedgerProcessRoute>().eq(SalesLedgerProcessRoute::getSalesLedgerId, salesLedger.getId()));
+ salesLedgerProcessRouteRecordService.remove(new LambdaQueryWrapper<SalesLedgerProcessRouteRecord>().eq(SalesLedgerProcessRouteRecord::getSalesLedgerId, salesLedger.getId()));
// 灏嗘暟鎹縼绉诲埌sales_ledger_process_route
List<ProcessRouteItem> routeItems = processRouteItemMapper.selectList(new LambdaQueryWrapper<ProcessRouteItem>().eq(ProcessRouteItem::getRouteId, processRoute.getId()));
@@ -783,6 +786,39 @@
salesLedgerProcessRouteList.add(ledgerProcessRoute);
}
salesLedgerProcessRouteService.saveBatch(salesLedgerProcessRouteList);
+
+ List<SalesLedgerProcessRoute> savedRoutes = salesLedgerProcessRouteService.list(new LambdaQueryWrapper<SalesLedgerProcessRoute>()
+ .eq(SalesLedgerProcessRoute::getSalesLedgerId, salesLedger.getId())
+ .eq(SalesLedgerProcessRoute::getProcessRouteId, processRoute.getId()));
+ Map<Long, SalesLedgerProcessRoute> routeMap = savedRoutes.stream()
+ .filter(item -> item.getProcessRouteItemId() != null)
+ .collect(Collectors.toMap(SalesLedgerProcessRoute::getProcessRouteItemId, item -> item, (a, b) -> a));
+
+ Map<Long, SalesLedgerProcessRouteRecord> inputRecordMap = new HashMap<>();
+ if (CollectionUtils.isNotEmpty(salesLedgerProcessRouteDto.getRecordList())) {
+ for (SalesLedgerProcessRouteRecord record : salesLedgerProcessRouteDto.getRecordList()) {
+ if (record != null && record.getProcessRouteItemId() != null) {
+ inputRecordMap.put(record.getProcessRouteItemId(), record);
+ }
+ }
+ }
+
+ List<SalesLedgerProcessRouteRecord> routeRecordList = new ArrayList<>();
+ for (ProcessRouteItem routeItem : routeItems) {
+ SalesLedgerProcessRoute route = routeMap.get(routeItem.getId());
+ if (route == null || route.getId() == null) {
+ continue;
+ }
+ SalesLedgerProcessRouteRecord inputRecord = inputRecordMap.get(routeItem.getId());
+ SalesLedgerProcessRouteRecord record = new SalesLedgerProcessRouteRecord();
+ record.setSalesLedgerId(salesLedger.getId());
+ record.setSalesLedgerProcessRouteId(route.getId());
+ Integer isCompleted = inputRecord != null && inputRecord.getIsCompleted() != null ? inputRecord.getIsCompleted() : 0;
+ record.setIsCompleted(isCompleted);
+ record.setCompletedTime(Objects.equals(isCompleted, 1) ? LocalDateTime.now() : null);
+ routeRecordList.add(record);
+ }
+ salesLedgerProcessRouteRecordService.saveBatch(routeRecordList);
}
/**
@@ -1175,6 +1211,11 @@
public SalesLedgerProcessRouteDto salesProcess(Long salesLedgerId) {
SalesLedgerProcessRouteDto dto = new SalesLedgerProcessRouteDto();
List<SalesLedgerProcessRoute> list = baseMapper.selectSalesProcess(salesLedgerId);
+ List<SalesLedgerProcessRouteRecord> recordList = salesLedgerProcessRouteRecordService.list(
+ new LambdaQueryWrapper<SalesLedgerProcessRouteRecord>()
+ .eq(SalesLedgerProcessRouteRecord::getSalesLedgerId, salesLedgerId)
+ .orderByAsc(SalesLedgerProcessRouteRecord::getId)
+ );
if (CollectionUtils.isNotEmpty(list)) {
Long processRouteId = list.get(0).getProcessRouteId();
ProcessRoute processRoute = processRouteMapper.selectById(processRouteId);
@@ -1201,6 +1242,17 @@
}
}
dto.setList(list);
+ if (CollectionUtils.isNotEmpty(list) && CollectionUtils.isNotEmpty(recordList)) {
+ Map<Long, Long> routeItemIdMap = list.stream()
+ .filter(item -> item.getId() != null && item.getProcessRouteItemId() != null)
+ .collect(Collectors.toMap(SalesLedgerProcessRoute::getId, SalesLedgerProcessRoute::getProcessRouteItemId, (a, b) -> a));
+ recordList.forEach(record -> {
+ if (record != null && record.getSalesLedgerProcessRouteId() != null) {
+ record.setProcessRouteItemId(routeItemIdMap.get(record.getSalesLedgerProcessRouteId()));
+ }
+ });
+ }
+ dto.setRecordList(recordList);
return dto;
}
@@ -3740,7 +3792,8 @@
.or().isNull(SalesLedger::getReviewStatus));
}
- List<SalesLedger> ledgerList = salesLedgerMapper.selectList(page, queryWrapper);
+ IPage<SalesLedger> ledgerPage = salesLedgerMapper.selectPage(page, queryWrapper);
+ List<SalesLedger> ledgerList = ledgerPage.getRecords();
// 2. 鏀堕泦鏁版嵁
List<SalesLedgerExportDto> ledgerExportList = new ArrayList<>();
@@ -3821,6 +3874,245 @@
log.error("瀵煎嚭閿�鍞彴璐﹀け璐�", e);
throw new ServiceException("瀵煎嚭澶辫触锛�" + e.getMessage());
}
+ }
+
+ @Override
+ public void exportProcessRoute(HttpServletResponse response, List<Long> salesLedgerIds, String completedTimeStart, String completedTimeEnd) {
+ try {
+ if (CollectionUtils.isEmpty(salesLedgerIds)) {
+ throw new ServiceException("璇烽�夋嫨瑕佸鍑虹殑閿�鍞彴璐�");
+ }
+ LocalDateTime startTime = parseCompletedTime(completedTimeStart);
+ LocalDateTime endTime = parseCompletedTime(completedTimeEnd);
+ if (startTime == null && endTime == null) {
+ startTime = LocalDate.now().atStartOfDay();
+ endTime = LocalDateTime.now();
+ } else {
+ if (startTime == null) {
+ startTime = LocalDate.now().atStartOfDay();
+ }
+ if (endTime == null) {
+ endTime = LocalDateTime.now();
+ }
+ }
+
+ LambdaQueryWrapper<SalesLedgerProcessRouteRecord> queryWrapper = Wrappers.<SalesLedgerProcessRouteRecord>lambdaQuery()
+ .eq(SalesLedgerProcessRouteRecord::getIsCompleted, 1)
+ .ge(SalesLedgerProcessRouteRecord::getCompletedTime, startTime)
+ .le(SalesLedgerProcessRouteRecord::getCompletedTime, endTime)
+ .orderByAsc(SalesLedgerProcessRouteRecord::getCompletedTime)
+ .orderByAsc(SalesLedgerProcessRouteRecord::getId);
+
+ if (CollectionUtils.isNotEmpty(salesLedgerIds)) {
+ queryWrapper.in(SalesLedgerProcessRouteRecord::getSalesLedgerId, salesLedgerIds);
+ }
+
+ List<SalesLedgerProcessRouteRecord> completedRoutes = salesLedgerProcessRouteRecordService.list(queryWrapper);
+ Map<Long, SalesLedger> salesLedgerMap = Collections.emptyMap();
+ Map<Long, SalesLedgerProcessRoute> routeMap = Collections.emptyMap();
+ Map<Long, ProcessRouteItem> processRouteItemMap = Collections.emptyMap();
+ Map<Long, List<SalesLedgerProduct>> productMap = Collections.emptyMap();
+
+ if (CollectionUtils.isNotEmpty(completedRoutes)) {
+ List<Long> routeSalesLedgerIds = completedRoutes.stream()
+ .map(SalesLedgerProcessRouteRecord::getSalesLedgerId)
+ .filter(Objects::nonNull)
+ .distinct()
+ .collect(Collectors.toList());
+ List<Long> salesLedgerProcessRouteIds = completedRoutes.stream()
+ .map(SalesLedgerProcessRouteRecord::getSalesLedgerProcessRouteId)
+ .filter(Objects::nonNull)
+ .distinct()
+ .collect(Collectors.toList());
+
+ if (CollectionUtils.isNotEmpty(routeSalesLedgerIds)) {
+ salesLedgerMap = salesLedgerMapper.selectBatchIds(routeSalesLedgerIds).stream()
+ .filter(Objects::nonNull)
+ .collect(Collectors.toMap(SalesLedger::getId, item -> item, (a, b) -> a));
+ List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>()
+ .in(SalesLedgerProduct::getSalesLedgerId, routeSalesLedgerIds)
+ .eq(SalesLedgerProduct::getType, 1)
+ .orderByAsc(SalesLedgerProduct::getSalesLedgerId)
+ .orderByAsc(SalesLedgerProduct::getId));
+ productMap = products.stream().collect(Collectors.groupingBy(
+ SalesLedgerProduct::getSalesLedgerId,
+ LinkedHashMap::new,
+ Collectors.toList()
+ ));
+ }
+
+ if (CollectionUtils.isNotEmpty(salesLedgerProcessRouteIds)) {
+ routeMap = salesLedgerProcessRouteService.listByIds(salesLedgerProcessRouteIds).stream()
+ .filter(Objects::nonNull)
+ .collect(Collectors.toMap(SalesLedgerProcessRoute::getId, item -> item, (a, b) -> a));
+ List<Long> processRouteItemIds = routeMap.values().stream()
+ .map(SalesLedgerProcessRoute::getProcessRouteItemId)
+ .filter(Objects::nonNull)
+ .distinct()
+ .collect(Collectors.toList());
+ if (CollectionUtils.isNotEmpty(processRouteItemIds)) {
+ processRouteItemMap = processRouteItemMapper.selectBatchIds(processRouteItemIds).stream()
+ .filter(Objects::nonNull)
+ .collect(Collectors.toMap(ProcessRouteItem::getId, item -> item, (a, b) -> a));
+ }
+ }
+ }
+
+ Map<Long, List<SalesLedgerProcessRouteRecord>> routeGroupMap = new LinkedHashMap<>();
+ for (SalesLedgerProcessRouteRecord record : completedRoutes) {
+ SalesLedgerProcessRoute route = routeMap.get(record.getSalesLedgerProcessRouteId());
+ if (route == null || route.getProcessRouteItemId() == null) {
+ continue;
+ }
+ routeGroupMap.computeIfAbsent(route.getProcessRouteItemId(), k -> new ArrayList<>()).add(record);
+ }
+
+ final Map<Long, ProcessRouteItem> finalProcessRouteItemMap = processRouteItemMap;
+ LinkedHashMap<String, List<List<Object>>> sheetMap = new LinkedHashMap<>();
+ List<Long> orderedProcessRouteItemIds = routeGroupMap.keySet().stream()
+ .sorted((left, right) -> compareProcessRouteItem(left, right, finalProcessRouteItemMap))
+ .collect(Collectors.toList());
+
+ for (Long processRouteItemId : orderedProcessRouteItemIds) {
+ ProcessRouteItem processRouteItem = finalProcessRouteItemMap.get(processRouteItemId);
+ String sheetName = buildUniqueSheetName(sheetMap, processRouteItem, processRouteItemId);
+ List<List<Object>> sheetData = new ArrayList<>();
+ sheetData.add(buildProcessRouteHeader());
+
+ for (SalesLedgerProcessRouteRecord route : routeGroupMap.getOrDefault(processRouteItemId, Collections.emptyList())) {
+ SalesLedger salesLedger = salesLedgerMap.get(route.getSalesLedgerId());
+ if (salesLedger == null) {
+ continue;
+ }
+ List<SalesLedgerProduct> products = productMap.getOrDefault(salesLedger.getId(), Collections.emptyList());
+ if (CollectionUtils.isEmpty(products)) {
+ sheetData.add(buildProcessRouteRow(salesLedger, null, route));
+ continue;
+ }
+ for (SalesLedgerProduct product : products) {
+ sheetData.add(buildProcessRouteRow(salesLedger, product, route));
+ }
+ }
+
+ if (sheetData.size() == 1) {
+ sheetData.add(Arrays.asList("", "", "", "", "", "", "", "", ""));
+ }
+ sheetMap.put(sheetName, sheetData);
+ }
+
+ if (sheetMap.isEmpty()) {
+ List<List<Object>> sheetData = new ArrayList<>();
+ sheetData.add(buildProcessRouteHeader());
+ sheetData.add(Arrays.asList("", "", "", "", "", "", ""));
+ sheetMap.put("宸ヨ壓璺嚎", sheetData);
+ }
+
+ com.ruoyi.common.utils.excel.ExcelUtils.exportManySheet(response, "閿�鍞彴璐﹀伐鑹鸿矾绾垮鍑�", sheetMap);
+ } catch (Exception e) {
+ log.error("瀵煎嚭鍞悗鍙拌处宸ヨ壓璺嚎澶辫触", e);
+ throw new ServiceException("瀵煎嚭鍞悗鍙拌处宸ヨ壓璺嚎澶辫触锛�" + e.getMessage());
+ }
+ }
+
+ private LocalDateTime parseCompletedTime(String value) {
+ if (!StringUtils.hasText(value)) {
+ return null;
+ }
+ String text = value.trim();
+ try {
+ return LocalDateTime.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+ } catch (Exception ex) {
+ try {
+ return LocalDateTime.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
+ } catch (Exception ignored) {
+ return LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay();
+ }
+ }
+ }
+
+ private int compareProcessRouteItem(Long left, Long right, Map<Long, ProcessRouteItem> processRouteItemMap) {
+ ProcessRouteItem leftItem = processRouteItemMap.get(left);
+ ProcessRouteItem rightItem = processRouteItemMap.get(right);
+ int leftSort = leftItem != null && leftItem.getDragSort() != null ? leftItem.getDragSort() : Integer.MAX_VALUE;
+ int rightSort = rightItem != null && rightItem.getDragSort() != null ? rightItem.getDragSort() : Integer.MAX_VALUE;
+ if (leftSort != rightSort) {
+ return Integer.compare(leftSort, rightSort);
+ }
+ String leftName = leftItem != null && StringUtils.hasText(leftItem.getProcessName()) ? leftItem.getProcessName() : "";
+ String rightName = rightItem != null && StringUtils.hasText(rightItem.getProcessName()) ? rightItem.getProcessName() : "";
+ int nameCompare = leftName.compareTo(rightName);
+ if (nameCompare != 0) {
+ return nameCompare;
+ }
+ return Long.compare(left, right);
+ }
+
+ private List<Object> buildProcessRouteHeader() {
+ return Arrays.asList("鏃ユ湡", "璁㈠崟缂栧彿", "瀹㈡埛鍚嶇О", "瑙勬牸", "鏁伴噺", "闈㈢Н", "鏄惁鏄伐绋�");
+ }
+
+ private List<Object> buildProcessRouteRow(SalesLedger salesLedger, SalesLedgerProduct product, SalesLedgerProcessRouteRecord route) {
+ List<Object> row = new ArrayList<>();
+ row.add(salesLedger.getEntryDate() == null ? "" : DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, salesLedger.getEntryDate()));
+ row.add(salesLedger.getSalesContractNo());
+ row.add(salesLedger.getCustomerName());
+ row.add(product == null ? "" : product.getSpecificationModel());
+ row.add(product == null ? "" : product.getQuantity());
+ row.add(product == null ? "" : resolveExportArea(product));
+ row.add("");
+ return row;
+ }
+
+ private BigDecimal resolveExportArea(SalesLedgerProduct product) {
+ if (product == null) {
+ return BigDecimal.ZERO;
+ }
+ if (product.getSettleTotalArea() != null) {
+ return product.getSettleTotalArea();
+ }
+ if (product.getActualTotalArea() != null) {
+ return product.getActualTotalArea();
+ }
+ BigDecimal qty = product.getQuantity() == null ? BigDecimal.ONE : product.getQuantity();
+ if (product.getSettlePieceArea() != null) {
+ return product.getSettlePieceArea().multiply(qty).setScale(2, RoundingMode.HALF_UP);
+ }
+ if (product.getActualPieceArea() != null) {
+ return product.getActualPieceArea().multiply(qty).setScale(2, RoundingMode.HALF_UP);
+ }
+ if (product.getWidth() != null && product.getHeight() != null) {
+ BigDecimal area = product.getWidth().multiply(product.getHeight())
+ .divide(new BigDecimal("1000000"), 2, RoundingMode.HALF_UP);
+ return area.multiply(qty).setScale(2, RoundingMode.HALF_UP);
+ }
+ return BigDecimal.ZERO;
+ }
+
+ private String buildUniqueSheetName(Map<String, List<List<Object>>> sheetMap, ProcessRouteItem processRouteItem, Long processRouteItemId) {
+ String baseName = processRouteItem != null && StringUtils.hasText(processRouteItem.getProcessName())
+ ? processRouteItem.getProcessName()
+ : "宸ュ簭" + processRouteItemId;
+ baseName = sanitizeSheetName(baseName);
+ String sheetName = baseName;
+ int suffix = 2;
+ while (sheetMap.containsKey(sheetName)) {
+ String suffixText = "_" + suffix++;
+ int maxBaseLength = 31 - suffixText.length();
+ String trimmedBase = baseName.length() > maxBaseLength ? baseName.substring(0, maxBaseLength) : baseName;
+ sheetName = trimmedBase + suffixText;
+ }
+ return sheetName;
+ }
+
+ private String sanitizeSheetName(String sheetName) {
+ if (!StringUtils.hasText(sheetName)) {
+ return "宸ヨ壓璺嚎";
+ }
+ String sanitized = sheetName.replaceAll("[\\\\/?*\\[\\]:]", "_").trim();
+ if (sanitized.isEmpty()) {
+ sanitized = "宸ヨ壓璺嚎";
+ }
+ return sanitized.length() > 31 ? sanitized.substring(0, 31) : sanitized;
}
/**
@@ -3927,4 +4219,4 @@
default: return "杩涜涓�";
}
}
-}
\ No newline at end of file
+}
--
Gitblit v1.9.3