From 55d694aaae4e421b5e55cd941500e08f85cb5d4d Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 27 八月 2026 18:21:33 +0800
Subject: [PATCH] feat(sales): 添加框架合同订单功能并优化销售台账管理
---
src/main/java/com/ruoyi/device/service/impl/DeviceAreaServiceImpl.java | 194 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 194 insertions(+), 0 deletions(-)
diff --git a/src/main/java/com/ruoyi/device/service/impl/DeviceAreaServiceImpl.java b/src/main/java/com/ruoyi/device/service/impl/DeviceAreaServiceImpl.java
new file mode 100644
index 0000000..06340f6
--- /dev/null
+++ b/src/main/java/com/ruoyi/device/service/impl/DeviceAreaServiceImpl.java
@@ -0,0 +1,194 @@
+package com.ruoyi.device.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.device.dto.DeviceAreaDto;
+import com.ruoyi.device.mapper.DeviceAreaMapper;
+import com.ruoyi.device.mapper.DeviceLedgerMapper;
+import com.ruoyi.device.pojo.DeviceArea;
+import com.ruoyi.device.pojo.DeviceLedger;
+import com.ruoyi.device.service.IDeviceAreaService;
+import com.ruoyi.device.vo.DeviceAreaTreeDto;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 璁惧鍖哄煙 Service 瀹炵幇
+ */
+@Service
+@RequiredArgsConstructor
+public class DeviceAreaServiceImpl extends ServiceImpl<DeviceAreaMapper, DeviceArea> implements IDeviceAreaService {
+
+ private final DeviceAreaMapper deviceAreaMapper;
+ private final DeviceLedgerMapper deviceLedgerMapper;
+
+ @Override
+ public List<DeviceAreaTreeDto> selectAreaTree() {
+ List<DeviceArea> all = this.list(new LambdaQueryWrapper<DeviceArea>().orderByAsc(DeviceArea::getSort));
+ if (all == null || all.isEmpty()) {
+ return new ArrayList<>();
+ }
+
+ // 缁熻姣忎釜鍖哄煙鐩存帴鎸傝浇鐨勮澶囨暟閲�
+ Map<Long, Long> directCountMap = deviceLedgerMapper.selectList(
+ new LambdaQueryWrapper<DeviceLedger>()
+ .select(DeviceLedger::getAreaId)
+ .isNotNull(DeviceLedger::getAreaId))
+ .stream()
+ .filter(d -> d.getAreaId() != null)
+ .collect(Collectors.groupingBy(DeviceLedger::getAreaId, Collectors.counting()));
+
+ Map<Long, DeviceArea> areaMap = all.stream()
+ .collect(Collectors.toMap(DeviceArea::getId, a -> a));
+
+ // 閫掑綊姹囨�绘瘡涓妭鐐圭殑璁惧鏁伴噺锛堝惈鎵�鏈夊瓙绾э級
+ Map<Long, Long> countMap = directCountMap.entrySet().stream()
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ for (DeviceArea area : all) {
+ accumulate(area.getId(), directCountMap.getOrDefault(area.getId(), 0L), countMap, areaMap);
+ }
+
+ List<Long> rootIds = all.stream()
+ .filter(a -> a.getParentId() == null || !areaMap.containsKey(a.getParentId()))
+ .map(DeviceArea::getId)
+ .collect(Collectors.toList());
+
+ List<DeviceAreaTreeDto> tree = new ArrayList<>();
+ for (Long rootId : rootIds) {
+ DeviceArea root = areaMap.get(rootId);
+ tree.add(buildNode(root, all, countMap));
+ }
+ return tree;
+ }
+
+ // 灏嗗綋鍓嶈妭鐐规暟閲忕疮鍔犲埌鎵�鏈夌绾ц妭鐐�
+ private void accumulate(Long areaId, Long count, Map<Long, Long> countMap, Map<Long, DeviceArea> areaMap) {
+ DeviceArea area = areaMap.get(areaId);
+ if (area == null) {
+ return;
+ }
+ countMap.merge(areaId, count, Long::sum);
+ // 娌跨鍏堥摼缁х画绱姞锛堥伩鍏嶇鍏堥摼寰幆渚濊禆锛�
+ if (area.getParentId() != null && areaMap.containsKey(area.getParentId())) {
+ accumulate(area.getParentId(), count, countMap, areaMap);
+ }
+ }
+
+ private DeviceAreaTreeDto buildNode(DeviceArea area, List<DeviceArea> all, Map<Long, Long> countMap) {
+ DeviceAreaTreeDto node = new DeviceAreaTreeDto();
+ node.setId(area.getId());
+ node.setParentId(area.getParentId());
+ node.setLabel(area.getName());
+ node.setDeviceCount(countMap.getOrDefault(area.getId(), 0L));
+ for (DeviceArea child : all) {
+ if (area.getId().equals(child.getParentId())) {
+ node.getChildren().add(buildNode(child, all, countMap));
+ }
+ }
+ return node;
+ }
+
+ @Override
+ public AjaxResult addArea(DeviceAreaDto dto) {
+ if (StringUtils.isEmpty(dto.getName())) {
+ return AjaxResult.error("鍖哄煙鍚嶇О涓嶈兘涓虹┖");
+ }
+ DeviceArea area = new DeviceArea();
+ area.setName(dto.getName());
+ area.setParentId(dto.getParentId());
+ area.setSort(dto.getSort());
+ area.setDeptId(dto.getDeptId());
+ area.setTenantId(SecurityUtils.getLoginUser().getTenantId());
+
+ if (dto.getParentId() != null) {
+ DeviceArea parent = this.getById(dto.getParentId());
+ if (parent == null) {
+ return AjaxResult.error("鐖剁骇鍖哄煙涓嶅瓨鍦�");
+ }
+ area.setAncestors(StringUtils.isEmpty(parent.getAncestors())
+ ? String.valueOf(parent.getId())
+ : parent.getAncestors() + "," + parent.getId());
+ }
+ this.save(area);
+ return AjaxResult.success();
+ }
+
+ @Override
+ public AjaxResult updateArea(DeviceAreaDto dto) {
+ if (dto.getId() == null) {
+ return AjaxResult.error("鍖哄煙ID涓嶈兘涓虹┖");
+ }
+ DeviceArea area = this.getById(dto.getId());
+ if (area == null) {
+ return AjaxResult.error("鍖哄煙涓嶅瓨鍦�");
+ }
+ // 涓嶅厑璁告妸鍖哄煙鎸傚埌鑷繁鐨勫瓙绾т笅锛岄伩鍏嶅惊鐜�
+ if (dto.getParentId() != null && dto.getParentId().equals(dto.getId())) {
+ return AjaxResult.error("涓嶈兘灏嗗尯鍩熸寕杞藉埌鑷韩");
+ }
+ if (dto.getParentId() != null && isDescendant(dto.getId(), dto.getParentId())) {
+ return AjaxResult.error("涓嶈兘灏嗗尯鍩熸寕杞藉埌鑷繁鐨勫瓙绾т笅");
+ }
+ area.setName(dto.getName());
+ area.setSort(dto.getSort());
+ area.setDeptId(dto.getDeptId());
+ if (!java.util.Objects.equals(dto.getParentId(), area.getParentId())) {
+ area.setParentId(dto.getParentId());
+ if (dto.getParentId() == null) {
+ area.setAncestors(null);
+ } else {
+ DeviceArea parent = this.getById(dto.getParentId());
+ if (parent == null) {
+ return AjaxResult.error("鐖剁骇鍖哄煙涓嶅瓨鍦�");
+ }
+ area.setAncestors(StringUtils.isEmpty(parent.getAncestors())
+ ? String.valueOf(parent.getId())
+ : parent.getAncestors() + "," + parent.getId());
+ }
+ }
+ this.updateById(area);
+ return AjaxResult.success();
+ }
+
+ private boolean isDescendant(Long targetId, Long candidateParentId) {
+ DeviceArea cur = this.getById(candidateParentId);
+ while (cur != null && cur.getParentId() != null) {
+ if (cur.getParentId().equals(targetId)) {
+ return true;
+ }
+ cur = this.getById(cur.getParentId());
+ }
+ return false;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public AjaxResult deleteArea(List<Long> ids) {
+ for (Long id : ids) {
+ DeviceArea area = this.getById(id);
+ if (area == null) {
+ return AjaxResult.error("鍖哄煙涓嶅瓨鍦�");
+ }
+ long childCount = this.count(new LambdaQueryWrapper<DeviceArea>().eq(DeviceArea::getParentId, id));
+ if (childCount > 0) {
+ return AjaxResult.error("璇ュ尯鍩熷瓨鍦ㄥ瓙绾у尯鍩燂紝璇峰厛鍒犻櫎瀛愮骇");
+ }
+ long deviceCount = deviceLedgerMapper.selectCount(
+ new LambdaQueryWrapper<DeviceLedger>().eq(DeviceLedger::getAreaId, id));
+ if (deviceCount > 0) {
+ return AjaxResult.error("璇ュ尯鍩熶笅瀛樺湪璁惧锛岃鍏堢Щ闄よ澶囧叧鑱�");
+ }
+ }
+ this.removeByIds(ids);
+ return AjaxResult.success();
+ }
+}
\ No newline at end of file
--
Gitblit v1.9.3