19 KiB
聚玩前端 缺陷审计报告
审计时间:2026-02-20 项目:聚玩(JuWan)— 基于 Next.js 16 + shadcn/ui + Tailwind CSS 4 的游戏陪玩平台前端 仓库结构:约 100 个源文件,分布在 app/(页面)、components/(共享组件)、lib/(工具/类型/mock 数据)、store/(Zustand 状态管理) 背景:本项目由 AI 辅助生成,本报告检查脏代码、AI 生成痕迹、劣质 UI 设计、与 PLAN.md 的偏差等问题 审计方法:8 个并行审计 Agent 分别负责不同维度(代码卫生、AI 痕迹、UI 设计、文案质量、mock 数据、架构、功能完整性),交叉验证
一、代码卫生
对全部 .ts/.tsx/.css/.json 文件做了关键词扫描。
扫描结果:全部为零。
@ts-ignore/@ts-expect-error/as any:零biome-ignore/eslint-disable/prettier-ignore:零console.log/console.warn/console.error:零- 空 catch 块:零
- 代码注释:整个 app/components/store/lib 目录没有一行注释
- AI 工具签名(Claude / Copilot / Cursor / GPT / Sisyphus / OpenCode):零
- 对话痕迹("根据你的要求" / "as you requested" 等):零
- Git 提交消息:风格统一(Conventional Commits),无 AI 工具提及
唯一残留:next.config.ts:4 的脚手架占位注释 /* config options here */。
结论:代码表面非常干净。AI 痕迹不在注释层面,而在内容和设计层面(见后续章节)。
二、Emoji 滥用
2.1 游戏图标用 emoji 代替 [严重]
lib/mock-data.ts 第 71-78 行定义了 8 个游戏,它们的 icon 字段全部使用 emoji 字符:
🎮(英雄联盟)👑(王者荣耀)🔫(和平精英)⚔️(原神)🌟(永劫无间)🪖(CS2)🛡️(DOTA2)💥(绝地求生)
这些 emoji 通过 {game.icon} 被渲染到以下 UI 位置:
app/(main)/page.tsx:46— 首页游戏分类卡片app/(main)/search/page.tsx:212— 搜索页游戏筛选标签app/(dashboard)/dashboard/services/new/page.tsx:73— 服务发布页游戏选择列表
这是典型的 AI 生成偷懒行为——用 emoji 代替真实图标。应替换为 lucide-react 图标或自定义 SVG 图标映射。
2.2 UI 标签中的 emoji [严重]
app/(main)/community/page.tsx:66 — 社区页帖子中出现 📋 关联订单秀单,在 UI 标签/区块标题场景使用 emoji 装饰,是典型 AI 生成风格。
2.3 可接受的 emoji [低]
lib/mock-data.ts:459 — 聊天消息 "感谢好评!下次继续带飞 💪",这是模拟用户聊天行为,emoji 使用合理,可保留。
三、AI 味文案
项目中没有直接的 AI 工具签名,但大量 UI 文案带有明显的 AI 生成特征——空洞的营销语、模板化表达、过于正式的语气。
3.1 首页/搜索页营销腔 [严重]
| 文件:行号 | 文案内容 | 问题 |
|---|---|---|
app/(main)/page.tsx:15 |
"专业陪玩、代练、上分,覆盖主流游戏,安全可靠" | 空洞的"全都好"营销句,任何平台都能用 |
app/(main)/search/page.tsx:383 |
"找到最适合你的游戏伙伴,一起畅玩游戏世界" | 泛化 AI 文案,无具体信息 |
app/(main)/search/page.tsx:407 |
"调整筛选条件以找到更匹配的陪玩" | 说明书口吻,不像产品在和用户说话 |
components/footer.tsx:14 |
"专业游戏陪玩服务平台" | 通用 slogan,品牌辨识度为零 |
3.2 Mock 数据中的模板化文案 [中等]
lib/mock-data.ts 中的文本内容几乎全部带有 AI 生成特征:
服务描述(第 87-135 行):标题和描述高度模板化——"上分陪玩"、"代练上星"、"带飞"、"安全高效"、"保证胜率60%+"。这些像是 AI 批量生成的电商文案,缺少真实卖家会写的个性化表达。
用户简介(第 37、56、65 行):营销腔明显——"全国百强"、"全球精英"、"专业工作室"。真实用户简介通常更随意。
店铺介绍(第 188 行):"专业电竞陪玩工作室,拥有50+签约打手,覆盖主流游戏"——万能介绍模板。
评价内容(第 280、292、304 行):语句太完整、太"好文案",缺少真实评价中常见的口语化表达、碎句、停顿词。
聊天消息(第 382、402 行):偏客服话术("请问什么时候方便开始"),真实私聊通常更短更随意。
通知文案(第 516 行):"聚玩春节活动即将开始,敬请期待!"——"敬请期待"式公告模板化明显。
3.3 页面文案细节 [中等]
| 文件:行号 | 文案内容 | 问题 |
|---|---|---|
app/(main)/post/new/page.tsx:110 |
"分享你的游戏体验..." | 典型 AI 占位句,泛而无指向 |
app/(main)/post/[id]/page.tsx:127 |
"来抢沙发吧" | 老论坛语感,和当前产品调性不匹配 |
app/(order)/review/[id]/page.tsx |
"确保真实性和公正性" | 偏 AI/公文腔 |
app/(main)/page.tsx:21 |
"搜索打手" | 用词偏硬,和"陪玩"语境不统一 |
3.4 术语不统一 [严重]
同一概念在不同位置使用不同称呼,这是 AI 分次生成不同页面时缺乏全局一致性的典型表现:
| 位置 | 对用户的称呼 | 对服务提供者的称呼 |
|---|---|---|
components/header.tsx:38 |
"消费者" | — |
| 社区页 roleLabels | "玩家" | — |
components/header.tsx:93 搜索框 |
— | "打手" |
| 首页/其他页面 | — | "陪玩" |
应建立统一的术语体系并全局替换。
四、Mock 数据 AI 味道
lib/mock-data.ts 是全站的模拟数据源,约 550 行。其中的数据分布和内容风格暴露了大量 AI 批量生成的特征。
4.1 用户名/昵称过于规整 [中等]
第 22-62 行定义了 5 个用户。用户名模式过于规整(全是英文词+下划线+拼音姓,如 pro_zhang、carry_chen),昵称过于"人设化"(张小明、李大神、王老板、陈Carry、刘甜甜)。真实用户名通常有数字、大小写混搭、随机后缀(如 xm_2003、LDShen666、甜甜酱w)。
4.2 数值分布过于理想化 [中等]
- 价格:全是整数且多为 5 的倍数(30、40、50),缺少真实定价噪声(如 23、29、33、58)
- 评分:集中在 4.7-4.9,完单率 0.97-0.99,区间极窄,分布过于理想化
- 订单总价:都刚好是服务单价×3(90/120/60),模式过齐
4.3 数据关联不匹配 [严重]
- 打手累计订单数很高(645/832/1256),但全局评论只有 3 条——一个接了 1256 单的打手只有 1 条评价,严重不合理
- 店铺写了 12 名打手、5600 单,但当前只挂了 2 名店内打手,样本关系断裂
4.4 数据结构冗余 [中等]
第 85-86、214-217 行:同一实体重复存储 id+name(如 gameId + gameName、consumerId + consumerName、playerId + playerName)。这种冗余容易导致数据漂移,是 AI "先堆字段再补逻辑"的常见写法。
五、类型建模问题
lib/types.ts 定义了全站的 TypeScript 类型。主要问题是约束过松——AI 倾向于用 optional 字段"兜住"所有情况,而不是用联合类型精确建模。
5.1 Order 状态机松散 [严重]
第 76-101 行:Order 类型用大量 optional 字段承载状态机(acceptedAt?、closedAt?、completedAt?、cancelledAt?),但没有按 status 区分的联合类型。例如,一个 status: "pending" 的订单在类型层面也允许有 completedAt,这在逻辑上是矛盾的。应改为按状态区分的判别联合类型。
5.2 其他类型问题 [中等]
| 位置 | 问题 |
|---|---|
types.ts:129-132 |
ChatSession 的 type 已区分 order/consultation,但 orderId 仍是 optional,缺少判别联合约束(type 为 order 时 orderId 应必填) |
types.ts:117-125 |
Dispute.result 与 status 无联动,resolved 状态时也可无结果 |
types.ts:18,29,31 |
Game.category、PlayerService.unit、availability 过宽(全是 string),应使用字面量联合类型 |
types.ts:112-113 |
Review.content? + sealed 缺语义关系,允许"无内容且未密封"等不自然组合 |
| 全局 | 时间字段全部裸 string,无 ISO 8601 / epoch 约束 |
六、代码架构问题
6.1 Auth 系统设计缺陷 [严重]
当前的认证系统是一个极简的 Zustand store,存在多个设计问题:
| 文件 | 问题 |
|---|---|
store/auth.ts |
login() 函数不接收任何参数(用户信息、token),直接硬编码设置登录状态 |
store/auth.ts |
switchRole() 无权限校验,任何人可切换到任何角色 |
store/login-dialog.ts |
状态过窄,只有 open/close,无法携带"登录后继续动作"的上下文(如用户点了收藏→弹登录→登录后应自动收藏) |
lib/use-require-auth.ts |
登录成功后不会自动续执被中断的操作 |
components/header.tsx |
用户信息来自 mock 常量而非 auth store,导致状态源分裂 |
6.2 重复代码 [中等]
以下常量/组件在多处重复定义,应提取到共享模块:
| 重复内容 | 出现位置 |
|---|---|
statusLabels(订单状态中文映射) |
app/(order)/orders/page.tsx:15、app/(order)/order/[id]/page.tsx:20、app/(dashboard)/dashboard/page.tsx:12 |
roleLabels(用户角色中文映射) |
app/(main)/community/page.tsx:9、app/(main)/post/[id]/page.tsx:12 |
| 侧栏组件结构 | components/account-sidebar.tsx 与 components/dashboard-sidebar.tsx 结构高度重复 |
| Layout 壳层 | app/(account)/layout.tsx 与 app/(dashboard)/layout.tsx 完全相同的侧栏+内容布局 |
6.3 过度工程 [低-中等]
| 位置 | 问题 |
|---|---|
app/(main)/search/page.tsx:77,82 |
对轻量计算(取最小价格、取单位)做了不必要的 useMemo |
app/(main)/search/page.tsx:335,354,355 |
对类型中已标记为必填的 services 字段做防御式 ?. + || [0] |
app/(order)/orders/page.tsx:105 |
JSX 内使用 IIFE(立即执行函数)做条件渲染,降低可读性 |
store/player-status.ts:9,22 |
getStatus 是单行包装函数(get().statuses[playerId]),抽象价值很低 |
6.4 响应式缺失 [中等]
components/account-sidebar.tsx和components/dashboard-sidebar.tsx固定w-56,无移动端断点- 对应的 layout 文件直接常驻侧栏,未做
md:以上的条件显示 - 移动端用户会看到被侧栏挤压的内容区
6.5 假异步模式 [中等]
以下 5 处使用 await new Promise((r) => setTimeout(r, 500)) 模拟表单提交,是 AI 生成 demo 的典型模式:
app/(auth)/login/page.tsx:31app/(auth)/register/page.tsx:38components/login-dialog.tsx:41app/(dashboard)/dashboard/services/new/page.tsx:44app/(main)/post/new/page.tsx:52
6.6 硬编码问题 [中等]
多处将用户 ID、数据索引等写死,导致页面只能展示特定 mock 数据:
| 位置 | 硬编码内容 |
|---|---|
app/(main)/player/[id]/page.tsx:34 |
收藏判断写死 userId === "u1" |
app/(main)/shop/[id]/page.tsx:29 |
收藏用户写死 u1 |
app/(order)/chat/[id]/page.tsx:29 |
当前用户写死 participants[0] |
app/(dashboard)/dashboard/page.tsx:27-28 |
直接取第一个 player/shop |
app/(dashboard)/dashboard/shop/page.tsx:13 |
固定 mockShops[0] |
app/(dashboard)/dashboard/shop/employees/page.tsx:23 |
写死 shop1 |
6.7 占位渲染 [严重]
以下位置有图片/上传等功能的数据结构,但 UI 只渲染了占位文字,是明显的原型态残留:
| 位置 | 占位内容 |
|---|---|
app/(main)/post/[id]/page.tsx:70 |
有图片数据却只渲染「图片」二字 |
app/(order)/dispute/[id]/page.tsx:81 |
证据图只渲染「截图」二字 |
app/(account)/verify/page.tsx:102 |
身份证上传是静态卡片 |
app/(dashboard)/dashboard/shop/templates/page.tsx:88 |
直接写死"原型演示中暂不支持拖拽" |
七、UI 设计质量
整体评价:项目功能上是完整的 Draft,但视觉上患有"shadcn 默认主题综合征"——看起来像 B2B SaaS 后台管理系统,而不是面向消费者的游戏平台。
7.1 各页面成熟度评级
| 页面 | 评级 | 核心问题 |
|---|---|---|
首页 app/(main)/page.tsx |
Prototype | Hero 区只是居中文字+两个按钮,零视觉冲击力;三段区块都用"标题+查看全部+卡片列表"重复模板 |
搜索页 app/(main)/search/page.tsx |
Draft(功能好) | 筛选/排序/移动端适配做得不错,但卡片信息过密缺视觉层次;整卡可点同时又有「查看详情」按钮,交互语义重复 |
打手详情 app/(main)/player/[id]/page.tsx |
Draft | 最通用的 profile 布局(头像左+信息右+Tabs 下),无个性;bio 区是纯灰色盒子 |
店铺详情 app/(main)/shop/[id]/page.tsx |
Draft | 不像店铺,像组件列表;banner 文字叠加用最基础的 bg-black/40 |
登录/注册 app/(auth)/ |
Prototype | 最简表单(图标+标题+输入框+按钮),无背景图/分屏布局/社交登录 |
订单管理 app/(order)/ |
Production-ready | 状态步骤指示器和上下文操作按钮做得不错 |
仪表盘 app/(dashboard)/ |
Production-ready(通用) | 零定制,和 shadcn/ui 官方示例一模一样;缺图表/趋势可视化 |
社区 app/(main)/community/page.tsx |
Draft | 通用论坛外观,帖子类型无视觉区分;缺最新/最热/关注切换和标签筛选 |
Header components/header.tsx |
Production-ready | 功能完整(sticky、backdrop-blur、移动端 Sheet),但缺品牌感 |
Footer components/footer.tsx |
Draft | 标准 4 列布局;支持区链接是纯 <span> 不可点击,用户预期会落空 |
7.2 系统性设计问题
品牌感缺失:app/globals.css 整套 CSS 变量接近黑白灰中性色,没有明确主色和游戏化氛围。作为游戏陪玩平台,视觉上应该有活力和沉浸感,而不是企业后台的冷淡风格。
Card 过度使用:几乎所有内容都装在 <Card> 组件里,1px 边框+白色背景,缺少视觉变化。应该用留白、背景色渐变、字体层级来分隔内容,而不是全靠卡片边框。
微交互缺失:当前 hover 效果只有 hover:shadow-md,缺少 scale 变化、颜色过渡、focus 指示器等。游戏平台用户期望更丰富的交互反馈。
暗色模式未考虑:游戏平台通常偏暗色主题,当前项目完全没有暗色模式的设计考虑。
字体配置不完整:app/layout.tsx 中只配了 Geist 字体的 latin subset,中文站点缺少中文字体配置,中文内容会 fallback 到系统默认字体。
导航设计问题:主导航是「首页/社区/订单/消息」,缺少核心业务入口"找陪玩"或"找店铺",新用户不知道从哪里开始。移动端抽屉里没有通知入口,和桌面端信息架构不对齐。
八、功能完整性(对照 PLAN.md)
PLAN.md 是本项目的需求规格文档。以下列出当前实现与 PLAN 之间的偏差。
8.1 未实现 / 不完整的功能
| 功能 | 当前状态 | 与 PLAN 的偏差 |
|---|---|---|
| 订单状态流转 | 不完整 | 只展示状态标签和步骤条,缺少接单、发起结单、确认结单、超时自动流转等可执行动作 |
| 争议仲裁 | 不完整 | 只有发起争议+静态详情展示,缺少双方举证、平台处理节点、申诉动作闭环 |
| 密封评价 | 未实现 | 只有文案提示"评价将在双方都提交后公开",但展示逻辑直接显示评价内容,未实现双方同时揭晓机制 |
| 聊天会话 | 部分实现 | 有咨询/订单会话标签和只读状态,但缺少咨询转订单、时效关闭、争议期特殊规则 |
| 店铺规则设置 | 未实现 | 派单模式、多店挂靠、独立接单等规则是只读 Badge 展示,不可配置 |
| 钱包分流 | 未实现 | 消费者充值和打手/店主提现混在同一界面,PLAN 要求按身份展示不同视图 |
| 身份认证审核 | 不完整 | 只有"填写→审核中"两个状态,缺少拒绝、补件、重新提交等完整审核状态机 |
| 搜索混合展示 | 未实现 | 当前只筛选 mockPlayers,PLAN 要求"店铺打手+独立打手混合展示" |
| 社区筛选排序 | 未实现 | 缺少时间/热度排序、标签/游戏筛选,PLAN 中有明确要求 |
8.2 违反 PLAN 的设计 [严重]
| 位置 | 问题 | PLAN 要求 |
|---|---|---|
app/(main)/shop/[id]/page.tsx:67-71 |
店铺公开页直接展示抽成比例(如"平台抽成 10%") | PLAN 明确规定消费者不可见抽成比例和打手实收金额 |
app/(account)/settings/page.tsx:74 |
设置页可直接切换到 owner/player 角色,无需认证 | PLAN 要求打手/店主身份需通过认证申请和审核后才能启用 |
九、优先级建议
P0 — 必须修(违反 PLAN 或严重 AI 痕迹)
- 删除 emoji 游戏图标,替换为 lucide-react 图标或自定义 SVG 映射
- 重写首页 hero 和搜索页的 AI 营销文案,使用具体、有人味的表达
- 统一术语体系(确定"陪玩"还是"打手","消费者"还是"玩家")
- 修复店铺页泄露抽成比例(违反 PLAN)
- 修复设置页可绕过认证直接切角色(违反 PLAN)
- 删除占位渲染和"原型演示"文案
P1 — 应该修(代码质量和数据真实性)
- 重写 mock 数据使其更真实(用户名加噪声、价格不规整、评分分布拉宽、评价口语化)
- 收敛重复常量(statusLabels、roleLabels)到
lib/constants.ts共享模块 - 加强类型建模(Order 按状态区分的联合类型、ChatSession 判别联合)
- 修复 auth store 设计(login 接收参数、switchRole 权限校验、登录后续执)
- 侧栏移动端适配(md: 断点条件显示)
- 配置中文字体 subset
- 修复 Footer 支持区链接不可点击
P2 — 设计提升(视觉和交互)
- 建立品牌色系,替换黑白灰中性色,体现游戏平台氛围
- 首页 hero 重设计(动态背景、品牌色、视觉冲击力)
- 减少 Card 过度使用,用留白和字体层级分隔内容
- 添加微交互(hover scale/color transition、loading skeleton)
- 暗色模式支持
- 登录页分屏设计(一侧表单、一侧品牌视觉)
- 仪表盘添加图表/趋势可视化
P3 — 功能补全(对照 PLAN.md)
- 订单状态机完整实现(接单→进行中→结单确认→完成,含超时机制)
- 密封评价双方揭晓机制
- 争议仲裁完整流程(双方举证→平台处理→结果→申诉)
- 聊天持久化和实时通信(WebSocket 或轮询)
- 钱包按身份分流视图
- 身份认证完整状态机(提交→审核→通过/拒绝→补件→重新提交)
- 搜索混合展示(店铺打手+独立打手)
- 社区筛选排序(最新/最热/关注、标签/游戏筛选)