From 41493c35ca5f743277dfcfb30b4bd07a5a7f844f Mon Sep 17 00:00:00 2001 From: eric Date: Sat, 6 Jun 2026 04:29:46 -0500 Subject: [PATCH] s'' --- .gitignore | 7 + PROJECT_ANALYSIS_REPORT.md | 548 +++++++++++ app/[locale]/ai/page.tsx | 46 +- app/[locale]/app/page.tsx | 73 ++ app/[locale]/dashboard/page.tsx | 325 +++++-- app/[locale]/dating/page.tsx | 159 +++- app/[locale]/discuss/page.tsx | 122 ++- app/[locale]/ebooks/[slug]/page.tsx | 109 +++ app/[locale]/feedback/page.tsx | 9 +- app/[locale]/gigs/page.tsx | 257 ++++- app/[locale]/join/page.tsx | 15 +- app/[locale]/join/paid/page.tsx | 13 +- app/[locale]/map/page.tsx | 22 +- app/[locale]/meetups/host/page.tsx | 39 +- app/[locale]/meetups/page.tsx | 42 +- app/[locale]/page.tsx | 358 ++++++- app/[locale]/report/data/page.tsx | 86 +- app/[locale]/services/page.tsx | 244 ++--- app/[locale]/tools/page.tsx | 78 +- app/[locale]/videos/[slug]/page.tsx | 94 ++ app/components/AuthModal.tsx | 3 +- app/components/CityModal.tsx | 311 +++++- app/components/HeroSection.tsx | 11 +- app/components/JoinModal.tsx | 7 +- app/components/Navbar.tsx | 7 +- app/data/cities.ts | 3 + app/globals.css | 24 +- app/lib/api-client.ts | 29 + app/lib/charts/MembersMap.tsx | 3 +- app/lib/payment/client.ts | 3 +- app/lib/payment/usePayStatusPoll.ts | 3 +- app/lib/pocketbase/auth.ts | 32 +- backend/.env.example | 7 + backend/__init__.py | 1 + backend/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 220 bytes .../__pycache__/enhanced_seed.cpython-312.pyc | Bin 0 -> 6884 bytes backend/__pycache__/init_db.cpython-312.pyc | Bin 0 -> 13468 bytes backend/__pycache__/main.cpython-312.pyc | Bin 0 -> 53879 bytes backend/__pycache__/pb_client.cpython-312.pyc | Bin 0 -> 6884 bytes backend/__pycache__/seed_data.cpython-312.pyc | Bin 0 -> 28836 bytes backend/__pycache__/settings.cpython-312.pyc | Bin 0 -> 2219 bytes backend/enhanced_seed.py | 180 ++++ backend/init_db.py | 325 +++++++ backend/main.py | 883 ++++++++++++++++++ backend/pb_client.py | 158 ++++ backend/requirements.txt | 7 + backend/seed_data.py | 373 ++++++++ backend/settings.py | 30 + messages/en.json | 18 +- messages/zh.json | 18 +- 50 files changed, 4666 insertions(+), 416 deletions(-) create mode 100644 PROJECT_ANALYSIS_REPORT.md create mode 100644 app/[locale]/app/page.tsx create mode 100644 app/[locale]/ebooks/[slug]/page.tsx create mode 100644 app/[locale]/videos/[slug]/page.tsx create mode 100644 app/lib/api-client.ts create mode 100644 backend/.env.example create mode 100644 backend/__init__.py create mode 100644 backend/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/__pycache__/enhanced_seed.cpython-312.pyc create mode 100644 backend/__pycache__/init_db.cpython-312.pyc create mode 100644 backend/__pycache__/main.cpython-312.pyc create mode 100644 backend/__pycache__/pb_client.cpython-312.pyc create mode 100644 backend/__pycache__/seed_data.cpython-312.pyc create mode 100644 backend/__pycache__/settings.cpython-312.pyc create mode 100644 backend/enhanced_seed.py create mode 100644 backend/init_db.py create mode 100644 backend/main.py create mode 100644 backend/pb_client.py create mode 100644 backend/requirements.txt create mode 100644 backend/seed_data.py create mode 100644 backend/settings.py diff --git a/.gitignore b/.gitignore index 3c0642c..59c9787 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,10 @@ next-env.d.ts node_modules dist build + +# local backend/runtime data +/data/ +/backend/uploads/ +/backend/.env +/tools/pocketbase/ +/tools/pocketbase.zip diff --git a/PROJECT_ANALYSIS_REPORT.md b/PROJECT_ANALYSIS_REPORT.md new file mode 100644 index 0000000..655f809 --- /dev/null +++ b/PROJECT_ANALYSIS_REPORT.md @@ -0,0 +1,548 @@ +# NomadCNA 前端项目分析报告 + +生成日期:2026-06-06 + +## 1. 分析范围与结论 + +本报告只分析当前仓库中的前端项目现状。仓库内虽然存在 `app/api`、PocketBase、支付、MinIO 等旧接口适配代码,但根据当前开发方向,这部分后端实现已隔离,后续应由 FastAPI + PocketBase 重新设计和实现。因此本文不会把旧 `app/api` 作为未来后端实现依据,只把它们作为“前端当前依赖的接口形状”记录,方便后续替换。 + +总体判断: + +- 当前项目是一个 Next.js 16 App Router 前端应用,核心体验已经具备较完整的页面骨架和视觉资产。 +- 主要业务数据仍以 TypeScript 静态数据、配置文件和页面内 mock 数据为主。 +- 前端已覆盖城市探索、下一站决策、社区加入、会员支付入口、聚会、匹配、讨论、赏金、工具箱、年报、地图、内容页和法律页等模块。 +- 后续真实开发重点不是重写 UI,而是抽离接口层、设计 PocketBase 数据模型、用 FastAPI 承接认证、业务规则、支付、上传、AI、统计等后端能力。 +- 当前前端和旧后端存在耦合,需要在后续开发中集中替换为统一 API client 和清晰的数据契约。 + +## 2. 技术栈概览 + +### 2.1 主要依赖 + +来自 `package.json`: + +- Next.js:`16.1.6` +- React / React DOM:`19.2.3` +- TypeScript:`^5` +- Tailwind CSS:`^4` +- ECharts:`^6.0.0` +- PocketBase JS SDK:`^0.26.8` +- MinIO SDK:`^8.0.7` +- 包管理:`pnpm@10.25.0` + +### 2.2 运行脚本 + +- `pnpm dev`:`next dev -p 3001 -H 0.0.0.0` +- `pnpm build`:生产构建 +- `pnpm start`:生产启动 +- `pnpm lint`:ESLint + +注意:`README.md` 中写的是打开 `http://localhost:3000`,但实际 dev 脚本端口是 `3001`,文档需要同步。 + +## 3. 目录结构与职责 + +当前关键目录: + +```text +app/ + [locale]/ 多语言页面路由 + components/ 通用前端组件 + context/ Locale / Theme Context + data/ 静态业务数据 + lib/ 前端工具库、旧服务适配、图表组件 + api/ 旧 Next API Route,后续不建议作为目标后端保留 +config/ 站点、导航、首页、页脚、服务配置 +i18n/ 本地化导航封装 +messages/ zh / en 文案 +public/ 静态资源 +``` + +### 3.1 前端核心文件 + +- `app/layout.tsx`:全局 HTML、主题脚本、ThemeProvider。 +- `app/[locale]/layout.tsx`:语言路由布局,加载多语言消息,挂载 Navbar。 +- `app/[locale]/page.tsx`:首页,包含 Hero、城市列表、筛选、热门路线、社区动态。 +- `app/globals.css`:Tailwind 4 入口、深色模式、全局布局类、城市卡片和表单样式。 +- `app/context/LocaleContext.tsx`:自定义 i18n Context 和路由跳转封装。 +- `app/context/ThemeContext.tsx`:亮色/暗色主题,使用 localStorage 保存偏好。 + +### 3.2 配置文件 + +- `config/site.config.ts`:站点标题、描述、口号。 +- `config/nav.config.ts`:顶部导航入口。 +- `config/home.config.ts`:首页成员头像、路线、热门话题、统计数据。 +- `config/footer.config.ts`:页脚链接。 +- `config/services.config.ts`、`config/domain.config.ts`:旧服务配置。未来后端重写时应重构为前端只保留 `NEXT_PUBLIC_API_BASE_URL` 等必要公开变量。 + +## 4. 页面模块梳理 + +当前 `app/[locale]` 下页面较完整,页面数量约 31 个。 + +### 4.1 首页与城市探索 + +相关文件: + +- `app/[locale]/page.tsx` +- `app/components/HeroSection.tsx` +- `app/components/FilterBar.tsx` +- `app/components/CityCard.tsx` +- `app/components/CityModal.tsx` +- `app/data/cities.ts` + +能力现状: + +- 首页展示城市卡片网格,支持按标签筛选和按综合评分、费用、网速、安全、游民数量、温度排序。 +- 城市数据来自 `app/data/cities.ts`,共 18 个城市。 +- `CityCard` 提供卡片 hover 评分展示。 +- `CityModal` 提供接近 Nomad List 风格的城市详情弹窗,但大量 tab 内容仍是占位。 +- 首页的成员、路线、热门话题、社区动态来自 `config/home.config.ts`。 + +后续真实化方向: + +- 城市、城市指标、标签、封面图、热度、评分、评论、气候、网速、生活成本应迁入 PocketBase。 +- 首页统计、热门路线、成员头像、热门话题应改由 FastAPI 聚合返回。 +- 筛选逻辑目前在前端内存完成;真实数据量上来后应由后端分页、排序、过滤。 + +### 4.2 下一站决策仪表盘 + +相关文件:`app/[locale]/dashboard/page.tsx` + +能力现状: + +- 用户可设置预算、最低网速、时区、签证偏好、希望认识的人群。 +- 实际筛选只使用预算和网速,数据来自本地 `cities`。 +- 成本曲线、游民密度热力图、AI 推荐等为占位。 + +后续真实化方向: + +- 建立城市推荐 API,根据预算、网速、气候、社区密度、签证、职业偏好等返回排序结果。 +- AI 推荐可以由 FastAPI 调用模型服务,结果落库便于复盘。 +- 图表数据需要后端提供时间序列、城市指标、用户偏好权重。 + +### 4.3 加入社区与会员支付 + +相关文件: + +- `app/[locale]/join/page.tsx` +- `app/[locale]/join/paid/page.tsx` +- `app/components/JoinModal.tsx` +- `app/components/AuthModal.tsx` +- `app/components/HeroSection.tsx` + +能力现状: + +- 首页 Hero 支持输入邮箱并进入加入/支付流程。 +- `/join` 是较完整的报名表单,包含昵称、性别、感情状态、职业、微信、手机、自我介绍、学历、毕业时间、头像/视频上传。 +- 当前页面会调用旧接口:`/api/auth/me`、`/api/join`、`/api/join/status`、`/api/vip/check`、`/api/upload-media`、`/api/pay/status`、`/api/meetup/*` 等。 +- 支付成功页负责完成订单、同步登录态、设置改密状态等。 + +后续真实化方向: + +- FastAPI 统一接管登录、报名、会员状态、订单创建、支付回调、支付状态查询、媒体上传。 +- PocketBase 存储用户、资料、报名表、会员权益、订单、支付流水。 +- 前端应只调用 FastAPI,不直接处理 PocketBase 管理员逻辑。 +- 支付状态和订单状态需要明确状态机,例如 `pending`、`paid`、`failed`、`expired`、`refunded`。 + +### 4.4 社区、匹配、聚会、讨论、赏金 + +相关页面: + +- `app/[locale]/dating/page.tsx` +- `app/[locale]/meetups/page.tsx` +- `app/[locale]/meetups/host/page.tsx` +- `app/[locale]/discuss/page.tsx` +- `app/[locale]/gigs/page.tsx` + +能力现状: + +- 匹配页有 profile card、喜欢/不感兴趣按钮、匹配类型 tab,但使用页面内 mock。 +- 聚会页有 upcoming / previous tab,聚会列表全部 hardcode。 +- 发起聚会页有表单,文案明确“演示模式,数据不会保存”。 +- 讨论页使用 `MOCK_TOPICS`,支持搜索过滤。 +- 赏金墙使用 `MOCK_GIGS`。 + +后续真实化方向: + +- 聚会:活动创建、审核、发布、报名、取消报名、参与者列表、城市筛选。 +- 匹配:个人资料、目标类型、滑动记录、互相喜欢、举报/拉黑、推荐排序。 +- 讨论:话题、评论、点赞、浏览数、标签、审核。 +- 赏金:任务发布、接单、交付、评价、平台抽成、支付/托管。 + +### 4.5 工具箱、AI、年报、地图和数据报告 + +相关页面: + +- `app/[locale]/tools/page.tsx` +- `app/[locale]/ai/page.tsx` +- `app/[locale]/report/page.tsx` +- `app/[locale]/report/data/page.tsx` +- `app/[locale]/map/page.tsx` +- `app/lib/charts/*` + +能力现状: + +- 工具箱包含静态汇率、税务估算、签证倒计时,FIRE 和气候查询为占位。 +- AI 页面为即将上线状态。 +- 年报页面是静态生成入口和展示样式。 +- 地图和数据报告使用 `MAP_CITIES` 静态城市坐标和 ECharts 地图组件。 + +后续真实化方向: + +- 汇率、天气、气候、签证政策属于外部数据集成,应由 FastAPI 定时同步或按需代理。 +- 年报依赖用户行程、城市停留、消费、活动报名、社区互动等真实数据。 +- 地图应聚合匿名化成员城市分布,避免暴露个人精确位置。 +- AI 需要用户上下文、城市数据和安全边界。 + +### 4.6 内容与静态信息页 + +相关页面: + +- `blog`、`careers`、`press`、`help` +- `about`、`contact`、`support` +- `terms`、`privacy`、`cookies`、`safety`、`guidelines` + +能力现状: + +- 多数内容来自 `app/data/mock.ts`。 +- 页面完成度适合 MVP 展示,但没有 CMS 或后台维护能力。 + +后续真实化方向: + +- 内容可先继续静态化,后期迁入 PocketBase 作为轻量 CMS。 +- 法律、隐私、帮助中心等应有版本号和更新时间。 +- 招聘、媒体报道、博客需要 slug、SEO metadata、草稿/发布状态。 + +## 5. 数据来源现状 + +### 5.1 静态数据 + +- `app/data/cities.ts`:18 个城市,含成本、网速、安全、温度、标签、封面、经纬度等。 +- `app/data/map-cities.ts`:地图城市坐标和成员数。 +- `app/data/mock.ts`:博客、招聘、媒体报道、帮助中心、安全指南、社区准则、联系信息、条款、隐私、Cookie。 +- `config/home.config.ts`:首页社群头像、旅行中成员、聚会、热门话题、路线、统计。 +- 页面内 mock:聚会、匹配、讨论、赏金等。 + +### 5.2 多语言数据 + +- `messages/zh.json` +- `messages/en.json` + +当前 i18n 是自定义 Context,不依赖 next-intl。优点是简单可控,缺点是类型约束弱,缺少自动 key 检查,也没有格式化复数、日期、变量插值的完整能力。 + +### 5.3 外部资源 + +当前大量图片来自: + +- `i.pravatar.cc` +- `images.unsplash.com` +- `api.dicebear.com` +- `logo.clearbit.com` + +这些适合原型阶段,但生产环境需要明确版权、可用性、缓存策略、头像隐私和图片优化策略。 + +## 6. 前端状态与交互方式 + +当前项目大量使用 client component: + +- `useState` 管理表单、弹窗、tab、筛选、排序。 +- `useMemo` 做城市筛选、聚会分类。 +- `localStorage` 保存主题、旧 PocketBase token、用户信息、支付订单。 +- `document.cookie` 保存旧支付订单状态和服务端 session。 +- `createPortal` 实现 AuthModal、JoinModal、CityModal。 +- `window.location.href` / `replace` 用于语言切换、支付回跳和登录同步。 + +后续建议: + +- 建立统一 `app/lib/api-client.ts` 或 `app/services/*`,集中处理 API base URL、鉴权、错误码、重试、超时。 +- 把旧 PocketBase 前端 SDK 调用逐步移除,前端只通过 FastAPI 访问业务接口。 +- 登录态统一为 httpOnly cookie + `/auth/me`,避免前端长期保存敏感 token。 +- 表单建议引入 schema 校验,例如 Zod;至少在前后端共享字段约束。 + +## 7. 当前主要风险 + +### 7.1 敏感信息风险 + +`.env.example` 和 `.env.local` 中存在 PocketBase 管理员邮箱和密码字段,并且当前样例包含明文值。即使这些只是旧后端配置,也应立即视为泄露风险: + +- 从仓库中移除真实凭据。 +- 轮换 PocketBase 管理员密码。 +- `.env.example` 只保留占位符。 +- 后续 FastAPI 服务端使用 Secret Manager 或部署平台环境变量。 + +### 7.2 前端与旧后端耦合 + +多个核心前端组件直接调用旧路径: + +- `Navbar`:`/api/auth/me`、`/api/auth/sync-session` +- `HeroSection`:`/api/auth/me`、`/api/meetup/check-user`、`/api/meetup/ensure-user` +- `JoinModal`:`/api/meetup/ensure-user` +- `join/page.tsx`:`/api/join`、`/api/join/status`、`/api/vip/check`、`/api/upload-media` +- `join/paid/page.tsx`:`/api/meetup/complete-order`、`/api/auth/change-password` +- payment hooks:`/api/pay`、`/api/pay/status` +- charts:`/api/geo/china` + +这些路径后续需要迁移到 FastAPI,并通过统一 API client 映射。 + +### 7.3 大量业务仍为 mock + +当前页面中明确存在“演示模式”“开发中”“即将上线”: + +- 反馈提交 +- 发起聚会 +- 成员地图 +- 数据报告 +- AI +- FIRE 计算器 +- 气候查询 +- 仪表盘图表 + +这不是坏事,说明前端原型覆盖面广;但后续排期需要明确哪些 mock 优先变成真实闭环。 + +### 7.4 日期数据过期 + +当前日期为 2026-06-06,但聚会页仍把 2026-03 和 2026-04 的活动标记为“即将举办”。后续真实数据必须由后端按当前时间计算活动状态,不能依赖静态 `isUpcoming`。 + +### 7.5 文档与实际运行不一致 + +- README 写 `localhost:3000`,脚本实际是 `3001`。 +- README 写 Node.js 18+,但 Next.js 16 / React 19 的实际运行要求需要在开发环境中确认并统一。 + +### 7.6 UI 资产和图片生产化不足 + +- 大量使用第三方随机头像和远程图片。 +- 未系统使用 `next/image`。 +- 没有图片域名、尺寸、占位、失败回退策略。 + +## 8. 后续 FastAPI + PocketBase 目标架构建议 + +### 8.1 推荐边界 + +建议后续边界如下: + +```text +Next.js 前端 + 只负责页面、交互、渲染、调用 FastAPI + +FastAPI + 负责业务 API、认证会话、权限、支付、上传、AI、统计聚合、外部服务集成 + +PocketBase + 负责数据存储、基础用户表、文件/记录管理、后台管理界面、必要的 realtime 能力 +``` + +关键原则: + +- 前端不要直接使用 PocketBase 管理员权限。 +- 复杂业务规则放在 FastAPI,不散落在前端。 +- PocketBase 作为数据和后台管理层,不承担所有业务流程。 +- 支付回调、会员开通、退款、上传鉴权、AI 调用必须走 FastAPI。 + +### 8.2 建议数据模型 + +首批 PocketBase collections 可按以下方向设计: + +- `users`:用户基础账号,可使用 PocketBase auth collection。 +- `profiles`:昵称、头像、职业、城市、简介、标签、匹配偏好。 +- `member_applications`:加入社区报名表。 +- `memberships`:会员等级、有效期、权益、状态。 +- `orders`:订单号、用户、金额、渠道、状态、业务类型。 +- `payment_events`:支付回调原始事件和处理状态。 +- `media_assets`:上传文件、类型、归属用户、用途。 +- `cities`:城市基础信息、slug、多语言名称、坐标、封面。 +- `city_metrics`:成本、网速、气候、安全、社区密度等指标。 +- `city_guides`:城市攻略、共享办公、社区推荐、tips。 +- `meetups`:聚会活动。 +- `meetup_rsvps`:活动报名关系。 +- `discussions`:讨论话题。 +- `comments`:评论。 +- `gigs`:赏金任务。 +- `gig_applications`:接单/投递。 +- `swipes`:匹配滑动记录。 +- `matches`:互相喜欢记录。 +- `feedback`:建议与 Bug 反馈。 +- `annual_reports`:年报生成结果和快照。 + +## 9. FastAPI API 清单草案 + +### 9.1 认证与用户 + +- `POST /auth/register` +- `POST /auth/login` +- `POST /auth/logout` +- `GET /auth/me` +- `POST /auth/change-password` +- `GET /users/me/profile` +- `PATCH /users/me/profile` + +### 9.2 加入社区与会员 + +- `GET /join/status` +- `POST /join/applications` +- `GET /memberships/me` +- `POST /payments/checkout` +- `GET /payments/{order_id}/status` +- `POST /payments/webhooks/{provider}` + +### 9.3 媒体上传 + +- `POST /media/uploads` +- `GET /media/{id}` +- `DELETE /media/{id}` + +### 9.4 城市与推荐 + +- `GET /cities` +- `GET /cities/{slug}` +- `GET /cities/{slug}/metrics` +- `GET /cities/{slug}/guide` +- `POST /recommendations/next-stop` +- `GET /routes/hot` + +### 9.5 社区模块 + +- `GET /meetups` +- `POST /meetups` +- `GET /meetups/{id}` +- `POST /meetups/{id}/rsvp` +- `DELETE /meetups/{id}/rsvp` +- `GET /discussions` +- `POST /discussions` +- `GET /discussions/{id}/comments` +- `POST /discussions/{id}/comments` + +### 9.6 匹配模块 + +- `GET /matches/candidates` +- `POST /matches/swipes` +- `GET /matches/me` +- `POST /reports/profile` +- `POST /blocks/profile` + +### 9.7 赏金与反馈 + +- `GET /gigs` +- `POST /gigs` +- `POST /gigs/{id}/apply` +- `POST /feedback` + +### 9.8 数据报告与 AI + +- `GET /stats/member-map` +- `GET /stats/city-ranking` +- `POST /reports/annual/generate` +- `GET /reports/annual/{id}` +- `POST /ai/assistant` + +## 10. 前端改造路线 + +### 阶段 0:清理与契约冻结 + +- 移除仓库中的真实密钥,轮换泄露风险凭据。 +- 明确旧 `app/api` 全部为 legacy,不继续扩展。 +- 建立 `NEXT_PUBLIC_API_BASE_URL`。 +- 梳理当前前端调用接口,写成接口契约文档。 +- 修正 README 端口和环境说明。 + +### 阶段 1:统一 API client + +- 新增统一 API client,集中处理: + - base URL + - credentials + - JSON 解析 + - 错误响应 + - 登录失效 + - loading / retry 策略 +- 替换 `fetch("/api/...")` 为领域服务函数,例如 `authApi.me()`、`joinApi.submit()`。 +- 前端保留 mock fallback,方便后端未完成时继续开发 UI。 + +### 阶段 2:认证、报名、支付闭环 + +优先原因:这是转化和会员收入核心链路。 + +- FastAPI 实现注册、登录、会话、改密。 +- FastAPI 实现报名表提交。 +- 实现支付下单、支付状态、支付回调、会员开通。 +- 实现上传鉴权和媒体资产记录。 +- 前端替换 Hero、JoinModal、JoinPage、JoinPaidPage、Navbar 的旧接口调用。 + +### 阶段 3:城市数据真实化 + +- 将 `cities.ts` 迁入 PocketBase。 +- 前端首页和仪表盘改为调用 `/cities`。 +- 城市详情弹窗拆分真实字段和占位字段。 +- 建立城市 slug,避免只用中文城市名作为业务 key。 + +### 阶段 4:社区功能真实化 + +- 聚会列表和发起聚会落库。 +- 讨论和评论落库。 +- 匹配候选人、滑动、match 记录落库。 +- 赏金墙发布和接单落库。 + +### 阶段 5:AI、年报、统计 + +- 接入 AI 助手。 +- 根据真实用户行为生成年度报告。 +- 地图、城市排名、增长趋势改由后端聚合。 + +### 阶段 6:运营后台与权限 + +- 使用 PocketBase Admin 作为轻量后台。 +- 增加内容审核、聚会审核、举报处理、会员管理、订单查询。 +- FastAPI 增加管理员 API 或管理脚本。 + +## 11. 建议优先级 + +P0: + +- 凭据清理与轮换。 +- 统一 API base URL 和 API client。 +- 认证、报名、支付、会员状态真实闭环。 +- 上传链路真实化。 + +P1: + +- 城市数据迁移 PocketBase。 +- 首页、城市详情、仪表盘接入真实城市 API。 +- 聚会列表和报名真实化。 +- 反馈提交真实化。 + +P2: + +- 匹配、讨论、赏金墙真实化。 +- 地图和数据报告真实化。 +- AI 助手上线。 + +P3: + +- 内容 CMS 化。 +- SEO metadata 完善。 +- 图片优化和 CDN 策略。 +- 自动化测试和监控。 + +## 12. 测试与验收建议 + +前端: + +- `pnpm lint` +- `pnpm build` +- 首页、加入表单、登录弹窗、支付回跳、城市筛选、语言切换、暗色模式的 Playwright E2E。 +- 移动端视口检查,尤其是首页网格、Join 表单、CityModal。 + +后端: + +- FastAPI 单元测试:认证、报名、支付状态机、权限。 +- 支付 webhook 幂等测试。 +- PocketBase collection rule 测试。 +- 媒体上传大小、类型、权限测试。 + +契约: + +- OpenAPI 自动生成。 +- 前端类型从 OpenAPI 生成或至少共享 DTO schema。 +- mock server 保持和 OpenAPI 一致。 + +## 13. 总结 + +当前项目的价值主要在前端产品原型和页面覆盖度:导航、首页、城市探索、会员加入、社区、工具、内容页都已经成型。短板集中在数据真实性、后端契约、认证支付安全、mock 数据和旧接口耦合。 + +后续开发不建议在旧 `app/api` 上继续补功能。更稳妥的路线是保留当前 Next.js 前端体验,新增 FastAPI 后端,PocketBase 作为数据和后台管理层,然后按“认证/报名/支付 -> 城市数据 -> 社区互动 -> AI/统计”的顺序逐步替换 mock 和旧接口。 diff --git a/app/[locale]/ai/page.tsx b/app/[locale]/ai/page.tsx index 16fb45f..d4adec6 100644 --- a/app/[locale]/ai/page.tsx +++ b/app/[locale]/ai/page.tsx @@ -3,11 +3,23 @@ import { useState } from "react"; import { useTranslation } from "@/i18n/navigation"; import Footer from "@/app/components/Footer"; +import { apiFetch } from "@/app/lib/api-client"; + +interface AssistantCity { + id: string; + slug?: string; + name: string; + costPerMonth?: number; + internetSpeed?: number; + overallScore?: number; +} export default function AIPage() { const { t } = useTranslation("ai"); const [query, setQuery] = useState(""); const [loading, setLoading] = useState(false); + const [answer, setAnswer] = useState(""); + const [cities, setCities] = useState([]); const exampleQueries = [ "我预算每月800刀,想亚洲热带,有稳定网,适合freelance写作,推荐城市+理由", @@ -15,11 +27,20 @@ export default function AIPage() { "生成3月清迈行程计划", ]; - const handleSubmit = (e: React.FormEvent) => { + const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!query.trim()) return; setLoading(true); - setTimeout(() => setLoading(false), 1500); + try { + const data = await apiFetch<{ answer: string; cities: AssistantCity[] }>("/api/ai/assistant", { + method: "POST", + body: JSON.stringify({ question: query }), + }); + setAnswer(data.answer); + setCities(data.cities || []); + } finally { + setLoading(false); + } }; return ( @@ -52,6 +73,25 @@ export default function AIPage() { + {(answer || cities.length > 0) && ( +
+ {answer &&

{answer}

} + {cities.length > 0 && ( +
+ {cities.map((city) => ( +
+

{city.name}

+

+ ¥{Number(city.costPerMonth || 0).toLocaleString()}/月 · {city.internetSpeed || 0}Mbps +

+

评分 {city.overallScore || "-"}/5

+
+ ))} +
+ )} +
+ )} +

{t("examples")} @@ -72,7 +112,7 @@ export default function AIPage() {

- {t("comingSoon")} + AI 助手已接入本机城市数据库,后续可替换为真实模型和用户画像推荐。