feat(FEAT-MO-001): 同步市场概览前端契约
This commit is contained in:
@@ -26,14 +26,7 @@
|
|||||||
},
|
},
|
||||||
"warnings": { "items": { "type": "string" }, "type": "array" }
|
"warnings": { "items": { "type": "string" }, "type": "array" }
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["snapshotId", "asOf", "source", "status", "warnings", "data"],
|
||||||
"snapshotId",
|
|
||||||
"asOf",
|
|
||||||
"source",
|
|
||||||
"status",
|
|
||||||
"warnings",
|
|
||||||
"data"
|
|
||||||
],
|
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"DependencyHealthDto": {
|
"DependencyHealthDto": {
|
||||||
@@ -70,14 +63,7 @@
|
|||||||
},
|
},
|
||||||
"warnings": { "items": { "type": "string" }, "type": "array" }
|
"warnings": { "items": { "type": "string" }, "type": "array" }
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["snapshotId", "asOf", "source", "status", "warnings", "data"],
|
||||||
"snapshotId",
|
|
||||||
"asOf",
|
|
||||||
"source",
|
|
||||||
"status",
|
|
||||||
"warnings",
|
|
||||||
"data"
|
|
||||||
],
|
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"HealthDependenciesDto": {
|
"HealthDependenciesDto": {
|
||||||
@@ -139,14 +125,7 @@
|
|||||||
},
|
},
|
||||||
"warnings": { "items": { "type": "string" }, "type": "array" }
|
"warnings": { "items": { "type": "string" }, "type": "array" }
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["snapshotId", "asOf", "source", "status", "warnings", "data"],
|
||||||
"snapshotId",
|
|
||||||
"asOf",
|
|
||||||
"source",
|
|
||||||
"status",
|
|
||||||
"warnings",
|
|
||||||
"data"
|
|
||||||
],
|
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"SectorDataDto": {
|
"SectorDataDto": {
|
||||||
@@ -172,14 +151,7 @@
|
|||||||
},
|
},
|
||||||
"warnings": { "items": { "type": "string" }, "type": "array" }
|
"warnings": { "items": { "type": "string" }, "type": "array" }
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["snapshotId", "asOf", "source", "status", "warnings", "data"],
|
||||||
"snapshotId",
|
|
||||||
"asOf",
|
|
||||||
"source",
|
|
||||||
"status",
|
|
||||||
"warnings",
|
|
||||||
"data"
|
|
||||||
],
|
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"SummaryDataDto": {
|
"SummaryDataDto": {
|
||||||
@@ -217,14 +189,7 @@
|
|||||||
},
|
},
|
||||||
"warnings": { "items": { "type": "string" }, "type": "array" }
|
"warnings": { "items": { "type": "string" }, "type": "array" }
|
||||||
},
|
},
|
||||||
"required": [
|
"required": ["snapshotId", "asOf", "source", "status", "warnings", "data"],
|
||||||
"snapshotId",
|
|
||||||
"asOf",
|
|
||||||
"source",
|
|
||||||
"status",
|
|
||||||
"warnings",
|
|
||||||
"data"
|
|
||||||
],
|
|
||||||
"type": "object"
|
"type": "object"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,15 +20,125 @@ export interface paths {
|
|||||||
patch?: never;
|
patch?: never;
|
||||||
trace?: never;
|
trace?: never;
|
||||||
};
|
};
|
||||||
|
'/api/v1/market-overview/breadth': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
get: operations['MarketOverviewController_getBreadth'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
'/api/v1/market-overview/funds': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
get: operations['MarketOverviewController_getFunds'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
'/api/v1/market-overview/indices': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
get: operations['MarketOverviewController_getIndices'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
'/api/v1/market-overview/sectors': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
get: operations['MarketOverviewController_getSectors'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
'/api/v1/market-overview/summary': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
get: operations['MarketOverviewController_getSummary'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
export type webhooks = Record<string, never>;
|
export type webhooks = Record<string, never>;
|
||||||
export interface components {
|
export interface components {
|
||||||
schemas: {
|
schemas: {
|
||||||
|
BreadthDataDto: {
|
||||||
|
advancing: number;
|
||||||
|
declining: number;
|
||||||
|
unchanged: number;
|
||||||
|
};
|
||||||
|
BreadthResponseDto: {
|
||||||
|
/** Format: date-time */
|
||||||
|
asOf: string;
|
||||||
|
data: components['schemas']['BreadthDataDto'] | null;
|
||||||
|
snapshotId: string;
|
||||||
|
/** @enum {string} */
|
||||||
|
source: 'tdx';
|
||||||
|
/** @enum {string} */
|
||||||
|
status: 'fresh' | 'delayed' | 'partial' | 'unavailable';
|
||||||
|
warnings: string[];
|
||||||
|
};
|
||||||
DependencyHealthDto: {
|
DependencyHealthDto: {
|
||||||
detail: string;
|
detail: string;
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
status: 'healthy' | 'unavailable' | 'disabled';
|
status: 'healthy' | 'unavailable' | 'disabled';
|
||||||
};
|
};
|
||||||
|
FundDataDto: {
|
||||||
|
items: string[];
|
||||||
|
};
|
||||||
|
FundsResponseDto: {
|
||||||
|
/** Format: date-time */
|
||||||
|
asOf: string;
|
||||||
|
data: components['schemas']['FundDataDto'] | null;
|
||||||
|
snapshotId: string;
|
||||||
|
/** @enum {string} */
|
||||||
|
source: 'tdx';
|
||||||
|
/** @enum {string} */
|
||||||
|
status: 'fresh' | 'delayed' | 'partial' | 'unavailable';
|
||||||
|
warnings: string[];
|
||||||
|
};
|
||||||
HealthDependenciesDto: {
|
HealthDependenciesDto: {
|
||||||
mysql: components['schemas']['DependencyHealthDto'];
|
mysql: components['schemas']['DependencyHealthDto'];
|
||||||
redis: components['schemas']['DependencyHealthDto'];
|
redis: components['schemas']['DependencyHealthDto'];
|
||||||
@@ -43,6 +153,62 @@ export interface components {
|
|||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
status: 'healthy' | 'unavailable';
|
status: 'healthy' | 'unavailable';
|
||||||
};
|
};
|
||||||
|
IndexQuoteDto: {
|
||||||
|
changePercent?: number | null;
|
||||||
|
code: string;
|
||||||
|
/** @enum {string} */
|
||||||
|
direction: 'up' | 'down' | 'flat';
|
||||||
|
name: string;
|
||||||
|
price: number;
|
||||||
|
tradeDate: string;
|
||||||
|
};
|
||||||
|
IndicesDataDto: {
|
||||||
|
items: components['schemas']['IndexQuoteDto'][];
|
||||||
|
};
|
||||||
|
IndicesResponseDto: {
|
||||||
|
/** Format: date-time */
|
||||||
|
asOf: string;
|
||||||
|
data: components['schemas']['IndicesDataDto'] | null;
|
||||||
|
snapshotId: string;
|
||||||
|
/** @enum {string} */
|
||||||
|
source: 'tdx';
|
||||||
|
/** @enum {string} */
|
||||||
|
status: 'fresh' | 'delayed' | 'partial' | 'unavailable';
|
||||||
|
warnings: string[];
|
||||||
|
};
|
||||||
|
SectorDataDto: {
|
||||||
|
items: string[];
|
||||||
|
};
|
||||||
|
SectorsResponseDto: {
|
||||||
|
/** Format: date-time */
|
||||||
|
asOf: string;
|
||||||
|
data: components['schemas']['SectorDataDto'] | null;
|
||||||
|
snapshotId: string;
|
||||||
|
/** @enum {string} */
|
||||||
|
source: 'tdx';
|
||||||
|
/** @enum {string} */
|
||||||
|
status: 'fresh' | 'delayed' | 'partial' | 'unavailable';
|
||||||
|
warnings: string[];
|
||||||
|
};
|
||||||
|
SummaryDataDto: {
|
||||||
|
drivers: string[];
|
||||||
|
marketStatus: string;
|
||||||
|
risks: string[];
|
||||||
|
sentimentStatus: string;
|
||||||
|
verdict: string;
|
||||||
|
volumeStatus: string;
|
||||||
|
};
|
||||||
|
SummaryResponseDto: {
|
||||||
|
/** Format: date-time */
|
||||||
|
asOf: string;
|
||||||
|
data: components['schemas']['SummaryDataDto'] | null;
|
||||||
|
snapshotId: string;
|
||||||
|
/** @enum {string} */
|
||||||
|
source: 'tdx';
|
||||||
|
/** @enum {string} */
|
||||||
|
status: 'fresh' | 'delayed' | 'partial' | 'unavailable';
|
||||||
|
warnings: string[];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
responses: never;
|
responses: never;
|
||||||
parameters: never;
|
parameters: never;
|
||||||
@@ -79,4 +245,99 @@ export interface operations {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
MarketOverviewController_getBreadth: {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['BreadthResponseDto'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
MarketOverviewController_getFunds: {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['FundsResponseDto'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
MarketOverviewController_getIndices: {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['IndicesResponseDto'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
MarketOverviewController_getSectors: {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['SectorsResponseDto'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
MarketOverviewController_getSummary: {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['SummaryResponseDto'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { describe, expect, it, vi } from 'vitest';
|
||||||
|
|
||||||
|
import type { RequestClient } from '@/utils/request';
|
||||||
|
import { createMarketOverviewApi } from './index';
|
||||||
|
|
||||||
|
describe('市场概览业务 API', () => {
|
||||||
|
it('使用独立版本化路径请求五个模块', async () => {
|
||||||
|
const requestMock = vi.fn((config: Parameters<RequestClient>[0]) => {
|
||||||
|
void config;
|
||||||
|
return Promise.resolve({});
|
||||||
|
});
|
||||||
|
const requestClient = requestMock as unknown as RequestClient;
|
||||||
|
const api = createMarketOverviewApi(requestClient);
|
||||||
|
|
||||||
|
await api.getSummary();
|
||||||
|
await api.getIndices();
|
||||||
|
await api.getBreadth();
|
||||||
|
await api.getSectors();
|
||||||
|
await api.getFunds();
|
||||||
|
|
||||||
|
expect(requestMock.mock.calls.map(([config]) => config.url)).toEqual([
|
||||||
|
'/api/v1/market-overview/summary',
|
||||||
|
'/api/v1/market-overview/indices',
|
||||||
|
'/api/v1/market-overview/breadth',
|
||||||
|
'/api/v1/market-overview/sectors',
|
||||||
|
'/api/v1/market-overview/funds',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import request, { type RequestClient } from '@/utils/request';
|
||||||
|
import type {
|
||||||
|
BreadthResponse,
|
||||||
|
FundsResponse,
|
||||||
|
IndicesResponse,
|
||||||
|
SectorsResponse,
|
||||||
|
SummaryResponse,
|
||||||
|
} from '@/types/market-overview';
|
||||||
|
|
||||||
|
export function createMarketOverviewApi(requestClient: RequestClient = request) {
|
||||||
|
return {
|
||||||
|
getSummary: () => requestClient<SummaryResponse>({ method: 'get', url: '/api/v1/market-overview/summary' }),
|
||||||
|
getIndices: () => requestClient<IndicesResponse>({ method: 'get', url: '/api/v1/market-overview/indices' }),
|
||||||
|
getBreadth: () => requestClient<BreadthResponse>({ method: 'get', url: '/api/v1/market-overview/breadth' }),
|
||||||
|
getSectors: () => requestClient<SectorsResponse>({ method: 'get', url: '/api/v1/market-overview/sectors' }),
|
||||||
|
getFunds: () => requestClient<FundsResponse>({ method: 'get', url: '/api/v1/market-overview/funds' }),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const marketOverviewApi = createMarketOverviewApi();
|
||||||
|
|
||||||
|
export default marketOverviewApi;
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import type { components } from '@/api/generated/schema';
|
||||||
|
|
||||||
|
export type SummaryResponse = components['schemas']['SummaryResponseDto'];
|
||||||
|
export type IndicesResponse = components['schemas']['IndicesResponseDto'];
|
||||||
|
export type BreadthResponse = components['schemas']['BreadthResponseDto'];
|
||||||
|
export type SectorsResponse = components['schemas']['SectorsResponseDto'];
|
||||||
|
export type FundsResponse = components['schemas']['FundsResponseDto'];
|
||||||
|
export type SummaryData = NonNullable<SummaryResponse['data']>;
|
||||||
|
export type IndicesData = NonNullable<IndicesResponse['data']>;
|
||||||
|
export type BreadthData = NonNullable<BreadthResponse['data']>;
|
||||||
|
export type SectorsData = NonNullable<SectorsResponse['data']>;
|
||||||
|
export type FundsData = NonNullable<FundsResponse['data']>;
|
||||||
|
|
||||||
|
export type OverviewModuleStatus = 'idle' | 'loading' | 'ready' | 'error';
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { describe, expect, it, vi } from 'vitest';
|
||||||
|
|
||||||
|
import { useMarketOverview } from './useMarketOverview';
|
||||||
|
|
||||||
|
const response = { source: 'tdx', status: 'fresh', data: null, snapshotId: '20260818-101500', asOf: '2026-08-18T10:15:00+08:00', warnings: [] } as const;
|
||||||
|
|
||||||
|
describe('市场概览状态', () => {
|
||||||
|
it('并行加载五个模块,一个模块失败不影响其他模块', async () => {
|
||||||
|
const api = {
|
||||||
|
getSummary: vi.fn().mockResolvedValue(response),
|
||||||
|
getIndices: vi.fn().mockRejectedValue(new Error('failed')),
|
||||||
|
getBreadth: vi.fn().mockResolvedValue(response),
|
||||||
|
getSectors: vi.fn().mockResolvedValue(response),
|
||||||
|
getFunds: vi.fn().mockResolvedValue(response),
|
||||||
|
};
|
||||||
|
const state = useMarketOverview(api);
|
||||||
|
|
||||||
|
await state.refresh();
|
||||||
|
|
||||||
|
expect(state.summary.value.status).toBe('ready');
|
||||||
|
expect(state.indices.value.status).toBe('error');
|
||||||
|
expect(state.breadth.value.status).toBe('ready');
|
||||||
|
expect(state.isLoading.value).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('分析偏好写入本地存储并可恢复', () => {
|
||||||
|
const first = useMarketOverview({} as never);
|
||||||
|
first.setAnalysisHorizon('短线');
|
||||||
|
first.setAnalysisEngine('混合');
|
||||||
|
|
||||||
|
const second = useMarketOverview({} as never);
|
||||||
|
|
||||||
|
expect(second.analysisHorizon.value).toBe('短线');
|
||||||
|
expect(second.analysisEngine.value).toBe('混合');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
import { computed, ref } from 'vue';
|
||||||
|
|
||||||
|
import marketOverviewApi, { type createMarketOverviewApi } from '@/api/market-overview';
|
||||||
|
import type {
|
||||||
|
BreadthResponse,
|
||||||
|
FundsResponse,
|
||||||
|
IndicesResponse,
|
||||||
|
OverviewModuleStatus,
|
||||||
|
SectorsResponse,
|
||||||
|
SummaryResponse,
|
||||||
|
} from '@/types/market-overview';
|
||||||
|
|
||||||
|
type MarketResponse = SummaryResponse | IndicesResponse | BreadthResponse | SectorsResponse | FundsResponse;
|
||||||
|
|
||||||
|
export interface OverviewModuleState<TResponse extends MarketResponse> {
|
||||||
|
status: OverviewModuleStatus;
|
||||||
|
response: TResponse | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createState<TResponse extends MarketResponse>(): OverviewModuleState<TResponse> {
|
||||||
|
return { status: 'idle', response: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
function readPreference(key: string, fallback: string): string {
|
||||||
|
try {
|
||||||
|
return window.localStorage.getItem(key) || fallback;
|
||||||
|
} catch {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function writePreference(key: string, value: string): void {
|
||||||
|
try {
|
||||||
|
window.localStorage.setItem(key, value);
|
||||||
|
} catch {
|
||||||
|
// 隐私模式或禁用存储时只保留本次页面状态,不让偏好存储阻断行情展示。
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useMarketOverview(api: ReturnType<typeof createMarketOverviewApi> = marketOverviewApi) {
|
||||||
|
const summary = ref<OverviewModuleState<SummaryResponse>>(createState());
|
||||||
|
const indices = ref<OverviewModuleState<IndicesResponse>>(createState());
|
||||||
|
const breadth = ref<OverviewModuleState<BreadthResponse>>(createState());
|
||||||
|
const sectors = ref<OverviewModuleState<SectorsResponse>>(createState());
|
||||||
|
const funds = ref<OverviewModuleState<FundsResponse>>(createState());
|
||||||
|
const analysisHorizon = ref(readPreference('a-share-analysis:overview-horizon', '综合'));
|
||||||
|
const analysisEngine = ref(readPreference('a-share-analysis:overview-engine', '规则'));
|
||||||
|
const isLoading = computed(() =>
|
||||||
|
[summary.value, indices.value, breadth.value, sectors.value, funds.value].some(
|
||||||
|
(module) => module.status === 'loading',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
function setLoading() {
|
||||||
|
summary.value.status = 'loading';
|
||||||
|
indices.value.status = 'loading';
|
||||||
|
breadth.value.status = 'loading';
|
||||||
|
sectors.value.status = 'loading';
|
||||||
|
funds.value.status = 'loading';
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadModule<TResponse extends MarketResponse>(
|
||||||
|
state: { value: OverviewModuleState<TResponse> },
|
||||||
|
loader: () => Promise<TResponse>,
|
||||||
|
): Promise<void> {
|
||||||
|
try {
|
||||||
|
state.value.response = await loader();
|
||||||
|
state.value.status = 'ready';
|
||||||
|
} catch {
|
||||||
|
state.value.response = null;
|
||||||
|
state.value.status = 'error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function refresh(): Promise<void> {
|
||||||
|
setLoading();
|
||||||
|
await Promise.all([
|
||||||
|
loadModule(summary, api.getSummary),
|
||||||
|
loadModule(indices, api.getIndices),
|
||||||
|
loadModule(breadth, api.getBreadth),
|
||||||
|
loadModule(sectors, api.getSectors),
|
||||||
|
loadModule(funds, api.getFunds),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAnalysisHorizon(value: string) {
|
||||||
|
analysisHorizon.value = value;
|
||||||
|
writePreference('a-share-analysis:overview-horizon', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAnalysisEngine(value: string) {
|
||||||
|
analysisEngine.value = value;
|
||||||
|
writePreference('a-share-analysis:overview-engine', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
summary,
|
||||||
|
indices,
|
||||||
|
breadth,
|
||||||
|
sectors,
|
||||||
|
funds,
|
||||||
|
isLoading,
|
||||||
|
analysisHorizon,
|
||||||
|
analysisEngine,
|
||||||
|
refresh,
|
||||||
|
setAnalysisHorizon,
|
||||||
|
setAnalysisEngine,
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user