常见二次开发实例¶
以下示例描述当前前端推荐模式。示例中的 /reports 是占位业务路径,不代表后端已经提供该接口。
1. 新增页面¶
1.1 创建路由入口¶
import type { Metadata } from 'next';
import ReportsPageContent from '@/components/reports/ReportsPageContent';
export const metadata: Metadata = {
title: '报表中心',
};
export default function ReportsPage() {
return <ReportsPageContent />;
}
1.2 创建业务组件¶
组件负责交互和业务展示。需要 Hooks 时添加 'use client'。
1.3 登录与功能控制¶
- 纯客户端动作使用
useRequireLogin(); - 整个页面必须登录才能访问时,增加服务端用户检查;
- 可选功能在页面入口使用运行时开关;
- 权限不能只靠“隐藏菜单”,服务端接口仍需做授权检查。
1.4 路径兼容¶
链接、跳转和回调地址应使用项目提供的应用路径函数,不能直接硬编码 /reports,否则部署到 APP_BASE_PATH 后可能跳转错误。
2. 新增后端 API 方法¶
2.1 在领域 Service 中定义类型和方法¶
import { apiClient } from '@/lib/api/axios';
interface ReportListParams {
keyword?: string;
}
interface ReportListItem {
id: string;
name: string;
}
interface ReportListResponse {
code: number;
message: string;
data: ReportListItem[];
}
export const reportService = {
fetchReports: (params?: ReportListParams) =>
apiClient.get<unknown, ReportListResponse>('/reports', { params }),
};
浏览器实际请求 /server/reports,通用 Route Handler 会转发到配置的上游 /reports。普通 CRUD 通常不需要新增代理 Route 文件。
2.2 选择调用方式¶
- 共享列表:在 Zustand Store 中调用并缓存;
- 表单保存:在组件中使用
useServiceRequest; - Server Component 首屏:创建
.server.tsService 并使用serverApiClient; - 长连接:使用显式 SSE Route 和
apiClient.stream()。
2.3 检查业务成功¶
修改类请求不能只检查 HTTP 状态,应使用项目统一业务响应检查,再进行:
- success message;
- 关闭弹窗;
- 刷新 Store;
- 记录成功日志。
3. 新增前端自有 Route Handler¶
仅当逻辑属于 Next.js 前端服务时使用 /api,例如签名、健康检查、前端日志或预览编排。
必须处理:
- 请求方法和 Content-Type;
- 身份和权限;
- 参数校验;
- server-only 密钥;
- 超时与外部请求限制;
- 结构化日志;
- 受控错误响应。
不要把 /api 变成第二套后端 CRUD 代理。
4. 新增弹窗¶
可参考:
src/components/layout/UserAvatarPopover/RedeemCodeModal.tsx;src/components/layout/UserAvatarPopover/index.tsx。
推荐模式:
- 父组件管理 open 状态;
- 弹窗定义清晰的 Props 接口;
- 使用 Ant Design Modal 和 Form;
- 使用
useServiceRequest提交; - 关闭时重置表单;
- 成功后调用
onSuccess通知父组件刷新; - 日志只记录事件和错误码,不记录表单敏感值。
5. 新增 Zustand Store¶
适用于跨页面或跨组件共享的数据:
- 在
src/stores/定义 state、actions 和创建函数; - 在
src/providers/StoresProvider/创建 Provider; - 将 Provider 加入总组合;
- 如需首屏数据,在服务端布局读取并注入 initial state;
- 组件使用 selector 订阅最小状态片段;
- 对并发列表请求增加去重或缓存策略。
不要把一次按钮提交也放进全局 Store;也不要在多个组件中分别 useEffect 请求同一份共享数据。
6. 新增运行时配置¶
浏览器可见配置¶
- 在
src/lib/runtime-config.ts增加类型和默认值; - 在根布局构建注入值;
- 在
src/lib/consts/env.client.ts通过统一函数读取; - 更新
.env.example和环境变量文档; - 验证容器重启后生效且不需要重新构建。
浏览器可见配置不能包含密钥。
服务端私密配置¶
- 在
src/lib/consts/env.server.ts增加 getter; - 保留
server-only防护; - 明确必填或可选;
- 只在 Server Component、Route Handler 或
.server.ts中调用; - 不注入
window.__RUNTIME_CONFIG__。
7. 新增功能开关¶
功能开关适合控制不同部署环境的功能差异,但必须明确:
- 前端隐藏不等于权限控制;
- 页面路由也要检查开关;
- 后端接口必须独立授权;
- 默认值要符合安全和兼容预期;
- 用户手册需要标记“按部署配置显示”。
8. 修改品牌和主题¶
品牌名称、Logo 和 Favicon 优先使用运行时配置。颜色和 Token 可通过:
src/styles/globals.css;src/theme/antd-theme.ts;public/branding/theme.css;- Compose 的可选品牌文件挂载。
不要在多个业务组件中分散硬编码项目品牌名称和颜色。
9. 新增长连接接口¶
参考现有 src/app/server/user/events/route.ts 和 Agent run Route:
- 使用 Node.js runtime;
- 设置动态模式和合理的
maxDuration; - 委托统一代理;
- 传递取消信号;
- 记录流建立、结束和失败;
- 在 Nginx 配置足够长的读写超时;
- 明确重试是否安全。
10. 二开完成定义¶
一项前端二开至少满足:
- 路由在根路径和项目部署前缀下都可用;
- 未登录、无权限和功能关闭状态正确;
- loading、empty、error、success 状态完整;
- 深色与浅色主题可读;
- 浏览器无新增未处理异常;
- 日志不包含敏感信息;
pnpm build成功;- 用户操作文档和项目配置说明同步更新。