feat: implement comprehensive Polymarket weather analysis service with frontend dashboard and market scanning capabilities

This commit is contained in:
2569718930@qq.com
2026-04-23 20:45:32 +08:00
parent 4f57d4ed1a
commit 54b326ff42
12 changed files with 323 additions and 154 deletions
+52 -3
View File
@@ -45,6 +45,11 @@ interface DashboardStoreValue extends DashboardState {
ensureCityMarketScan: (
cityName: string,
force?: boolean,
options?: {
lite?: boolean;
marketSlug?: string | null;
targetDate?: string | null;
},
) => Promise<CityDetail["market_scan"] | null>;
focusCity: (cityName: string) => Promise<void>;
forecastModalMode: ForecastModalMode | null;
@@ -298,6 +303,39 @@ function mergeCityDetail(
};
}
function mergeMarketScan(
current: CityDetail["market_scan"] | undefined,
incoming: CityDetail["market_scan"] | null | undefined,
): CityDetail["market_scan"] | undefined {
if (!incoming) return current;
if (!current) return incoming || undefined;
const preserveHeavySlices = incoming.scan_scope === "lite";
const nextTopBuckets =
preserveHeavySlices &&
(!Array.isArray(incoming.top_buckets) || incoming.top_buckets.length === 0)
? current.top_buckets
: incoming.top_buckets;
const nextAllBuckets =
preserveHeavySlices &&
(!Array.isArray(incoming.all_buckets) || incoming.all_buckets.length === 0)
? current.all_buckets
: incoming.all_buckets;
const nextRecentTrades =
preserveHeavySlices &&
(!Array.isArray(incoming.recent_trades) || incoming.recent_trades.length === 0)
? current.recent_trades
: incoming.recent_trades;
return {
...current,
...incoming,
top_buckets: nextTopBuckets,
all_buckets: nextAllBuckets,
recent_trades: nextRecentTrades,
};
}
function toHistoryMeta(payload: HistoryPayload): HistoryPayloadMeta {
const history = Array.isArray(payload.history) ? payload.history : [];
const previewCount = Number(payload.preview_count || history.length || 0);
@@ -569,7 +607,15 @@ export function DashboardStoreProvider({
return detail;
};
const ensureCityMarketScan = async (cityName: string, force = false) => {
const ensureCityMarketScan = async (
cityName: string,
force = false,
options?: {
lite?: boolean;
marketSlug?: string | null;
targetDate?: string | null;
},
) => {
let cached = cityDetailsByName[cityName];
try {
if (!cached) {
@@ -577,7 +623,10 @@ export function DashboardStoreProvider({
}
const payload = await dashboardClient.getCityMarketScan(cityName, {
force,
targetDate: cached?.local_date || selectedForecastDate || null,
lite: options?.lite === true,
marketSlug: options?.marketSlug || null,
targetDate:
options?.targetDate || cached?.local_date || selectedForecastDate || null,
});
if (!payload.market_scan) return null;
setCityDetailsByName((current) => {
@@ -587,7 +636,7 @@ export function DashboardStoreProvider({
...current,
[cityName]: {
...detail,
market_scan: payload.market_scan || undefined,
market_scan: mergeMarketScan(detail.market_scan, payload.market_scan),
},
};
});