mirror of
https://gitee.com/pnoker/iot-dc3.git
synced 2026-09-01 15:33:10 +08:00
refactor!(web): parse identifiers as strings and drop json-bigint
BREAKING CHANGE: frontend identifier types converge to string and the json-bigint dependency is removed; the backend now emits string ids.
This commit is contained in:
@@ -54,6 +54,7 @@ iot-dc3/
|
||||
├── dc3-coverage/ aggregate JaCoCo report and absolute coverage gate
|
||||
├── dc3-e2e/ Testcontainers-backed end-to-end tests
|
||||
├── dc3/ compose files, environment files, scripts, and generated release notes
|
||||
├── docs/design/ design documents (e.g. `mq-abstraction.md` — proposed pluggable broker port)
|
||||
├── Makefile preferred backend/container command entrypoint
|
||||
└── .mvn/settings.xml local Maven mirror configuration
|
||||
```
|
||||
@@ -213,7 +214,7 @@ Key rules:
|
||||
- `verbatimModuleSyntax` is enabled. Use `import type` for every type-only import; Vue components, functions, and icons
|
||||
remain normal value imports.
|
||||
- Use `<Entity>Form` for create/update payloads and `<Entity>Record` for read responses.
|
||||
- Represent Java 64-bit IDs as strings and preserve the existing JSONBigInt handling.
|
||||
- Represent Java 64-bit IDs as strings. The backend emits identifiers as JSON strings on the HTTP contract, so standard JSON parsing (no JSONBigInt) is sufficient.
|
||||
- API wrappers mirror backend cardinality: `getXxx` for one value, `listXxx` for collections/maps/pages, and
|
||||
`addXxx`/`updateXxx`/`deleteXxx` for mutations.
|
||||
- Reuse CRUD helpers from `src/api/common.ts` and API bases from `src/config/constant/api.ts`; keep API wrappers thin.
|
||||
|
||||
@@ -64,7 +64,6 @@
|
||||
"highlight.js": "^11.11.1",
|
||||
"js-base64": "^3.9.1",
|
||||
"js-cookie": "^3.0.8",
|
||||
"json-bigint": "^1.0.0",
|
||||
"marked": "^18.0.6",
|
||||
"mitt": "^3.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
@@ -78,7 +77,6 @@
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@playwright/test": "^1.62.0",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/json-bigint": "^1.0.4",
|
||||
"@types/node": "^26.1.1",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"@typescript-eslint/eslint-plugin": "^8.64.0",
|
||||
|
||||
Generated
-23
@@ -45,9 +45,6 @@ importers:
|
||||
js-cookie:
|
||||
specifier: ^3.0.8
|
||||
version: 3.0.8
|
||||
json-bigint:
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0
|
||||
marked:
|
||||
specifier: ^18.0.6
|
||||
version: 18.0.6
|
||||
@@ -82,9 +79,6 @@ importers:
|
||||
'@types/js-cookie':
|
||||
specifier: ^3.0.6
|
||||
version: 3.0.6
|
||||
'@types/json-bigint':
|
||||
specifier: ^1.0.4
|
||||
version: 1.0.4
|
||||
'@types/node':
|
||||
specifier: ^26.1.1
|
||||
version: 26.1.1
|
||||
@@ -774,9 +768,6 @@ packages:
|
||||
'@types/jsesc@2.5.1':
|
||||
resolution: {integrity: sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==}
|
||||
|
||||
'@types/json-bigint@1.0.4':
|
||||
resolution: {integrity: sha512-ydHooXLbOmxBbubnA7Eh+RpBzuaIiQjh8WGJYQB50JFGFrdxW7JzVlyEV7fAXw0T2sqJ1ysTneJbiyNLqZRAag==}
|
||||
|
||||
'@types/json-schema@7.0.15':
|
||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||
|
||||
@@ -1185,9 +1176,6 @@ packages:
|
||||
bidi-js@1.0.3:
|
||||
resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==}
|
||||
|
||||
bignumber.js@9.0.0:
|
||||
resolution: {integrity: sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==}
|
||||
|
||||
birpc@2.6.1:
|
||||
resolution: {integrity: sha512-LPnFhlDpdSH6FJhJyn4M0kFO7vtQ5iPw24FnG0y21q09xC7e8+1LeR31S1MAIrDAHp4m7aas4bEkTDTvMAtebQ==}
|
||||
|
||||
@@ -1841,9 +1829,6 @@ packages:
|
||||
engines: {node: '>=6'}
|
||||
hasBin: true
|
||||
|
||||
json-bigint@1.0.0:
|
||||
resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==}
|
||||
|
||||
json-buffer@3.0.1:
|
||||
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
|
||||
|
||||
@@ -3418,8 +3403,6 @@ snapshots:
|
||||
|
||||
'@types/jsesc@2.5.1': {}
|
||||
|
||||
'@types/json-bigint@1.0.4': {}
|
||||
|
||||
'@types/json-schema@7.0.15': {}
|
||||
|
||||
'@types/lodash-es@4.17.12':
|
||||
@@ -3960,8 +3943,6 @@ snapshots:
|
||||
dependencies:
|
||||
require-from-string: 2.0.2
|
||||
|
||||
bignumber.js@9.0.0: {}
|
||||
|
||||
birpc@2.6.1: {}
|
||||
|
||||
boolbase@1.0.0: {}
|
||||
@@ -4610,10 +4591,6 @@ snapshots:
|
||||
|
||||
jsesc@3.1.0: {}
|
||||
|
||||
json-bigint@1.0.0:
|
||||
dependencies:
|
||||
bignumber.js: 9.0.0
|
||||
|
||||
json-buffer@3.0.1: {}
|
||||
|
||||
json-schema-traverse@0.4.1: {}
|
||||
|
||||
@@ -21,13 +21,13 @@ import type {AlertPageQuery, AlertSource} from '@/config/types/dashboard';
|
||||
|
||||
export const alertPage = (body: AlertPageQuery = {}) => httpPost(`${API_DATA_BASE}/dashboard/alert/page`, body);
|
||||
|
||||
export const alertConfirm = (source: AlertSource, id: string | number) =>
|
||||
export const alertConfirm = (source: AlertSource, id: string) =>
|
||||
httpPost(`${API_DATA_BASE}/dashboard/alert/confirm`, undefined, {params: {source, id}});
|
||||
|
||||
export const alertUnconfirm = (source: AlertSource, id: string | number) =>
|
||||
export const alertUnconfirm = (source: AlertSource, id: string) =>
|
||||
httpPost(`${API_DATA_BASE}/dashboard/alert/unconfirm`, undefined, {params: {source, id}});
|
||||
|
||||
export const alertBulkConfirm = (items: Array<{ source: AlertSource; id: string | number }>, confirm: boolean) =>
|
||||
export const alertBulkConfirm = (items: Array<{ source: AlertSource; id: string }>, confirm: boolean) =>
|
||||
httpPost(`${API_DATA_BASE}/dashboard/alert/bulk_confirm`, {items, confirm});
|
||||
|
||||
export const alertTrend = (days = 30) => httpGet(`${API_DATA_BASE}/dashboard/alert/trend`, {params: {days}});
|
||||
|
||||
@@ -801,7 +801,7 @@ const handlePromptClick = (item: AssistantPromptItem) => {
|
||||
draft.value = `${item.label || ''}${description}`.trim();
|
||||
};
|
||||
|
||||
const handleModelChange = (model: string | number) => {
|
||||
const handleModelChange = (model: string) => {
|
||||
void agenticStore.setSelectedModel(model);
|
||||
};
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ const nameField: Record<EntityKind, string> = {
|
||||
point: 'pointName',
|
||||
};
|
||||
|
||||
async function fetchMissing(kind: EntityKind, rawIds: Array<string | number>): Promise<void> {
|
||||
async function fetchMissing(kind: EntityKind, rawIds: Array<string>): Promise<void> {
|
||||
if (!rawIds || rawIds.length === 0) return;
|
||||
const locale = String(i18n.global.locale.value);
|
||||
const cacheKey = (id: string) => `${locale}:${id}`;
|
||||
@@ -150,33 +150,33 @@ async function fetchMissing(kind: EntityKind, rawIds: Array<string | number>): P
|
||||
export type AlertSourceKind = 'point' | 'device' | 'driver';
|
||||
|
||||
export const useEntityNames = () => {
|
||||
const cachedName = (kind: EntityKind, id: string | number): string =>
|
||||
const cachedName = (kind: EntityKind, id: string): string =>
|
||||
cache[kind][`${String(i18n.global.locale.value)}:${String(id)}`] ?? String(id);
|
||||
|
||||
const resolveDevices = (ids: Array<string | number>) => fetchMissing('device', ids);
|
||||
const resolveDrivers = (ids: Array<string | number>) => fetchMissing('driver', ids);
|
||||
const resolveProfiles = (ids: Array<string | number>) => fetchMissing('profile', ids);
|
||||
const resolvePoints = (ids: Array<string | number>) => fetchMissing('point', ids);
|
||||
const resolveDevices = (ids: Array<string>) => fetchMissing('device', ids);
|
||||
const resolveDrivers = (ids: Array<string>) => fetchMissing('driver', ids);
|
||||
const resolveProfiles = (ids: Array<string>) => fetchMissing('profile', ids);
|
||||
const resolvePoints = (ids: Array<string>) => fetchMissing('point', ids);
|
||||
|
||||
const deviceName = (id: string | number | undefined | null): string =>
|
||||
const deviceName = (id: string | undefined | null): string =>
|
||||
id == null ? '' : cachedName('device', id);
|
||||
const driverName = (id: string | number | undefined | null): string =>
|
||||
const driverName = (id: string | undefined | null): string =>
|
||||
id == null ? '' : cachedName('driver', id);
|
||||
const profileName = (id: string | number | undefined | null): string =>
|
||||
const profileName = (id: string | undefined | null): string =>
|
||||
id == null ? '' : cachedName('profile', id);
|
||||
const pointName = (id: string | number | undefined | null): string =>
|
||||
const pointName = (id: string | undefined | null): string =>
|
||||
id == null ? '' : cachedName('point', id);
|
||||
|
||||
/** Resolve a mixed batch of (source, id) rows in one call. */
|
||||
const resolveBySource = async (
|
||||
rows: Array<{
|
||||
source: AlertSourceKind;
|
||||
sourceId: string | number;
|
||||
sourceId: string;
|
||||
}>
|
||||
): Promise<void> => {
|
||||
const ptIds: Array<string | number> = [];
|
||||
const devIds: Array<string | number> = [];
|
||||
const drvIds: Array<string | number> = [];
|
||||
const ptIds: Array<string> = [];
|
||||
const devIds: Array<string> = [];
|
||||
const drvIds: Array<string> = [];
|
||||
for (const r of rows) {
|
||||
if (r.source === 'point') ptIds.push(r.sourceId);
|
||||
else if (r.source === 'device') devIds.push(r.sourceId);
|
||||
@@ -185,7 +185,7 @@ export const useEntityNames = () => {
|
||||
await Promise.all([resolvePoints(ptIds), resolveDevices(devIds), resolveDrivers(drvIds)]);
|
||||
};
|
||||
|
||||
const nameBySource = (source: AlertSourceKind, id: string | number): string => {
|
||||
const nameBySource = (source: AlertSourceKind, id: string): string => {
|
||||
if (source === 'point') return pointName(id);
|
||||
if (source === 'driver') return driverName(id);
|
||||
return deviceName(id);
|
||||
|
||||
@@ -25,40 +25,16 @@ import {failMessage, warnMessage} from '@/utils/notificationUtil';
|
||||
import {getStorage, removeStorage} from '@/utils/storageUtil';
|
||||
import {isNull} from '@/utils/validationUtil';
|
||||
import router from '@/config/router';
|
||||
import JSONBigInt from 'json-bigint';
|
||||
|
||||
/**
|
||||
* JSONBigInt parser instance with storeAsString option
|
||||
*/
|
||||
const JSONBigIntStr = JSONBigInt({storeAsString: true});
|
||||
|
||||
/**
|
||||
* Transform response data using JSONBigInt to handle large integers
|
||||
*
|
||||
* @param data Raw response data
|
||||
* @returns Parsed data
|
||||
*/
|
||||
function transformResponse(data: any): any {
|
||||
if (typeof data !== 'string' || data === '') {
|
||||
return data;
|
||||
}
|
||||
try {
|
||||
return JSONBigIntStr.parse(data);
|
||||
} catch {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom Axios instance with default configuration
|
||||
* Handles large integers via JSONBigInt and includes authentication headers
|
||||
* Includes authentication headers
|
||||
*/
|
||||
const request: AxiosInstance = axios.create({
|
||||
timeout: AXIOS_CONFIG.TIMEOUT,
|
||||
withCredentials: true,
|
||||
headers: {Accept: AXIOS_CONFIG.HEADERS.ACCEPT, 'Content-Type': AXIOS_CONFIG.HEADERS.CONTENT_TYPE},
|
||||
validateStatus: (status) => status >= AXIOS_CONFIG.MIN_STATUS && status <= AXIOS_CONFIG.MAX_STATUS,
|
||||
transformResponse: [transformResponse],
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -111,7 +111,7 @@ export interface AgenticMessage {
|
||||
export interface AgenticMessageContent {
|
||||
text?: string;
|
||||
format?: string;
|
||||
attachments?: number[];
|
||||
attachments?: string[];
|
||||
tools?: string[];
|
||||
traces?: AgenticTraceEvent[];
|
||||
charts?: AgenticVisualizationSpec[];
|
||||
@@ -165,7 +165,7 @@ export interface AgenticMessageTokens {
|
||||
}
|
||||
|
||||
export interface AgenticAttachment {
|
||||
id: number;
|
||||
id: string;
|
||||
conversationId: string;
|
||||
fileName: string;
|
||||
contentType: string;
|
||||
@@ -209,7 +209,7 @@ export interface AgenticChatCompletionRequest {
|
||||
* Leaving this empty is rejected by the backend with HTTP 400.
|
||||
*/
|
||||
conversationId: string;
|
||||
attachments?: number[];
|
||||
attachments?: string[];
|
||||
reasoning?: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ export interface UserRecord extends UserForm {
|
||||
|
||||
export interface RoleForm {
|
||||
id?: string;
|
||||
parentRoleId?: number | string;
|
||||
parentRoleId?: string;
|
||||
roleName?: string;
|
||||
roleCode?: string;
|
||||
enableFlag?: string;
|
||||
@@ -63,7 +63,7 @@ export interface RoleRecord extends RoleForm {
|
||||
|
||||
export interface MenuForm {
|
||||
id?: string;
|
||||
parentMenuId?: number | string;
|
||||
parentMenuId?: string;
|
||||
menuName?: string;
|
||||
menuCode?: string;
|
||||
menuTypeFlag?: string;
|
||||
@@ -93,13 +93,13 @@ export interface MenuRecord extends MenuForm {
|
||||
|
||||
export interface ResourceForm {
|
||||
id?: string;
|
||||
parentResourceId?: number | string;
|
||||
parentResourceId?: string;
|
||||
resourceName?: string;
|
||||
resourceCode?: string;
|
||||
serviceName?: string;
|
||||
resourceTypeFlag?: string;
|
||||
resourceScopeFlag?: string;
|
||||
entityId?: string | number;
|
||||
entityId?: string;
|
||||
resourceExt?: Record<string, unknown>;
|
||||
enableFlag?: string;
|
||||
remark?: string;
|
||||
|
||||
@@ -112,24 +112,24 @@ export interface TopologyResponse {
|
||||
|
||||
export interface FlappingSource {
|
||||
source: AlertSource;
|
||||
sourceId: number | string;
|
||||
sourceId: string;
|
||||
eventTypeFlag: number;
|
||||
count: number;
|
||||
}
|
||||
|
||||
export interface CorrelationPair {
|
||||
aSource: AlertSource;
|
||||
aSourceId: number | string;
|
||||
aSourceId: string;
|
||||
aEventType: number;
|
||||
bSource: AlertSource;
|
||||
bSourceId: number | string;
|
||||
bSourceId: string;
|
||||
bEventType: number;
|
||||
coCount: number;
|
||||
}
|
||||
|
||||
export interface PeerDeviation {
|
||||
profileId: number | string;
|
||||
deviceId: number | string;
|
||||
profileId: string;
|
||||
deviceId: string;
|
||||
alarmCount: number;
|
||||
peerMedian: number;
|
||||
ratio: number;
|
||||
@@ -159,20 +159,20 @@ export interface ProtocolHealth {
|
||||
|
||||
export interface ChangeImpact {
|
||||
kind: ChangeKind;
|
||||
entityId: number | string;
|
||||
entityId: string;
|
||||
operateTime: string;
|
||||
}
|
||||
|
||||
export interface SilentSource {
|
||||
deviceId: number | string;
|
||||
pointId: number | string;
|
||||
deviceId: string;
|
||||
pointId: string;
|
||||
lastSeen: string;
|
||||
silentSeconds: number;
|
||||
}
|
||||
|
||||
export interface CoverageGapItem {
|
||||
pointId: number | string;
|
||||
profileId: number | string;
|
||||
pointId: string;
|
||||
profileId: string;
|
||||
}
|
||||
|
||||
export interface CoverageGap {
|
||||
|
||||
@@ -172,7 +172,7 @@ export interface EventInfoForm {
|
||||
|
||||
export interface GroupForm {
|
||||
id?: string;
|
||||
parentGroupId?: number | string | null;
|
||||
parentGroupId?: string | null;
|
||||
groupTypeFlag?: string;
|
||||
groupName?: string;
|
||||
groupCode?: string;
|
||||
|
||||
@@ -295,7 +295,7 @@ export const agenticActions: LocalizedAction[] = [
|
||||
];
|
||||
|
||||
export const agenticAttachments: AgenticAttachment[] = [
|
||||
{id: 91001, conversationId: sessionDefs[3]!.id, fileName: 'opcua-handshake-20260811.log', contentType: 'text/plain', size: 2516582, createTime: at(1, 10, 58)},
|
||||
{id: 91002, conversationId: sessionDefs[5]!.id, fileName: 'M-104-vibration-spectrum.csv', contentType: 'text/csv', size: 486210, createTime: at(3, 9, 54)},
|
||||
{id: 91003, conversationId: sessionDefs[6]!.id, fileName: 'canary-rollout-metrics.json', contentType: 'application/json', size: 128044, createTime: at(4, 16, 50)},
|
||||
{id: '91001', conversationId: sessionDefs[3]!.id, fileName: 'opcua-handshake-20260811.log', contentType: 'text/plain', size: 2516582, createTime: at(1, 10, 58)},
|
||||
{id: '91002', conversationId: sessionDefs[5]!.id, fileName: 'M-104-vibration-spectrum.csv', contentType: 'text/csv', size: 486210, createTime: at(3, 9, 54)},
|
||||
{id: '91003', conversationId: sessionDefs[6]!.id, fileName: 'canary-rollout-metrics.json', contentType: 'application/json', size: 128044, createTime: at(4, 16, 50)},
|
||||
];
|
||||
|
||||
@@ -115,7 +115,7 @@ export const users: UserRecord[] = userDefs.map((u, i) => ({
|
||||
// nested under ROLE_OPERATOR / ROLE_ADMIN to exercise the role tree.
|
||||
|
||||
interface RoleDef {
|
||||
parentRoleId: number;
|
||||
parentRoleId: string;
|
||||
roleName: string;
|
||||
roleCode: string;
|
||||
remark: string;
|
||||
@@ -123,11 +123,11 @@ interface RoleDef {
|
||||
}
|
||||
|
||||
const roleDefs: RoleDef[] = [
|
||||
{parentRoleId: 0, roleName: '系统管理员', roleCode: 'ROLE_ADMIN', remark: '内置超级管理员,拥有全部权限'},
|
||||
{parentRoleId: 0, roleName: '运维人员', roleCode: 'ROLE_OPERATOR', remark: '负责设备与驱动的日常运维'},
|
||||
{parentRoleId: 0, roleName: '只读访客', roleCode: 'ROLE_VIEWER', remark: '仅可查看监控数据'},
|
||||
{parentRoleId: 2, roleName: '运维组长', roleCode: 'ROLE_OPERATOR_LEAD', remark: '运维组长,可管理运维人员'},
|
||||
{parentRoleId: 1, roleName: '审计员', roleCode: 'ROLE_AUDITOR', remark: '审计员,查看审计与日志', enabled: false},
|
||||
{parentRoleId: '0', roleName: '系统管理员', roleCode: 'ROLE_ADMIN', remark: '内置超级管理员,拥有全部权限'},
|
||||
{parentRoleId: '0', roleName: '运维人员', roleCode: 'ROLE_OPERATOR', remark: '负责设备与驱动的日常运维'},
|
||||
{parentRoleId: '0', roleName: '只读访客', roleCode: 'ROLE_VIEWER', remark: '仅可查看监控数据'},
|
||||
{parentRoleId: '2', roleName: '运维组长', roleCode: 'ROLE_OPERATOR_LEAD', remark: '运维组长,可管理运维人员'},
|
||||
{parentRoleId: '1', roleName: '审计员', roleCode: 'ROLE_AUDITOR', remark: '审计员,查看审计与日志', enabled: false},
|
||||
];
|
||||
|
||||
export const roles: RoleRecord[] = roleDefs.map((r, i) => ({
|
||||
|
||||
@@ -36,7 +36,7 @@ const KEEP = {content: {keep: ''}};
|
||||
export const groups: GroupRecord[] = [
|
||||
{
|
||||
id: '1',
|
||||
parentGroupId: 0,
|
||||
parentGroupId: '0',
|
||||
groupTypeFlag: 'DRIVER',
|
||||
groupName: '驱动分组',
|
||||
groupCode: 'DRIVER-GROUP',
|
||||
@@ -49,7 +49,7 @@ export const groups: GroupRecord[] = [
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
parentGroupId: 1,
|
||||
parentGroupId: '1',
|
||||
groupTypeFlag: 'DRIVER',
|
||||
groupName: 'Modbus 驱动组',
|
||||
groupCode: 'DRIVER-MODBUS',
|
||||
@@ -62,7 +62,7 @@ export const groups: GroupRecord[] = [
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
parentGroupId: 0,
|
||||
parentGroupId: '0',
|
||||
groupTypeFlag: 'DEVICE',
|
||||
groupName: '设备分组',
|
||||
groupCode: 'DEVICE-GROUP',
|
||||
@@ -75,7 +75,7 @@ export const groups: GroupRecord[] = [
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
parentGroupId: 3,
|
||||
parentGroupId: '3',
|
||||
groupTypeFlag: 'DEVICE',
|
||||
groupName: '温湿度设备组',
|
||||
groupCode: 'DEVICE-TH',
|
||||
@@ -88,7 +88,7 @@ export const groups: GroupRecord[] = [
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
parentGroupId: 3,
|
||||
parentGroupId: '3',
|
||||
groupTypeFlag: 'DEVICE',
|
||||
groupName: '电力设备组',
|
||||
groupCode: 'DEVICE-POWER',
|
||||
@@ -238,7 +238,7 @@ export const apis: ApiRecord[] = [
|
||||
export const resources: ResourceRecord[] = [
|
||||
{
|
||||
id: '5001',
|
||||
parentResourceId: 0,
|
||||
parentResourceId: '0',
|
||||
resourceName: '根资源',
|
||||
resourceCode: 'ROOT',
|
||||
serviceName: 'dc3-manager',
|
||||
@@ -253,7 +253,7 @@ export const resources: ResourceRecord[] = [
|
||||
},
|
||||
{
|
||||
id: '5002',
|
||||
parentResourceId: 5001,
|
||||
parentResourceId: '5001',
|
||||
resourceName: '驱动新增',
|
||||
resourceCode: 'driver_add',
|
||||
serviceName: 'dc3-manager',
|
||||
@@ -268,7 +268,7 @@ export const resources: ResourceRecord[] = [
|
||||
},
|
||||
{
|
||||
id: '5003',
|
||||
parentResourceId: 5001,
|
||||
parentResourceId: '5001',
|
||||
resourceName: '设备查询',
|
||||
resourceCode: 'device_list',
|
||||
serviceName: 'dc3-manager',
|
||||
@@ -283,7 +283,7 @@ export const resources: ResourceRecord[] = [
|
||||
},
|
||||
{
|
||||
id: '5004',
|
||||
parentResourceId: 5001,
|
||||
parentResourceId: '5001',
|
||||
resourceName: '位号更新',
|
||||
resourceCode: 'point_update',
|
||||
serviceName: 'dc3-data',
|
||||
@@ -298,7 +298,7 @@ export const resources: ResourceRecord[] = [
|
||||
},
|
||||
{
|
||||
id: '5005',
|
||||
parentResourceId: 5001,
|
||||
parentResourceId: '5001',
|
||||
resourceName: '模板删除',
|
||||
resourceCode: 'profile_delete',
|
||||
serviceName: 'dc3-manager',
|
||||
|
||||
@@ -34,8 +34,8 @@ interface NodeOpts {
|
||||
* static demo matches what the backend serves; resolveMenuTitle prefers content.titles.
|
||||
*/
|
||||
const mk = (menuCode: string, opts: NodeOpts = {}): MenuNode => ({
|
||||
id: ++seq,
|
||||
parentMenuId: 0,
|
||||
id: String(++seq),
|
||||
parentMenuId: '0',
|
||||
menuName: opts.menuName ?? menuCode,
|
||||
menuCode,
|
||||
menuIndex: opts.menuIndex,
|
||||
|
||||
@@ -71,7 +71,7 @@ export const useAgenticStore = defineStore('agentic', () => {
|
||||
const currentAbortController = ref<AbortController>();
|
||||
const messagesByConversation = ref<Record<string, AgenticMessage[]>>(readCachedMessages());
|
||||
const attachmentsByConversation = ref<Record<string, AgenticAttachment[]>>({});
|
||||
const pendingAttachmentIdsByConversation = ref<Record<string, number[]>>({});
|
||||
const pendingAttachmentIdsByConversation = ref<Record<string, string[]>>({});
|
||||
const pendingActionsByConversation = ref<Record<string, AgenticAction[]>>({});
|
||||
const traceEventsByConversation = ref<Record<string, AgenticTraceEvent[]>>({});
|
||||
|
||||
@@ -206,7 +206,7 @@ export const useAgenticStore = defineStore('agentic', () => {
|
||||
persistMessages();
|
||||
};
|
||||
|
||||
const selectSession = async (conversationId?: string | number) => {
|
||||
const selectSession = async (conversationId?: string) => {
|
||||
if (!conversationId) {
|
||||
return;
|
||||
}
|
||||
@@ -405,7 +405,7 @@ export const useAgenticStore = defineStore('agentic', () => {
|
||||
];
|
||||
};
|
||||
|
||||
const removeLocalAttachment = (attachmentId: number) => {
|
||||
const removeLocalAttachment = (attachmentId: string) => {
|
||||
const conversationId = activeConversationId.value;
|
||||
pendingAttachmentIdsByConversation.value[conversationId] = (
|
||||
pendingAttachmentIdsByConversation.value[conversationId] || []
|
||||
@@ -472,7 +472,7 @@ export const useAgenticStore = defineStore('agentic', () => {
|
||||
}
|
||||
};
|
||||
|
||||
const setSelectedModel = async (model: string | number) => {
|
||||
const setSelectedModel = async (model: string) => {
|
||||
const nextModel = resolveModelName(String(model || ''));
|
||||
selectedModel.value = nextModel;
|
||||
applyModelCapabilities();
|
||||
|
||||
@@ -20,8 +20,8 @@ import {defineStore} from 'pinia';
|
||||
import {listMenuTree} from '@/api/menu';
|
||||
|
||||
export interface MenuNode {
|
||||
id: number | string;
|
||||
parentMenuId: number | string;
|
||||
id: string;
|
||||
parentMenuId: string;
|
||||
menuName: string;
|
||||
menuCode: string;
|
||||
menuTypeFlag?: string;
|
||||
@@ -86,7 +86,7 @@ export const useMenuStore = defineStore('menu', {
|
||||
*/
|
||||
findById:
|
||||
(state) =>
|
||||
(id: number | string): MenuNode | undefined => {
|
||||
(id: string): MenuNode | undefined => {
|
||||
const key = String(id);
|
||||
const walk = (nodes: MenuNode[]): MenuNode | undefined => {
|
||||
for (const n of nodes) {
|
||||
|
||||
@@ -40,7 +40,7 @@ export type AlertSourceKind = 'point' | 'device' | 'driver';
|
||||
* kind. Router errors (e.g. aborted nav during transitions) are swallowed
|
||||
* so callers don't have to .catch() themselves.
|
||||
*/
|
||||
export const jumpToEntity = (router: Router, kind: JumpKind, id: string | number): void => {
|
||||
export const jumpToEntity = (router: Router, kind: JumpKind, id: string): void => {
|
||||
const idStr = String(id);
|
||||
if (!idStr) return;
|
||||
switch (kind) {
|
||||
@@ -66,7 +66,7 @@ export const jumpToEntity = (router: Router, kind: JumpKind, id: string | number
|
||||
/**
|
||||
* Jump to the per-source event list with the source id pre-filtered.
|
||||
*/
|
||||
export const jumpToSourceEvents = (router: Router, source: AlertSourceKind, sourceId: string | number): void => {
|
||||
export const jumpToSourceEvents = (router: Router, source: AlertSourceKind, sourceId: string): void => {
|
||||
let name: string;
|
||||
if (source === 'point') name = 'settingsPointAlarm';
|
||||
else if (source === 'driver') name = 'settingsDriverAlarm';
|
||||
|
||||
@@ -720,7 +720,7 @@ export default defineComponent({
|
||||
listDriverInfoByDeviceId(reactiveData.id)
|
||||
.then((res) => {
|
||||
const formData: AttributeFormData = reactiveData.driverFormData;
|
||||
res.data.forEach((info: { attributeId: string | number; id: any; configValue: any }) => {
|
||||
res.data.forEach((info: { attributeId: string; id: any; configValue: any }) => {
|
||||
const attributeCode = reactiveData.driverAttributeTable[info.attributeId];
|
||||
const attribute = reactiveData.driverAttributes.find((item) => item.attributeCode === attributeCode);
|
||||
if (attribute) {
|
||||
@@ -778,7 +778,7 @@ export default defineComponent({
|
||||
return listPointInfoByDeviceId(reactiveData.id)
|
||||
.then((infoRes) => {
|
||||
(infoRes.data || []).forEach(
|
||||
(info: { pointId: string; attributeId: string | number; id: string; configValue: unknown }) => {
|
||||
(info: { pointId: string; attributeId: string; id: string; configValue: unknown }) => {
|
||||
const attributeCode = reactiveData.pointAttributeTable[info.attributeId];
|
||||
const attribute = reactiveData.pointAttributes.find((item) => item.attributeCode === attributeCode);
|
||||
const row = rowTable[info.pointId];
|
||||
@@ -842,7 +842,7 @@ export default defineComponent({
|
||||
return listCommandInfoByDeviceId(reactiveData.id)
|
||||
.then((infoRes) => {
|
||||
(infoRes.data || []).forEach(
|
||||
(info: { commandId: string; attributeId: string | number; id: string; configValue: unknown }) => {
|
||||
(info: { commandId: string; attributeId: string; id: string; configValue: unknown }) => {
|
||||
const attributeCode = reactiveData.commandAttributeTable[info.attributeId];
|
||||
const attribute = reactiveData.commandAttributes.find((item) => item.attributeCode === attributeCode);
|
||||
const row = rowTable[String(info.commandId)];
|
||||
@@ -903,7 +903,7 @@ export default defineComponent({
|
||||
return listEventInfoByDeviceId(reactiveData.id)
|
||||
.then((infoRes) => {
|
||||
(infoRes.data || []).forEach(
|
||||
(info: { eventId: string; attributeId: string | number; id: string; configValue: unknown }) => {
|
||||
(info: { eventId: string; attributeId: string; id: string; configValue: unknown }) => {
|
||||
const attributeCode = reactiveData.eventAttributeTable[info.attributeId];
|
||||
const attribute = reactiveData.eventAttributes.find((item) => item.attributeCode === attributeCode);
|
||||
const row = rowTable[String(info.eventId)];
|
||||
|
||||
@@ -69,10 +69,10 @@ import {useEntityNames} from '@/composables/useEntityNames';
|
||||
import type {AlertSource} from '@/config/types/dashboard';
|
||||
|
||||
interface AlertRow {
|
||||
id: number | string;
|
||||
id: string;
|
||||
source: AlertSource;
|
||||
sourceId: number | string;
|
||||
pointId: number | string;
|
||||
sourceId: string;
|
||||
pointId: string;
|
||||
eventTypeFlag: number;
|
||||
confirmFlag: string;
|
||||
createTime: string;
|
||||
|
||||
@@ -70,9 +70,9 @@ import {streamLatest} from '@/api/dashboard';
|
||||
import DashboardCard from '@/components/card/dashboard/DashboardCard.vue';
|
||||
|
||||
interface Row {
|
||||
deviceId: number | string;
|
||||
pointId: number | string;
|
||||
driverId?: number | string;
|
||||
deviceId: string;
|
||||
pointId: string;
|
||||
driverId?: string;
|
||||
// driverName / deviceName / pointName are populated server-side by
|
||||
// DashboardServiceImpl.latestStream via the metadata facades, so the
|
||||
// feed can render the full tuple without a separate lookup round-trip.
|
||||
|
||||
@@ -132,7 +132,7 @@ const addThing = (form: unknown, done: () => void) => {
|
||||
});
|
||||
};
|
||||
|
||||
const disableThing = (id: number | string, done: () => void) => {
|
||||
const disableThing = (id: string, done: () => void) => {
|
||||
updateProfile({id: String(id), enableFlag: 'DISABLE'})
|
||||
.then(() => {
|
||||
successMessage();
|
||||
@@ -145,7 +145,7 @@ const disableThing = (id: number | string, done: () => void) => {
|
||||
});
|
||||
};
|
||||
|
||||
const enableThing = (id: number | string, done: () => void) => {
|
||||
const enableThing = (id: string, done: () => void) => {
|
||||
updateProfile({id: String(id), enableFlag: 'ENABLE'})
|
||||
.then(() => {
|
||||
successMessage();
|
||||
@@ -158,7 +158,7 @@ const enableThing = (id: number | string, done: () => void) => {
|
||||
});
|
||||
};
|
||||
|
||||
const deleteThing = (id: number | string, done: () => void) => {
|
||||
const deleteThing = (id: string, done: () => void) => {
|
||||
deleteProfile(String(id))
|
||||
.then(() => {
|
||||
successMessage();
|
||||
|
||||
@@ -118,7 +118,7 @@ const providers = ref<AgenticProvider[]>([]);
|
||||
|
||||
interface ModelConfigQuery {
|
||||
model?: string;
|
||||
providerId?: string | number;
|
||||
providerId?: string;
|
||||
enableFlag?: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ watch(locale, load);
|
||||
onMounted(load);
|
||||
onUnmounted(() => graph?.destroy());
|
||||
|
||||
const nodeId = (source: string, id: number | string) => `${source}:${id}`;
|
||||
const nodeId = (source: string, id: string) => `${source}:${id}`;
|
||||
|
||||
const renderGraph = () => {
|
||||
const container = graphRef.value;
|
||||
@@ -95,7 +95,7 @@ const renderGraph = () => {
|
||||
graph?.destroy();
|
||||
|
||||
// Convert pairs → unique nodes + weighted edges.
|
||||
const nodeMap = new Map<string, { id: string; data: { source: string; sid: number | string; name: string } }>();
|
||||
const nodeMap = new Map<string, { id: string; data: { source: string; sid: string; name: string } }>();
|
||||
const edges: Array<{ source: string; target: string; data: { weight: number } }> = [];
|
||||
for (const p of pairs.value) {
|
||||
const aId = nodeId(p.aSource, p.aSourceId);
|
||||
|
||||
@@ -61,7 +61,7 @@ import type {AlertSource} from '@/config/types/dashboard';
|
||||
|
||||
interface StormRow {
|
||||
source: AlertSource;
|
||||
sourceId: number | string;
|
||||
sourceId: string;
|
||||
count: number;
|
||||
}
|
||||
|
||||
|
||||
@@ -191,10 +191,10 @@ import type {RangeKey} from '@/components/segmented/RangeSegmented.vue';
|
||||
import RangeSegmented from '@/components/segmented/RangeSegmented.vue';
|
||||
|
||||
interface Row {
|
||||
id: number | string;
|
||||
id: string;
|
||||
source: 'point' | 'device' | 'driver';
|
||||
sourceId: number | string;
|
||||
pointId: number | string;
|
||||
sourceId: string;
|
||||
pointId: string;
|
||||
eventTypeFlag: number;
|
||||
alarmLevelFlag?: number;
|
||||
confirmFlag: string;
|
||||
|
||||
@@ -60,9 +60,9 @@ import {useEntityNames} from '@/composables/useEntityNames';
|
||||
import type {AlertSource} from '@/config/types/dashboard';
|
||||
|
||||
interface Row {
|
||||
id: number | string;
|
||||
id: string;
|
||||
source: AlertSource;
|
||||
sourceId: number | string;
|
||||
sourceId: string;
|
||||
createTime: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ import {listResourceByRoleId, listRoleResourceBind} from '@/api/roleResourceBind
|
||||
|
||||
interface ResourceNode {
|
||||
id: string;
|
||||
parentResourceId?: string | number;
|
||||
parentResourceId?: string;
|
||||
resourceName: string;
|
||||
resourceCode: string;
|
||||
resourceTypeFlag: string;
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import {expect, type Locator, type Page} from '@playwright/test';
|
||||
import JSONBigInt from 'json-bigint';
|
||||
import type {RouteIds} from './routes';
|
||||
|
||||
export interface PageHealth {
|
||||
@@ -60,7 +59,6 @@ export interface E2eDataContext {
|
||||
cleanup: () => Promise<void>;
|
||||
}
|
||||
|
||||
const JSONBigIntStr = JSONBigInt({storeAsString: true});
|
||||
const E2E_CREDENTIALS = {
|
||||
tenant: process.env.E2E_TENANT || 'default',
|
||||
name: process.env.E2E_USERNAME || 'dc3',
|
||||
@@ -194,7 +192,7 @@ export async function apiPost<T = unknown>(
|
||||
|
||||
let data: unknown;
|
||||
try {
|
||||
data = JSONBigIntStr.parse(response.text);
|
||||
data = JSON.parse(response.text);
|
||||
} catch {
|
||||
data = response.text;
|
||||
}
|
||||
@@ -244,7 +242,7 @@ export async function apiGet<T = unknown>(
|
||||
|
||||
let data: unknown;
|
||||
try {
|
||||
data = JSONBigIntStr.parse(response.text);
|
||||
data = JSON.parse(response.text);
|
||||
} catch {
|
||||
data = response.text;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ describe('axios request instance', () => {
|
||||
notificationSpies.warnMessage.mockClear();
|
||||
});
|
||||
|
||||
it('injects auth headers and parses large integer JSON responses as strings', async () => {
|
||||
it('injects auth headers and preserves string identifiers in JSON responses', async () => {
|
||||
setStorage(AUTH_HEADERS.TENANT, 'default');
|
||||
setStorage(AUTH_HEADERS.LOGIN, 'dc3');
|
||||
|
||||
@@ -62,7 +62,7 @@ describe('axios request instance', () => {
|
||||
// Token is NOT injected — it travels in an httpOnly cookie.
|
||||
expect(config.headers.get(AUTH_HEADERS.TOKEN)).toBeUndefined();
|
||||
|
||||
return responseOf(config, 200, '{"ok":true,"code":0,"message":"success","data":{"id":9007199254740993}}');
|
||||
return responseOf(config, 200, '{"ok":true,"code":0,"message":"success","data":{"id":"9007199254740993"}}');
|
||||
});
|
||||
|
||||
const response = await request({
|
||||
|
||||
Reference in New Issue
Block a user