UNPKG

@truenewx/tnxcore

Version:

互联网技术解决方案:JavaScript核心扩展支持

209 lines (184 loc) 6.25 kB
import util from '../util/index.ts'; import {get} from './index.ts'; export type ApiModelPropertyType = 'TEXT' | 'EMAIL' | 'URL' | 'INTEGER' | 'DECIMAL' | 'BOOLEAN' | 'DATE' | 'TIME' | 'DATETIME' | 'OPTION' export type EnumItem = { key: string; caption: string; ordinal: number; disabled?: boolean; searchIndex?: string; attachment?: Record<string, string>; } export type EnumType = { name: string; subname?: string; items: EnumItem[]; } export type ApiModelPropertyMeta = { caption: string; type: ApiModelPropertyType; validation?: Record<string, any>; enums?: EnumItem[]; } export type ApiModelMeta = Record<string, ApiModelPropertyMeta>; export type Region = { level: number; code: string; caption: string; suffix: string; group?: string; subs?: Region[]; } const metas: Record<string, ApiModelMeta> = {} const enumTypeMapping: Record<string, EnumType> = {} const regionMapping: Record<string, Region> = {} export async function getMeta(urlOrType: string): Promise<ApiModelMeta> { if (metas[urlOrType]) { return metas[urlOrType]; } else { let url = '/api/meta/' + (urlOrType.includes('/') ? 'method' : 'model'); let params = urlOrType.includes('/') ? {url: urlOrType} : {type: urlOrType}; let meta = await get<ApiModelMeta>(url, params); if (meta) { metas[urlOrType] = meta; } return meta; } } function getEnumTypeMappingKey(type: string, subType?: string): string { return subType ? (type + '-' + subType) : type; } export function addEnumType(enumType: EnumType): void { const mappingKey = getEnumTypeMappingKey(enumType.name, enumType.subname); if (!enumTypeMapping[mappingKey]) { enumTypeMapping[mappingKey] = enumType; } } export async function resolveEnumType(name: string, subname?: string): Promise<EnumType> { const mapping = enumTypeMapping; const mappingKey = getEnumTypeMappingKey(name, subname); if (mapping[mappingKey]) { return mapping[mappingKey]; } else { const enumType = await get<EnumType>('/api/meta/enum/type', {name, subname}); mapping[mappingKey] = enumType; return enumType; } } export async function resolveEnumItems(type: string, subType?: string): Promise<EnumItem[] | null> { const enumType = await resolveEnumType(type, subType); // 返回深度克隆的选项集,以免调用者改动选项影响缓存数据 return (enumType?.items) ? enumType.items.clone(true) : null; } export async function resolveEnumItem(type: string, subType: string | null, key: string): Promise<EnumItem | null> { if (!key) { return null; } let items = getCachedEnumItems(type, subType); if (!items) { items = await resolveEnumItems(type, subType); } return getEnumItem(items, key); } function getCachedEnumItems(type: string, subtype?: string): EnumItem[] | null { const mappingKey = getEnumTypeMappingKey(type, subtype); let enumType = enumTypeMapping[mappingKey]; return enumType ? enumType.items : null; } function getEnumItem(items: EnumItem[] | null, key: string): EnumItem | null { if (Array.isArray(items)) { for (let item of items) { if (item.key === key) { return item; } } } return null; } export async function resolveEnumCaption(type: string, subtype: string | null, key: string): Promise<string> { let item = await resolveEnumItem(type, subtype, key); return item ? item.caption : ''; } /** * 当可确定已缓存指定枚举类型时,获取指定枚举项的显示名称 * @param type 枚举类型名 * @param subtype 子类型名 * @param key 枚举项的键 * @return 指定枚举项的显示名称,没找到时返回null */ export function getEnumCaption(type: string, subtype: string | null, key: string): string | null { let items = getCachedEnumItems(type, subtype); if (items) { for (let item of items) { if (item.key === key) { return item.caption; } } } return null; } /** * 当可确定已缓存指定枚举类型时,获取指定枚举项的键 * @param type 枚举类型名 * @param subtype 子类型名 * @param caption 枚举项的显示名称 * @return {*|null} 指定枚举项的键,没找到时返回null */ export function getEnumKey(type: string, subtype: string | null, caption: string): string | null { let items = getCachedEnumItems(type, subtype); if (items) { for (let item of items) { if (item.caption === caption) { return item.key; } } } return null; } export function clearEnumTypeCache(name: string, subname?: string): void { const mappingKey = getEnumTypeMappingKey(name, subname); delete enumTypeMapping[mappingKey]; } export function getRandomEnumItemKey(type: string, onlyDev: boolean = true): string | null { if (onlyDev && util.build.isProduction()) { return null; } let items = getCachedEnumItems(type); if (items && items.length) { let index = util.number.randomInt(0, items.length - 1); return items[index].key; } return null; } export async function loadRegion(regionCode: string, level: number = 3): Promise<Region> { level = Math.min(level, 3); let cacheKey = regionCode + '.' + level; let region = regionMapping[cacheKey]; if (!region) { region = await get<Region>('/api/region/' + regionCode); filterRegionSubs(region, level); regionMapping[cacheKey] = region; } return region; } function filterRegionSubs(region: Region, level: number) { if (region.subs) { if (region.level >= level) { delete region.subs; } else { for (let sub of region.subs) { filterRegionSubs(sub, level); } } } }