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

17 KiB
Raw Blame History

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 导入规范

// ✅ 正确用法

// 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 最佳实践:

// ✅ 正确用法

// 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 代码注释规范

// ✅ 正确用法

/**
 * 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 打包命令

# 开发模式
npm run dev

# 生产打包
npm run build

# 预览生产构建
npm run preview

# 类型检查
npm run type-check

# 代码格式化
npm run format

# 代码检查
npm run lint

4.2 环境配置

.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 构建优化

代码分割

// 路由懒加载
const routes = [
  {
    path: "/admin/system-info",
    component: () => import("@/pages/mall/admin/maintain/system-info.uvue"),
  },
];

资源优化

// 图片优化
const image = 'image.webp' // 使用现代格式

// CSS 优化
// 在 uni.scss 中定义所有常用颜色和尺寸变量
$primary-color: #1890ff
$space-md: 16px

5. 测试规范

5.1 单元测试

// 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 测试运行命令

# 运行所有测试
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 优化技巧

// 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 日志记录

// 使用结构化日志
import { logger } from "@/utils/logger.uts";

// 不同级别
logger.debug("调试信息"); // 开发使用
logger.info("信息"); // 正常操作
logger.warn("警告"); // 可能的问题
logger.error("错误"); // 出现问题

7.2 错误跟踪

// 全局错误处理
app.config.errorHandler = (err, instance, info) => {
  logger.error("应用错误:", err);
  // 发送到错误追踪服务
  trackError(err);
};

// 未捕获的 Promise 拒绝
window.addEventListener("unhandledrejection", (event) => {
  logger.error("未处理的 Promise 拒绝:", event.reason);
});

7.3 性能监测

// 性能标记
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 脚本

{
  "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 依赖最小化

  • 避免重复的依赖
  • 定期更新依赖
  • 移除未使用的依赖
  • 选择轻量级替代品
# 检查未使用的依赖
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

# 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 格式

# 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