diff --git a/package.json b/package.json index 85349d9..591c861 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "shrimp-server", - "version": "0.6.8", + "version": "0.6.9", "description": "Shrimp 框架后端 — 声明式字段驱动的 Node.js 管理后台框架(Express + Mongoose + JWT)", "main": "dist/main/index.js", "types": "dist/main/index.d.ts", diff --git a/src/Shrimp/ShrimpTableModule.ts b/src/Shrimp/ShrimpTableModule.ts index 642a101..3d52eb7 100644 --- a/src/Shrimp/ShrimpTableModule.ts +++ b/src/Shrimp/ShrimpTableModule.ts @@ -239,23 +239,21 @@ export class ShrimpTableModule = ITableCrudProto } /** - * 顶层 relation 字段批量解析成 refs 字典: { moduleKey: { id: 显示名 } }。 + * relation 字段(含 tab 分支里的嵌套 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 {} + if (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 add = (moduleKey: string, labelKey: string, id: any) => { + let b = buckets.get(moduleKey) + if (!b) buckets.set(moduleKey, (b = { labelKey, ids: new Set() })) + b.ids.add(String(id)) } + for (const row of rows) { + this.collectRefs(this.fields, (k) => row[k], add) + } + if (buckets.size === 0) return {} const refs: Record> = {} for (const [moduleKey, b] of buckets) { const dict: Record = {} @@ -269,6 +267,20 @@ export class ShrimpTableModule = ITableCrudProto return refs } + /** 递归收集 relation 引用:relation 叶子直接收;tab 按 value.type 进选中分支继续下钻(覆盖嵌套/tab套tab) */ + private collectRefs(fields: IFieldConfig[], valueOf: (key: string) => any, add: (moduleKey: string, labelKey: string, id: any) => void): void { + for (const f of fields) { + const v = valueOf(f.key) + if (v == null) continue + if (f.type === "relation" && f.relation) { + ;(Array.isArray(v) ? v : [v]).forEach((id: any) => id != null && add(f.relation!.moduleKey, f.relation!.labelKey, id)) + } else if (f.type === ShrimpFieldTypes.Tab && Array.isArray(f.tabs) && typeof v === "object") { + const branch = f.tabs.find(t => t.key === v.type) + if (branch) this.collectRefs(branch.fields, (k) => v[k], add) + } + } + } + private excludeKeys(item: any, keys: string[]): any { if (keys.length === 0) return item const result = { ...item } @@ -282,10 +294,6 @@ export class ShrimpTableModule = ITableCrudProto return this.excludeKeys(item, this.fields.filter(f => f.hidden).map(f => f.key)) } - private getRelationFields(): IFieldConfig[] { - return this.fields.filter(f => f.type === "relation" && f.relation) - } - private buildQuery(query?: IPageQuery & any): IShrimpQuery { const { keyword, page, pageSize, sortBy, sortOrder, filter, ownerId } = query || {} const p = page || 1