diff --git a/build/extraResources/influxdb-1.7.0/data/_internal/monitor/1/fields.idx b/build/extraResources/influxdb-1.7.0/data/_internal/monitor/1/fields.idx new file mode 100644 index 0000000..59ad966 Binary files /dev/null and b/build/extraResources/influxdb-1.7.0/data/_internal/monitor/1/fields.idx differ diff --git a/frontend/src/api/steady/steadyDataView/index.ts b/frontend/src/api/steady/steadyDataView/index.ts index 8990c71..2f088e1 100644 --- a/frontend/src/api/steady/steadyDataView/index.ts +++ b/frontend/src/api/steady/steadyDataView/index.ts @@ -29,6 +29,12 @@ export const createSteadyChecksquareTask = (params: SteadyDataView.SteadyChecksq }) } +export const deleteSteadyChecksquareTasks = (taskIds: SteadyDataView.SteadyChecksquareDeleteParams) => { + return http.post('/steady/data-view/checksquare/delete', taskIds, { + loading: false + }) +} + export const getSteadyChecksquareDetail = (taskId: string) => { return http.get('/steady/data-view/checksquare/detail', { taskId }, { loading: false }) } diff --git a/frontend/src/api/steady/steadyDataView/interface/index.ts b/frontend/src/api/steady/steadyDataView/interface/index.ts index 2042fe2..a431d6e 100644 --- a/frontend/src/api/steady/steadyDataView/interface/index.ts +++ b/frontend/src/api/steady/steadyDataView/interface/index.ts @@ -103,6 +103,8 @@ export namespace SteadyDataView { timeEnd: string } + export type SteadyChecksquareDeleteParams = string[] + export interface SteadyChecksquareTask { taskId: string taskNo?: string @@ -114,6 +116,7 @@ export namespace SteadyDataView { taskStatus?: 'SUCCESS' | string itemCount?: number abnormalItemCount?: number + minDataIntegrity?: number | null maxMissingRate?: number | null createTime?: string } @@ -146,6 +149,8 @@ export namespace SteadyDataView { expectedPointCount?: number actualPointCount?: number missingPointCount?: number + dataIntegrity?: number | null + dataIntegrityText?: string | null missingRate?: number | null missingRateText?: string | null maxContinuousMissingMinutes?: number @@ -167,6 +172,8 @@ export namespace SteadyDataView { expectedPointCount?: number actualPointCount?: number missingPointCount?: number + dataIntegrity?: number | null + dataIntegrityText?: string | null missingRate?: number | null missingRateText?: string | null maxContinuousMissingMinutes?: number diff --git a/frontend/src/api/tools/mmsmapping/index.ts b/frontend/src/api/tools/mmsmapping/index.ts index 20f5460..db8b157 100644 --- a/frontend/src/api/tools/mmsmapping/index.ts +++ b/frontend/src/api/tools/mmsmapping/index.ts @@ -9,6 +9,22 @@ const buildIcdFormData = (icdFile: File) => { return formData } +export const listDeviceTypesApi = () => { + return http.get('/api/mms-mapping/dev-types') +} + +export const createDeviceTypeApi = (params: MmsMapping.CreateDeviceTypeRequest) => { + return http.post('/api/mms-mapping/dev-types', params) +} + +export const saveIcdCheckResultApi = (id: string, params: MmsMapping.SaveIcdCheckResultRequest) => { + return http.post(`/api/mms-mapping/dev-types/${id}/icd-check-result`, params) +} + +export const pqdifCheckApi = (id: string) => { + return http.post(`/api/mms-mapping/dev-types/${id}/pqdif-check`) +} + export const getIcdApi = (params: MmsMapping.GetIcdParams) => { const formData = buildIcdFormData(params.icdFile) diff --git a/frontend/src/api/tools/mmsmapping/interface/index.ts b/frontend/src/api/tools/mmsmapping/interface/index.ts index a9e940f..497c055 100644 --- a/frontend/src/api/tools/mmsmapping/interface/index.ts +++ b/frontend/src/api/tools/mmsmapping/interface/index.ts @@ -128,4 +128,37 @@ export namespace MmsMapping { version: string author: string } + + export interface DeviceType { + id?: string + name?: string + icdId?: string + icdName?: string + icdPath?: string + icdResult?: number + icdMsg?: string + reportName?: string + canCheckIcd?: boolean + canCheckPqdif?: boolean + } + + export interface CreateDeviceTypeRequest { + name: string + icdId?: string + icdName?: string + icdPath?: string + reportName?: string + } + + export interface SaveIcdCheckResultRequest { + mappingJson?: string + xml?: string + result: number + msg?: string + } + + export interface PqdifCheckPlaceholder { + status?: string + message?: string + } } diff --git a/frontend/src/routers/index.ts b/frontend/src/routers/index.ts index 577648d..f5420ca 100644 --- a/frontend/src/routers/index.ts +++ b/frontend/src/routers/index.ts @@ -89,12 +89,6 @@ router.beforeEach(async (to, from, next) => { } } - syncHomeStateWithMenus() - logRouterPerf('before-each-menu-sync', guardStart, { - path: to.path, - from: from.path, - hasActivateInfo: authStore.activateInfoLoadedGet - }) await authStore.setRouteName(to.name as string) if (!authStore.activateInfoLoadedGet) { diff --git a/frontend/src/routers/modules/check-menu-navigation-performance-contract.mjs b/frontend/src/routers/modules/check-menu-navigation-performance-contract.mjs new file mode 100644 index 0000000..3c0c0b6 --- /dev/null +++ b/frontend/src/routers/modules/check-menu-navigation-performance-contract.mjs @@ -0,0 +1,56 @@ +import fs from 'fs' +import path from 'path' +import { fileURLToPath } from 'url' + +const currentDir = path.dirname(fileURLToPath(import.meta.url)) +const srcRoot = path.resolve(currentDir, '../..') + +const files = { + router: path.resolve(srcRoot, 'routers/index.ts'), + authStore: path.resolve(srcRoot, 'stores/modules/auth.ts'), + utils: path.resolve(srcRoot, 'utils/index.ts') +} + +const read = file => fs.readFileSync(file, 'utf8') + +const routerSource = read(files.router) +const authStoreSource = read(files.authStore) +const utilsSource = read(files.utils) + +const expectations = [ + { + name: 'auth store owns cached flat/show/breadcrumb menu state', + pass: + /flatMenuList:\s*\[\]/.test(authStoreSource) && + /showMenuList:\s*\[\]/.test(authStoreSource) && + /breadcrumbList:\s*\{\}/.test(authStoreSource) + }, + { + name: 'auth store refreshes derived menus when auth menu list changes', + pass: /refreshDerivedMenus\(\)/.test(authStoreSource) && /this\.refreshDerivedMenus\(\)/.test(authStoreSource) + }, + { + name: 'menu derivation helpers avoid JSON stringify deep clone', + pass: + !/getFlatMenuList[\s\S]*JSON\.parse\(JSON\.stringify/.test(utilsSource) && + !/getShowMenuList[\s\S]*JSON\.parse\(JSON\.stringify/.test(utilsSource) + }, + { + name: 'router beforeEach does not sync home state on every navigation', + pass: !/before-each-menu-sync/.test(routerSource) + }, + { + name: 'router syncs home state after dynamic menu initialization', + pass: /syncHomeStateWithMenus\(\)/.test(routerSource) && /first-sync-home-state/.test(routerSource) + } +] + +const failures = expectations.filter(item => !item.pass) + +if (failures.length) { + console.error('Menu navigation performance contract failed:') + failures.forEach(item => console.error(`- ${item.name}`)) + process.exit(1) +} + +console.log('Menu navigation performance contract passed') diff --git a/frontend/src/routers/modules/staticRouter.ts b/frontend/src/routers/modules/staticRouter.ts index e6cd8f4..83391e2 100644 --- a/frontend/src/routers/modules/staticRouter.ts +++ b/frontend/src/routers/modules/staticRouter.ts @@ -63,6 +63,16 @@ export const staticRouter: RouteRecordRaw[] = [ title: 'MMS 映射' } }, + { + path: '/tools/mmsMapping/deviceTypes', + name: 'toolMmsMappingDeviceTypes', + alias: ['/tools/mmsmapping/deviceTypes', '/tools/mms-mapping/device-types'], + component: () => import('@/views/tools/mmsMapping/deviceTypes/index.vue'), + meta: { + cacheName: 'MmsDeviceTypesView', + title: '设备类型校验' + } + }, { path: '/tools/addData', name: 'toolAddData', diff --git a/frontend/src/stores/interface/index.ts b/frontend/src/stores/interface/index.ts index f2b3ce7..80537da 100644 --- a/frontend/src/stores/interface/index.ts +++ b/frontend/src/stores/interface/index.ts @@ -60,6 +60,9 @@ export interface AuthState { [key: string]: string[] } authMenuList: Menu.MenuOptions[] + showMenuList: Menu.MenuOptions[] + flatMenuList: Menu.MenuOptions[] + breadcrumbList: { [key: string]: Menu.MenuOptions[] } showMenuFlag: boolean activateInfo: Activate.ActivationCodePlaintext activateInfoLoaded: boolean diff --git a/frontend/src/stores/modules/auth.ts b/frontend/src/stores/modules/auth.ts index 2601e6e..34fd8ac 100644 --- a/frontend/src/stores/modules/auth.ts +++ b/frontend/src/stores/modules/auth.ts @@ -10,6 +10,9 @@ export const useAuthStore = defineStore(AUTH_STORE_KEY, { state: (): AuthState => ({ authButtonList: {}, authMenuList: [], + showMenuList: [], + flatMenuList: [], + breadcrumbList: {}, routeName: '', showMenuFlag: localStorage.getItem('showMenuFlag') === 'true', activateInfo: {} as Activate.ActivationCodePlaintext, @@ -18,9 +21,9 @@ export const useAuthStore = defineStore(AUTH_STORE_KEY, { getters: { authButtonListGet: state => state.authButtonList, authMenuListGet: state => state.authMenuList, - showMenuListGet: state => getShowMenuList(state.authMenuList), - flatMenuListGet: state => getFlatMenuList(state.authMenuList), - breadcrumbListGet: state => getAllBreadcrumbList(state.authMenuList), + showMenuListGet: state => state.showMenuList, + flatMenuListGet: state => state.flatMenuList, + breadcrumbListGet: state => state.breadcrumbList, showMenuFlagGet: state => state.showMenuFlag, activateInfoGet: state => state.activateInfo, activateInfoLoadedGet: state => state.activateInfoLoaded @@ -33,6 +36,13 @@ export const useAuthStore = defineStore(AUTH_STORE_KEY, { async getAuthMenuList() { const { data: menuData } = await getAuthMenuListApi() this.authMenuList = normalizeBusinessMenus(filterBusinessMenus(menuData)) + // 菜单派生数据只在菜单源数据变化时重算,避免每次路由跳转都深拷贝整棵菜单。 + this.refreshDerivedMenus() + }, + refreshDerivedMenus() { + this.showMenuList = getShowMenuList(this.authMenuList) + this.flatMenuList = getFlatMenuList(this.authMenuList) + this.breadcrumbList = getAllBreadcrumbList(this.authMenuList) }, async setRouteName(name: string) { this.routeName = name @@ -40,6 +50,9 @@ export const useAuthStore = defineStore(AUTH_STORE_KEY, { async resetAuthStore() { this.authButtonList = {} this.authMenuList = [] + this.showMenuList = [] + this.flatMenuList = [] + this.breadcrumbList = {} this.routeName = '' this.showMenuFlag = false this.activateInfo = {} diff --git a/frontend/src/utils/index.ts b/frontend/src/utils/index.ts index 53e87b0..ea4f653 100644 --- a/frontend/src/utils/index.ts +++ b/frontend/src/utils/index.ts @@ -1,5 +1,5 @@ import { isArray, isNumber } from '@/utils/is' -import { FieldNamesProps } from '@/components/ProTable/interface' +import type { FieldNamesProps } from '@/components/ProTable/interface' const mode = import.meta.env.VITE_ROUTER_MODE @@ -152,8 +152,7 @@ export function getUrlWithParams() { * @returns {Array} */ export function getFlatMenuList(menuList: Menu.MenuOptions[]): Menu.MenuOptions[] { - const newMenuList: Menu.MenuOptions[] = JSON.parse(JSON.stringify(menuList)) - return newMenuList.flatMap(item => [item, ...(item.children ? getFlatMenuList(item.children) : [])]) + return menuList.flatMap(item => [item, ...(item.children?.length ? getFlatMenuList(item.children) : [])]) } /** @@ -161,12 +160,13 @@ export function getFlatMenuList(menuList: Menu.MenuOptions[]): Menu.MenuOptions[ * @param {Array} menuList 菜单列表 * @returns {Array} * */ -export function getShowMenuList(menuList: Menu.MenuOptions[]) { - const newMenuList: Menu.MenuOptions[] = JSON.parse(JSON.stringify(menuList)) - return newMenuList.filter(item => { - item.children?.length && (item.children = getShowMenuList(item.children)) - return !item.meta?.isHide - }) +export function getShowMenuList(menuList: Menu.MenuOptions[]): Menu.MenuOptions[] { + return menuList + .filter(item => !item.meta?.isHide) + .map(item => ({ + ...item, + children: item.children?.length ? getShowMenuList(item.children) : item.children + })) } export function getFirstMenuPath(menuList: Menu.MenuOptions[]): string { diff --git a/frontend/src/views/steady/checksquare/components/ChecksquareDetailPanel.vue b/frontend/src/views/steady/checksquare/components/ChecksquareDetailPanel.vue index 1cfa002..6c1d3a3 100644 --- a/frontend/src/views/steady/checksquare/components/ChecksquareDetailPanel.vue +++ b/frontend/src/views/steady/checksquare/components/ChecksquareDetailPanel.vue @@ -1,123 +1,131 @@ @@ -129,6 +137,7 @@ import { CHECKSQUARE_STAT_TYPES, collectMissingSegments, formatChecksquareStatType, + formatDataIntegrity, formatStatMissingRate, resolveChecksquareRowName } from '../utils/checksquareTable' @@ -244,30 +253,10 @@ watch( diff --git a/frontend/src/views/steady/checksquare/components/ChecksquareTaskTable.vue b/frontend/src/views/steady/checksquare/components/ChecksquareTaskTable.vue index 0579965..43dc7d5 100644 --- a/frontend/src/views/steady/checksquare/components/ChecksquareTaskTable.vue +++ b/frontend/src/views/steady/checksquare/components/ChecksquareTaskTable.vue @@ -11,21 +11,21 @@ + + diff --git a/frontend/src/views/tools/mmsMapping/index.vue b/frontend/src/views/tools/mmsMapping/index.vue index abc6f3a..7f4ef54 100644 --- a/frontend/src/views/tools/mmsMapping/index.vue +++ b/frontend/src/views/tools/mmsMapping/index.vue @@ -52,9 +52,14 @@ :can-generate-xml-mapping="canGenerateXmlMapping" :is-generating-xml="isGeneratingXml" :show-xml-mapping-tab="showXmlMappingTab" + :show-save-icd-check-result="showSaveIcdCheckResult" + :can-save-icd-check-result="canSaveIcdCheckResult" + :is-saving-icd-check-result="isSavingIcdCheckResult" + :save-icd-check-result-text="saveIcdCheckResultText" @export-mapping="handleExportMapping" @generate-xml-mapping="handleGenerateXmlMapping" @update-mapping-json="handleUpdateMappingJson" + @save-icd-check-result="handleSaveIcdCheckResult" /> @@ -70,6 +75,7 @@