更新steering文件

This commit is contained in:
徐星 2026-04-13 09:28:48 +08:00
parent 99c0ff37d5
commit cc6dc177e4
4 changed files with 887 additions and 1 deletions

833
.kiro/steering/frontend.md Normal file
View File

@ -0,0 +1,833 @@
# 前端技术规范
## 运行环境
- 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` 不依赖 `ui`
- `utils` 不依赖 `ui`
- `ui` 可依赖 `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`
### 导入规范
#### 导入顺序
```typescript
// 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` 语法
```typescript
// 组件导出示例
export { Button } from './Button';
export type { ButtonProps, ButtonVariant } from './Button';
```
### 组件规范
#### Server Components vs Client Componentsapps/web
- 默认使用 Server ComponentsNext.js App Router 约定)
- 仅在需要交互state、effects、event handlers时使用 Client Components
- Client Components 必须在文件顶部添加 `"use client"` 指令
- 布局组件Layout默认为 Server Component
- 数据获取优先在 Server Component 中完成
```typescript
// 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');
// ...
}
```
#### 组件结构顺序
```typescript
// 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 |
#### 响应式断点
```css
/* Mobile-first */
/* 默认:< 769px (Mobile) */
/* md: >= 769px (Tablet) */
/* lg: >= 1025px (Desktop) */
```
### TypeScript 规范
- 启用 strict 模式
- 禁止使用 `any`,如必须使用需添加注释说明原因
- 函数参数和返回值必须有明确的类型注解
- 优先使用 `interface` 定义对象类型,`type` 用于联合类型、工具类型
- 使用 `as const` 断言定义常量对象
- 异步函数返回类型明确标注 `Promise<T>`
- 使用 TypeScript 枚举或联合字面量类型替代魔法字符串
```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-intlapps/web
#### 翻译文件
- 翻译文件位于 `apps/web/messages/` 目录
- 文件格式JSON`zh-CN.json`、`en.json`
- 使用命名空间分隔:`home`、`products`、`common`、`nav` 等
#### 使用方式
```typescript
// 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 不可用时使用本地回退内容
```typescript
// 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
- 自动刷新过期 TokenAccess Token + Refresh Token 双令牌)
- API 请求前缀:`/admin/*`(需认证)
#### React Query 约定
- 使用 Query Key 工厂模式
- 避免在组件中直接调用 `fetch`,通过 hooks 封装
- 乐观更新用于即时反馈操作
### 路由规范
#### Next.js App Routerapps/web
- 使用文件系统路由:`app/` 目录
- 动态路由参数为 `Promise` 类型:`params: Promise<{ slug: string }>`
- 布局使用 `layout.tsx`,页面使用 `page.tsx`
- 加载状态使用 `loading.tsx`
- 错误处理使用 `error.tsx`
- ISR 策略:首页 30 分钟,产品页 1 小时
#### React Routerapps/admin
- 使用 `createBrowserRouter` 配置路由
- 所有页面使用 `lazy()` 懒加载实现代码分割
- `AuthGuard` 组件保护需要认证的路由
- 路由守卫在 `src/router/AuthGuard.tsx`
- 布局结构:`DashboardLayout`(侧边栏 + 内容区)和 `AuthLayout`(登录页)
### 表单规范
- 使用 React Hook Form 管理表单状态
- 使用 Zod 定义验证 schema
- 通过 `zodResolver` 连接 React Hook Form 和 Zod
```typescript
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:1WCAG 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 # 统一导出
```
### 多语言内容类型模式
```typescript
type Locale = 'zh-CN' | 'en';
// 多语言内容统一使用 Record 类型
interface Product {
id: string;
name: Record<Locale, string>;
description: Record<Locale, string>;
}
```
### API 响应类型模式
```typescript
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 接口必须导出
- 可复用组件支持 `className` prop 以允许样式扩展
- 可交互组件支持 `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 QueryAPI 数据、缓存、失效)
全局客户端状态 → Zustand认证、UI 偏好、语言偏好、权限缓存)
表单状态 → React Hook Form + Zod表单字段、验证
组件内临时状态 → React useState / useReducer弹窗开关等局部状态
```
**关键原则**API 返回的数据绝不放进 ZustandZustand 只放客户端独有状态。
#### Zustand Store 结构
- `useAuthStore` — 认证状态user、login、logout替代现有 AuthProvider Context
- `useUIStore` — 全局 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 层控制
```tsx
// 按钮级权限控制示例
<PermissionGate permission="devices.list.export">
<Button onClick={handleExport}>导出设备列表</Button>
</PermissionGate>
```
## 环境变量
### apps/web
```env
NEXT_PUBLIC_DEFAULT_LOCALE=zh-CN
NEXT_PUBLIC_SITE_URL=http://localhost:3002
NEXT_PUBLIC_API_URL=http://localhost:3001
```
### apps/admin
```env
VITE_API_URL=http://localhost:3001
PORT=3003
```
## 常用命令
```bash
# 安装依赖
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 请求代理至后端服务

View File

@ -1,2 +1,4 @@
{"timestamp":"00:00:01.061","source":"Server","level":"LOG","message":""} {"timestamp":"00:00:01.061","source":"Server","level":"LOG","message":""}
{"timestamp":"00:00:03.305","source":"Browser","level":"INFO","message":"%cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold"} {"timestamp":"00:00:03.305","source":"Browser","level":"INFO","message":"%cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold"}
{"timestamp":"19:08:22.325","source":"Browser","level":"INFO","message":"%cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold"}
{"timestamp":"19:08:25.916","source":"Browser","level":"INFO","message":"%cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold"}

View File

@ -1,3 +1,14 @@
{ {
"/config-files/page": "app/config-files/page.js" "/_not-found/page": "app/_not-found/page.js",
"/boards/page": "app/boards/page.js",
"/calibration/page": "app/calibration/page.js",
"/config-files/page": "app/config-files/page.js",
"/devices/page": "app/devices/page.js",
"/firmware/page": "app/firmware/page.js",
"/licenses/page": "app/licenses/page.js",
"/models/page": "app/models/page.js",
"/page": "app/page.js",
"/registration/page": "app/registration/page.js",
"/repair/page": "app/repair/page.js",
"/scrap/page": "app/scrap/page.js"
} }

File diff suppressed because one or more lines are too long