203 lines
6.2 KiB
TypeScript
203 lines
6.2 KiB
TypeScript
|
|
import type { LocationQueryValue } from 'vue-router';
|
||
|
|
import { request } from '../request';
|
||
|
|
import {
|
||
|
|
type ServiceRequestResult,
|
||
|
|
normalizeNullableStringId,
|
||
|
|
normalizeStringId,
|
||
|
|
safeJsonRequestConfig
|
||
|
|
} from './shared';
|
||
|
|
|
||
|
|
interface BackendObjectContextMenuDTO {
|
||
|
|
key?: string | null;
|
||
|
|
label?: string | null;
|
||
|
|
routeKey?: string | null;
|
||
|
|
routePath?: string | null;
|
||
|
|
id?: string | number | null;
|
||
|
|
name?: string | null;
|
||
|
|
path?: string | 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 BackendProductContextRoleDTO {
|
||
|
|
roleId?: string | number | null;
|
||
|
|
roleCode?: string | null;
|
||
|
|
roleName?: string | null;
|
||
|
|
}
|
||
|
|
|
||
|
|
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;
|
||
|
|
currentRole?: BackendProductContextRoleDTO | 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 normalizeCurrentRole(role: BackendProductContextRoleDTO) {
|
||
|
|
return {
|
||
|
|
roleId: normalizeStringId(role.roleId || ''),
|
||
|
|
roleCode: normalizeString(role.roleCode),
|
||
|
|
roleName: normalizeString(role.roleName)
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
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 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.currentRole !== undefined) {
|
||
|
|
summary.currentRole = data.currentRole ? normalizeCurrentRole(data.currentRole) : null;
|
||
|
|
}
|
||
|
|
|
||
|
|
return Object.keys(summary).length ? summary : null;
|
||
|
|
}
|
||
|
|
|
||
|
|
function createContextApiUrl(config: App.ObjectContext.DomainConfig, objectId: string) {
|
||
|
|
if (config.contextApiObjectIdPlacement !== 'path') {
|
||
|
|
return config.contextApiPath;
|
||
|
|
}
|
||
|
|
|
||
|
|
const placeholder = `{${config.contextApiObjectIdParamKey}}`;
|
||
|
|
|
||
|
|
return config.contextApiPath.replace(placeholder, encodeURIComponent(objectId));
|
||
|
|
}
|
||
|
|
|
||
|
|
function normalizeObjectContext(
|
||
|
|
config: App.ObjectContext.DomainConfig,
|
||
|
|
objectId: string,
|
||
|
|
data: BackendObjectContextDTO
|
||
|
|
): Api.ObjectContext.ContextInfo {
|
||
|
|
const rawMenus = data.contextScopedMenus ?? data.menus ?? data.navs ?? [];
|
||
|
|
const contextScopedMenus = rawMenus.map(menu => normalizeMenu(menu));
|
||
|
|
const firstRoutableMenu = getFirstRoutableMenu(contextScopedMenus);
|
||
|
|
const currentProduct = data.currentProduct ? normalizeCurrentProduct(data.currentProduct) : 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 || objectId,
|
||
|
|
objectName: normalizeString(data.objectName || currentProduct?.name),
|
||
|
|
objectSummary: normalizeObjectSummary(data),
|
||
|
|
contextScopedMenus,
|
||
|
|
buttonCodes: data.buttonCodes ?? data.buttons ?? [],
|
||
|
|
defaultRouteKey: data.defaultRouteKey || firstRoutableMenu?.routeKey || '',
|
||
|
|
defaultRoutePath:
|
||
|
|
normalizeRoutePath(data.defaultRoutePath) || firstRoutableMenu?.routePath || config.fallbackDefaultRoutePath
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function fetchGetObjectContext(
|
||
|
|
config: App.ObjectContext.DomainConfig,
|
||
|
|
objectId: string
|
||
|
|
): Promise<ServiceRequestResult<Api.ObjectContext.ContextInfo>> {
|
||
|
|
const result = await request<BackendObjectContextDTO>({
|
||
|
|
...safeJsonRequestConfig,
|
||
|
|
url: createContextApiUrl(config, objectId),
|
||
|
|
method: 'get',
|
||
|
|
params:
|
||
|
|
config.contextApiObjectIdPlacement === 'path'
|
||
|
|
? undefined
|
||
|
|
: ({
|
||
|
|
[config.contextApiObjectIdParamKey]: objectId
|
||
|
|
} satisfies Record<string, LocationQueryValue | LocationQueryValue[]>)
|
||
|
|
});
|
||
|
|
|
||
|
|
if (result.error || !result.data) {
|
||
|
|
return result as ServiceRequestResult<Api.ObjectContext.ContextInfo>;
|
||
|
|
}
|
||
|
|
|
||
|
|
return {
|
||
|
|
...result,
|
||
|
|
data: normalizeObjectContext(config, objectId, result.data)
|
||
|
|
};
|
||
|
|
}
|