From b975da2896e65e1f2b5f91fe63d92b80b1d8452e Mon Sep 17 00:00:00 2001 From: Harry Huang Date: Sun, 9 Nov 2025 19:29:09 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E4=BA=86Dashboar?= =?UTF-8?q?d=E7=9A=84=E5=86=85=E5=B5=8C=E8=A1=A8=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- messages/en.json | 5 +- messages/zh.json | 5 +- src/app/[locale]/dashboard/LoginForm.tsx | 10 +- src/app/[locale]/dashboard/Revenue.tsx | 2 +- src/app/[locale]/dashboard/page.tsx | 119 +++++++++++-- src/components/YearMonthPicker.tsx | 216 ++++++++++++++++++----- 6 files changed, 294 insertions(+), 63 deletions(-) diff --git a/messages/en.json b/messages/en.json index 7c42d08..e5cdd65 100644 --- a/messages/en.json +++ b/messages/en.json @@ -212,7 +212,8 @@ "tooltip": "Query through UserAgent", "confirm": "Confirm", "error": "Please confirm that you have entered the correct content", - "dashboardTitle": "MirrorChyan x {rid} {date} Sales Dashboard", + "dashboardTitle": "MirrorChyan Sales Dashboard", + "dashboardSubTitle": "MirrorChyan x {rid} {date}", "export": "Export CSV file", "application": "Applications", "userAgent": "Checkin user agents", @@ -229,6 +230,8 @@ "count": "Deals", "monthlyCount": "Monthly Sales", "monthlyAmount": "Monthly Revenue", + "refresh": "Refresh", + "refreshSuccess": "Refresh was successful", "lineChart": { "toggleCount": "Click to switch to sales volume", "toggleAmount": "Click to switch to sales revenue", diff --git a/messages/zh.json b/messages/zh.json index 46caf30..a5ac602 100644 --- a/messages/zh.json +++ b/messages/zh.json @@ -206,7 +206,8 @@ "tooltip": "通过请求源查询", "confirm": "确认", "error": "~(>_<) 怎么不对呢!是不是手指抖了一下呀?", - "dashboardTitle": "Mirror酱 x {rid} {date} 销售看板", + "dashboardTitle": "Mirror酱 销售看板", + "dashboardSubTitle": "Mirror酱 x {rid} {date}", "export": "导出 CSV 文件", "application": "应用", "userAgent": "签到源", @@ -223,6 +224,8 @@ "count": "销量", "monthlyCount": "月销售总量", "monthlyAmount": "月销售总额", + "refresh": "重新查询", + "refreshSuccess": "(☆▽☆) 数据更新成功", "lineChart": { "toggleCount": "点击切换为销量", "toggleAmount": "点击切换为销售额", diff --git a/src/app/[locale]/dashboard/LoginForm.tsx b/src/app/[locale]/dashboard/LoginForm.tsx index a38c238..c71d581 100644 --- a/src/app/[locale]/dashboard/LoginForm.tsx +++ b/src/app/[locale]/dashboard/LoginForm.tsx @@ -10,7 +10,13 @@ import YearMonthPicker from "@/components/YearMonthPicker"; import { RevenueResponse, RevenueType } from "@/app/[locale]/dashboard/page"; type LoginFormProps = { - onLoginSuccess: (data: RevenueType[], rid: string, date: string) => void; + onLoginSuccess: ( + data: RevenueType[], + rid: string, + date: string, + token?: string, + isUa?: boolean + ) => void; }; export default function LoginForm({ onLoginSuccess }: LoginFormProps) { @@ -54,7 +60,7 @@ export default function LoginForm({ onLoginSuccess }: LoginFormProps) { return; } - onLoginSuccess(response.data, rid, month); + onLoginSuccess(response.data, rid, month, token, isUa); } catch (error) { console.error("Error:", error); closeAll(); diff --git a/src/app/[locale]/dashboard/Revenue.tsx b/src/app/[locale]/dashboard/Revenue.tsx index db9de14..d131fc5 100644 --- a/src/app/[locale]/dashboard/Revenue.tsx +++ b/src/app/[locale]/dashboard/Revenue.tsx @@ -259,7 +259,7 @@ export default function Revenue({ revenueData, onLogOut, rid, date }: RevenuePro {/* 标题区 */}

- {t("dashboardTitle", { rid, date })} + {t("dashboardSubTitle", { rid, date })}

{/* 导出按钮移动到标题右侧 */} + )} +
+ + +
+ {showArrow && ( + + )}
); } From 91e04696623746ff6fdb2e707a6f1cf9fe49784e Mon Sep 17 00:00:00 2001 From: Harry Huang Date: Mon, 10 Nov 2025 02:01:33 +0800 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20=E6=9B=B4=E6=94=B9=E5=86=85?= =?UTF-8?q?=E5=B5=8C=E6=97=A5=E6=9C=9F=E8=A1=A8=E5=8D=95=E7=9A=84=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E4=BD=8D=E7=BD=AE=E5=92=8C=E6=97=B6=E6=9C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- messages/en.json | 3 +- messages/zh.json | 3 +- src/app/[locale]/dashboard/Revenue.tsx | 57 +++++++++++++++++++------- src/app/[locale]/dashboard/page.tsx | 36 +++++----------- 4 files changed, 55 insertions(+), 44 deletions(-) diff --git a/messages/en.json b/messages/en.json index e5cdd65..875c8e7 100644 --- a/messages/en.json +++ b/messages/en.json @@ -212,8 +212,7 @@ "tooltip": "Query through UserAgent", "confirm": "Confirm", "error": "Please confirm that you have entered the correct content", - "dashboardTitle": "MirrorChyan Sales Dashboard", - "dashboardSubTitle": "MirrorChyan x {rid} {date}", + "dashboard": "MirrorChyan x {rid} Sales Dashboard", "export": "Export CSV file", "application": "Applications", "userAgent": "Checkin user agents", diff --git a/messages/zh.json b/messages/zh.json index a5ac602..84e8f41 100644 --- a/messages/zh.json +++ b/messages/zh.json @@ -206,8 +206,7 @@ "tooltip": "通过请求源查询", "confirm": "确认", "error": "~(>_<) 怎么不对呢!是不是手指抖了一下呀?", - "dashboardTitle": "Mirror酱 销售看板", - "dashboardSubTitle": "Mirror酱 x {rid} {date}", + "dashboardTitle": "Mirror酱 x {rid} 销售看板", "export": "导出 CSV 文件", "application": "应用", "userAgent": "签到源", diff --git a/src/app/[locale]/dashboard/Revenue.tsx b/src/app/[locale]/dashboard/Revenue.tsx index d131fc5..45c94b2 100644 --- a/src/app/[locale]/dashboard/Revenue.tsx +++ b/src/app/[locale]/dashboard/Revenue.tsx @@ -2,19 +2,22 @@ import { useEffect, useMemo, useState } from "react"; import { useTranslations } from "next-intl"; -import { Button, Card, Skeleton } from "@heroui/react"; +import { Button, Card, Skeleton, Popover, PopoverTrigger, PopoverContent } from "@heroui/react"; import { debounce } from "lodash"; import { Cell, Legend, Pie, PieChart, ResponsiveContainer, Tooltip, TooltipProps } from "recharts"; import { Props } from "recharts/types/component/DefaultLegendContent"; import { RevenueType } from "@/app/[locale]/dashboard/page"; import SalesList from "@/app/[locale]/dashboard/SalesList"; import SalesLineChart from "@/app/[locale]/dashboard/SalesLineChart"; +import YearMonthPicker from "@/components/YearMonthPicker"; type RevenueProps = { revenueData: RevenueType[]; onLogOut: () => void; date: string; rid: string; + month: string; + onMonthChange: (month: string) => void; }; type ChartDataItem = { @@ -29,7 +32,14 @@ type SalesPieChartProps = { title: string; }; -export default function Revenue({ revenueData, onLogOut, rid, date }: RevenueProps) { +export default function Revenue({ + revenueData, + onLogOut, + rid, + date, + month, + onMonthChange, +}: RevenueProps) { const t = useTranslations("Dashboard"); const [isLoading, setIsLoading] = useState(true); useEffect(() => { @@ -39,7 +49,7 @@ export default function Revenue({ revenueData, onLogOut, rid, date }: RevenuePro setTimeout(() => { setIsLoading(false); }, 1000); - }, []); + }, [revenueData, onLogOut]); // Prepare chart data const applicationData = useMemo(() => { @@ -255,21 +265,38 @@ export default function Revenue({ revenueData, onLogOut, rid, date }: RevenuePro return (
-
+
{/* 标题区 */}
-

- {t("dashboardSubTitle", { rid, date })} +

+ {t("dashboardTitle", { rid })}

- {/* 导出按钮移动到标题右侧 */} - + +
+

+ + + {date} + + + + + +

+ + +
diff --git a/src/app/[locale]/dashboard/page.tsx b/src/app/[locale]/dashboard/page.tsx index 0c86310..574553f 100644 --- a/src/app/[locale]/dashboard/page.tsx +++ b/src/app/[locale]/dashboard/page.tsx @@ -2,12 +2,10 @@ import { useState, useEffect, useRef } from "react"; import { useTranslations } from "next-intl"; -import { Card } from "@heroui/react"; import { addToast, closeAll } from "@heroui/toast"; import { CLIENT_BACKEND } from "@/app/requests/misc"; import Revenue from "@/app/[locale]/dashboard/Revenue"; import LoginForm from "@/app/[locale]/dashboard/LoginForm"; -import YearMonthPicker from "@/components/YearMonthPicker"; export type RevenueType = { activated_at: Date; @@ -38,6 +36,7 @@ export default function Dashboard() { const [currentToken, setCurrentToken] = useState(""); const [currentIsUa, setCurrentIsUa] = useState(false); const [month, setMonth] = useState(""); + const [pendingMonth, setPendingMonth] = useState(""); // Debounce timer for query form const debounceTimer = useRef(null); @@ -56,19 +55,20 @@ export default function Dashboard() { if (token) setCurrentToken(token); if (isUa !== undefined) setCurrentIsUa(isUa); setMonth(date); + setPendingMonth(""); setIsLogin(true); }; // Query effect for when month changes useEffect(() => { - if (!month || !currentRid || !currentToken) return; + if (!pendingMonth || !currentRid || !currentToken) return; if (debounceTimer.current) clearTimeout(debounceTimer.current); debounceTimer.current = setTimeout(async () => { try { const response: RevenueResponse = await fetch( - `${CLIENT_BACKEND}/api/billing/revenue?rid=${currentRid}&date=${month}&is_ua=${+currentIsUa}`, + `${CLIENT_BACKEND}/api/billing/revenue?rid=${currentRid}&date=${pendingMonth}&is_ua=${+currentIsUa}`, { headers: { Authorization: currentToken }, } @@ -76,12 +76,9 @@ export default function Dashboard() { if (response.ec === 200) { closeAll(); - addToast({ - description: t("refreshSuccess"), - color: "success", - }); setRevenueData(response.data); - setCurrentDate(month); + setMonth(pendingMonth); + setCurrentDate(pendingMonth); } else { closeAll(); addToast({ @@ -102,7 +99,7 @@ export default function Dashboard() { return () => { if (debounceTimer.current) clearTimeout(debounceTimer.current); }; - }, [month, currentRid, currentToken, currentIsUa, t]); + }, [pendingMonth, currentRid, currentToken, currentIsUa, t]); const handleLogOut = () => { setIsLogin(false); @@ -112,6 +109,7 @@ export default function Dashboard() { setCurrentToken(""); setCurrentIsUa(false); setMonth(""); + setPendingMonth(""); }; // If not logged in, show the standalone login form @@ -126,27 +124,15 @@ export default function Dashboard() { // If logged in, show dashboard view with embedded query form on the top return (
-
- {/* Header area with title */} -
-

- {t("dashboardTitle")} -

-
- - {/* Query form */} -
- - - -
- +
{/* Revenue charts and data display */}
From 4d4781d8ba9fad3f645cadeee236cd31d75f1b7f Mon Sep 17 00:00:00 2001 From: Harry Huang Date: Mon, 10 Nov 2025 02:21:32 +0800 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E9=87=8D?= =?UTF-8?q?=E6=96=B0=E6=9F=A5=E8=AF=A2=E7=9A=84=E4=BD=93=E9=AA=8C=E5=92=8C?= =?UTF-8?q?=E9=B2=81=E6=A3=92=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- messages/en.json | 1 - messages/zh.json | 1 - src/app/[locale]/dashboard/page.tsx | 6 ++++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/messages/en.json b/messages/en.json index 875c8e7..32fa0e0 100644 --- a/messages/en.json +++ b/messages/en.json @@ -229,7 +229,6 @@ "count": "Deals", "monthlyCount": "Monthly Sales", "monthlyAmount": "Monthly Revenue", - "refresh": "Refresh", "refreshSuccess": "Refresh was successful", "lineChart": { "toggleCount": "Click to switch to sales volume", diff --git a/messages/zh.json b/messages/zh.json index 84e8f41..228f72c 100644 --- a/messages/zh.json +++ b/messages/zh.json @@ -223,7 +223,6 @@ "count": "销量", "monthlyCount": "月销售总量", "monthlyAmount": "月销售总额", - "refresh": "重新查询", "refreshSuccess": "(☆▽☆) 数据更新成功", "lineChart": { "toggleCount": "点击切换为销量", diff --git a/src/app/[locale]/dashboard/page.tsx b/src/app/[locale]/dashboard/page.tsx index 574553f..cc01f09 100644 --- a/src/app/[locale]/dashboard/page.tsx +++ b/src/app/[locale]/dashboard/page.tsx @@ -66,6 +66,8 @@ export default function Dashboard() { if (debounceTimer.current) clearTimeout(debounceTimer.current); debounceTimer.current = setTimeout(async () => { + if (month === pendingMonth) return; + try { const response: RevenueResponse = await fetch( `${CLIENT_BACKEND}/api/billing/revenue?rid=${currentRid}&date=${pendingMonth}&is_ua=${+currentIsUa}`, @@ -76,6 +78,10 @@ export default function Dashboard() { if (response.ec === 200) { closeAll(); + addToast({ + description: t("refreshSuccess"), + color: "success", + }); setRevenueData(response.data); setMonth(pendingMonth); setCurrentDate(pendingMonth);