Files
medical-mall/docs/admin/ENGINEERING_BEST_PRACTICES.md
2026-02-02 20:07:37 +08:00

762 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Uni-App-X 工程化最佳实践
## 📚 概述
本文档介绍了 mall 项目的工程化实践,包括项目结构、开发流程、构建配置、代码规范等内容,参考 CRMEB 的工程化标准。
---
## 1. 项目结构
### 1.1 推荐目录结构
```
mall/
├── ai/ # AI 相关配置
├── components/
│ ├── analytics/ # 分析组件
│ ├── basic/ # ✨ 基础组件 (新增)
│ │ ├── Button.uvue
│ │ ├── Input.uvue
│ │ ├── Select.uvue
│ │ ├── Checkbox.uvue
│ │ ├── Radio.uvue
│ │ ├── Toggle.uvue
│ │ └── DatePicker.uvue
│ ├── container/ # ✨ 容器组件 (新增)
│ │ ├── Card.uvue
│ │ ├── Modal.uvue
│ │ ├── Drawer.uvue
│ │ ├── Collapse.uvue
│ │ ├── Tabs.uvue
│ │ └── Pagination.uvue
│ ├── data/ # ✨ 数据展示组件 (新增)
│ │ ├── Table.uvue
│ │ ├── List.uvue
│ │ ├── Tree.uvue
│ │ ├── Tag.uvue
│ │ ├── Badge.uvue
│ │ └── Avatar.uvue
│ ├── form/ # ✨ 表单组件 (新增)
│ │ ├── Form.uvue
│ │ ├── FormItem.uvue
│ │ ├── FormGroup.uvue
│ │ ├── Upload.uvue
│ │ └── RichEditor.uvue
│ ├── feedback/ # ✨ 反馈组件 (新增)
│ │ ├── Message.uvue
│ │ ├── Alert.uvue
│ │ ├── Tooltip.uvue
│ │ ├── Loading.uvue
│ │ ├── Empty.uvue
│ │ └── Error.uvue
│ ├── navigation/ # ✨ 导航组件 (新增)
│ │ ├── Breadcrumb.uvue
│ │ ├── Menu.uvue
│ │ ├── Navbar.uvue
│ │ └── Sidebar.uvue
│ ├── supadb/ # 数据库组件
│ └── ...
├── docs/
│ ├── STYLE_SPECIFICATION.md # ✨ 样式规范
│ ├── PAGE_STRUCTURE_SPECIFICATION.md # ✨ 页面结构规范
│ ├── COMPONENT_SPECIFICATION.md # ✨ 组件规范
│ ├── IMPLEMENTATION_ROADMAP.md # ✨ 实现路线图
│ ├── ENGINEERING_BEST_PRACTICES.md # ✨ 工程化最佳实践
│ └── ...
├── layouts/
│ ├── admin/
│ │ ├── AdminLayout.uvue # 增强版
│ │ └── utils/
│ │ ├── menu.uts
│ │ ├── nav.uts
│ │ └── state.uts
│ └── ...
├── pages/
│ ├── templates/ # ✨ 页面模板 (新增)
│ │ ├── ListPage.uvue
│ │ ├── FormPage.uvue
│ │ └── DetailPage.uvue
│ ├── mall/
│ │ ├── admin/
│ │ │ ├── maintain/
│ │ │ │ └── system-info.uvue
│ │ │ └── ...
│ │ └── ...
│ └── ...
├── styles/ # ✨ 全局样式 (优化)
│ ├── common.scss # 通用样式
│ ├── utilities.scss # 工具类
│ └── variables.scss # 变量(引用 uni.scss
├── uni_modules/
│ ├── ak-req/
│ ├── charts/
│ └── ...
├── utils/
│ ├── request.uts # 网络请求
│ ├── store.uts # 状态管理
│ ├── validators.uts # ✨ 验证器工具
│ ├── format.uts # ✨ 格式化工具
│ └── ...
├── uni.scss # ✨ 设计变量系统 (已更新)
├── App.uvue
├── main.js
├── main.uts
├── manifest.json
├── package.json
├── tsconfig.json
├── pages.json
├── platformConfig.json
└── README.md
```
### 1.2 新增目录说明
| 目录 | 用途 | 说明 |
| ------------------------ | -------- | ------------------------------ |
| `components/basic/` | 基础组件 | Button, Input, Select 等 |
| `components/container/` | 容器组件 | Card, Modal, Pagination 等 |
| `components/data/` | 数据展示 | Table, List, Tree 等 |
| `components/form/` | 表单组件 | Form, FormItem, Upload 等 |
| `components/feedback/` | 反馈组件 | Message, Alert, Loading 等 |
| `components/navigation/` | 导航组件 | Breadcrumb, Menu, Navbar 等 |
| `pages/templates/` | 页面模板 | ListPage, FormPage, DetailPage |
| `styles/` | 全局样式 | 共享样式和工具类 |
---
## 2. 开发规范
### 2.1 文件命名规范
| 类型 | 规范 | 示例 |
| -------- | ------------------ | ---------------------------------- |
| 组件文件 | PascalCase | `Button.uvue`, `FormItem.uvue` |
| 业务页面 | kebab-case | `system-info.uvue` |
| 工具脚本 | camelCase + .uts | `validators.uts`, `formatters.uts` |
| 样式文件 | kebab-case + .scss | `common.scss`, `utilities.scss` |
| 配置文件 | camelCase + .uts | `config.uts` |
| 常量文件 | UPPER_SNAKE_CASE | `CONSTANTS.uts` |
### 2.2 导入规范
```typescript
// ✅ 正确用法
// 1. 组件导入
import Button from '@/components/basic/Button.uvue'
import Card from '@/components/container/Card.uvue'
import Table from '@/components/data/Table.uvue'
// 2. 工具导入
import { validateEmail, validatePhone } from '@/utils/validators.uts'
import { formatDate, formatTime } from '@/utils/format.uts'
// 3. 类型导入 (UTS)
import type { MenuConfig } from '@/types/mall-types.uts'
// 4. 样式导入
import '@/styles/common.scss'
// ❌ 错误用法
// 不要使用相对路径
import Button from '../../../components/basic/Button.uvue' // ❌
// 不要混乱地导入
import * from '@/components/basic/Button.uvue' // ❌
// 不要导入 node_modules 中的代码(除非必要)
import { ref } from 'vue' // 这是可以的,但应该在文件顶部
```
### 2.3 TypeScript 规范
虽然使用 UTSUni-App TypeScript但也遵循 TypeScript 最佳实践:
```typescript
// ✅ 正确用法
// 1. 定义类型接口
interface ButtonProps {
type?: "primary" | "default" | "danger";
size?: "sm" | "md" | "lg";
label: string;
disabled?: boolean;
loading?: boolean;
}
// 2. 使用类型标注
const props = withDefaults(defineProps<ButtonProps>(), {
type: "primary",
size: "md",
disabled: false,
loading: false,
});
// 3. 定义事件类型
const emit = defineEmits<{
click: [];
change: [value: string];
submit: [formData: Record<string, any>];
}>();
// 4. 使用类型断言(谨慎)
const element = event.target as HTMLInputElement;
// ❌ 错误用法
// 不要使用 any 类型
const data: any = {
// ❌
name: "test",
};
// 不要忽略类型检查
const props = defineProps({
// ❌ 无类型定义
label: String,
});
// 不要过度使用 as
const value = data as unknown as string as number; // ❌
```
### 2.4 代码注释规范
```typescript
// ✅ 正确用法
/**
* Button 组件
* 支持多种类型、尺寸和状态
*
* @example
* <Button type="primary" label="创建" @click="handleCreate" />
*/
export default {
name: "Button",
// ...
};
// 方法注释
/**
* 处理按钮点击事件
* @param event - 点击事件
* @returns 无返回值
*/
const handleClick = (event: Event) => {
// ...
};
// 复杂逻辑注释
if (loading.value) {
// 加载中时显示加载指示器
return showLoadingIndicator();
}
// ❌ 错误用法
// 不要写无用的注释
const name = ref(""); // 设置 name ❌
// 不要注释掉代码
// const oldWay = () => { ... } ❌
// 不要写过时的注释
// TODO: 这个任务已经完成了 ❌
```
---
## 3. Git 工作流
### 3.1 分支策略
采用 Git Flow 分支模式:
```
main (生产分支)
release/v1.0.0 (发布分支)
develop (开发分支)
feature/component-button (功能分支)
feature/page-list (功能分支)
bugfix/sidebar-display (缺陷分支)
```
### 3.2 分支命名规范
| 分支类型 | 命名规范 | 示例 |
| -------- | ------------------------ | -------------------------- |
| 功能分支 | `feature/<feature-name>` | `feature/component-button` |
| 缺陷分支 | `bugfix/<bug-name>` | `bugfix/sidebar-display` |
| 热修复 | `hotfix/<issue>` | `hotfix/security-issue` |
| 发布分支 | `release/v<version>` | `release/v1.0.0` |
### 3.3 提交消息规范
遵循 Conventional Commits 规范:
```
<type>(<scope>): <subject>
<body>
<footer>
```
#### 类型 (type)
| 类型 | 说明 |
| -------- | ---------------------- |
| feat | 新功能 |
| fix | 缺陷修复 |
| docs | 文档更新 |
| style | 代码格式(不影响功能) |
| refactor | 代码重构 |
| perf | 性能优化 |
| test | 添加测试 |
| chore | 构建/依赖/工具 |
#### 示例
```
feat(components): add Button component with 4 types and 3 sizes
- Support primary, default, danger, success types
- Support sm, md, lg sizes
- Support disabled and loading states
- Add unit tests and documentation
Closes #123, #124
```
### 3.4 代码审查清单
推送 PR 前检查:
- [ ] 代码遵循样式规范
- [ ] 所有变量使用 uni.scss 设计变量
- [ ] 添加了必要的注释
- [ ] 编写了单元测试
- [ ] 文档已更新
- [ ] 无 console.log 和调试代码
- [ ] 无未使用的导入
- [ ] 类型检查无错误
---
## 4. 构建和打包
### 4.1 打包命令
```bash
# 开发模式
npm run dev
# 生产打包
npm run build
# 预览生产构建
npm run preview
# 类型检查
npm run type-check
# 代码格式化
npm run format
# 代码检查
npm run lint
```
### 4.2 环境配置
`.env` 文件中配置:
```env
# .env.development
VITE_API_BASE_URL=http://localhost:3000
VITE_APP_ENV=development
# .env.production
VITE_API_BASE_URL=https://api.example.com
VITE_APP_ENV=production
```
### 4.3 构建优化
#### 代码分割
```typescript
// 路由懒加载
const routes = [
{
path: "/admin/system-info",
component: () => import("@/pages/mall/admin/maintain/system-info.uvue"),
},
];
```
#### 资源优化
```typescript
// 图片优化
const image = 'image.webp' // 使用现代格式
// CSS 优化
// 在 uni.scss 中定义所有常用颜色和尺寸变量
$primary-color: #1890ff
$space-md: 16px
```
---
## 5. 测试规范
### 5.1 单元测试
```typescript
// Button.test.ts
import { describe, it, expect, vi } from "vitest";
import { mount } from "@vue/test-utils";
import Button from "@/components/basic/Button.uvue";
describe("Button Component", () => {
it("renders button with label", () => {
const wrapper = mount(Button, {
props: { label: "Click me" },
});
expect(wrapper.text()).toBe("Click me");
});
it("emits click event when clicked", async () => {
const wrapper = mount(Button, {
props: { label: "Click" },
});
await wrapper.find("button").trigger("click");
expect(wrapper.emitted("click")).toBeTruthy();
});
it("disables button when disabled prop is true", () => {
const wrapper = mount(Button, {
props: { label: "Click", disabled: true },
});
expect(wrapper.find("button").attributes("disabled")).toBeDefined();
});
it("applies correct class based on type prop", () => {
const wrapper = mount(Button, {
props: { label: "Click", type: "danger" },
});
expect(wrapper.find("button").classes()).toContain("btn-danger");
});
});
```
### 5.2 测试覆盖率目标
| 类型 | 目标 |
| -------- | ----- |
| 语句覆盖 | ≥ 80% |
| 分支覆盖 | ≥ 75% |
| 函数覆盖 | ≥ 80% |
| 行覆盖 | ≥ 80% |
### 5.3 测试运行命令
```bash
# 运行所有测试
npm run test
# 运行特定文件的测试
npm run test Button
# 生成覆盖率报告
npm run test:coverage
# 监视模式
npm run test:watch
```
---
## 6. 性能优化
### 6.1 加载性能目标
| 指标 | 目标 | 当前 |
| ------------------ | ------ | ---- |
| FCP (首次内容绘制) | < 1.5s | TBD |
| LCP (最大内容绘制) | < 2.5s | TBD |
| CLS (累积布局偏移) | < 0.1 | TBD |
| TTI (可交互时间) | < 3s | TBD |
### 6.2 优化技巧
```typescript
// 1. 虚拟滚动(大列表)
<virtual-scroller :items="largeList" :item-height="50">
<template #default="{ item }">
<div>{{ item }}</div>
</template>
</virtual-scroller>
// 2. 图片懒加载
<img v-lazy="imageUrl" />
// 3. 路由懒加载
const routes = [
{
path: '/admin',
component: () => import('@/layouts/admin/AdminLayout.uvue'),
},
]
// 4. 代码分割
const Table = defineAsyncComponent(() =>
import('@/components/data/Table.uvue')
)
// 5. 防抖和节流
import { debounce, throttle } from 'lodash-es'
const handleSearch = debounce(() => {
// 搜索逻辑
}, 300)
```
---
## 7. 监测和日志
### 7.1 日志记录
```typescript
// 使用结构化日志
import { logger } from "@/utils/logger.uts";
// 不同级别
logger.debug("调试信息"); // 开发使用
logger.info("信息"); // 正常操作
logger.warn("警告"); // 可能的问题
logger.error("错误"); // 出现问题
```
### 7.2 错误跟踪
```typescript
// 全局错误处理
app.config.errorHandler = (err, instance, info) => {
logger.error("应用错误:", err);
// 发送到错误追踪服务
trackError(err);
};
// 未捕获的 Promise 拒绝
window.addEventListener("unhandledrejection", (event) => {
logger.error("未处理的 Promise 拒绝:", event.reason);
});
```
### 7.3 性能监测
```typescript
// 性能标记
performance.mark("page-load-start");
// ... 页面加载逻辑 ...
performance.mark("page-load-end");
performance.measure("page-load", "page-load-start", "page-load-end");
const measure = performance.getEntriesByName("page-load")[0];
logger.info(`页面加载时间: ${measure.duration}ms`);
```
---
## 8. 依赖管理
### 8.1 package.json 脚本
```json
{
"scripts": {
"dev": "uni dev:h5",
"build": "uni build:h5",
"preview": "vite preview",
"type-check": "tsc --noEmit",
"format": "prettier --write .",
"lint": "eslint . --ext .vue,.ts,.uts",
"test": "vitest",
"test:coverage": "vitest --coverage"
}
}
```
### 8.2 依赖最小化
- 避免重复的依赖
- 定期更新依赖
- 移除未使用的依赖
- 选择轻量级替代品
```bash
# 检查未使用的依赖
npm ls --depth=0
# 检查过时的依赖
npm outdated
```
---
## 9. 文档维护
### 9.1 文档位置
所有文档都放在 `docs/` 目录:
```
docs/
├── STYLE_SPECIFICATION.md
├── PAGE_STRUCTURE_SPECIFICATION.md
├── COMPONENT_SPECIFICATION.md
├── IMPLEMENTATION_ROADMAP.md
├── ENGINEERING_BEST_PRACTICES.md
└── README.md
```
### 9.2 文档更新频率
| 文档 | 更新频率 | 维护者 |
| -------------- | -------- | ---------- |
| 样式规范 | 半年 | 设计团队 |
| 页面结构规范 | 每月 | 前端团队 |
| 组件规范 | 每月 | 前端团队 |
| 实现路线图 | 每周 | 项目经理 |
| 工程化最佳实践 | 按需 | 技术负责人 |
### 9.3 README 模板
每个模块都应有 README.md
```markdown
# Module Name
## 描述
简明扼要的模块描述
## 结构
```
module/
├── Component.uvue
├── types.uts
└── utils.uts
```
## 使用方法
代码示例
## 贡献指南
如何贡献
## 许可证
MIT
```
---
## 10. 发布流程
### 10.1 版本管理
使用语义化版本 (Semantic Versioning):
```
MAJOR.MINOR.PATCH
v1.2.3
```
- **MAJOR**: 不兼容的改动
- **MINOR**: 新增功能(向后兼容)
- **PATCH**: 缺陷修复
### 10.2 发布检查清单
在发布新版本前:
- [ ] 所有测试通过
- [ ] 文档更新
- [ ] CHANGELOG 更新
- [ ] 版本号更新 (package.json)
- [ ] Git 标签创建
- [ ] 构建成功
- [ ] 性能检测通过
- [ ] 安全审计通过
### 10.3 CHANGELOG 格式
```markdown
# Changelog
## [1.2.0] - 2026-02-28
### Added
- 新增 Button 组件
- 新增 Input 组件
- 新增表单验证器
### Changed
- 更新设计变量系统
- 改进性能40% 更快)
### Fixed
- 修复 Modal 动画闪烁问题
- 修复移动端布局问题
### Deprecated
- 弃用旧的 Button 样式
### Security
- 修复 XSS 漏洞
```
---
## 📝 总结
**工程化核心原则**:
1. **代码一致性** - 遵循命名和格式规范
2. **自动化** - 使用脚本和工具自动化重复任务
3. **可维护性** - 清晰的代码和充分的文档
4. **可测试性** - 编写可测试的代码
5. **性能** - 不断监测和优化
**禁止做法**:
- 不要不遵循 Git 工作流
- 不要提交到 main 分支(使用 PR
- 不要忽视代码审查
- 不要发布前没有测试
- 不要创建无文档的代码
---
**文档版本**: 1.0
**最后更新**: 2026-01-31
**维护者**: AI Assistant