From 696577b49fe68241d19117311d8d1dbad82b282e Mon Sep 17 00:00:00 2001 From: alikia2x Date: Mon, 29 Dec 2025 02:43:51 +0800 Subject: [PATCH] add: logging for cf workers, fix missing seconds in frontend --- packages/cf-worker/src/index.ts | 51 ++- packages/temp_frontend/app/app.css | 367 ++++++++++++------ .../app/components/SearchResults.tsx | 2 +- packages/temp_frontend/app/root.tsx | 11 - .../app/routes/home/Milestone.tsx | 1 - .../app/routes/song/[id]/info/index.tsx | 2 +- .../routes/song/[id]/info/snapshotsView.tsx | 2 +- 7 files changed, 292 insertions(+), 144 deletions(-) diff --git a/packages/cf-worker/src/index.ts b/packages/cf-worker/src/index.ts index ee98830..24f9e3e 100644 --- a/packages/cf-worker/src/index.ts +++ b/packages/cf-worker/src/index.ts @@ -12,7 +12,7 @@ */ import { connect } from "cloudflare:sockets"; -import { HttpParser, MessageType } from '@alikia/http-parser'; +import { HttpParser, MessageType } from "@alikia/http-parser"; interface ProxyConfig { TIMEOUT_MS: number; @@ -127,7 +127,7 @@ async function handleSocket( buffer.push(value); } - const rawContent = concatUint8Arrays(...buffer) + const rawContent = concatUint8Arrays(...buffer); const parser = new HttpParser(); @@ -138,10 +138,10 @@ async function handleSocket( return { data: new TextDecoder().decode(msg.body), time: Math.floor((requestTime + Date.now()) / 2), - } + }; } } - + throw new Error("Invalid response"); } @@ -165,8 +165,11 @@ async function handleFetch( }; } -function createJsonResponse(data: ProxyResponseData): Response { - return new Response(JSON.stringify(data), { +function createJsonResponse(data: ProxyResponseData, requestId: string): Response { + return new Response(JSON.stringify({ + ...data, + requestId, + }), { headers: { "Access-Control-Allow-Origin": "*", "Content-Type": "application/json", @@ -174,12 +177,13 @@ function createJsonResponse(data: ProxyResponseData): Response { }); } -function createErrorResponse(message: string, status: number): Response { +function createErrorResponse(message: string, status: number, requestId: string): Response { return new Response( JSON.stringify({ data: "", error: message, time: Date.now(), + requestId, }), { headers: { @@ -193,8 +197,11 @@ function createErrorResponse(message: string, status: number): Response { export default { async fetch(request: Request, _env: Env, _ctx: ExecutionContext): Promise { + const requestId = crypto.randomUUID().slice(0, 8); // Track this specific request + if (request.method !== "POST") { - return createErrorResponse("Method not allowed", 405); + console.warn(`[${requestId}] Method Not Allowed: ${request.method}`); + return createErrorResponse("Method not allowed", 405, requestId); } let targetUrl: string; @@ -206,25 +213,39 @@ export default { targetUrl = body.url; new URL(targetUrl); customHeaders = body.headers || {}; - } catch { - return createErrorResponse("Invalid request", 400); + console.log(`[${requestId}] Proxying request to: ${targetUrl}`); + } catch (err) { + console.error(`[${requestId}] Body Parse Error:`, err); + return createErrorResponse("Invalid request", 400, requestId); } try { + console.log(`[${requestId}] Attempting handleSocket...`); const data = await withTimeout( handleSocket(targetUrl, customHeaders, requestTime), CONFIG.TIMEOUT_MS ); - return createJsonResponse(data); - } catch { + console.log(`[${requestId}] Success via handleSocket (${Date.now() - requestTime}ms)`); + return createJsonResponse(data, requestId); + } catch (socketErr: any) { + console.warn( + `[${requestId}] handleSocket failed: ${socketErr.message}. Falling back to fetch...` + ); + try { const data = await withTimeout( handleFetch(targetUrl, customHeaders, requestTime), CONFIG.TIMEOUT_MS ); - return createJsonResponse(data); - } catch { - return createErrorResponse("Socket timeout", 504); + console.log( + `[${requestId}] Success via handleFetch (${Date.now() - requestTime}ms)` + ); + return createJsonResponse(data, requestId); + } catch (fetchErr: any) { + console.error( + `[${requestId}] Critical Failure: Both Socket and Fetch failed. Error: ${fetchErr.message}` + ); + return createErrorResponse(`Proxy failure: ${fetchErr.message}`, 504, requestId); } } }, diff --git a/packages/temp_frontend/app/app.css b/packages/temp_frontend/app/app.css index 6d0b2e4..82d6b7a 100644 --- a/packages/temp_frontend/app/app.css +++ b/packages/temp_frontend/app/app.css @@ -2,149 +2,288 @@ @import "tw-animate-css"; body { - @apply dark:bg-zinc-950 dark:text-white; + @apply dark:bg-zinc-950 dark:text-white; } input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-results-button, input[type="search"]::-webkit-search-results-decoration { - display: none; + display: none; } input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { - -webkit-appearance: none; - margin: 0; + -webkit-appearance: none; + margin: 0; } input[type="number"] { - -moz-appearance: textfield; + -moz-appearance: textfield; } .stat-num { - font-family: "Inter", sans-serif; - font-feature-settings: "tnum"; + font-family: "Inter", sans-serif; + font-feature-settings: "tnum"; } .xAxis .recharts-cartesian-axis-ticks { - transform: translateX(-7px); + transform: translateX(-7px); } @theme inline { - --radius-sm: calc(var(--radius) - 4px); - --radius-md: calc(var(--radius) - 2px); - --radius-lg: var(--radius); - --radius-xl: calc(var(--radius) + 4px); - --color-background: var(--background); - --color-foreground: var(--foreground); - --color-card: var(--card); - --color-card-foreground: var(--card-foreground); - --color-popover: var(--popover); - --color-popover-foreground: var(--popover-foreground); - --color-primary: var(--primary); - --color-primary-foreground: var(--primary-foreground); - --color-secondary: var(--secondary); - --color-secondary-foreground: var(--secondary-foreground); - --color-muted: var(--muted); - --color-muted-foreground: var(--muted-foreground); - --color-accent: var(--accent); - --color-accent-foreground: var(--accent-foreground); - --color-destructive: var(--destructive); - --color-border: var(--border); - --color-input: var(--input); - --color-ring: var(--ring); - --color-chart-1: var(--chart-1); - --color-chart-2: var(--chart-2); - --color-chart-3: var(--chart-3); - --color-chart-4: var(--chart-4); - --color-chart-5: var(--chart-5); - --color-sidebar: var(--sidebar); - --color-sidebar-foreground: var(--sidebar-foreground); - --color-sidebar-primary: var(--sidebar-primary); - --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); - --color-sidebar-accent: var(--sidebar-accent); - --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); - --color-sidebar-border: var(--sidebar-border); - --color-sidebar-ring: var(--sidebar-ring); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); } :root { - --radius: 1rem; - --background: oklch(1 0 0); - --foreground: oklch(0.145 0 0); - --card: oklch(1 0 0); - --card-foreground: oklch(0.145 0 0); - --popover: oklch(1 0 0); - --popover-foreground: oklch(0.145 0 0); - --primary: oklch(0.205 0 0); - --primary-foreground: oklch(0.985 0 0); - --secondary: oklch(0.92 0 0); - --secondary-foreground: oklch(0.305 0 0); - --muted: oklch(0.97 0 0); - --muted-foreground: oklch(0.556 0 0); - --accent: oklch(0.95 0 0); - --accent-foreground: oklch(0.205 0 0); - --destructive: oklch(0.577 0.245 27.325); - --border: oklch(0.922 0 0); - --input: oklch(0.922 0 0); - --ring: oklch(0.708 0 0); - --chart-1: oklch(0.646 0.222 41.116); - --chart-2: oklch(0.6 0.118 184.704); - --chart-3: oklch(0.398 0.07 227.392); - --chart-4: oklch(0.828 0.189 84.429); - --chart-5: oklch(0.769 0.188 70.08); - --sidebar: oklch(0.985 0 0); - --sidebar-foreground: oklch(0.145 0 0); - --sidebar-primary: oklch(0.205 0 0); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.97 0 0); - --sidebar-accent-foreground: oklch(0.205 0 0); - --sidebar-border: oklch(0.922 0 0); - --sidebar-ring: oklch(0.708 0 0); + --radius: 1rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.92 0 0); + --secondary-foreground: oklch(0.305 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.95 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); } @media (prefers-color-scheme: dark) { - :root { - --background: oklch(0.145 0 0); - --foreground: oklch(0.985 0 0); - --card: oklch(0.205 0 0); - --card-foreground: oklch(0.985 0 0); - --popover: oklch(0.205 0 0); - --popover-foreground: oklch(0.985 0 0); - --primary: oklch(0.922 0 0); - --primary-foreground: oklch(0.205 0 0); - --secondary: oklch(0.269 0 0); - --secondary-foreground: oklch(0.85 0 0); - --muted: oklch(0.188 0 0); - --muted-foreground: oklch(0.708 0 0); - --accent: oklch(0.269 0 0); - --accent-foreground: oklch(0.985 0 0); - --destructive: oklch(0.704 0.191 22.216); - --border: oklch(1 0 0 / 10%); - --input: oklch(1 0 0 / 15%); - --ring: oklch(0.556 0 0); - --chart-1: oklch(0.488 0.243 264.376); - --chart-2: oklch(0.696 0.17 162.48); - --chart-3: oklch(0.769 0.188 70.08); - --chart-4: oklch(0.627 0.265 303.9); - --chart-5: oklch(0.645 0.246 16.439); - --sidebar: oklch(0.205 0 0); - --sidebar-foreground: oklch(0.985 0 0); - --sidebar-primary: oklch(0.488 0.243 264.376); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.269 0 0); - --sidebar-accent-foreground: oklch(0.985 0 0); - --sidebar-border: oklch(1 0 0 / 10%); - --sidebar-ring: oklch(0.556 0 0); - } + :root { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.85 0 0); + --muted: oklch(0.188 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); + } } @layer base { - * { - @apply border-border outline-ring/50; - } - body { - @apply bg-background text-foreground; - } + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } +} + +/* cyrillic-ext */ +@font-face { + font-family: "Inter"; + font-style: italic; + font-weight: 100 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcCm3FwrK3iLTcvnUwkT9mI1F55MKw.woff2) format("woff2"); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: "Inter"; + font-style: italic; + font-weight: 100 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcCm3FwrK3iLTcvnUwAT9mI1F55MKw.woff2) format("woff2"); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: "Inter"; + font-style: italic; + font-weight: 100 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcCm3FwrK3iLTcvnUwgT9mI1F55MKw.woff2) format("woff2"); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: "Inter"; + font-style: italic; + font-weight: 100 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcCm3FwrK3iLTcvnUwcT9mI1F55MKw.woff2) format("woff2"); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: "Inter"; + font-style: italic; + font-weight: 100 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcCm3FwrK3iLTcvnUwsT9mI1F55MKw.woff2) format("woff2"); + unicode-range: + U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, + U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: "Inter"; + font-style: italic; + font-weight: 100 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcCm3FwrK3iLTcvnUwoT9mI1F55MKw.woff2) format("woff2"); + unicode-range: + U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, + U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: "Inter"; + font-style: italic; + font-weight: 100 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcCm3FwrK3iLTcvnUwQT9mI1F54.woff2) format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, + U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: "Inter"; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcCo3FwrK3iLTcvvYwYZ8UA3J58.woff2) format("woff2"); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: "Inter"; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcCo3FwrK3iLTcvmYwYZ8UA3J58.woff2) format("woff2"); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: "Inter"; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcCo3FwrK3iLTcvuYwYZ8UA3J58.woff2) format("woff2"); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: "Inter"; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcCo3FwrK3iLTcvhYwYZ8UA3J58.woff2) format("woff2"); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: "Inter"; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcCo3FwrK3iLTcvtYwYZ8UA3J58.woff2) format("woff2"); + unicode-range: + U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, + U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: "Inter"; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcCo3FwrK3iLTcvsYwYZ8UA3J58.woff2) format("woff2"); + unicode-range: + U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, + U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: "Inter"; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: url(https://fonts.gstatic.com/s/inter/v20/UcCo3FwrK3iLTcviYwYZ8UA3.woff2) format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, + U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } diff --git a/packages/temp_frontend/app/components/SearchResults.tsx b/packages/temp_frontend/app/components/SearchResults.tsx index 76c117b..c49710b 100644 --- a/packages/temp_frontend/app/components/SearchResults.tsx +++ b/packages/temp_frontend/app/components/SearchResults.tsx @@ -6,7 +6,7 @@ interface SearchResultsProps { query: string; } -export const formatDateTime = (date: Date, showYear = true, showSec = false): string => { +export const formatDateTime = (date: Date, showYear = true, showSec = true): string => { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); // 月份从0开始,补0 const day = String(date.getDate()).padStart(2, "0"); diff --git a/packages/temp_frontend/app/root.tsx b/packages/temp_frontend/app/root.tsx index 53f73dc..cb44cf7 100644 --- a/packages/temp_frontend/app/root.tsx +++ b/packages/temp_frontend/app/root.tsx @@ -18,17 +18,6 @@ export const links: Route.LinksFunction = () => [ href: "https://fonts.gstatic.com", rel: "preconnect", }, - { - as: "style", - href: "https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap", - rel: "preload", - }, - { - href: "https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap", - media: "print", - onload: "this.media='all'", - rel: "stylesheet", - }, ]; export function Layout({ children }: { children: React.ReactNode }) { diff --git a/packages/temp_frontend/app/routes/home/Milestone.tsx b/packages/temp_frontend/app/routes/home/Milestone.tsx index 54c08bb..e921537 100644 --- a/packages/temp_frontend/app/routes/home/Milestone.tsx +++ b/packages/temp_frontend/app/routes/home/Milestone.tsx @@ -8,7 +8,6 @@ import { Skeleton } from "@/components/ui/skeleton"; import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { MilestoneVideoCard } from "./MilestoneVideoCard"; -// @ts-expect-error idk const app = treaty(import.meta.env.VITE_API_URL!); export type CloseMilestoneInfo = Awaited< diff --git a/packages/temp_frontend/app/routes/song/[id]/info/index.tsx b/packages/temp_frontend/app/routes/song/[id]/info/index.tsx index 32cc915..a99c6d0 100644 --- a/packages/temp_frontend/app/routes/song/[id]/info/index.tsx +++ b/packages/temp_frontend/app/routes/song/[id]/info/index.tsx @@ -55,7 +55,7 @@ export function formatHours(hours: number): string { export function addHoursToNow(hours: number): string { const d = new Date(); d.setSeconds(d.getSeconds() + hours * 3600); - return `${d.getFullYear()}-${(d.getMonth() + 1).toString().padStart(2, "0")}-${d.getDate().toString().padStart(2, "0")} ${d.getHours().toString().padStart(2, "0")}:${d.getMinutes().toString().padStart(2, "0")}`; + return formatDateTime(d, true) } export default function SongInfo({ loaderData }: Route.ComponentProps) { diff --git a/packages/temp_frontend/app/routes/song/[id]/info/snapshotsView.tsx b/packages/temp_frontend/app/routes/song/[id]/info/snapshotsView.tsx index f56ba37..2afbebd 100644 --- a/packages/temp_frontend/app/routes/song/[id]/info/snapshotsView.tsx +++ b/packages/temp_frontend/app/routes/song/[id]/info/snapshotsView.tsx @@ -185,7 +185,7 @@ export const SnapshotsView = ({ > {achievement.milestoneName}( {achievement.milestone.toLocaleString()}) -{" "} - {formatDateTime(new Date(achievement.achievedAt))} + {formatDateTime(new Date(achievement.achievedAt), true, false)} {achievement.timeTaken && ` - 用时 ${achievement.timeTaken}`}

))}