移除 Polymarket 价格层 UI:删除 MarketDecisionLine 组件及相关数据流
This commit is contained in:
@@ -10,7 +10,6 @@ import { MobileDecisionCard } from "@/components/dashboard/scan-terminal/MobileD
|
|||||||
import { ModelEvidencePanel } from "@/components/dashboard/scan-terminal/ModelEvidencePanel";
|
import { ModelEvidencePanel } from "@/components/dashboard/scan-terminal/ModelEvidencePanel";
|
||||||
import { WeatherDecisionBand } from "@/components/dashboard/scan-terminal/WeatherDecisionBand";
|
import { WeatherDecisionBand } from "@/components/dashboard/scan-terminal/WeatherDecisionBand";
|
||||||
import {
|
import {
|
||||||
buildMarketDecisionView,
|
|
||||||
buildWeatherDecisionView,
|
buildWeatherDecisionView,
|
||||||
resolveExpectedHighCandidate,
|
resolveExpectedHighCandidate,
|
||||||
} from "@/components/dashboard/scan-terminal/city-card-decision-utils";
|
} from "@/components/dashboard/scan-terminal/city-card-decision-utils";
|
||||||
@@ -24,7 +23,6 @@ import { LoadingSignal } from "@/components/dashboard/scan-terminal/LoadingSigna
|
|||||||
import type { AiPinnedCity } from "@/components/dashboard/scan-terminal/types";
|
import type { AiPinnedCity } from "@/components/dashboard/scan-terminal/types";
|
||||||
import {
|
import {
|
||||||
useAiCityForecast,
|
useAiCityForecast,
|
||||||
useCityMarketScan,
|
|
||||||
} from "@/components/dashboard/scan-terminal/use-ai-city-card-data";
|
} from "@/components/dashboard/scan-terminal/use-ai-city-card-data";
|
||||||
import { getDisplayAirportPrimary } from "@/lib/airport-observation-display";
|
import { getDisplayAirportPrimary } from "@/lib/airport-observation-display";
|
||||||
import type { CityDetail, ScanOpportunityRow } from "@/lib/dashboard-types";
|
import type { CityDetail, ScanOpportunityRow } from "@/lib/dashboard-types";
|
||||||
@@ -184,28 +182,6 @@ function buildModelFreshnessValue(detail: CityDetail | null, locale: string, isE
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildMarketFreshnessValue({
|
|
||||||
isEn,
|
|
||||||
marketScan,
|
|
||||||
marketStatus,
|
|
||||||
}: {
|
|
||||||
isEn: boolean;
|
|
||||||
marketScan: ReturnType<typeof useCityMarketScan>["marketScan"];
|
|
||||||
marketStatus: ReturnType<typeof useCityMarketScan>["marketStatus"];
|
|
||||||
}) {
|
|
||||||
if (marketStatus === "loading") return isEn ? "syncing" : "同步中";
|
|
||||||
if (!marketScan?.available) return isEn ? "temporarily unavailable" : "暂不可用";
|
|
||||||
const quoteAgeMs = Number(
|
|
||||||
marketScan.quote_age_ms ??
|
|
||||||
marketScan.yes_token?.quote_age_ms ??
|
|
||||||
marketScan.no_token?.quote_age_ms,
|
|
||||||
);
|
|
||||||
if (Number.isFinite(quoteAgeMs) && quoteAgeMs >= 0) {
|
|
||||||
return formatFreshnessAge(quoteAgeMs / 60_000, isEn);
|
|
||||||
}
|
|
||||||
return isEn ? "synced" : "已同步";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AiPinnedCityCard({
|
export function AiPinnedCityCard({
|
||||||
item,
|
item,
|
||||||
detail,
|
detail,
|
||||||
@@ -287,11 +263,6 @@ export function AiPinnedCityCard({
|
|||||||
locale,
|
locale,
|
||||||
report,
|
report,
|
||||||
});
|
});
|
||||||
const { marketScan, marketStatus } = useCityMarketScan({
|
|
||||||
detail,
|
|
||||||
detailCityName,
|
|
||||||
enabled: Boolean(detail),
|
|
||||||
});
|
|
||||||
const isRefreshing = refreshingDetail || aiForecast.status === "loading";
|
const isRefreshing = refreshingDetail || aiForecast.status === "loading";
|
||||||
const [isCompactCard, setIsCompactCard] = useState(false);
|
const [isCompactCard, setIsCompactCard] = useState(false);
|
||||||
|
|
||||||
@@ -382,13 +353,6 @@ export function AiPinnedCityCard({
|
|||||||
debNumber != null
|
debNumber != null
|
||||||
? formatTemperatureValue(debNumber, tempSymbol, { digits: 1 })
|
? formatTemperatureValue(debNumber, tempSymbol, { digits: 1 })
|
||||||
: "--";
|
: "--";
|
||||||
const marketDecisionView = buildMarketDecisionView({
|
|
||||||
expectedHigh: decisionExpectedHighNumber,
|
|
||||||
isEn,
|
|
||||||
marketScan,
|
|
||||||
marketStatus,
|
|
||||||
tempSymbol,
|
|
||||||
});
|
|
||||||
const aiMeta = aiCityForecast?._polyweather_meta || null;
|
const aiMeta = aiCityForecast?._polyweather_meta || null;
|
||||||
const guardReason = aiMeta?.deterministic_guard_reason || {};
|
const guardReason = aiMeta?.deterministic_guard_reason || {};
|
||||||
const observationStale = Boolean(
|
const observationStale = Boolean(
|
||||||
@@ -436,7 +400,6 @@ export function AiPinnedCityCard({
|
|||||||
aiRuleEvidenceMode,
|
aiRuleEvidenceMode,
|
||||||
isEn,
|
isEn,
|
||||||
isHkoObservation,
|
isHkoObservation,
|
||||||
marketDecisionView,
|
|
||||||
modelHighlyConsistent,
|
modelHighlyConsistent,
|
||||||
needsNextBulletin,
|
needsNextBulletin,
|
||||||
observationStale,
|
observationStale,
|
||||||
@@ -451,16 +414,6 @@ export function AiPinnedCityCard({
|
|||||||
value: buildModelFreshnessValue(detail, locale, isEn),
|
value: buildModelFreshnessValue(detail, locale, isEn),
|
||||||
tone: "fresh" as const,
|
tone: "fresh" as const,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: isEn ? "Market" : "市场价格",
|
|
||||||
value: buildMarketFreshnessValue({ isEn, marketScan, marketStatus }),
|
|
||||||
tone:
|
|
||||||
marketDecisionView.status === "ready"
|
|
||||||
? ("fresh" as const)
|
|
||||||
: marketDecisionView.status === "loading"
|
|
||||||
? ("loading" as const)
|
|
||||||
: ("stale" as const),
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
const freshnessSeparator = isEn ? ": " : ":";
|
const freshnessSeparator = isEn ? ": " : ":";
|
||||||
const localizedRisksRaw =
|
const localizedRisksRaw =
|
||||||
@@ -480,17 +433,6 @@ export function AiPinnedCityCard({
|
|||||||
(isEn ? aiForecast.payload?.reason_en : aiForecast.payload?.reason_zh) ||
|
(isEn ? aiForecast.payload?.reason_en : aiForecast.payload?.reason_zh) ||
|
||||||
aiForecast.payload?.reason ||
|
aiForecast.payload?.reason ||
|
||||||
"";
|
"";
|
||||||
const marketLineText =
|
|
||||||
marketDecisionView.status === "ready"
|
|
||||||
? `${marketDecisionView.bucketLabel} · ${marketDecisionView.priceText}`
|
|
||||||
: marketDecisionView.status === "loading"
|
|
||||||
? isEn
|
|
||||||
? "syncing"
|
|
||||||
: "同步中"
|
|
||||||
: isEn
|
|
||||||
? "temporarily unavailable"
|
|
||||||
: "暂不可用";
|
|
||||||
|
|
||||||
const collapseId = `ai-city-body-${normalizeCityKey(item.cityName) || item.addedAt}`;
|
const collapseId = `ai-city-body-${normalizeCityKey(item.cityName) || item.addedAt}`;
|
||||||
const loadingCopy = getCityLoadingCopy({ isEn, isHkoObservation });
|
const loadingCopy = getCityLoadingCopy({ isEn, isHkoObservation });
|
||||||
const handleRefresh = (event: MouseEvent<HTMLButtonElement>) => {
|
const handleRefresh = (event: MouseEvent<HTMLButtonElement>) => {
|
||||||
@@ -522,7 +464,6 @@ export function AiPinnedCityCard({
|
|||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
data-ai-status={decisionState.aiStatus}
|
data-ai-status={decisionState.aiStatus}
|
||||||
data-evidence-quality={decisionState.evidenceQuality}
|
data-evidence-quality={decisionState.evidenceQuality}
|
||||||
data-market-status={decisionState.marketStatus}
|
|
||||||
data-recommendation={decisionState.recommendation}
|
data-recommendation={decisionState.recommendation}
|
||||||
data-urgency={decisionState.urgency}
|
data-urgency={decisionState.urgency}
|
||||||
>
|
>
|
||||||
@@ -550,8 +491,6 @@ export function AiPinnedCityCard({
|
|||||||
isRefreshing={isRefreshing}
|
isRefreshing={isRefreshing}
|
||||||
localModelSupportNote={localModelSupportNote}
|
localModelSupportNote={localModelSupportNote}
|
||||||
localizedFinalJudgment={localizedFinalJudgment}
|
localizedFinalJudgment={localizedFinalJudgment}
|
||||||
marketDecisionView={marketDecisionView}
|
|
||||||
marketLineText={marketLineText}
|
|
||||||
onRefresh={handleRefresh}
|
onRefresh={handleRefresh}
|
||||||
onRemove={handleRemove}
|
onRemove={handleRemove}
|
||||||
peakWindow={peakWindow}
|
peakWindow={peakWindow}
|
||||||
@@ -587,8 +526,6 @@ export function AiPinnedCityCard({
|
|||||||
decisionView={decisionView}
|
decisionView={decisionView}
|
||||||
decisionWhyText={decisionState.primaryReason}
|
decisionWhyText={decisionState.primaryReason}
|
||||||
isEn={isEn}
|
isEn={isEn}
|
||||||
marketDecisionView={marketDecisionView}
|
|
||||||
marketLineText={marketLineText}
|
|
||||||
paceDeltaText={paceView?.deltaText || "--"}
|
paceDeltaText={paceView?.deltaText || "--"}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ import {
|
|||||||
type StatusTone,
|
type StatusTone,
|
||||||
} from "@/components/dashboard/scan-terminal/CityStatusTags";
|
} from "@/components/dashboard/scan-terminal/CityStatusTags";
|
||||||
import { LoadingSignal } from "@/components/dashboard/scan-terminal/LoadingSignal";
|
import { LoadingSignal } from "@/components/dashboard/scan-terminal/LoadingSignal";
|
||||||
import { MarketDecisionLine } from "@/components/dashboard/scan-terminal/MarketDecisionLine";
|
|
||||||
import { ModelEvidencePanel } from "@/components/dashboard/scan-terminal/ModelEvidencePanel";
|
import { ModelEvidencePanel } from "@/components/dashboard/scan-terminal/ModelEvidencePanel";
|
||||||
import type { MarketDecisionView } from "@/components/dashboard/scan-terminal/city-card-decision-utils";
|
|
||||||
import type { CityDecisionState } from "@/components/dashboard/scan-terminal/city-decision-state";
|
import type { CityDecisionState } from "@/components/dashboard/scan-terminal/city-decision-state";
|
||||||
import {
|
import {
|
||||||
getCityLoadingCopy,
|
getCityLoadingCopy,
|
||||||
@@ -48,8 +46,6 @@ export function MobileDecisionCard({
|
|||||||
isRefreshing,
|
isRefreshing,
|
||||||
localModelSupportNote,
|
localModelSupportNote,
|
||||||
localizedFinalJudgment,
|
localizedFinalJudgment,
|
||||||
marketDecisionView,
|
|
||||||
marketLineText,
|
|
||||||
onRefresh,
|
onRefresh,
|
||||||
onRemove,
|
onRemove,
|
||||||
peakWindow,
|
peakWindow,
|
||||||
@@ -78,8 +74,6 @@ export function MobileDecisionCard({
|
|||||||
isRefreshing: boolean;
|
isRefreshing: boolean;
|
||||||
localModelSupportNote: string;
|
localModelSupportNote: string;
|
||||||
localizedFinalJudgment: string;
|
localizedFinalJudgment: string;
|
||||||
marketDecisionView: MarketDecisionView;
|
|
||||||
marketLineText: string;
|
|
||||||
onRefresh: (event: MouseEvent<HTMLButtonElement>) => void;
|
onRefresh: (event: MouseEvent<HTMLButtonElement>) => void;
|
||||||
onRemove: (event: MouseEvent<HTMLButtonElement>) => void;
|
onRemove: (event: MouseEvent<HTMLButtonElement>) => void;
|
||||||
peakWindow: string;
|
peakWindow: string;
|
||||||
@@ -140,11 +134,6 @@ export function MobileDecisionCard({
|
|||||||
|
|
||||||
<p className="scan-mobile-decision-reason">{decisionState.primaryReason}</p>
|
<p className="scan-mobile-decision-reason">{decisionState.primaryReason}</p>
|
||||||
<CityStatusTags tags={statusTags} />
|
<CityStatusTags tags={statusTags} />
|
||||||
<MarketDecisionLine
|
|
||||||
isEn={isEn}
|
|
||||||
marketDecisionView={marketDecisionView}
|
|
||||||
marketLineText={marketLineText}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{!detail ? (
|
{!detail ? (
|
||||||
<div className="scan-ai-city-loading">
|
<div className="scan-ai-city-loading">
|
||||||
|
|||||||
@@ -1,25 +1,17 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import type {
|
import type { WeatherDecisionView } from "@/components/dashboard/scan-terminal/city-card-decision-utils";
|
||||||
MarketDecisionView,
|
|
||||||
WeatherDecisionView,
|
|
||||||
} from "@/components/dashboard/scan-terminal/city-card-decision-utils";
|
|
||||||
import { MarketDecisionLine } from "@/components/dashboard/scan-terminal/MarketDecisionLine";
|
|
||||||
|
|
||||||
export function WeatherDecisionBand({
|
export function WeatherDecisionBand({
|
||||||
decisionView,
|
decisionView,
|
||||||
decisionWhyText,
|
decisionWhyText,
|
||||||
isEn,
|
isEn,
|
||||||
marketDecisionView,
|
|
||||||
marketLineText,
|
|
||||||
paceDeltaText,
|
paceDeltaText,
|
||||||
}: {
|
}: {
|
||||||
decisionView: WeatherDecisionView;
|
decisionView: WeatherDecisionView;
|
||||||
decisionWhyText: string;
|
decisionWhyText: string;
|
||||||
isEn: boolean;
|
isEn: boolean;
|
||||||
marketDecisionView: MarketDecisionView;
|
|
||||||
marketLineText: string;
|
|
||||||
paceDeltaText: string;
|
paceDeltaText: string;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
@@ -28,11 +20,6 @@ export function WeatherDecisionBand({
|
|||||||
<span>{decisionView.kicker}</span>
|
<span>{decisionView.kicker}</span>
|
||||||
<strong>{decisionView.action}</strong>
|
<strong>{decisionView.action}</strong>
|
||||||
<p className="scan-ai-decision-why">{decisionWhyText}</p>
|
<p className="scan-ai-decision-why">{decisionWhyText}</p>
|
||||||
<MarketDecisionLine
|
|
||||||
isEn={isEn}
|
|
||||||
marketDecisionView={marketDecisionView}
|
|
||||||
marketLineText={marketLineText}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="scan-ai-decision-metrics">
|
<div className="scan-ai-decision-metrics">
|
||||||
<span>
|
<span>
|
||||||
@@ -42,10 +29,6 @@ export function WeatherDecisionBand({
|
|||||||
<span>
|
<span>
|
||||||
{isEn ? "Path delta" : "路径偏差"} <b>{paceDeltaText}</b>
|
{isEn ? "Path delta" : "路径偏差"} <b>{paceDeltaText}</b>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
|
||||||
{isEn ? "Quote status" : "报价状态"}{" "}
|
|
||||||
<b>{marketDecisionView.status === "ready" ? (isEn ? "Ready" : "已同步") : marketDecisionView.status === "loading" ? (isEn ? "Loading" : "同步中") : (isEn ? "Unavailable" : "不可用")}</b>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ export function runTests() {
|
|||||||
aiRuleEvidenceMode: false,
|
aiRuleEvidenceMode: false,
|
||||||
isEn: false,
|
isEn: false,
|
||||||
isHkoObservation: false,
|
isHkoObservation: false,
|
||||||
marketDecisionView: market("ready"),
|
|
||||||
modelHighlyConsistent: true,
|
modelHighlyConsistent: true,
|
||||||
needsNextBulletin: false,
|
needsNextBulletin: false,
|
||||||
observationStale: false,
|
observationStale: false,
|
||||||
@@ -51,7 +50,6 @@ export function runTests() {
|
|||||||
aiRuleEvidenceMode: false,
|
aiRuleEvidenceMode: false,
|
||||||
isEn: false,
|
isEn: false,
|
||||||
isHkoObservation: false,
|
isHkoObservation: false,
|
||||||
marketDecisionView: market("unavailable"),
|
|
||||||
modelHighlyConsistent: false,
|
modelHighlyConsistent: false,
|
||||||
needsNextBulletin: false,
|
needsNextBulletin: false,
|
||||||
observationStale: false,
|
observationStale: false,
|
||||||
@@ -61,9 +59,6 @@ export function runTests() {
|
|||||||
peakHasPassed: false,
|
peakHasPassed: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.equal(marketUnavailable.marketStatus, "unavailable");
|
|
||||||
assert.match(marketUnavailable.primaryReason, /暂无可交易价格/);
|
|
||||||
assert.doesNotMatch(marketUnavailable.primaryReason, /未接入|系统缺失|系统坏/);
|
|
||||||
|
|
||||||
const fallback = buildCityDecisionState({
|
const fallback = buildCityDecisionState({
|
||||||
aiCityForecast: null,
|
aiCityForecast: null,
|
||||||
@@ -71,7 +66,6 @@ export function runTests() {
|
|||||||
aiRuleEvidenceMode: true,
|
aiRuleEvidenceMode: true,
|
||||||
isEn: false,
|
isEn: false,
|
||||||
isHkoObservation: false,
|
isHkoObservation: false,
|
||||||
marketDecisionView: market("ready"),
|
|
||||||
modelHighlyConsistent: false,
|
modelHighlyConsistent: false,
|
||||||
needsNextBulletin: false,
|
needsNextBulletin: false,
|
||||||
observationStale: false,
|
observationStale: false,
|
||||||
@@ -91,7 +85,6 @@ export function runTests() {
|
|||||||
aiRuleEvidenceMode: false,
|
aiRuleEvidenceMode: false,
|
||||||
isEn: false,
|
isEn: false,
|
||||||
isHkoObservation: false,
|
isHkoObservation: false,
|
||||||
marketDecisionView: market("ready"),
|
|
||||||
modelHighlyConsistent: false,
|
modelHighlyConsistent: false,
|
||||||
needsNextBulletin: true,
|
needsNextBulletin: true,
|
||||||
observationStale: false,
|
observationStale: false,
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ export function runTests() {
|
|||||||
aiRuleEvidenceMode: false,
|
aiRuleEvidenceMode: false,
|
||||||
isEn: false,
|
isEn: false,
|
||||||
isHkoObservation: false,
|
isHkoObservation: false,
|
||||||
marketDecisionView: readyMarket,
|
|
||||||
modelHighlyConsistent: true,
|
modelHighlyConsistent: true,
|
||||||
needsNextBulletin: false,
|
needsNextBulletin: false,
|
||||||
observationStale: false,
|
observationStale: false,
|
||||||
@@ -47,7 +46,6 @@ export function runTests() {
|
|||||||
aiRuleEvidenceMode: false,
|
aiRuleEvidenceMode: false,
|
||||||
isEn: false,
|
isEn: false,
|
||||||
isHkoObservation: false,
|
isHkoObservation: false,
|
||||||
marketDecisionView: readyMarket,
|
|
||||||
modelHighlyConsistent: false,
|
modelHighlyConsistent: false,
|
||||||
needsNextBulletin: false,
|
needsNextBulletin: false,
|
||||||
observationStale: true,
|
observationStale: true,
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import type { MarketDecisionView } from "@/components/dashboard/scan-terminal/city-card-decision-utils";
|
|
||||||
import type {
|
import type {
|
||||||
AiCityForecastPayload,
|
AiCityForecastPayload,
|
||||||
AiCityForecastState,
|
AiCityForecastState,
|
||||||
@@ -12,7 +11,6 @@ export type CityDecisionAiStatus =
|
|||||||
| "deepseek-loading"
|
| "deepseek-loading"
|
||||||
| "complete"
|
| "complete"
|
||||||
| "fallback";
|
| "fallback";
|
||||||
export type CityDecisionMarketStatus = "ready" | "loading" | "unavailable";
|
|
||||||
export type StatusBadgeTone = "green" | "blue" | "amber" | "red" | "muted";
|
export type StatusBadgeTone = "green" | "blue" | "amber" | "red" | "muted";
|
||||||
|
|
||||||
export type StatusBadge = {
|
export type StatusBadge = {
|
||||||
@@ -27,8 +25,6 @@ export type CityDecisionState = {
|
|||||||
aiStatus: CityDecisionAiStatus;
|
aiStatus: CityDecisionAiStatus;
|
||||||
aiStatusLabel: string;
|
aiStatusLabel: string;
|
||||||
aiStatusTone: StatusBadgeTone;
|
aiStatusTone: StatusBadgeTone;
|
||||||
marketStatus: CityDecisionMarketStatus;
|
|
||||||
marketStatusTone: StatusBadgeTone;
|
|
||||||
badges: StatusBadge[];
|
badges: StatusBadge[];
|
||||||
primaryReason: string;
|
primaryReason: string;
|
||||||
};
|
};
|
||||||
@@ -82,19 +78,12 @@ function resolveAiStatusView(aiStatus: CityDecisionAiStatus, isEn: boolean) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveMarketTone(status: CityDecisionMarketStatus): StatusBadgeTone {
|
|
||||||
if (status === "ready") return "green";
|
|
||||||
if (status === "loading") return "blue";
|
|
||||||
return "muted";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildCityDecisionState({
|
export function buildCityDecisionState({
|
||||||
aiCityForecast,
|
aiCityForecast,
|
||||||
aiForecast,
|
aiForecast,
|
||||||
aiRuleEvidenceMode,
|
aiRuleEvidenceMode,
|
||||||
isEn,
|
isEn,
|
||||||
isHkoObservation,
|
isHkoObservation,
|
||||||
marketDecisionView,
|
|
||||||
modelHighlyConsistent,
|
modelHighlyConsistent,
|
||||||
needsNextBulletin,
|
needsNextBulletin,
|
||||||
observationStale,
|
observationStale,
|
||||||
@@ -108,7 +97,6 @@ export function buildCityDecisionState({
|
|||||||
aiRuleEvidenceMode: boolean;
|
aiRuleEvidenceMode: boolean;
|
||||||
isEn: boolean;
|
isEn: boolean;
|
||||||
isHkoObservation: boolean;
|
isHkoObservation: boolean;
|
||||||
marketDecisionView: MarketDecisionView;
|
|
||||||
modelHighlyConsistent: boolean;
|
modelHighlyConsistent: boolean;
|
||||||
needsNextBulletin: boolean;
|
needsNextBulletin: boolean;
|
||||||
observationStale: boolean;
|
observationStale: boolean;
|
||||||
@@ -119,11 +107,9 @@ export function buildCityDecisionState({
|
|||||||
}): CityDecisionState {
|
}): CityDecisionState {
|
||||||
const aiStatus = resolveAiStatus({ aiCityForecast, aiForecast, aiRuleEvidenceMode });
|
const aiStatus = resolveAiStatus({ aiCityForecast, aiForecast, aiRuleEvidenceMode });
|
||||||
const aiStatusView = resolveAiStatusView(aiStatus, isEn);
|
const aiStatusView = resolveAiStatusView(aiStatus, isEn);
|
||||||
const marketStatus = marketDecisionView.status;
|
|
||||||
const marketStatusTone = resolveMarketTone(marketStatus);
|
|
||||||
const evidenceQuality: CityDecisionEvidenceQuality = observationStale
|
const evidenceQuality: CityDecisionEvidenceQuality = observationStale
|
||||||
? "stale"
|
? "stale"
|
||||||
: aiStatus === "fallback" || marketStatus === "unavailable"
|
: aiStatus === "fallback"
|
||||||
? "mixed"
|
? "mixed"
|
||||||
: "fresh";
|
: "fresh";
|
||||||
const urgency: CityDecisionUrgency = peakHasPassed
|
const urgency: CityDecisionUrgency = peakHasPassed
|
||||||
@@ -152,11 +138,7 @@ export function buildCityDecisionState({
|
|||||||
? isEn
|
? isEn
|
||||||
? "Observation is stale and needs the next report. Use only as background reference until fresh data arrives."
|
? "Observation is stale and needs the next report. Use only as background reference until fresh data arrives."
|
||||||
: "观测已过旧,需要下一报文确认。当前数据仅作背景参考,建议等待新报文后再做判断。"
|
: "观测已过旧,需要下一报文确认。当前数据仅作背景参考,建议等待新报文后再做判断。"
|
||||||
: marketStatus === "unavailable"
|
: modelHighlyConsistent
|
||||||
? isEn
|
|
||||||
? "Weather evidence is usable, but no tradable quote is available yet. Weather judgment still applies."
|
|
||||||
: "天气证据可参考,但暂无可交易价格。天气判断仍可参考,无需急于操作。"
|
|
||||||
: modelHighlyConsistent
|
|
||||||
? isEn
|
? isEn
|
||||||
? "Models are aligned; wait for observation confirmation. A clear direction should emerge after the next report."
|
? "Models are aligned; wait for observation confirmation. A clear direction should emerge after the next report."
|
||||||
: "模型高度一致,等待实测确认。下一报文后方向会更明确。"
|
: "模型高度一致,等待实测确认。下一报文后方向会更明确。"
|
||||||
@@ -205,12 +187,6 @@ export function buildCityDecisionState({
|
|||||||
tone: aiStatusView.tone,
|
tone: aiStatusView.tone,
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
marketStatus === "unavailable"
|
|
||||||
? {
|
|
||||||
label: isEn ? "Market unavailable" : "市场价暂不可用",
|
|
||||||
tone: marketStatusTone,
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
modelHighlyConsistent
|
modelHighlyConsistent
|
||||||
? {
|
? {
|
||||||
label: isEn ? "Models agree" : "模型高度一致",
|
label: isEn ? "Models agree" : "模型高度一致",
|
||||||
@@ -232,8 +208,6 @@ export function buildCityDecisionState({
|
|||||||
aiStatus,
|
aiStatus,
|
||||||
aiStatusLabel: aiStatusView.label,
|
aiStatusLabel: aiStatusView.label,
|
||||||
aiStatusTone: aiStatusView.tone,
|
aiStatusTone: aiStatusView.tone,
|
||||||
marketStatus,
|
|
||||||
marketStatusTone,
|
|
||||||
badges,
|
badges,
|
||||||
primaryReason,
|
primaryReason,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user