- 👥 12{t("people")}
+ 👥 {t("meetupPeople")}
{memberPhotos.slice(0, 5).map((m) => (
diff --git a/app/[locale]/report/data/page.tsx b/app/[locale]/report/data/page.tsx
new file mode 100644
index 0000000..9122b96
--- /dev/null
+++ b/app/[locale]/report/data/page.tsx
@@ -0,0 +1,109 @@
+"use client";
+
+import { useTheme } from "@/app/context/ThemeContext";
+import { useLocale, useTranslation } from "@/i18n/navigation";
+import { Link } from "@/i18n/navigation";
+import { MembersMap, BarChart, PieChart, LineChart } from "@/app/lib/charts";
+import { MAP_CITIES } from "@/app/data/map-cities";
+
+// 演示数据
+const getCityBarData = (locale: "zh" | "en") =>
+ [...MAP_CITIES]
+ .sort((a, b) => b.nomadsNow - a.nomadsNow)
+ .slice(0, 10)
+ .map((c) => ({ name: locale === "zh" ? c.name : c.nameEn, value: c.nomadsNow }));
+
+const REGION_PIE_DATA = [
+ { name: "华东", value: 3200 },
+ { name: "华南", value: 1800 },
+ { name: "西南", value: 2100 },
+ { name: "华北", value: 1200 },
+ { name: "其他", value: 700 },
+];
+
+const GROWTH_LINE_DATA = {
+ xAxis: ["1月", "2月", "3月", "4月", "5月", "6月"],
+ series: [
+ { name: "新增成员", data: [320, 480, 520, 610, 720, 850] },
+ { name: "活跃城市", data: [12, 14, 15, 16, 17, 18] },
+ ],
+};
+
+export default function DataReportPage() {
+ const { t } = useTranslation("dataReport");
+ const locale = useLocale();
+ const { theme } = useTheme();
+ const dark = theme === "dark";
+
+ return (
+
+
+
+
+
+ {/* 成员地图 */}
+
+
+ {t("membersMap")}
+
+
+
+
+
+
+ {/* 图表网格 */}
+
+
+
+
+
+
+ {t("demoHint")}
+
+
+
+ );
+}
diff --git a/app/[locale]/report/page.tsx b/app/[locale]/report/page.tsx
index 23d9dcf..7c7c180 100644
--- a/app/[locale]/report/page.tsx
+++ b/app/[locale]/report/page.tsx
@@ -1,7 +1,7 @@
"use client";
import { useState } from "react";
-import { useTranslation } from "@/i18n/navigation";
+import { Link, useTranslation } from "@/i18n/navigation";
import Footer from "@/app/components/Footer";
export default function ReportPage() {
@@ -18,6 +18,12 @@ export default function ReportPage() {
{t("subtitle")}
+
+ 📊 {t("dataReport")}
+
{!generated ? (
diff --git a/app/api/geo/china/route.ts b/app/api/geo/china/route.ts
new file mode 100644
index 0000000..debfbb4
--- /dev/null
+++ b/app/api/geo/china/route.ts
@@ -0,0 +1,20 @@
+import { NextResponse } from "next/server";
+
+/**
+ * 代理中国地图 GeoJSON,避免前端 CORS
+ */
+export async function GET() {
+ try {
+ const res = await fetch(
+ "https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json"
+ );
+ const data = await res.json();
+ return NextResponse.json(data);
+ } catch (e) {
+ console.error("Failed to fetch china map:", e);
+ return NextResponse.json(
+ { error: "Failed to load map" },
+ { status: 500 }
+ );
+ }
+}
diff --git a/app/components/CityCard.tsx b/app/components/CityCard.tsx
index 282e5b6..955af60 100644
--- a/app/components/CityCard.tsx
+++ b/app/components/CityCard.tsx
@@ -2,6 +2,7 @@
import { memo, useState } from "react";
import { City } from "../data/cities";
+import { useTranslation } from "@/i18n/navigation";
function ratingToPercent(rating: string): number {
const m: Record