Merge branch 'develop' into codex/point

This commit is contained in:
yuxuanhui
2026-08-31 16:14:35 +08:00
86 changed files with 13384 additions and 217 deletions
+91
View File
@@ -3,6 +3,17 @@ import { createRootRoute, createRoute, Outlet } from "@tanstack/react-router"
import { AppLayout } from "@/app/layout/app-layout"
import { ComponentsPreviewPage } from "@/features/components/pages/components-preview-page"
import { HomePage } from "@/features/home/pages/home-page"
import {
radarMetricKinds,
radarRankSides,
radarViews,
sectorTypes,
type RadarMetricKind,
type RadarRankSide,
type RadarView,
type SectorType,
} from "@/features/sector-radar/api/sector-radar.types"
import { SectorRadarPage } from "@/features/sector-radar/pages/sector-radar-page"
import {
selectionCategoryFilters,
selectionSorts,
@@ -28,6 +39,63 @@ const indexRoute = createRoute({
component: HomePage,
})
const sectorRadarRoute = createRoute({
getParentRoute: () => workspaceRoute,
path: "/sector-radar",
validateSearch: (search: Record<string, unknown>) => {
const rawPage = Number(search.page)
const rawPageSize = Number(search.pageSize)
const rawRankChangeDays = Number(search.rankChangeDays)
const page =
Number.isFinite(rawPage) && rawPage >= 1 ? Math.floor(rawPage) : 1
const pageSize = [10, 20, 50].includes(rawPageSize) ? rawPageSize : 20
const rankChangeDays =
Number.isFinite(rawRankChangeDays) &&
rawRankChangeDays >= 1 &&
rawRankChangeDays <= 5
? Math.floor(rawRankChangeDays)
: 1
const searchValue =
typeof search.search === "string" ? search.search.slice(0, 100) : ""
const tradeDate =
typeof search.tradeDate === "string" && isValidTradeDate(search.tradeDate)
? search.tradeDate
: undefined
const sectorType = validatedSearchValue<SectorType>(
search.sectorType,
sectorTypes,
"concept",
)
const view = validatedSearchValue<RadarView>(
search.view,
radarViews,
"amount",
)
const rankChangeMetric = validatedSearchValue<RadarMetricKind>(
search.rankChangeMetric,
radarMetricKinds,
"amount",
)
const side = validatedSearchValue<RadarRankSide>(
search.side,
radarRankSides,
"all",
)
return {
tradeDate,
sectorType,
view,
rankChangeMetric,
rankChangeDays,
side,
search: searchValue,
page,
pageSize,
}
},
component: SectorRadarPage,
})
const selectionRoute = createRoute({
getParentRoute: () => workspaceRoute,
path: "/selection",
@@ -72,8 +140,31 @@ const componentsRoute = createRoute({
export const routeTree = rootRoute.addChildren([
workspaceRoute.addChildren([
indexRoute,
sectorRadarRoute,
selectionRoute,
syncRoute,
componentsRoute,
]),
])
function validatedSearchValue<Value extends string>(
value: unknown,
allowed: readonly Value[],
fallback: Value,
): Value {
return typeof value === "string" && allowed.includes(value as Value)
? (value as Value)
: fallback
}
function isValidTradeDate(value: string) {
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value)
if (!match) return false
const parsed = new Date(`${value}T00:00:00Z`)
return (
!Number.isNaN(parsed.getTime()) &&
parsed.getUTCFullYear() === Number(match[1]) &&
parsed.getUTCMonth() + 1 === Number(match[2]) &&
parsed.getUTCDate() === Number(match[3])
)
}