28 KiB
28 KiB
前端技术规范
运行环境
- Node.js >= 20.9
- npm >= 10.x
项目结构
Monorepo 架构
- 包管理:npm workspaces + Turborepo 2.0
- 项目根目录:
geo_bsp/ - 共享包命名空间:
@geomative/*
应用划分
apps/
├── web/ # 公开网站 — Next.js 16 (Turbopack),端口 3000(国际站) / 3002(中文站)
├── admin/ # 后台管理系统 — Vite 6 + React 19 + React Router DOM 7,端口 3003
└── api/ # 后端 API 服务 — Hono,端口 3001
packages/
├── types/ # 共享 TypeScript 类型定义 (@geomative/types)
├── ui/ # 共享 UI 组件库 (@geomative/ui)
├── utils/ # 共享工具函数 (@geomative/utils)
└── config/ # 共享配置 — Tailwind、ESLint、Prettier、TSConfig (@geomative/config)
共享包依赖方向
config -> types -> utils -> ui -> apps/*
- 禁止循环依赖
types不依赖uiutils不依赖uiui可依赖types和utils
技术栈
| 类别 | 技术 | 版本 |
|---|---|---|
| 前端框架 | Next.js (App Router) | 16 |
| 后台管理 | Vite + React Router DOM | 6 / 7 |
| UI 库 | React | 19 |
| 样式方案 | Tailwind CSS | 3.4 |
| 类型系统 | TypeScript | 5.0+ |
| 服务端状态 | TanStack React Query | API 数据获取、缓存、同步 |
| 客户端状态 | Zustand | 全局 UI 状态、认证状态、权限缓存(仅 admin) |
| 表单处理 | React Hook Form + Zod | - |
| 富文本编辑 | Tiptap | - |
| 国际化 | next-intl | 4.9 |
| 认证 | JWT + RBAC | - |
apps/web — 公开网站
路由结构(App Router)
app/
├── page.tsx # 首页
├── layout.tsx # 根布局(国际化)
├── globals.css # 全局样式
│
├── about/ # 关于我们
│ ├── company/ # 公司介绍
│ ├── history/ # 发展历程
│ ├── certifications/ # 资质认证
│ ├── partners/ # 合作伙伴
│ ├── dealers/ # 经销商
│ └── contact/ # 联系我们
│
├── products/ # 产品中心
│ ├── [category]/ # 产品分类
│ └── [category]/[slug]/ # 产品详情
│
├── solutions/ # 解决方案
│ ├── page.tsx # 方案总览
│ └── [slug]/ # 方案详情
│
├── academy/ # 技术学院
│ ├── product-operation/ # 产品操作
│ ├── case-library/ # 案例库
│ ├── geophysical-knowledge/ # 物探知识
│ └── certification/ # 认证培训
│
├── support/ # 技术支持
│ ├── knowledge-base/ # 知识库
│ ├── faq/ # FAQ
│ ├── downloads/ # 下载中心
│ ├── software-updates/ # 软件更新
│ ├── after-sales/ # 售后服务
│ └── warranty/ # 保修政策
│
├── community/ # 社区动态
├── geometa/ # GeoMeta 平台
├── configurator/ # 报价配置器
├── cases/[slug]/ # 案例详情
├── pages/[slug]/ # 动态页面
├── privacy-policy/ # 隐私政策
└── terms-of-use/ # 使用条款
关键配置
- ISR 策略:首页 30 分钟,产品页 1 小时
- 动态路由参数为
Promise类型:params: Promise<{ slug: string }> - 开发模式使用
--turbopack标志 - 多语言:中文站无前缀,国际站
/en前缀
apps/admin — 后台管理系统
当前架构(Vite + React Router)
Admin 使用 Vite 6 + React 19 + React Router DOM 7,非 Next.js。路由通过 createBrowserRouter 配置,所有页面使用 lazy() 懒加载实现代码分割。
apps/admin/src/
├── components/
│ ├── editor/ # Tiptap 富文本编辑器
│ ├── help/ # 帮助系统组件
│ ├── navigation/ # 导航管理组件
│ ├── seo/ # SEO 管理组件
│ └── structured-editors/ # 结构化页面编辑器
├── data/help/ # 帮助文档数据
├── hooks/ # 自定义 Hooks
├── lib/
│ ├── auth.ts # JWT Token 管理
│ ├── api-client.ts # API 客户端(自动刷新 Token)
│ ├── help-utils.ts # 帮助工具
│ └── utils.ts # 通用工具
├── pages/ # 页面组件(全部懒加载)
├── providers/
│ ├── auth-provider.tsx # 认证上下文(将迁移至 useAuthStore)
│ └── query-provider.tsx # React Query Provider
├── stores/ # Zustand 全局状态管理
│ ├── useAuthStore.ts # 认证状态(替代 AuthProvider Context)
│ ├── useUIStore.ts # 全局 UI 状态(侧边栏折叠、全局 loading,持久化)
│ ├── useLocaleStore.ts # 编辑器语言偏好(持久化)
│ └── usePermissionStore.ts # 权限数据缓存(为细粒度权限矩阵预留)
└── router/
├── index.tsx # 路由配置(createBrowserRouter)
├── AppRouter.tsx # 路由容器
├── DashboardLayout.tsx # 仪表盘布局(侧边栏 + 内容区)
├── AuthLayout.tsx # 登录页布局
└── AuthGuard.tsx # 路由守卫(JWT 认证检查)
当前路由结构
/login # 登录页(AuthLayout)
/ # 仪表盘首页(AuthGuard 保护)
/navigation # 导航管理
/navigation/:menuId # 菜单分支列表
/navigation/:menuId/:branchId # 子分支列表
/navigation/:menuId/:branchId/sub/:subBranchId # 子分支详情
/pages # 页面列表
/pages/:pageId # 页面编辑器
/pages/fixed/:slug # 固定页面编辑器
/content # 内容管理首页
/content/events # 活动管理
/content/news # 新闻管理
/content/reveals # 发布管理
/downloads # 下载资源列表
/downloads/categories # 下载分类管理
/downloads/:id # 下载资源编辑器
/analytics # 数据分析
/permissions # 权限管理
/settings # 系统设置
/about-me # 个人信息
/manual # 使用手册
/help/:pageId # 帮助详情
当前侧边栏菜单
导航管理 /navigation module: navigation
页面管理 /pages module: pages
内容管理 /content module: content
权限管理 /permissions module: permissions
系统设置 /settings module: settings
使用手册 /manual module: settings
About Me /about-me module: settings
多模块演进计划
Admin 将从当前单一 CMS 后台演进为统一企业管理平台,新增设备管理、报价管理、运输管理等模块。详见 docNew/12-Admin多模块架构设计.md。
目标目录结构(演进后):
app/(dashboard)/
├── layout.tsx # 统一布局,侧边栏按权限动态渲染
├── (cms)/ # 官网管理模块
│ ├── navigation/ # 导航管理
│ ├── pages/ # 页面管理
│ ├── content/ # 内容管理
│ ├── downloads/ # 下载资源
│ └── seo/ # SEO 管理
├── (devices)/ # 设备管理模块(新增)
│ ├── list/ # 设备列表
│ ├── [id]/ # 设备详情
│ ├── maintenance/ # 维护记录
│ └── categories/ # 设备分类
├── (quotations)/ # 报价系统模块(新增)
│ ├── list/ # 报价列表
│ ├── create/ # 新建报价
│ ├── [id]/ # 报价详情
│ └── templates/ # 报价模板
├── (shipping)/ # 运输管理模块(新增)
│ ├── orders/ # 运输工单
│ ├── tracking/ # 物流追踪
│ └── logistics/ # 物流商管理
└── (system)/ # 系统管理(跨模块)
├── users/ # 用户管理
├── roles/ # 角色管理 + 权限矩阵配置
├── locales/ # 语言设置
└── settings/ # 系统配置
目标侧边栏分组(按权限动态渲染):
官网管理
├── 导航管理
├── 页面管理
├── 内容管理
└── 下载资源
设备管理(新增)
├── 设备列表
├── 维护记录
└── 设备分类
报价管理(新增)
├── 报价列表
├── 新建报价
└── 报价模板
运输管理(新增)
├── 运输工单
├── 物流追踪
└── 物流商管理
系统设置
├── 用户管理
├── 角色权限
├── 语言设置
└── 系统配置
模块间隔离原则:
- 路由隔离:每个模块独立路由分组
(module-name)/ - 组件隔离:模块专用组件放模块目录内,跨模块复用的提取到
packages/ui - API 隔离:每个模块独立 API namespace(如
/admin/devices/*) - 类型隔离:每个模块独立类型文件,通过
packages/types统一导出 - 状态隔离:React Query key 使用模块前缀(如
['devices', 'list']),Zustand store 按职责拆分不按模块拆分 - 禁止跨模块直接引用,必须通过共享包通信
API 路由规划
/admin/auth/* # 认证(现有)
/admin/navigation/* # 导航管理(现有)
/admin/pages/* # 页面管理(现有)
/admin/content/* # 内容管理(现有)
/admin/analytics/* # 数据分析(现有)
/admin/downloads/* # 下载资源(现有)
/admin/users/* # 用户管理(现有)
/admin/devices/* # 设备管理(新增)
/admin/quotations/* # 报价管理(新增)
/admin/shipping/* # 运输管理(新增)
/admin/permissions/* # 权限矩阵管理(新增)
编码规范
命名规范
文件命名
- 组件文件:PascalCase,如
Button.tsx、HeroCarousel.tsx - 工具/钩子文件:camelCase,如
useAuth.ts、fetchNavigation.ts - 类型文件:camelCase,如
models.ts、cms.ts - 样式文件:kebab-case,如
globals.css - 配置文件:kebab-case,如
tailwind.config.ts、next.config.ts - 页面目录:kebab-case,如
products/、solutions/、tech-academy/ - 测试文件:被测文件名 +
.test.ts(x),如Button.test.tsx
代码命名
- 组件名:PascalCase,如
LayoutShell、HomeHero - 函数/变量名:camelCase,如
fetchNavigation、activeLocale - 常量:UPPER_SNAKE_CASE,如
MAX_RETRIES、DEFAULT_LOCALE - 类型/接口名:PascalCase,如
NavigationItem、PageContent - 枚举值:PascalCase,如
ButtonVariant.Primary - 自定义 Hook:
use前缀,如useAuth、useTranslations - 事件处理函数:
handle前缀,如handleSubmit、handleClick - 布尔变量/属性:
is/has/should前缀,如isLoading、hasError
类型命名后缀约定
- API 响应类型:
XxxResponse,如ProductsResponse - API 请求参数:
XxxRequest,如CreatePageRequest - Props 类型:
XxxProps,如ButtonProps - 状态类型:
XxxState,如FormState - 枚举类型:无后缀,如
Locale、ButtonVariant
导入规范
导入顺序
// 1. React / Next.js 核心模块
import { useState, useEffect } from 'react';
import { NextRequest } from 'next/server';
// 2. 第三方库
import { useTranslations } from 'next-intl';
import { useForm } from 'react-hook-form';
// 3. 共享包 (@geomative/*)
import { NavigationItem, Product } from '@geomative/types';
import { Button, Card } from '@geomative/ui';
// 4. 应用内部模块(使用路径别名)
import { apiClient } from '@/lib/api';
import { AuthProvider } from '@/providers/auth-provider';
// 5. 相对路径导入
import { LayoutClientShell } from './components/LayoutClientShell';
import { fetchNavigation } from '../lib/navigation';
// 6. 类型导入(使用 type 关键字)
import type { Metadata } from 'next';
路径别名
apps/web:使用@/前缀映射到src/或根目录apps/admin:使用@/前缀映射到src/- 共享包:使用
@geomative/*命名空间
导出规范
- 优先使用命名导出(named export)
- 每个组件文件一个主组件导出
- 使用 barrel export(
index.ts)整理模块导出 - 类型导出使用
export type语法
// 组件导出示例
export { Button } from './Button';
export type { ButtonProps, ButtonVariant } from './Button';
组件规范
Server Components vs Client Components(apps/web)
- 默认使用 Server Components(Next.js App Router 约定)
- 仅在需要交互(state、effects、event handlers)时使用 Client Components
- Client Components 必须在文件顶部添加
"use client"指令 - 布局组件(Layout)默认为 Server Component
- 数据获取优先在 Server Component 中完成
// Server Component — 默认,无需声明
export default async function ProductPage({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
const product = await fetchProduct(slug);
return <ProductDetail product={product} />;
}
// Client Component — 需要交互时使用
"use client"
import { useState } from 'react';
export function ProductFilter({ categories }: ProductFilterProps) {
const [active, setActive] = useState<string>('all');
// ...
}
组件结构顺序
// 1. "use client" 指令(如需要)
"use client"
// 2. 导入
import { useState } from 'react';
// 3. 类型定义
interface ExampleProps {
title: string;
children: React.ReactNode;
}
// 4. 组件定义
export function Example({ title, children }: ExampleProps) {
// 4a. hooks
const t = useTranslations('common');
// 4b. 派生状态
const formattedTitle = title.toUpperCase();
// 4c. 事件处理
const handleClick = () => { /* ... */ };
// 4d. 渲染
return (
<div onClick={handleClick}>
<h2>{formattedTitle}</h2>
{children}
</div>
);
}
组件设计原则
- 单一职责:每个组件只做一件事
- 组合优于继承:使用 children 和 props 组合
- Props 解构:始终解构 props,不要使用
props.xxx - Forward Ref:可复用组件需要支持 ref 转发
- 有意义的默认值:为可选 props 提供合理的默认值
样式规范
Tailwind CSS 使用约定
- 使用 Tailwind 工具类,禁止手写 CSS(除非 CSS 变量或动画关键帧)
- 类名顺序遵循一致性(建议:布局 -> 尺寸 -> 间距 -> 排版 -> 颜色 -> 其他)
- 超过 5 个类名时考虑提取为组件或使用
@apply(谨慎使用) - 响应式设计使用 Mobile-first 方式:
md:->lg: - 条件样式使用模板字符串或
clsx/cn工具函数
设计令牌(Design Tokens)
| 令牌 | 值 | 用途 |
|---|---|---|
| 主色 | #3a6b35 |
品牌绿,CTA 按钮、强调元素 |
| 辅色 | 大地色系 | 深绿、岩石灰、矿物绿 |
| 字体 | Inter | 英文主字体 |
| 中文回退 | Source Han Sans SC, PingFang SC | 中文排版 |
| 断点 | md: 769px, lg: 1025px |
响应式分界 |
| 触摸目标 | 最小 44px | 移动端可访问性 |
| 对比度 | >= 4.5:1 | WCAG 2.1 AA |
响应式断点
/* Mobile-first */
/* 默认:< 769px (Mobile) */
/* md: >= 769px (Tablet) */
/* lg: >= 1025px (Desktop) */
TypeScript 规范
- 启用 strict 模式
- 禁止使用
any,如必须使用需添加注释说明原因 - 函数参数和返回值必须有明确的类型注解
- 优先使用
interface定义对象类型,type用于联合类型、工具类型 - 使用
as const断言定义常量对象 - 异步函数返回类型明确标注
Promise<T> - 使用 TypeScript 枚举或联合字面量类型替代魔法字符串
// 推荐
interface NavigationItem {
id: string;
title: Record<Locale, string>;
path: string;
}
type Locale = 'zh-CN' | 'en';
type ButtonVariant = 'primary' | 'secondary' | 'outline';
// 避免
const config: any = {}; // 禁止
function handleClick(e) { /* ... */ } // 缺少类型
国际化规范(next-intl,apps/web)
翻译文件
- 翻译文件位于
apps/web/messages/目录 - 文件格式:JSON(
zh-CN.json、en.json) - 使用命名空间分隔:
home、products、common、nav等
使用方式
// Server Component
import { useTranslations } from 'next-intl';
export default function Page() {
const t = useTranslations('home');
return <h1>{t('title')}</h1>;
}
// Client Component
"use client"
import { useTranslations } from 'next-intl';
export function ProductCard() {
const t = useTranslations('products');
return <span>{t('addToCart')}</span>;
}
内容回退机制
- 回退链:请求语言 -> 基准语言 ->
en - 多语言内容使用
Record<Locale, string>类型存储 - 导航项通过
visible_locales控制语言可见性
URL 策略
- 中文站:无语言前缀(如
/products) - 国际站:
/en前缀(如/en/products) - SEO 自动生成 hreflang 替代链接
API 调用规范
数据获取(apps/web)
- Server Components 中直接使用
fetch或 API 客户端 - Client Components 中使用 TanStack React Query
- API 调用超时设置:5 秒
- API 不可用时使用本地回退内容
// Server Component 数据获取
async function getProduct(slug: string) {
try {
const res = await fetch(`${API_URL}/api/products/${slug}`, { next: { revalidate: 3600 } });
if (!res.ok) throw new Error('Failed to fetch');
return await res.json();
} catch {
return getFallbackProduct(slug); // 回退机制
}
}
API 客户端(apps/admin)
- 使用
src/lib/api-client.ts统一管理 API 请求 - JWT Token 存储在 localStorage
- 自动刷新过期 Token(Access Token + Refresh Token 双令牌)
- API 请求前缀:
/admin/*(需认证)
React Query 约定
- 使用 Query Key 工厂模式
- 避免在组件中直接调用
fetch,通过 hooks 封装 - 乐观更新用于即时反馈操作
路由规范
Next.js App Router(apps/web)
- 使用文件系统路由:
app/目录 - 动态路由参数为
Promise类型:params: Promise<{ slug: string }> - 布局使用
layout.tsx,页面使用page.tsx - 加载状态使用
loading.tsx - 错误处理使用
error.tsx - ISR 策略:首页 30 分钟,产品页 1 小时
React Router(apps/admin)
- 使用
createBrowserRouter配置路由 - 所有页面使用
lazy()懒加载实现代码分割 AuthGuard组件保护需要认证的路由- 路由守卫在
src/router/AuthGuard.tsx - 布局结构:
DashboardLayout(侧边栏 + 内容区)和AuthLayout(登录页)
表单规范
- 使用 React Hook Form 管理表单状态
- 使用 Zod 定义验证 schema
- 通过
zodResolver连接 React Hook Form 和 Zod
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
const schema = z.object({
email: z.string().email(),
password: z.string().min(8),
});
type LoginForm = z.infer<typeof schema>;
export function LoginForm() {
const { register, handleSubmit, formState: { errors } } = useForm<LoginForm>({
resolver: zodResolver(schema),
});
// ...
}
注释规范
- 公共组件和 Hook 必须有 JSDoc 注释
- 复杂业务逻辑处需有行内注释说明意图
- 禁止保留无意义的注释和注释掉的废弃代码
// TODO:标注待办事项,需包含上下文说明// NOTE:标注重要设计决策或注意事项
错误处理规范
- 页面级错误使用
error.tsx捕获 - API 调用失败必须提供回退方案
- 禁止捕获错误后不做任何处理(空 catch)
- 用户操作失败时展示友好的错误提示
- 使用 TypeScript 的 discriminated union 处理不同状态
性能规范
- Server Components:默认使用,减少客户端 JS 体积
- 代码分割:路由级自动分割,大型组件使用
dynamic()懒加载 - 图片优化:使用
OptimizedImage组件或 Next.js<Image> - ISR:合理设置页面重新验证时间
- Bundle 分析:定期检查包体积
- Standalone 输出:生产构建使用
output: 'standalone'
无障碍规范(A11y)
- 语义化 HTML:使用正确的标签(
<nav>、<main>、<article>) - 图片必须提供
alt属性 - 表单控件必须关联
<label> - 交互元素必须有键盘操作支持
- 焦点管理:模态框打开时捕获焦点,关闭时恢复焦点
- 颜色对比度 >= 4.5:1(WCAG 2.1 AA)
- 触摸目标最小 44px
共享类型定义(packages/types)
文件结构
packages/types/src/
├── models.ts # 核心数据模型(User, Product, Quotation 等)
├── cms.ts # CMS 内容类型(Navigation, Pages, SEO 等)
├── api.ts # API 请求/响应类型
├── admin.ts # 后台管理相关类型(RBAC 等)
├── configurator.ts # 报价配置器类型
├── device.ts # 设备管理相关类型(规划中)
├── quotation.ts # 报价系统相关类型(规划中)
├── shipping.ts # 运输管理相关类型(规划中)
├── permission.ts # 细粒度权限矩阵类型(规划中)
└── index.ts # 统一导出
多语言内容类型模式
type Locale = 'zh-CN' | 'en';
// 多语言内容统一使用 Record 类型
interface Product {
id: string;
name: Record<Locale, string>;
description: Record<Locale, string>;
}
API 响应类型模式
interface ApiResponse<T> {
data: T;
message?: string;
meta?: {
total: number;
page: number;
pageSize: number;
};
}
共享组件库(packages/ui)
组件层级(Atomic Design)
packages/ui/src/
├── atoms/ # 原子组件:Button, Card, Typography, Icon, Input, Select, Textarea
├── navigation/ # 导航组件:Navbar, MobileNav, LanguageSwitcher, StickySubNav, Breadcrumb
├── layout/ # 布局组件:Footer, MapEmbed
├── content/ # 内容组件:HeroCarousel, ImageGallery, Accordion, VideoEmbed, ScrollAnimation
├── forms/ # 表单组件:ContactForm, ContactFormValidation
├── auth/ # 认证组件:AuthProvider, useAuth, NavbarAvatar, LoginPrompt
├── analytics/ # 分析组件:GoogleAnalytics, BaiduAnalytics, trackEvent
├── performance/ # 性能组件:OptimizedImage
└── index.ts # Barrel export
计划新增组件(多模块演进)
packages/ui/src/
├── data-table/ # 通用数据表格(设备列表、报价列表等复用)
│ ├── DataTable.tsx
│ ├── DataTablePagination.tsx
│ ├── DataTableFilter.tsx
│ └── DataTableExport.tsx
└── module-shell/ # 模块通用外壳(列表页、详情页模板)
├── ListPageShell.tsx
└── DetailPageShell.tsx
组件开发规范
- 每个组件独立文件,文件名与组件名一致
- 组件必须包含 TypeScript 类型定义
- Props 接口必须导出
- 可复用组件支持
classNameprop 以允许样式扩展 - 可交互组件支持
ref转发
共享工具函数(packages/utils)
packages/utils/src/
├── admin.ts # 管理后台工具函数(权限判断、数据转换等)
├── api.ts # API 相关工具
├── cms.ts # CMS 内容处理工具
├── configurator.ts # 报价配置器工具
├── models.ts # 数据模型工具
└── index.ts # 统一导出
认证与权限
管理员认证(apps/admin)
- JWT 双令牌:Access Token(短期)+ Refresh Token(长期)
- Token 存储在 localStorage
- API 客户端自动刷新过期 Token
AuthGuard保护路由
状态管理分层(apps/admin)
详见 docNew/13-Admin状态管理设计.md。
服务端状态 → TanStack React Query(API 数据、缓存、失效)
全局客户端状态 → Zustand(认证、UI 偏好、语言偏好、权限缓存)
表单状态 → React Hook Form + Zod(表单字段、验证)
组件内临时状态 → React useState / useReducer(弹窗开关等局部状态)
关键原则:API 返回的数据绝不放进 Zustand,Zustand 只放客户端独有状态。
Zustand Store 结构
useAuthStore— 认证状态(user、login、logout),替代现有 AuthProvider ContextuseUIStore— 全局 UI 状态(sidebarCollapsed 持久化、globalLoading)useLocaleStore— 编辑器语言偏好(activeLocale 持久化,统一各编辑器组件的语言切换)usePermissionStore— 权限缓存(permissions 列表、hasPermission 判断,为细粒度权限矩阵预留)
Store 开发规范
- 文件名:
use+ 名称 +Store.ts,如useAuthStore.ts - 使用 selector 精确选择避免不必要重渲染:
const user = useAuthStore((s) => s.user) - 持久化使用
zustand/middleware的persist中间件,partialize只持久化需要的字段 - 敏感数据不持久化,每次登录重新获取
用户认证(apps/web)
- GeoPlatform OAuth 统一登录
- 环境变量配置 OAuth 参数
当前 RBAC 角色
| 角色 | 标识 | 说明 |
|---|---|---|
| 超级管理员 | super_admin |
全部权限 |
| 内容编辑 | content_editor |
内容相关权限 |
| 市场营销 | marketing |
内容 + 分析权限 |
| 查看者 | viewer |
只读权限 |
权限模块:navigation, pages, analytics, permissions, settings, content
权限矩阵演进(规划中)
从固定四级角色升级为 角色 + 细粒度权限矩阵:
角色(可自定义创建)
└── 绑定权限项
权限项 = 模块 + 资源 + 操作
模块: cms | devices | quotations | shipping | system
资源: 各模块下的具体资源
操作: view | create | edit | delete | export
权限标识命名规范:{module}.{resource}.{action}
cms.pages.view— 查看页面devices.list.export— 导出设备数据quotations.create.view— 查看新建报价页面system.roles.edit— 编辑角色权限
前端权限控制层级:
- 侧边栏:根据用户权限动态渲染
- 页面级:路由守卫检查模块访问权限
- 操作级:
PermissionGate组件包裹按钮 - API 级:后端中间件校验,前端仅做 UI 层控制
// 按钮级权限控制示例
<PermissionGate permission="devices.list.export">
<Button onClick={handleExport}>导出设备列表</Button>
</PermissionGate>
环境变量
apps/web
NEXT_PUBLIC_DEFAULT_LOCALE=zh-CN
NEXT_PUBLIC_SITE_URL=http://localhost:3002
NEXT_PUBLIC_API_URL=http://localhost:3001
apps/admin
VITE_API_URL=http://localhost:3001
PORT=3003
常用命令
# 安装依赖
npm install
# 启动开发(全部)
npm run dev
# 启动开发(指定应用)
npm run dev --filter=web # 前端网站
npm run dev --filter=admin # 后台管理
# 构建
npm run build
npm run build --filter=web
npm run build:cn # 中文站
npm run build:en # 国际站
# 代码检查
npm run lint
# 测试
npm run test
npm run test --filter=admin
部署
Web 应用(Next.js)
- 生产构建使用
output: 'standalone'优化 - ISR 增量静态再生平衡性能与内容时效性
- Nginx 反向代理,中英文站点独立部署
Admin 应用(Vite)
- 静态资源构建,部署至 CDN 或 Nginx
- API 请求代理至后端服务