feat: add frontend development guidelines and structure documentation
- Introduced API guidelines for interface contracts and request handling. - Added design tokens usage guidelines for consistent styling across the project. - Established DTO guidelines for defining request parameters and response data types. - Created frontend structure guidelines to clarify directory organization and code placement rules. - Compiled a comprehensive frontend development guideline document covering various aspects of the development process. - Implemented quality guidelines to ensure code maintainability and adherence to best practices.
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
# 接口契约规范
|
||||
|
||||
> 前端接口定义、请求封装与数据消费的规范。
|
||||
|
||||
---
|
||||
|
||||
## 目标
|
||||
|
||||
前端接口层的职责是:
|
||||
|
||||
- 统一管理页面访问后端的请求入口
|
||||
- 为页面、Hooks、组件提供稳定、易读的调用方式
|
||||
- 隔离具体请求库、URL 拼接、参数序列化等实现细节
|
||||
- 让页面开发只关心“调用什么接口、拿到什么数据”
|
||||
|
||||
当前仓库的接口文件统一放在 `src/api/`;现阶段不要为单个页面单独创建页面私有 `api-*` 文件,除非页面内已经形成明确且稳定的局部接口簇。
|
||||
|
||||
## 设计原则
|
||||
|
||||
- 接口方法名必须表达业务意图,而不是后端实现细节
|
||||
- 一个方法只负责一个清晰的业务动作
|
||||
- 页面层拿到的是“可直接消费的数据”,不要把请求库细节泄漏到页面
|
||||
- 相同业务模块的接口按文件聚合,避免散落在多个目录
|
||||
- 优先保持新增兼容,避免随意改动已有方法签名或返回结构
|
||||
|
||||
## 接口文件规范
|
||||
|
||||
- 文件名统一以 `api-` 开头,使用横杠连接
|
||||
- 一个业务模块对应一个接口文件,例如 `api-user.ts`、`api-order.ts`
|
||||
- 文件中只写接口定义与请求调用,不写页面逻辑、组件逻辑、复杂数据转换
|
||||
- 所有接口通过 `src/api/index.ts` 统一导出
|
||||
- 优先按业务域聚合到现有 `api-*.ts`,不要为单个接口随意新建文件
|
||||
|
||||
## 方法设计规范
|
||||
|
||||
- 方法名统一使用动词开头,表达查询、创建、更新、删除等业务动作
|
||||
- 参数少且稳定时可直接传基础参数;参数较多或未来可能扩展时,统一使用对象参数
|
||||
- 返回值应尽量稳定,避免同一接口一会儿返回数组、一会儿返回对象
|
||||
- 不要让页面知道完整 URL、Header 拼装、重试策略等底层细节
|
||||
- 不要在接口方法中混入 `setState`、弹窗提示、路由跳转等 UI 副作用
|
||||
|
||||
示例:
|
||||
|
||||
```ts
|
||||
export function apiGetKnowledgeList(params: GetKnowledgeListParams) {
|
||||
return request<GetKnowledgeListResponse>({
|
||||
url: "/knowledge/list",
|
||||
method: "GET",
|
||||
params,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## 参数与返回值规范
|
||||
|
||||
- 参数类型、返回值类型要明确,避免 `any`
|
||||
- 字段命名以页面业务语义为准,不要直接照搬后端数据库字段语义
|
||||
- 可选字段必须是“明确可选”,不能依赖不清晰的 `null / undefined` 约定
|
||||
- 列表、分页、详情等场景的数据结构要保持一致性
|
||||
- 如果页面需要二次加工,优先在页面侧的 Hook、组件组装层或局部工具中处理,而不是污染全局接口层
|
||||
|
||||
## 错误处理规范
|
||||
|
||||
- 接口层负责抛出或透传标准化错误,不负责直接渲染 UI
|
||||
- 不要把底层错误文本原样暴露给页面做业务判断
|
||||
- 页面只依赖可行动的信息,例如状态码、错误码、错误类型
|
||||
- 同类接口的错误处理方式要一致,避免部分返回 `null`、部分直接抛错
|
||||
|
||||
## 变更与兼容性
|
||||
|
||||
修改已有接口前先检查:
|
||||
|
||||
- 是否已有页面、Hook、组件依赖当前签名
|
||||
- 是否可以通过“新增字段/新增方法”代替破坏式修改
|
||||
- 是否需要同步调整对应类型定义与页面消费逻辑
|
||||
|
||||
推荐顺序:
|
||||
|
||||
1. 先新增兼容字段或新方法
|
||||
2. 逐步迁移调用方
|
||||
3. 最后再移除旧结构
|
||||
@@ -0,0 +1,272 @@
|
||||
# 设计变量使用规范
|
||||
|
||||
> 基于 `@oppein-react/design-tokens` 的前端样式实现规范。
|
||||
|
||||
---
|
||||
|
||||
## 目标
|
||||
|
||||
本规范用于统一项目中颜色、间距、字体、圆角、阴影和主题语义变量的使用方式,避免出现以下问题:
|
||||
|
||||
- 同一项目内同时混用 token、硬编码 HEX 和临时样式值
|
||||
- 视觉稿已统一,但代码层无法稳定复用设计变量
|
||||
- 亮暗主题切换时,组件样式无法跟随语义变量变化
|
||||
- 业务组件直接依赖底层常量,导致样式难以替换和升级
|
||||
|
||||
核心原则:
|
||||
|
||||
1. 业务样式优先消费 CSS 变量或 UnoCSS token class
|
||||
2. 语义优先于具体色值,优先写 `var(--op-primary)` 而不是固定品牌阶值
|
||||
3. 亮暗主题切换统一通过 `.dark` 类名驱动,不在组件内自行维护双份颜色
|
||||
4. TypeScript token 常量仅用于脚本、配置、图表主题等非 CSS 场景
|
||||
|
||||
---
|
||||
|
||||
## 安装与接入
|
||||
|
||||
### 包安装
|
||||
|
||||
- 外部项目需要先配置 npm registry,再安装 `@oppein-react/design-tokens`
|
||||
- monorepo 内部 workspace 包,依赖统一写成 `"@oppein-react/design-tokens": "workspace:*"`
|
||||
- 设计变量包是叶子包,不应再反向依赖业务包
|
||||
|
||||
### CSS 注入
|
||||
|
||||
- 应用入口必须导入 `@oppein-react/design-tokens/css`
|
||||
- 入口导入只能做一次,避免在页面组件或局部样式文件重复注入
|
||||
- 推荐放在 `src/main.ts` 或应用级入口文件
|
||||
|
||||
示例:
|
||||
|
||||
```ts
|
||||
import "@oppein-react/design-tokens/css";
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 样式消费规则
|
||||
|
||||
### 1. CSS 变量
|
||||
|
||||
适用场景:
|
||||
|
||||
- 组件样式文件
|
||||
- CSS Modules
|
||||
- 全局样式
|
||||
- 需要跟随暗色主题自动切换的颜色、阴影、背景、边框
|
||||
|
||||
规则:
|
||||
|
||||
- 全局 CSS 变量统一使用 `--op-` 前缀
|
||||
- 颜色优先使用语义变量,如 `--op-primary`、`--op-background`、`--op-foreground`
|
||||
- 只有在明确需要某个色板阶值时,才使用 `--op-color-brand-6` 这类全局色板变量
|
||||
- 间距、圆角、阴影统一使用 token 变量,不要自己再写一套近似值
|
||||
|
||||
示例:
|
||||
|
||||
```css
|
||||
.page {
|
||||
color: var(--op-foreground);
|
||||
background: var(--op-background);
|
||||
}
|
||||
|
||||
.primary-button {
|
||||
color: var(--op-color-white);
|
||||
background: var(--op-primary);
|
||||
border-radius: var(--op-radius-button);
|
||||
box-shadow: var(--op-shadow-1);
|
||||
padding: var(--op-spacing-xs) var(--op-spacing-sm);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. UnoCSS token class
|
||||
|
||||
适用场景:
|
||||
|
||||
- 项目已经启用 UnoCSS
|
||||
- 样式以原子类为主,且希望直接映射设计 token
|
||||
|
||||
规则:
|
||||
|
||||
- `uno.config.ts` 中统一启用 `presetOppein()`
|
||||
- 业务代码直接使用 token class,如 `bg-background`、`text-foreground`、`rounded-card`
|
||||
- 不要一边启用 preset,一边继续大面积写无语义的颜色 class 或硬编码 style
|
||||
- 如需覆盖品牌主色,可在 `presetOppein({ primary })` 中配置,不在业务组件中零散覆盖
|
||||
|
||||
示例:
|
||||
|
||||
```ts
|
||||
import { defineConfig, presetUno } from "unocss";
|
||||
import { presetOppein } from "@oppein-react/design-tokens/unocss";
|
||||
|
||||
export default defineConfig({
|
||||
presets: [presetUno(), presetOppein()],
|
||||
});
|
||||
```
|
||||
|
||||
```tsx
|
||||
export function Example() {
|
||||
return (
|
||||
<div className="bg-background text-foreground p-md rounded-card">
|
||||
<button className="bg-primary text-white px-sm py-xs rounded-button">
|
||||
保存
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 变量选择顺序
|
||||
|
||||
新增样式时,按以下顺序选择 token:
|
||||
|
||||
1. 先找语义变量
|
||||
例如:`--op-primary`、`--op-background-secondary`、`--op-border`
|
||||
2. 再找语义尺寸变量
|
||||
例如:`--op-spacing-md`、`--op-radius-card`、`--op-shadow-2`
|
||||
3. 最后才使用全局色板阶值
|
||||
例如:`--op-color-brand-6`
|
||||
|
||||
只有在以下场景允许直接使用色板阶值:
|
||||
|
||||
- 图表配色
|
||||
- 特殊插画或装饰性视觉
|
||||
- 设计稿明确指定阶值,而不是语义角色
|
||||
|
||||
---
|
||||
|
||||
## 主题切换规则
|
||||
|
||||
- 亮色主题默认挂在 `:root`
|
||||
- 暗色主题统一挂在 `.dark`
|
||||
- 切换主题时,只允许操作根节点的 `dark` 类名
|
||||
- 禁止在业务组件内通过条件分支手写两套 HEX 颜色实现明暗主题
|
||||
|
||||
示例:
|
||||
|
||||
```ts
|
||||
document.documentElement.classList.toggle("dark", isDark);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## TypeScript 常量使用边界
|
||||
|
||||
`@oppein-react/design-tokens` 导出的 `colors`、`spacing`、`radius`、`shadows`、`lightTheme`、`darkTheme` 适用于:
|
||||
|
||||
- 图表主题
|
||||
- JS 配置对象
|
||||
- 运行时计算
|
||||
- 非 CSS 场景的默认值或映射表
|
||||
|
||||
禁止把这些常量当作业务组件样式的默认写法,尤其不要在 JSX 内直接硬塞原始色值:
|
||||
|
||||
```ts
|
||||
import { colors, lightTheme, radius, spacing } from "@oppein-react/design-tokens";
|
||||
|
||||
const primary = colors.brand[6];
|
||||
const pageBackground = lightTheme.background;
|
||||
const cardRadius = radius.card;
|
||||
const gap = spacing.md;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 禁止行为
|
||||
|
||||
- 在组件、页面、全局样式中硬编码颜色值,如 `#3370FF`、`rgba(0,0,0,.12)`,而对应 token 已存在
|
||||
- 新增一套项目私有的 `--primary`、`--brand-blue` 之类变量,与 `--op-` 体系并行
|
||||
- 在组件内部手动维护亮色和暗色两套颜色常量
|
||||
- CSS 变量已经能表达的场景,仍在 JS 中拼接大量内联样式对象
|
||||
- 为了局部视觉效果随意创造规范外阴影、圆角和间距值
|
||||
|
||||
---
|
||||
|
||||
## Wrong vs Correct
|
||||
|
||||
### 颜色
|
||||
|
||||
#### Wrong
|
||||
|
||||
```css
|
||||
.tab-active {
|
||||
color: #3370ff;
|
||||
border-color: #3370ff;
|
||||
}
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```css
|
||||
.tab-active {
|
||||
color: var(--op-primary);
|
||||
border-color: var(--op-primary);
|
||||
}
|
||||
```
|
||||
|
||||
### 圆角与阴影
|
||||
|
||||
#### Wrong
|
||||
|
||||
```css
|
||||
.card {
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 6px 18px rgba(17, 26, 44, 0.08);
|
||||
}
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```css
|
||||
.card {
|
||||
border-radius: var(--op-radius-card);
|
||||
box-shadow: var(--op-shadow-2);
|
||||
}
|
||||
```
|
||||
|
||||
### 主题切换
|
||||
|
||||
#### Wrong
|
||||
|
||||
```tsx
|
||||
const style = {
|
||||
color: isDark ? "#ffffff" : "#1f2329",
|
||||
background: isDark ? "#141414" : "#ffffff",
|
||||
};
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```tsx
|
||||
document.documentElement.classList.toggle("dark", isDark);
|
||||
```
|
||||
|
||||
```css
|
||||
.panel {
|
||||
color: var(--op-foreground);
|
||||
background: var(--op-background);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 开发与验收清单
|
||||
|
||||
提交前至少确认:
|
||||
|
||||
- 入口是否已注入 `@oppein-react/design-tokens/css`
|
||||
- 颜色、圆角、阴影、间距是否优先使用了 `--op-` 变量
|
||||
- 可用语义变量时,是否避免了直接写色板阶值
|
||||
- 是否避免新增硬编码 HEX、RGB、RGBA
|
||||
- 暗色模式是否通过 `.dark` 驱动,而不是组件局部条件分支
|
||||
- 项目启用 UnoCSS 时,是否已优先使用 token class 而非重复造 class
|
||||
|
||||
---
|
||||
|
||||
## 相关规范
|
||||
|
||||
- 视觉语义与组件形态:`DESIGN.md`
|
||||
- 目录和样式归属:`frontend-structure-guidelines.md`
|
||||
- 提交前检查:`quality-guidelines.md`
|
||||
@@ -0,0 +1,73 @@
|
||||
# 类型定义规范
|
||||
|
||||
> 前端请求参数、响应数据类型以及页面数据模型的定义规范。
|
||||
|
||||
---
|
||||
|
||||
## 命名原则
|
||||
|
||||
- 类型名要体现用途,例如 `LoginParams`、`OrderListItem`、`UserDetailResponse`
|
||||
- 优先使用业务语义命名,不用后端传输层术语硬套前端场景
|
||||
- 名称要与实际使用场景一致,不要出现“通用类型”却只服务单一页面的情况
|
||||
- 页面私有类型优先就近定义在页面目录;全局复用类型再抽到公共位置
|
||||
|
||||
---
|
||||
|
||||
## 字段设计原则
|
||||
|
||||
- 只保留当前页面、组件、Hook 真实需要的字段
|
||||
- 字段语义必须单一明确,不要一个字段承担多种含义
|
||||
- 嵌套对象只在确实提升可读性时使用,避免过深层级
|
||||
- 能用稳定基础类型表达的,不要额外包一层无意义对象
|
||||
- 禁止为了“以后可能会用”提前塞入无消费方字段
|
||||
|
||||
---
|
||||
|
||||
## 类型边界
|
||||
|
||||
- 区分“接口原始返回类型”和“页面消费后的展示类型”
|
||||
- 不要把后端所有字段原样铺到页面组件 props 中
|
||||
- 页面展示需要格式化、组合、兜底时,应在 `utils/` 或 `hooks/` 做转换
|
||||
- 同一个后端实体被多个页面以不同方式使用时,允许定义多个前端视图类型
|
||||
|
||||
---
|
||||
|
||||
## 默认值与可选值
|
||||
|
||||
- 可选字段要明确标注 `?`,不要靠调用方猜测
|
||||
- 默认值策略必须显式,不要把隐式兜底散落在多个组件里
|
||||
- 会影响页面分支逻辑的字段,必须明确说明为空时的处理方式
|
||||
- 列表字段默认值、布尔字段默认值、文本占位值等应在消费层统一处理
|
||||
|
||||
---
|
||||
|
||||
## 映射规范
|
||||
|
||||
- 映射的目标是让页面更好用,不是机械复制后端结构
|
||||
- 不要保留“临时透传字段”或无人消费的中间字段
|
||||
- 若多个页面需要不同数据形状,应该拆成不同类型,而不是堆成一个超大类型
|
||||
- 时间、金额、状态文案等展示型字段,优先通过派生字段生成,避免在组件内部重复处理
|
||||
|
||||
## 前端类型安全
|
||||
|
||||
- 禁止在新增代码中使用无约束的 `any`
|
||||
- 对枚举值、状态值、字典值,优先用联合类型或 `enum` 明确约束
|
||||
- 组件 Props 类型要最小化,只暴露组件真正需要的数据
|
||||
- 需要缓存、比较、序列化的数据结构,应保持简单、稳定、可预期
|
||||
|
||||
## 示例
|
||||
|
||||
```ts
|
||||
export type KnowledgeListParams = {
|
||||
keyword?: string;
|
||||
pageNo: number;
|
||||
pageSize: number;
|
||||
};
|
||||
|
||||
export type KnowledgeListItem = {
|
||||
id: string;
|
||||
title: string;
|
||||
status: "draft" | "published";
|
||||
updatedAt: string;
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,221 @@
|
||||
# 前端目录与代码放置规范
|
||||
|
||||
> 说明真实分层、目录职责和新增代码放置规则。
|
||||
|
||||
---
|
||||
|
||||
## 适用范围
|
||||
|
||||
单包 Vite + React/Vue + TypeScript 项目。
|
||||
|
||||
---
|
||||
|
||||
## src 根目录结构
|
||||
|
||||
```
|
||||
src/
|
||||
├── api/ # 业务接口入口,按领域拆文件并统一导出
|
||||
├── assets/ # 静态资源占位目录
|
||||
├── common/ # 站点级常量、配置、静态数据、共享类型
|
||||
├── components/ # 跨页面复用组件
|
||||
├── hooks/ # 跨页面复用的 Hooks (React) / Composables (Vue)
|
||||
├── pages/ # 路由页面
|
||||
├── router/ # 路由配置
|
||||
├── styles/ # 全局样式入口
|
||||
├── utils/ # 通用工具
|
||||
├── App.tsx # 应用壳 (React 为 .tsx,Vue 为 .vue)
|
||||
└── main.ts # 启动入口
|
||||
```
|
||||
|
||||
新增目录前先判断能否归入已有层级;不要为了单个文件再造一层。
|
||||
|
||||
---
|
||||
|
||||
## 各层职责
|
||||
|
||||
### `src/api`
|
||||
|
||||
用于集中管理接口方法,按业务域拆分,例如:
|
||||
|
||||
- `api-user.ts`
|
||||
- `api-order.ts`
|
||||
- `api-product.ts`
|
||||
|
||||
约束:
|
||||
|
||||
- 文件名统一使用 `api-*.ts`
|
||||
- 所有接口通过 `src/api/index.ts` 暴露
|
||||
- 页面、组件、Hook 不直接拼 URL 或内联请求逻辑
|
||||
|
||||
### `src/common`
|
||||
|
||||
放站点级共享数据和基础类型,不放页面局部常量。
|
||||
|
||||
典型内容:
|
||||
|
||||
- `config.ts`
|
||||
- `constants.ts`
|
||||
- `enum.ts`
|
||||
- `site-data.ts`
|
||||
- `site-types.ts`
|
||||
|
||||
站点级常量、配置、枚举、共享类型优先放此处;可远程获取的数据优先通过 `api/` + 页面 Hooks 获取,不要堆积在 `common/`。
|
||||
|
||||
### `src/components`
|
||||
|
||||
放多个页面都会复用的通用组件和布局组件。
|
||||
|
||||
典型示例:
|
||||
|
||||
- `layout-shell.tsx` (React) / `layout-shell.vue` (Vue)
|
||||
- `nav-header.tsx` / `nav-header.vue`
|
||||
- `content-card.tsx` / `content-card.vue`
|
||||
- `loading-state.tsx` / `loading-state.vue`
|
||||
- `empty-state.tsx` / `empty-state.vue`
|
||||
- `modal-common.tsx` / `modal-common.vue`
|
||||
|
||||
约束:
|
||||
|
||||
- 文件名统一使用小写横杠
|
||||
- 只有跨页面复用的组件才放这里
|
||||
- 某个页面特有的展示块,优先直接放该页面目录下,避免过早公共化
|
||||
|
||||
### `src/hooks`
|
||||
|
||||
放跨页面复用的状态与异步逻辑。React 中称为 Hooks,Vue 中称为 Composables。
|
||||
|
||||
典型示例:
|
||||
|
||||
- `use-promise-data.ts`
|
||||
- `use-form.ts`
|
||||
- `use-modal.ts`
|
||||
- `use-table.ts`
|
||||
|
||||
约束:
|
||||
|
||||
- 文件名统一使用 `use-*.ts`(React Hooks 和 Vue Composables 均遵循此命名)
|
||||
- 负责复用逻辑,不负责路由结构和大块 UI 拼装
|
||||
|
||||
### `src/pages`
|
||||
|
||||
页面层按路由语义组织,一个目录对应一个页面或页面组。
|
||||
|
||||
典型结构:
|
||||
|
||||
```
|
||||
pages/
|
||||
├── home/index.tsx (或 index.vue)
|
||||
├── list/index.tsx (或 index.vue)
|
||||
├── list/detail/index.tsx (或 index.vue)
|
||||
├── admin/index.tsx (或 index.vue)
|
||||
└── admin/components/admin-table.tsx (或 .vue)
|
||||
```
|
||||
|
||||
约束:
|
||||
|
||||
- 路由页面入口统一使用 `index.tsx` (React) 或 `index.vue` (Vue)
|
||||
- 有明确子路由的页面,使用目录嵌套表达层级,例如 `list/detail/`
|
||||
- 页面目录名统一使用小写横杠,例如 `order-detail/` 而非 `orderDetail/`
|
||||
- 仅后台页面共享的组件,放在 `pages/admin/components/`,不要提到全局 `components/`
|
||||
- 如果未来某个页面出现多个私有组件、Hook、转换函数,可以在该页面目录下新增 `components/`、`hooks/`、`utils/` 子目录;尚未形成稳定模式前,不要预先创建空目录
|
||||
|
||||
### `src/router`
|
||||
|
||||
集中声明路由和布局装配关系,例如通过 layout route 划分不同壳层。
|
||||
|
||||
|
||||
### `src/utils`
|
||||
|
||||
放纯工具函数和请求封装,不承载业务页面状态。
|
||||
|
||||
典型文件:
|
||||
|
||||
- `request.ts`
|
||||
- `format.ts`
|
||||
- `storage.ts`
|
||||
- `validate.ts`
|
||||
|
||||
请求封装、通用工具函数优先放在此处,不要散落到页面或 `api-*` 文件中。
|
||||
|
||||
### `src/styles`
|
||||
|
||||
全局样式入口和主题变量注入位置。
|
||||
|
||||
职责:
|
||||
|
||||
- 导入设计变量包 CSS,如 `@your-design-system/tokens/css`
|
||||
- 全局基础样式、重置样式、通用动画
|
||||
- 禁止在组件内重复引入设计变量 CSS,统一从 `styles/` 入口注入
|
||||
|
||||
### `src/assets`
|
||||
|
||||
静态资源占位目录。
|
||||
|
||||
职责:
|
||||
|
||||
- 存放图片、字体、SVG 等静态文件
|
||||
- 通过 Vite 自动处理路径引用,禁止手写相对路径拼接到 `public/`
|
||||
- 单个页面私有的静态资源,优先放在该页面目录下
|
||||
|
||||
---
|
||||
|
||||
## 命名约定速查
|
||||
|
||||
| 类型 | 命名规则 | 示例 | 说明 |
|
||||
|---|---|---|---|
|
||||
| 接口文件 | `api-{domain}.ts` | `api-user.ts` | 按业务域拆分,统一从 `index.ts` 导出 |
|
||||
| Hook/Composable 文件 | `use-{feature}.ts` | `use-form.ts` | React Hooks / Vue Composables 通用命名 |
|
||||
| 组件文件 | 小写横杠 | `content-card.tsx` / `.vue` | 仅跨页面复用的组件 |
|
||||
| 页面入口 | `index.tsx` / `index.vue` | `pages/home/index.tsx` | 每个路由页面对应一个入口 |
|
||||
| 页面目录 | 小写横杠 | `order-detail/` | 有子路由时使用目录嵌套 |
|
||||
| 工具文件 | 小写横杠 | `format.ts` | 纯函数,不承载业务状态 |
|
||||
| 样式文件 | 小写横杠 | `index.css` | 全局样式入口 |
|
||||
|
||||
---
|
||||
|
||||
## 新增代码放置规则
|
||||
|
||||
### 新增页面
|
||||
|
||||
- 新页面先放到 `src/pages/<route-segment>/index.tsx` (React) 或 `index.vue` (Vue)
|
||||
- 有详情页或子页时,用子目录表达路由层级
|
||||
- 页面只负责组装,不要把可复用块全部堆进页面入口文件
|
||||
|
||||
### 新增共享组件
|
||||
|
||||
满足下面任一条件才放 `src/components/`:
|
||||
|
||||
- 至少被两个页面复用
|
||||
- 明显属于布局壳、空态、加载态、卡片、分页这类跨页面基础组件
|
||||
|
||||
否则放到对应页面目录下。
|
||||
|
||||
### 新增接口
|
||||
|
||||
- 按业务域加到现有 `api-*.ts`,不要为单个接口新建零散文件
|
||||
- 新增业务域时,才创建新的 `api-<domain>.ts`
|
||||
- 同步更新 `src/api/index.ts`
|
||||
|
||||
### 新增共享数据或类型
|
||||
|
||||
- 纯配置、导航、枚举、常量放 `src/common/`
|
||||
- 类型优先就近放到使用域;只有被多个页面共享时,才进入 `site-types.ts` 或拆新的共享类型文件
|
||||
|
||||
---
|
||||
|
||||
## 反模式
|
||||
|
||||
- 把接口请求直接写进页面组件,绕过 `src/api/`
|
||||
- 把后台专用页面组件放进全局 `src/components/`
|
||||
- 为了“看起来规范”预先创建大量空的页面私有 `hooks/`、`utils/`、`components/`
|
||||
- 把路由层级和目录层级写反,例如把详情页和列表页并列平铺但路由嵌套
|
||||
- 在 `common/` 堆放只给单页使用的常量或转换函数
|
||||
|
||||
---
|
||||
|
||||
## 修改前检查
|
||||
|
||||
- 这段代码是路由页面、共享组件、共享 Hook/Composable、共享数据,还是接口定义?
|
||||
- 这个文件未来是否很可能被第二个页面复用?
|
||||
- 是否应该先并入现有业务域文件,而不是新造目录?
|
||||
- 是否和 `src/router/` 的路由分组保持一致?
|
||||
@@ -0,0 +1,95 @@
|
||||
# 前端开发规范
|
||||
|
||||
> 前端开发的总入口,覆盖目录组织、接口设计、类型定义、UI 实现与质量要求。
|
||||
|
||||
---
|
||||
|
||||
## 概述
|
||||
|
||||
本规范用于统一前端项目的开发方式,目标是让代码在以下几个方面保持稳定:
|
||||
|
||||
- 可读:目录、命名、职责边界清晰,方便快速定位代码
|
||||
- 可维护:页面逻辑拆分合理,避免巨型组件和重复实现
|
||||
- 可复用:公共能力与页面私有能力边界明确,减少污染
|
||||
- 可演进:接口、类型、页面结构支持逐步扩展,不因小改动造成大面积返工
|
||||
|
||||
核心原则:
|
||||
|
||||
1. 就近原则:只在当前页面使用的代码,放在当前页面目录下
|
||||
2. 分层清晰:全局公共层、页面私有层、接口层各司其职
|
||||
3. 命名统一:文件名、目录名、Hooks、弹窗组件遵循固定规则
|
||||
4. 类型明确:接口参数、返回值、组件 Props、状态值都应具备清晰类型
|
||||
5. 优先复用:抽公共前先确认真的复用,抽公共后保持通用而不过度设计
|
||||
|
||||
---
|
||||
|
||||
## 编码环境
|
||||
|
||||
- Vue / React,使用 TypeScript
|
||||
- Vite、路由库(React Router / Vue Router)、Axios 等常见前端库
|
||||
|
||||
---
|
||||
|
||||
## 开发前检查清单
|
||||
|
||||
开始修改前端代码前,请先确认:
|
||||
|
||||
1. 这次改动是否真的属于前端层,而不是后端或其它层
|
||||
2. 需求影响的是全局公共能力,还是某个页面私有能力
|
||||
3. 涉及接口时,参数、返回值、错误处理方式是否已经明确
|
||||
4. 涉及样式、主题或视觉变量时,是否优先使用 `@oppein-react/design-tokens`
|
||||
5. 新增命名是否使用业务语义,而不是后端表结构或临时术语
|
||||
6. 是否有现成组件、Hooks、工具函数、类型定义或设计 token 可以复用
|
||||
7. 改动是否会影响现有页面、公共组件或既有接口调用方式
|
||||
|
||||
---
|
||||
|
||||
## 规范索引
|
||||
|
||||
| 规范 | 作用 | 适用场景 |
|
||||
|---|---|---|
|
||||
| [前端结构规范](./frontend-structure-guidelines.md) | 约束 `src` 下各层目录职责、页面私有结构和命名方式 | 新建页面、重构目录、抽离公共能力前必读 |
|
||||
| [UI 设计规范](../../../DESIGN.md) | 规范界面实现方式、视觉一致性和交互呈现 | 新做页面、优化样式、补充组件展示时阅读 |
|
||||
| [设计变量使用规范](./design-tokens-guidelines.md) | 规范 `@oppein-react/design-tokens` 的接入、变量消费、主题切换与 UnoCSS 使用方式 | 新增样式、主题切换、替换硬编码颜色、接入 UnoCSS token 时必读 |
|
||||
| [接口契约规范](./api-guidelines.md) | 规范前端接口文件、请求封装、错误处理和兼容性 | 新增接口、调整请求参数、封装请求工具时阅读 |
|
||||
| [类型定义规范](./dto-guidelines.md) | 规范请求参数、响应数据、页面消费模型和类型边界 | 新增类型、重构数据结构、拆分页面模型时阅读 |
|
||||
| [质量规范](./quality-guidelines.md) | 规范代码质量、拆分方式、验证要求和评审重点 | 开发中自检、提测前、收尾时阅读 |
|
||||
|
||||
---
|
||||
|
||||
## 推荐使用方式
|
||||
|
||||
可以把这套规范理解成一个简单流程:
|
||||
|
||||
1. 先看 `frontend-structure-guidelines.md`
|
||||
确认代码该放全局、页面私有,还是接口层
|
||||
2. 涉及样式、主题和设计变量时看 `design-tokens-guidelines.md` 和 `DESIGN.md`
|
||||
确保颜色、间距、圆角、阴影、亮暗主题实现方式一致
|
||||
3. 涉及请求与数据时看 `api-guidelines.md` 和 `dto-guidelines.md`
|
||||
确保接口定义、类型建模、页面消费方式一致
|
||||
4. 涉及页面与交互时看 `DESIGN.md`
|
||||
保证页面结构、交互体验与视觉实现符合要求
|
||||
5. 提交前看 `quality-guidelines.md`
|
||||
做最后的质量自检与风险排查
|
||||
|
||||
---
|
||||
|
||||
## 完成前自检
|
||||
|
||||
完成前端改动前,至少确认以下几点:
|
||||
|
||||
- 目录层级是否正确,页面私有代码是否已就近放置
|
||||
- 接口是否统一从约定目录导出,是否避免了页面内联请求实现
|
||||
- 类型是否明确,是否避免了新增 `any`
|
||||
- 样式是否优先使用了 `@oppein-react/design-tokens` 的语义变量或 UnoCSS token class
|
||||
- 页面是否拆分合理,是否把复杂逻辑从主页面组件下沉
|
||||
- 公共能力是否真的具备复用价值,而不是过早抽象
|
||||
- 构建是否通过,关键路径是否完成本地验证
|
||||
|
||||
---
|
||||
|
||||
## 语言要求
|
||||
|
||||
- 所有规范文档、注释、提交信息统一使用**简体中文**
|
||||
- 代码中的变量名、函数名、类型名可以使用英文
|
||||
- 命名应优先体现业务语义,避免使用模糊缩写与临时命名
|
||||
@@ -0,0 +1,55 @@
|
||||
# 前端质量规范
|
||||
|
||||
> 前端代码质量、可维护性与交付前检查规范。
|
||||
|
||||
---
|
||||
|
||||
## 必须遵守
|
||||
|
||||
- 页面主文件聚焦页面组装,复杂逻辑下沉到 `components/`、`hooks/`、`utils/`
|
||||
- 目录与命名遵循 `frontend-structure-guidelines.md` 约定
|
||||
- 接口层、页面层、公共层职责明确,不交叉污染
|
||||
- 新增类型、常量、工具函数前先搜索是否已有可复用实现
|
||||
- 公共组件保持通用,页面私有组件就近放置
|
||||
|
||||
---
|
||||
|
||||
## 禁止行为
|
||||
|
||||
- 页面直接内联大段请求逻辑,绕过 `api/` 或页面私有接口文件
|
||||
- 本应页面私有的组件、Hooks、工具函数被随意放进全局公共目录
|
||||
- 组件 Props、接口返回值、Hook 返回值大量使用 `any`
|
||||
- 在组件渲染过程中执行复杂计算、重复格式化、重复创建临时对象而不做整理
|
||||
- 一个页面目录里同时堆放列表、详情、弹窗、表单等多种耦合逻辑却不拆分
|
||||
- 把样式、请求、副作用、状态管理全部写进一个超大组件
|
||||
|
||||
---
|
||||
|
||||
## GIT提交规范
|
||||
|
||||
- 所有AI生成的代码提交必须在Git commit message中标识AI模型名称,格式为 `[AI-{模型名称}]`,例如 `[AI-Qoder] 添加用户列表页面`
|
||||
|
||||
---
|
||||
|
||||
## 测试要求
|
||||
|
||||
至少需要验证:
|
||||
|
||||
- 页面能正常渲染,关键交互路径不报错
|
||||
- 新增或修改的接口调用参数、返回值与页面消费逻辑一致
|
||||
- 条件渲染、空态、加载态、异常态至少人工验证一遍
|
||||
- 抽取出的工具函数、格式化函数、状态转换函数应补单元测试(如果项目已具备测试设施)
|
||||
- 改动公共组件或公共 Hook 时,要确认现有调用方未被破坏
|
||||
|
||||
如果项目暂时没有完整测试设施,至少保证能通过构建,并完成核心路径的本地人工验证。
|
||||
|
||||
---
|
||||
|
||||
## 代码审查清单
|
||||
|
||||
- 这个改动是否放在了正确目录,而不是图省事塞进页面主文件?
|
||||
- 新增公共能力之前,是否确认过它不是页面私有逻辑?
|
||||
- 是否存在命名模糊、职责混乱、目录层级不清的问题?
|
||||
- 接口、类型、组件、Hooks 之间的数据流是否清晰可读?
|
||||
- 是否引入了重复实现,本可以复用已有工具或组件?
|
||||
- 构建、类型检查、本地页面验证是否已经完成?
|
||||
Reference in New Issue
Block a user