diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysCategoryController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysCategoryController.java index c93e5b2..5961764 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysCategoryController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysCategoryController.java @@ -416,13 +416,7 @@ public class SysCategoryController { * 递归求子节点 同步加载用到 */ private void loadAllCategoryChildren(List ls) { - for (TreeSelectModel tsm : ls) { - List temp = this.sysCategoryService.queryListByPid(tsm.getKey()); - if(temp!=null && temp.size()>0) { - tsm.setChildren(temp); - loadAllCategoryChildren(temp); - } - } + this.sysCategoryService.fillCategoryChildrenBatch(ls); } /** diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysCategoryMapper.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysCategoryMapper.java index 208ba7e..c676b39 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysCategoryMapper.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysCategoryMapper.java @@ -28,6 +28,11 @@ public interface SysCategoryMapper extends BaseMapper { */ public List queryListByPid(@Param("pid") String pid,@Param("query") Map query); + /** + * 批量按父 id 查询子节点(树同步加载按层拉取,避免 N+1) + */ + List queryListByPidIn(@Param("pids") List pids, @Param("query") Map query); + /** * 通过code查询分类字典表 * @param code diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysCategoryMapper.xml b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysCategoryMapper.xml index 741670c..6c32069 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysCategoryMapper.xml +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysCategoryMapper.xml @@ -33,5 +33,36 @@ + + diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysCategoryService.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysCategoryService.java index 607d2c5..652f672 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysCategoryService.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysCategoryService.java @@ -98,4 +98,11 @@ public interface ISysCategoryService extends IService { */ List loadDictItemByNames(String names, boolean delNotExist); + /** + * 按层批量补全子节点(替代逐节点递归 queryListByPid,显著减少数据库往返) + * + * @param nodes 首层节点列表(通常来自 {@link #queryListByCode}) + */ + void fillCategoryChildrenBatch(List nodes); + } diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java index cff09f8..5410273 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysCategoryServiceImpl.java @@ -126,6 +126,37 @@ public class SysCategoryServiceImpl extends ServiceImpl nodes) { + if (nodes == null || nodes.isEmpty()) { + return; + } + List frontier = new ArrayList<>(nodes); + while (!frontier.isEmpty()) { + List pids = frontier.stream().map(TreeSelectModel::getKey).filter(Objects::nonNull).collect(Collectors.toList()); + if (pids.isEmpty()) { + break; + } + List allChildren = baseMapper.queryListByPidIn(pids, null); + if (allChildren == null || allChildren.isEmpty()) { + break; + } + Map> byParent = allChildren.stream().collect(Collectors.groupingBy(TreeSelectModel::getParentId)); + List nextFrontier = new ArrayList<>(); + for (TreeSelectModel parent : frontier) { + List ch = byParent.get(parent.getKey()); + if (ch != null && !ch.isEmpty()) { + parent.setChildren(ch); + nextFrontier.addAll(ch); + } + } + if (nextFrontier.isEmpty()) { + break; + } + frontier = nextFrontier; + } + } + @Override public String queryIdByCode(String code) { return baseMapper.queryIdByCode(code); diff --git a/jeecgboot-vue3/src/views/mes/material/MesMixerMaterialList.vue b/jeecgboot-vue3/src/views/mes/material/MesMixerMaterialList.vue index 26edd29..06bb3b0 100644 --- a/jeecgboot-vue3/src/views/mes/material/MesMixerMaterialList.vue +++ b/jeecgboot-vue3/src/views/mes/material/MesMixerMaterialList.vue @@ -114,6 +114,8 @@ const { tableContext, onExportXls, onImportXls } = useListPage({ title: '密炼物料信息', api: list, columns, + // 避免:表格默认 immediate 请求一次 + onMounted 末尾 reload 再请求一次(进入页列表闪两次) + immediate: false, canResize: true, formConfig: { labelWidth: 120, schemas: searchFormSchema, autoSubmitOnEnter: true, showAdvancedButton: true }, actionColumn: { width: 120 }, @@ -227,9 +229,8 @@ function findNodeByKey(nodes: Recordable[], key: string): Recordable | null { async function loadCategoryTree() { treeLoading.value = true; try { - const root = await fetchMaterialCategoryRoot(); + const [root, res] = await Promise.all([fetchMaterialCategoryRoot(), loadCategoryTreeRoot({ async: false, pcode: 'XSLMES_MATERIAL' })]); materialCategoryRootId.value = root?.id != null ? String(root.id) : ''; - const res = await loadCategoryTreeRoot({ async: false, pcode: 'XSLMES_MATERIAL' }); rawCategoryTree.value = Array.isArray(res) ? res : []; if (!materialCategoryRootId.value || !rawCategoryTree.value.length) { createMessage.warning('未加载到物料分类树,请确认分类字典根编码 XSLMES_MATERIAL 已存在。'); diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslUnit/MesXslUnitList.vue b/jeecgboot-vue3/src/views/xslmes/mesXslUnit/MesXslUnitList.vue index 47fcfff..a37b367 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslUnit/MesXslUnitList.vue +++ b/jeecgboot-vue3/src/views/xslmes/mesXslUnit/MesXslUnitList.vue @@ -271,9 +271,9 @@ async function loadCategoryTree() { treeLoading.value = true; try { - const root = await fetchUnitCategoryRoot(); + // 根节点查询与整棵树接口并行,减少串行等待;后端已改为按层批量查子节点,降低 DB 往返 + const [root, res] = await Promise.all([fetchUnitCategoryRoot(), loadUnitCategoryTreeRoot({ async: false, pcode: 'XSLMES_UNIT' })]); unitCategoryRootId.value = root?.id != null ? String(root.id) : ''; - const res = await loadUnitCategoryTreeRoot({ async: false, pcode: 'XSLMES_UNIT' }); rawUnitCategoryTree.value = Array.isArray(res) ? res : []; if (!unitCategoryRootId.value || !rawUnitCategoryTree.value.length) { createMessage.warning('未加载到单位分类树,请确认已执行库脚本且分类字典根编码为 XSLMES_UNIT。'); @@ -295,6 +295,8 @@ title: '单位管理', api: list, columns, + // 避免:表格默认 immediate 请求一次 + onMounted 末尾 reload 再请求一次(进入页列表闪两次) + immediate: false, canResize: true, formConfig: { schemas: searchFormSchema, diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/MesXslWarehouseList.vue b/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/MesXslWarehouseList.vue index ab7e221..43db4f3 100644 --- a/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/MesXslWarehouseList.vue +++ b/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/MesXslWarehouseList.vue @@ -294,9 +294,8 @@ async function loadCategoryTree() { treeLoading.value = true; try { - const root = await fetchWarehouseCategoryRoot(); + const [root, res] = await Promise.all([fetchWarehouseCategoryRoot(), loadCategoryTreeRoot({ async: false, pcode: 'XSLMES_WH' })]); warehouseCategoryRootId.value = root?.id != null ? String(root.id) : ''; - const res = await loadCategoryTreeRoot({ async: false, pcode: 'XSLMES_WH' }); rawWarehouseCategoryTree.value = Array.isArray(res) ? res : []; if (!warehouseCategoryRootId.value || !rawWarehouseCategoryTree.value.length) { createMessage.warning('未加载到仓库分类树,请确认已执行库脚本并已在「分类字典」中维护根节点 XSLMES_WH。'); @@ -385,6 +384,8 @@ title: '仓库管理', api: list, columns, + // 避免:表格默认 immediate 请求一次 + onMounted 末尾 reload 再请求一次(进入页列表闪两次) + immediate: false, canResize: true, formConfig: { schemas: searchFormSchema,