200 lines
6.5 KiB
TypeScript
200 lines
6.5 KiB
TypeScript
import { normalizeNullableStringId, normalizeStringId } from './shared';
|
|
|
|
export interface BackendObjectContextMenuDTO {
|
|
key?: string | null;
|
|
label?: string | null;
|
|
routeKey?: string | null;
|
|
routePath?: string | null;
|
|
id?: string | number | null;
|
|
name?: string | null;
|
|
path?: string | null;
|
|
icon?: string | null;
|
|
sort?: number | null;
|
|
children?: BackendObjectContextMenuDTO[] | null;
|
|
}
|
|
|
|
interface BackendProductContextProductDTO {
|
|
id?: string | number | null;
|
|
code?: string | null;
|
|
directionCode?: string | null;
|
|
name?: string | null;
|
|
managerUserId?: string | number | null;
|
|
statusCode?: string | null;
|
|
}
|
|
|
|
interface BackendProjectContextProjectDTO {
|
|
id?: string | number | null;
|
|
projectCode?: string | null;
|
|
projectName?: string | null;
|
|
projectType?: string | null;
|
|
productId?: string | number | null;
|
|
managerUserId?: string | number | null;
|
|
statusCode?: string | null;
|
|
}
|
|
|
|
interface BackendObjectContextRoleDTO {
|
|
roleId?: string | number | null;
|
|
roleCode?: string | null;
|
|
roleName?: string | null;
|
|
guestFlag?: boolean | null;
|
|
}
|
|
|
|
export interface BackendObjectContextDTO {
|
|
domainKey?: string | null;
|
|
objectType?: string | null;
|
|
objectId?: string | number | null;
|
|
objectName?: string | null;
|
|
objectSummary?: Record<string, unknown> | null;
|
|
menus?: BackendObjectContextMenuDTO[] | null;
|
|
contextScopedMenus?: BackendObjectContextMenuDTO[] | null;
|
|
buttonCodes?: string[] | null;
|
|
currentProduct?: BackendProductContextProductDTO | null;
|
|
currentProject?: BackendProjectContextProjectDTO | null;
|
|
currentRole?: BackendObjectContextRoleDTO | null;
|
|
navs?: BackendObjectContextMenuDTO[] | null;
|
|
buttons?: string[] | null;
|
|
defaultRouteKey?: string | null;
|
|
defaultRoutePath?: string | null;
|
|
}
|
|
|
|
function normalizeString(value: string | number | null | undefined) {
|
|
if (value === null || value === undefined) {
|
|
return '';
|
|
}
|
|
|
|
return String(value);
|
|
}
|
|
|
|
function normalizeRoutePath(path: string | null | undefined) {
|
|
const normalizedPath = normalizeString(path).trim();
|
|
|
|
if (!normalizedPath) {
|
|
return '';
|
|
}
|
|
|
|
if (normalizedPath.startsWith('/')) {
|
|
return normalizedPath;
|
|
}
|
|
|
|
return `/${normalizedPath}`;
|
|
}
|
|
|
|
function normalizeCurrentProduct(
|
|
product: BackendProductContextProductDTO
|
|
): Record<'id' | 'code' | 'directionCode' | 'name' | 'managerUserId' | 'statusCode', string> {
|
|
return {
|
|
id: normalizeStringId(product.id || ''),
|
|
code: normalizeString(product.code),
|
|
directionCode: normalizeString(product.directionCode),
|
|
name: normalizeString(product.name),
|
|
managerUserId: normalizeNullableStringId(product.managerUserId) ?? '',
|
|
statusCode: normalizeString(product.statusCode)
|
|
};
|
|
}
|
|
|
|
function normalizeCurrentProject(project: BackendProjectContextProjectDTO) {
|
|
return {
|
|
id: normalizeStringId(project.id || ''),
|
|
projectCode: normalizeString(project.projectCode),
|
|
projectName: normalizeString(project.projectName),
|
|
projectType: normalizeString(project.projectType),
|
|
productId: normalizeNullableStringId(project.productId),
|
|
managerUserId: normalizeNullableStringId(project.managerUserId) ?? '',
|
|
statusCode: normalizeString(project.statusCode)
|
|
};
|
|
}
|
|
|
|
function normalizeCurrentRole(role: BackendObjectContextRoleDTO) {
|
|
return {
|
|
roleId: normalizeStringId(role.roleId || ''),
|
|
roleCode: normalizeString(role.roleCode),
|
|
roleName: normalizeString(role.roleName),
|
|
guestFlag: Boolean(role.guestFlag)
|
|
};
|
|
}
|
|
|
|
function normalizeMenu(menu: BackendObjectContextMenuDTO): App.ObjectContext.Menu {
|
|
const routeKey = normalizeString(menu.routeKey);
|
|
const routePath = normalizeRoutePath(menu.routePath || menu.path);
|
|
const key = normalizeString(menu.key || routeKey || routePath || menu.id);
|
|
|
|
return {
|
|
key,
|
|
label: normalizeString(menu.label || menu.name),
|
|
routeKey: routeKey || null,
|
|
routePath: routePath || null,
|
|
children: menu.children?.map(child => normalizeMenu(child)) || []
|
|
};
|
|
}
|
|
|
|
function getFirstNonEmptyMenuSource(data: BackendObjectContextDTO) {
|
|
const menuSources = [data.contextScopedMenus, data.menus, data.navs];
|
|
|
|
return menuSources.find(source => Array.isArray(source) && source.length > 0) || [];
|
|
}
|
|
|
|
function getFirstRoutableMenu(menus: App.ObjectContext.Menu[]): App.ObjectContext.Menu | null {
|
|
for (const menu of menus) {
|
|
if (menu.routeKey || menu.routePath) {
|
|
return menu;
|
|
}
|
|
|
|
const firstChildMenu = menu.children?.length ? getFirstRoutableMenu(menu.children) : null;
|
|
|
|
if (firstChildMenu) {
|
|
return firstChildMenu;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function normalizeObjectSummary(data: BackendObjectContextDTO): App.ObjectContext.Summary | null {
|
|
if (data.objectSummary) {
|
|
return data.objectSummary;
|
|
}
|
|
|
|
const summary: App.ObjectContext.Summary = {};
|
|
|
|
if (data.currentProduct) {
|
|
summary.currentProduct = normalizeCurrentProduct(data.currentProduct);
|
|
}
|
|
|
|
if (data.currentProject) {
|
|
summary.currentProject = normalizeCurrentProject(data.currentProject);
|
|
}
|
|
|
|
if (data.currentRole !== undefined) {
|
|
summary.currentRole = data.currentRole ? normalizeCurrentRole(data.currentRole) : null;
|
|
}
|
|
|
|
return Object.keys(summary).length ? summary : null;
|
|
}
|
|
|
|
// 待重构:拆 helper 以降低复杂度,暂以 disable 注释临时放行
|
|
// eslint-disable-next-line complexity
|
|
export function normalizeObjectContext(
|
|
config: App.ObjectContext.DomainConfig,
|
|
objectId: string,
|
|
data: BackendObjectContextDTO
|
|
): Api.ObjectContext.ContextInfo {
|
|
const rawMenus = getFirstNonEmptyMenuSource(data);
|
|
const contextScopedMenus = rawMenus.map(menu => normalizeMenu(menu));
|
|
const firstRoutableMenu = getFirstRoutableMenu(contextScopedMenus);
|
|
const currentProduct = data.currentProduct ? normalizeCurrentProduct(data.currentProduct) : null;
|
|
const currentProject = data.currentProject ? normalizeCurrentProject(data.currentProject) : null;
|
|
|
|
return {
|
|
domainKey: (data.domainKey || config.domainKey) as App.ObjectContext.DomainKey,
|
|
objectType: (data.objectType || config.objectType) as App.ObjectContext.ObjectType,
|
|
objectId: normalizeString(data.objectId) || currentProduct?.id || currentProject?.id || objectId,
|
|
objectName: normalizeString(data.objectName || currentProduct?.name || currentProject?.projectName),
|
|
objectSummary: normalizeObjectSummary(data),
|
|
contextScopedMenus,
|
|
buttonCodes: data.buttonCodes ?? data.buttons ?? [],
|
|
defaultRouteKey: data.defaultRouteKey || firstRoutableMenu?.routeKey || '',
|
|
defaultRoutePath:
|
|
normalizeRoutePath(data.defaultRoutePath) || firstRoutableMenu?.routePath || config.fallbackDefaultRoutePath
|
|
};
|
|
}
|