@truenewx/tnxcore
Version:
互联网技术解决方案:JavaScript核心扩展支持
209 lines (184 loc) • 6.25 kB
text/typescript
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);
}
}
}
}