From 8f9dfd40e02363fbf503e2110efa5674b122e979 Mon Sep 17 00:00:00 2001 From: wc24 Date: Mon, 29 Jun 2026 20:17:26 +0800 Subject: [PATCH] =?UTF-8?q?feat(relation):=20=E7=94=A8=E6=95=B4=E9=A1=B5?= =?UTF-8?q?=20refs=20=E5=AD=97=E5=85=B8=E6=9B=BF=E4=BB=A3=E9=80=90?= =?UTF-8?q?=E8=A1=8C=20=5Flabel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit list 响应新增 refs: { moduleKey: { id: 显示名 } },整页一次性按模块批量查、去重; 去掉 relation 的 populateItems→${key}_label 逐行注入。前端显示时按 id 查 refs。 tab 的 resLabel/_label 不动(留待复合那步)。这是嵌套引用的地基:collectRefs 以后加 tab 的 children() 下钻即可覆盖任意深度。 --- package.json | 2 +- src/IShrimpType.ts | 1 + src/Shrimp/ShrimpTableModule.ts | 48 ++++++++++++++++++++++----------- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 366e6d2..7d6a992 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "shrimp-server", - "version": "0.6.6", + "version": "0.6.7", "description": "Shrimp 框架后端 — 声明式字段驱动的 Node.js 管理后台框架(Express + Mongoose + JWT)", "main": "dist/main/index.js", "types": "dist/main/index.d.ts", diff --git a/src/IShrimpType.ts b/src/IShrimpType.ts index b39a766..341f7d1 100644 --- a/src/IShrimpType.ts +++ b/src/IShrimpType.ts @@ -320,6 +320,7 @@ export interface IPageResult { page: number // 当前页码 pageSize: number // 每页数量 totalPages: number // 总页数 + refs?: Record> // relation 显示名字典: { moduleKey: { id: 显示名 } },前端显示时查名,替代逐行 _label } // ============== 数据源查询协议 ============== diff --git a/src/Shrimp/ShrimpTableModule.ts b/src/Shrimp/ShrimpTableModule.ts index 9c50537..0dad6ef 100644 --- a/src/Shrimp/ShrimpTableModule.ts +++ b/src/Shrimp/ShrimpTableModule.ts @@ -230,22 +230,45 @@ export class ShrimpTableModule = ITableCrudProto private async prepareResponseItems(items: any[]): Promise { if (items.length === 0) return items - const populates = this.getRelationPopulates() - if (populates.length > 0 && this.dataSource.populateItems) { - await this.dataSource.populateItems(items, populates, this.root.crudRegistry) - } return Promise.all(items.map(item => this.processResItem(item))) } private async prepareResponseItem(item: any): Promise { if (!item) return item - const populates = this.getRelationPopulates() - if (populates.length > 0 && this.dataSource.populateItems) { - await this.dataSource.populateItems([item], populates, this.root.crudRegistry) - } return this.processResItem(item) } + /** + * 顶层 relation 字段批量解析成 refs 字典: { moduleKey: { id: 显示名 } }。 + * 整页一次性、按模块各查一次 $in,去重;替代逐行注入 ${key}_label。前端显示时按 id 查名。 + */ + private async buildRefs(rows: any[]): Promise>> { + const relFields = this.getRelationFields() + if (relFields.length === 0 || rows.length === 0) return {} + const buckets = new Map }>() + for (const row of rows) { + for (const f of relFields) { + const v = row[f.key] + if (v == null) continue + const { moduleKey, labelKey } = f.relation! + let b = buckets.get(moduleKey) + if (!b) buckets.set(moduleKey, (b = { labelKey, ids: new Set() })) + ;(Array.isArray(v) ? v : [v]).forEach((id: any) => id != null && b!.ids.add(String(id))) + } + } + const refs: Record> = {} + for (const [moduleKey, b] of buckets) { + const dict: Record = {} + const crud = this.root.crudRegistry.get(moduleKey) + if (crud && b.ids.size > 0) { + const res = await crud.list({ where: { _id: { in: Array.from(b.ids) } }, limit: b.ids.size }) + for (const d of res.list as any[]) dict[String(d._id)] = d[b.labelKey] + } + refs[moduleKey] = dict + } + return refs + } + private excludeKeys(item: any, keys: string[]): any { if (keys.length === 0) return item const result = { ...item } @@ -263,14 +286,6 @@ export class ShrimpTableModule = ITableCrudProto return this.fields.filter(f => f.type === "relation" && f.relation) } - private getRelationPopulates(): IShrimpPopulate[] { - return this.getRelationFields().map(f => ({ - key: f.key, - moduleKey: f.relation!.moduleKey, - labelKey: f.relation!.labelKey, - })) - } - private buildQuery(query?: IPageQuery & any): IShrimpQuery { const { keyword, page, pageSize, sortBy, sortOrder, filter, ownerId } = query || {} const p = page || 1 @@ -339,6 +354,7 @@ export class ShrimpTableModule = ITableCrudProto const result = await this.dataSource.list(shrimpQuery) result.list = await this.prepareResponseItems(result.list) result.list = result.list.map(item => this.filterHidden(item)) + result.refs = await this.buildRefs(result.list) return result }