diff --git a/packages/model/src/template-model-data.ts b/packages/model/src/template-model-data.ts index 6e5fa21f39dfc0ba3e37da4079d41264fd11c1e9..9c2b79e0bef4d33afcf2216d4b2617aecb58c814 100644 --- a/packages/model/src/template-model-data.ts +++ b/packages/model/src/template-model-data.ts @@ -18,6 +18,7 @@ import { ViewStyle } from './model/app/view-style'; import { UILogic } from './model/app/ui-logic'; import { GlobalModel } from './model/global-model'; import { ApiDtoModel } from './model/system/api-dto-model'; +import { plural, ServicePathUtil } from './utils'; /** * 模板单个渲染对象 @@ -47,6 +48,18 @@ export class TemplateModelData { */ protected dslHelper = new DSLHelper(); + + /** + * 服务路径拼接工具 + * + * @author zk + * @date 2023-06-14 10:06:29 + * @protected + * @type {ServicePathUtil} + * @memberof TemplateModelData + */ + protected servicePathUtil!: ServicePathUtil; + /** * Creates an instance of TemplateModelData. * @@ -58,6 +71,8 @@ export class TemplateModelData { if (global) { Object.assign(this.data, global); } + const appModel = this.data.app as AppModel; + this.servicePathUtil = new ServicePathUtil(appModel); } /** @@ -240,7 +255,11 @@ export class TemplateModelData { */ setAppEntity(appEntity: AppEntityModel): void { this.set('appEntity', appEntity); - this.set('appEntityDSL', this.dslHelper.appDataEntity(appEntity.M)); + const model = this.dslHelper.appDataEntity(appEntity.M); + const list = this.servicePathUtil.calcRequestPaths(model.id!); + model.requestPaths = list; + model.codeName2 = plural(model.codeName!); + this.set('appEntityDSL', model); const text = kebabCase(appEntity.codeName).toLowerCase(); this.set('appEntities', text); } diff --git a/packages/model/src/utils/index.ts b/packages/model/src/utils/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..3afdda0c6037fd9c8c947ef3c558d569d3484d95 --- /dev/null +++ b/packages/model/src/utils/index.ts @@ -0,0 +1,2 @@ +export { plural, pluralLower } from './plural/plural'; +export { ServicePathUtil } from './service-path-util/service-path-util'; diff --git a/packages/model/src/utils/plural/plural.ts b/packages/model/src/utils/plural/plural.ts new file mode 100644 index 0000000000000000000000000000000000000000..b5d6e3eb99cdf6d097d7d6a119bc6578f7be8d4d --- /dev/null +++ b/packages/model/src/utils/plural/plural.ts @@ -0,0 +1,27 @@ +import * as pluralize from 'pluralize'; + +/** + * 英文转复数写法 + * + * @author chitanda + * @date 2022-08-25 18:08:41 + * @export + * @param {string} key + * @return {*} {string} + */ +export function plural(key: string): string { + return pluralize(key); +} + +/** + * 英文转复数写法并转全小写 + * + * @author chitanda + * @date 2022-08-25 18:08:23 + * @export + * @param {string} key + * @return {*} {string} + */ +export function pluralLower(key: string): string { + return plural(key).toLowerCase(); +} diff --git a/packages/model/src/utils/service-path-util/service-path-util.ts b/packages/model/src/utils/service-path-util/service-path-util.ts new file mode 100644 index 0000000000000000000000000000000000000000..08934ac79eb2d1f6c1937fa7e24fd5a1b568e0f4 --- /dev/null +++ b/packages/model/src/utils/service-path-util/service-path-util.ts @@ -0,0 +1,246 @@ +import { calcUniqueTag } from '@ibiz/rt-model-api'; +import { pluralLower } from '../plural/plural'; + +/** + * 获取服务拼接递归对象 + */ +export type ServicePathDeep = [IModel, ServicePathDeep[]]; + +/** + * 服务路径项 + */ +export type ServicePathItem = { + /** + * 实体代码名称(标准) + * + * @author chitanda + * @date 2022-08-25 18:08:35 + * @type {string} + */ + codeName: string; + /** + * 实体代码名称(小写) + * + * @author chitanda + * @date 2022-08-25 18:08:54 + * @type {string} + */ + lower: string; + /** + * 实体代码名称复数(小写) + * + * @author chitanda + * @date 2022-08-25 18:08:13 + * @type {string} + */ + plural: string; +}; + +/** + * 服务路径拼接工具 + * + * @author chitanda + * @date 2022-08-22 21:08:52 + * @export + * @class ServicePathUtil + */ +export class ServicePathUtil { + /** + * 应用实体关系 + * + * @author chitanda + * @date 2022-08-22 22:08:18 + * @protected + * @type {Map} <应用实体 id, 应用实体父关系> + */ + protected entityRsMap: Map = new Map(); + + /** + * 实体资源路径 + * + * @author chitanda + * @date 2022-08-22 22:08:58 + * @protected + * @type {Map} + */ + protected entityRsPathMap: Map = new Map(); + + protected allDERss: IModel[] = []; + protected appDataEntities: IModel[] = []; + + + constructor(appModel: IModel) { + const allDataEntities: IModel[] = appModel.M + .getAllPSAppDataEntities as IModel[]; + allDataEntities.forEach(item => { + item.id = calcUniqueTag(item, false); + }); + const allAppDERSs = appModel.M.getAllPSAppDERSs as IModel[]; + allAppDERSs.forEach(item => { + const major = item.getMajorPSAppDataEntity; + const minor = item.getMinorPSAppDataEntity; + item.majorAppDataEntityId = calcUniqueTag(major, false); + item.minorAppDataEntityId = calcUniqueTag(minor, false); + }); + this.allDERss = allAppDERSs; + this.appDataEntities = allDataEntities; + } + + /** + * 根据应用主实体过滤从关系集合 + * + * @author chitanda + * @date 2023-04-20 17:04:34 + * @protected + * @param {string} id + * @return {*} {IModel[]} + */ + protected filterDERSs(id: string): IModel[] { + if (this.entityRsMap.has(id)) { + return this.entityRsMap.get(id)!; + } + const items = this.allDERss.filter(item => { + if (item.minorAppDataEntityId === id) { + return item; + } + return null; + }); + if (items.length > 0) { + this.entityRsMap.set(id, items); + } + return items; + } + + /** + * 计算指定应用实体所有资源路径 + * + * @author chitanda + * @date 2023-04-22 13:04:27 + * @param {string} id + * @return {*} {string[]} + */ + calcRequestPaths(id: string): string[] { + const paths = this.calcPaths(id); + return paths.map(path => { + return path.map(item => `${item.plural}/\${${item.lower}}`).join('/'); + }); + } + + /** + * 计算指定实体所有资源路径 + * + * @author chitanda + * @date 2023-04-22 13:04:36 + * @protected + * @param {string} id + * @return {*} {ServicePathItem[][]} 返回顺序为 [祖父实体,爷爷实体,父实体,当前实体] + */ + protected calcPaths(id: string): ServicePathItem[][] { + const entityRef = this.appDataEntities.find(item => item.id === id); + if (!entityRef) { + throw new Error(`未找到实体 ${id}`); + } + const { codeName } = entityRef; + if (this.entityRsPathMap.has(codeName)) { + return this.entityRsPathMap.get(codeName)!; + } + const deRss = this.filterDERSs(id); + if (deRss) { + const arr = this.calcDeepPath(deRss); + this.deepFillPath(codeName, [codeName], arr); + let paths = this.entityRsPathMap.get(codeName); + if (paths) { + paths = this.sortPath(paths); + this.entityRsPathMap.set(codeName, paths); + return paths; + } + } + return []; + } + + /** + * 计算递归资源路径 + * + * @author chitanda + * @date 2022-08-22 22:08:32 + * @protected + * @param {IModel[]} deRss + * @return {*} {ServicePathDeep[]} + */ + protected calcDeepPath(deRss: IModel[], num: number = 0): ServicePathDeep[] { + if (num > 10) { + throw new Error('服务路径计算超过最大层级 10'); + } + num += 1; + const arr: ServicePathDeep[] = []; + deRss.forEach(rs => { + const items = this.filterDERSs(rs.majorDECodeName!); + arr.push([rs, this.calcDeepPath(items, num)]); + }); + return arr; + } + + /** + * 递归填充计算所有资源路径 + * + * @author chitanda + * @date 2022-08-22 22:08:04 + * @protected + * @param {string} deCodeName + * @param {string[]} pathNames + * @param {ServicePathDeep[]} items + */ + protected deepFillPath( + deCodeName: string, + pathNames: string[], + items: ServicePathDeep[], + ): void { + items.forEach(item => { + const [rs, children] = item; + if (children.length > 0) { + this.deepFillPath( + deCodeName, + [...pathNames, rs.majorDECodeName!], + children, + ); + } else { + if (!this.entityRsPathMap.has(deCodeName)) { + this.entityRsPathMap.set(deCodeName, []); + } + const arr = this.entityRsPathMap.get(deCodeName)!; + + arr.push( + [ + ...pathNames.map(pathName => { + return { + codeName: pathName, + lower: pathName.toLowerCase(), + plural: pluralLower(pathName), + }; + }), + { + codeName: rs.majorDECodeName!, + lower: rs.majorDECodeName!.toLowerCase(), + plural: pluralLower(rs.majorDECodeName!), + }, + ].reverse(), + ); + } + }); + } + + /** + * 排序资源路径顺序 + * + * @author chitanda + * @date 2022-08-22 22:08:44 + * @protected + * @param {ServicePathItem[][]} paths + * @return {*} {ServicePathItem[][]} + */ + protected sortPath(paths: ServicePathItem[][]): ServicePathItem[][] { + return paths.sort((a, b) => { + return b.length - a.length; + }); + } +}