feat: sync vehicle monitoring and accumulated platform updates

Add monitoring metrics, numeric sorting, report-time display, vehicle number labels, and map layout fixes. Include accumulated mileage, hydrogen, OneOS authentication, open platform, ingestion, deployment, and UI updates.

Exclude temporary files, generated reports, and credentials. Validate frontend 632 tests and production build, API packages, vehicle-map tests, and release installer tests. Gateway suite has one pre-existing date-sensitive identity throttling test failure reproduced on the parent commit.
This commit is contained in:
lingniu
2026-10-26 18:05:59 +08:00
parent 8b32ae2988
commit d6b957dfc8
290 changed files with 28238 additions and 1647 deletions
@@ -11,6 +11,9 @@ import {
afterEach(() => {
delete window.__LINGNIU_APP_CONFIG__;
delete window.AMapLoader;
delete window.AMapUI;
delete window.AMapUIProtocol;
document.querySelector('script[src="https://webapi.amap.com/ui/1.1/main.js?v=1.1.1"]')?.remove();
document.querySelector('script[src="https://webapi.amap.com/loader.js"]')?.remove();
});
@@ -71,3 +74,32 @@ test('removes a failed loader script so a later request can recover', async () =
window.AMapLoader = { load: vi.fn().mockResolvedValue(amap) };
await expect(loadAMap(['AMap.ToolBar'])).resolves.toBe(amap);
});
test('resolves the local security proxy to the absolute URL required by the SDK', async () => {
window.__LINGNIU_APP_CONFIG__ = { amapWebJsKey: 'amap-web-key', amapSecurityServiceHost: '/_AMapService' };
window.AMapLoader = { load: vi.fn().mockResolvedValue({}) };
await loadAMap(['AMap.Scale']);
expect(window._AMapSecurityConfig).toEqual({ serviceHost: `${window.location.origin}/_AMapService` });
});
test('waits for the base SDK before district UI and retries a failed SDK initialization', async () => {
vi.resetModules();
const { loadAMapDistrictExplorer } = await import('./amap');
let completeSDK!: (value: AMapLike) => void;
const sdk = new Promise<AMapLike>((resolve) => { completeSDK = resolve; });
const load = vi.fn().mockRejectedValueOnce(new Error('SDK unavailable')).mockReturnValueOnce(sdk);
window.__LINGNIU_APP_CONFIG__ = { amapWebJsKey: 'amap-web-key' };
window.AMapLoader = { load };
const uiScript = () => document.querySelector<HTMLScriptElement>('script[src="https://webapi.amap.com/ui/1.1/main.js?v=1.1.1"]');
await expect(loadAMapDistrictExplorer()).rejects.toThrow('SDK unavailable');
expect(uiScript()).toBeNull();
const district = loadAMapDistrictExplorer();
await vi.waitFor(() => expect(load).toHaveBeenCalledTimes(2));
expect(uiScript()).toBeNull();
completeSDK({} as AMapLike);
await vi.waitFor(() => expect(uiScript()).not.toBeNull());
class DistrictExplorer {}
window.AMapUI = { loadUI: (_modules, callback) => callback(DistrictExplorer) };
uiScript()!.dispatchEvent(new Event('load'));
await expect(district).resolves.toBe(DistrictExplorer);
});
@@ -181,6 +181,8 @@ function loadScript(src: string) {
}
function loadAMapUIScript() {
// AMapUI otherwise inherits HTTP from the local development page for modules.
window.AMapUIProtocol = 'https:';
const src = 'https://webapi.amap.com/ui/1.1/main.js?v=1.1.1';
return new Promise<void>((resolve, reject) => {
if (window.AMapUI) {
@@ -316,7 +318,7 @@ export function loadAMap(plugins: AMapPlugin[] = ['AMap.Scale']) {
return cached;
}
if (config.securityServiceHost) {
window._AMapSecurityConfig = { serviceHost: config.securityServiceHost };
window._AMapSecurityConfig = { serviceHost: new URL(config.securityServiceHost, window.location.origin).href };
} else if (config.securityJsCode) {
window._AMapSecurityConfig = { securityJsCode: config.securityJsCode };
}
@@ -340,6 +342,8 @@ export function loadAMap(plugins: AMapPlugin[] = ['AMap.Scale']) {
}
export async function loadAMapDistrictExplorer(): Promise<AMapDistrictExplorerConstructor> {
// Province aggregation can start before the map effect finishes loading the SDK.
await loadAMap([]);
await loadAMapUIScript();
if (!window.AMapUI) {
throw new Error('高德行政区组件不可用');