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