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 | 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> { const result = await request({ ...safeJsonRequestConfig, url: createContextApiUrl(config, objectId), method: 'get', params: config.contextApiObjectIdPlacement === 'path' ? undefined : ({ [config.contextApiObjectIdParamKey]: objectId } satisfies Record) }); if (result.error || !result.data) { return result as ServiceRequestResult; } return { ...result, data: normalizeObjectContext(config, objectId, result.data) }; }