# 📊 依赖关系图

‍```
┌─────────────────┐
│      App        │  ← 业务开发层（用户自定义业务模块）
│   (用户业务)     │    电商、CRM、ERP等具体业务逻辑
└─────────────────┘
         ↓
┌─────────────────┐
│     Common      │  ← 框架通用服务层（企业级通用功能）
│ (框架通用服务)   │    用户管理、权限管理、菜单管理
└─────────────────┘    文件上传、通知服务、系统设置
         ↓              数据字典、缓存服务、队列服务
┌─────────────────┐
│      Core       │  ← 核心基础设施层（底层基础设施）
│   (基础设施)     │    认证核心、数据库核心、验证核心
└─────────────────┘    HTTP核心、缓存核心、队列核心
         ↓
┌─────────────────┐
│     Vendor      │  ← 第三方服务适配层
│   (外部集成)     │    存储、支付、通信、云服务适配
└─────────────────┘

┌─────────────────┐
│     Addons      │  ← 插件扩展层（可插拔功能模块）
│   (插件扩展)     │    扩展框架功能，不影响核心稳定性
└─────────────────┘
```

## 📚 参考文档

- **Vben Admin 官方文档**: https://doc.vben.pro/
- **项目技术栈**: Vue 3 + TypeScript + Vite + Element Plus
- **UI 组件库**: Element Plus (当前项目使用)
- **表单组件**: Vben Form (支持 Element Plus、Ant Design Vue、Naive UI 等多种 UI 库适配)

---

## 📐 项目规范（代码风格与约定）

本节定义目录结构、导入顺序、命名、方法与引用等统一规范，用于指导日常开发与 Code Review。

### 1) 目录结构规范

```
src/
├─ addon/      # 插件扩展层：可插拔功能模块，不影响核心稳定性
├─ app/        # 应用层：用户业务开发模块
│  ├─ ecommerce/  # 电商业务模块
│  ├─ crm/        # CRM 业务模块
│  └─ erp/        # ERP 业务模块
├─ common/     # 框架通用服务层：用户、权限、菜单、文件、通知、系统设置等
├─ config/     # 配置层：集中化配置与校验
├─ core/       # 基础设施：数据库、缓存、HTTP、认证、日志等核心能力封装
├─ vendor/     # 第三方适配：支付、存储、短信、云服务等
└─ main.ts     # 应用入口
```

- 依赖方向：App → Common → Core → Vendor；禁止反向依赖与跨层耦合。
- Addon 可依赖 Common/Core，但 App/Common/Core 不得依赖 Addon。
- 模块划分以领域边界为单位，保持高内聚、低耦合。

### 2) 导入顺序与分组

1. Node.js 内置模块
2. 第三方依赖（npm 包）
3. 项目内部模块
4. 父级目录（../）
5. 同级目录（./）
6. 索引文件（index）

示例：
```ts
// 1) Node 内置
import * as fs from 'fs';
import * as path from 'path';

// 2) 外部依赖
import { Controller } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';

// 3) 内部模块
import { LoggerService } from '../../core/logger';

// 4) 父级目录
import { BaseController } from '../base';

// 5) 同级目录
import { UserService } from './user.service';

// 6) 索引
import { CreateUserDto } from './dto';
```

### 3) 命名规范

- 文件：
  - 控制器 `*.controller.ts`，服务 `*.service.ts`，实体 `*.entity.ts`，DTO `*.dto.ts`
  - 接口 `*.interface.ts`，类型 `*.type.ts`，常量 `*.constant.ts`，配置 `*.config.ts`，模块 `*.module.ts`
- 类：`UserController`、`UserService`、`UserEntity`、`CreateUserDto`
- 变量/方法：camelCase；布尔值以 `is/has/can/should` 开头；必要时私有方法可用前缀 `_`（可选）

### 4) 方法与类设计

- 单一职责、短小精悍，每个方法聚焦一个清晰目标
- 依赖注入优先，避免在方法中直接构造依赖
- 显式返回类型，避免 any；公共方法尽量无副作用
- 错误优先返回与早失败（early return），减少嵌套

### 5) 引用与依赖约束

- 严格遵循分层依赖：App → Common → Core → Vendor
- 禁止跨域（跨子域模块）直接依赖，使用约定接口与适配器
- 避免循环依赖；必要时通过接口、token 或事件解耦
- 推荐在每层提供 index.ts 作为 barrel 导出，统一对外 API

### 6) 类型、实体与 DTO

- 优先使用 interface，合理使用泛型提升复用
- DTO 与 Entity 分离：DTO 负责入参校验（class-validator），Entity 负责持久化结构
- 禁止直接在控制器接收实体，必须使用 DTO 并开启全局 ValidationPipe（已开启）

### 7) 错误处理与日志

- 统一抛出框架异常（如 NotFoundException、BadRequestException），或自定义异常族
- 记录错误日志，包含 requestId（CLS 已接入）、上下文与栈信息
- 外部接口与关键链路增加 info 级打点，敏感信息不可入日志

### 8) 注释规范

- 公共类与复杂方法使用 JSDoc 注释；重要分支与特殊处理写明原因
- 使用 TODO / FIXME 标注技术债与待优化点

### 9) 代码质量与提交

- Prettier + ESLint 强制统一风格；提交前 lint-staged 自动修复
- Git 提交遵循 Conventional Commits；使用 `npm run commit` 触发交互式提交

### 10) 模块骨架推荐

```
feature/
├─ feature.module.ts
├─ feature.controller.ts
├─ feature.service.ts
├─ entities/
│  └─ feature.entity.ts
├─ dto/
│  ├─ create-feature.dto.ts
│  └─ update-feature.dto.ts
└─ feature.repository.ts   # 如需自定义仓储
```

- Common 层提供通用能力（用户、权限、菜单…），App 层仅组合与编排，尽量避免在 App 层重复造轮子。

### 11) API 约定

- Swagger 注解最小化：`@ApiTags`、`@ApiOperation`、`@ApiBearerAuth`（如需鉴权）
- 错误码与响应体保持一致性（统一响应封装可在 Common 层提供）

### 12) 性能与安全

- 优先分页与选择性字段；避免 N+1 查询，必要时使用关联加载或查询优化
- 合理使用缓存与索引；异步/队列处理重任务
- 输入校验与输出清洗；开启限流与安全中间件；严禁在日志中打印密钥/密码

> 以上规范作为默认约束，后续将根据业务与基础设施演进持续完善。
---

## 🔒 层级约束（强制）

- 允许依赖：
  - App(modules) → App(common) → Core（严格单向）
  - Vendor 仅提供第三方适配器，不依赖 App/Core 任何实现
  - Addon 可依赖 App(common)/Core，但 App/Core 不得依赖 Addon
- 禁止依赖：
  - App(common) → App(modules)（反向依赖）
  - Core → App（反向依赖）
  - App(common) → Vendor（直接依赖第三方），必须通过 Core 暴露的抽象端口（Port/Token）间接使用 Vendor
  - 同层不同域模块严禁相互依赖其内部实现，唯一入口为该域公开的 index.ts 或导出 API
- 访问 Vendor 的约束：
  - 第三方 SDK/Client 在 Vendor 层实现具体 Adapter；Core 层定义抽象 Port/Token 并注入；Common 只依赖 Core 的抽象，不直接 import Vendor
- 运行时注册约束：
  - 所有外部资源（Redis、OSS、SMTP、SMS 等）统一在 Vendor 模块封装 Provider；由 Core 定义抽象并在应用 root 注册，Common 仅消费抽象

## 🧭 导入约束执行（建议自动化）

- ESLint 约束（示例片段，后续可合并到 eslint.config.mjs）：
```js
// import 方向约束，禁止反向与跨层内部实现依赖
rules: {
  'no-restricted-imports': [
    'error',
    {
      patterns: [
        // Common 禁止依赖 App、Vendor
        { group: ['@app/*', 'src/app/*', '@vendor/*', 'src/vendor/*'], message: 'Common 层禁止依赖 App/Vendor，请依赖 Core 抽象' },
        // Core 禁止依赖 App/Common/Vendor
        { group: ['@app/*', 'src/app/*', '@common/*', 'src/common/*', '@vendor/*', 'src/vendor/*'], message: 'Core 层禁止依赖上层与 Vendor 实现' },
        // 任何层禁止 import 同层其他域的内部文件（建议各域仅通过 index.ts 暴露）
        { group: ['**/*/internal/**'], message: '禁止依赖其他域内部实现，请通过其公共 API' },
      ],
    },
  ],
}
```
- 路径别名建议（仅规范，不立即修改）：
  - @app/*，@common/*，@core/*，@vendor/*
  - 同层跨域访问仅允许 import 其公共 API（index.ts 或 public API 文件）

## 🧩 层级职责与能力清单

- Core（核心基础设施）
  - 配置系统（ConfigModule + Joi 校验）
  - 数据库（TypeORM 基类：BaseEntity/BaseRepository，事务、审计字段）
  - 日志（Winston + nest-winston，按日切割，CLS requestId）
  - 缓存抽象（Cache Port，默认内存，提供 Redis 端口定义）
  - 队列抽象（Bull Port，重试、延时、并发控制）
  - HTTP 客户端封装（重试、超时、熔断占位）
  - 安全与鉴权抽象（密码策略、加密、加盐、签名、ACL/RBAC 接口）
  - 全局管道/过滤器/拦截器（ValidationPipe、异常过滤、响应封装、日志/耗时拦截）
  - 限流封装（Throttler）
  - 事件总线（EventEmitter 封装）
  - 请求上下文（CLS，traceId/requestId）

- App/Common（通用业务能力，内置功能）
  - 账户与组织：User、Dept/Org、Profile
  - 认证与授权：Auth（登录/登出/刷新）、JWT、RBAC（Role/Permission/Menu/Route）
  - 系统配置：SystemConfig、参数配置、开关项、Settings（Email/SMS/Storage/Payment/Login）
  - 字典中心：Dictionary/Enum 管理
  - 文件中心：上传、元数据、存储策略（通过 Core 抽象对接 Vendor）
  - 通知中心：邮件/短信/站内信（通过 Core 抽象）
  - 审计与操作日志：请求追踪、关键操作记录
  - 任务调度：定时任务编排（cron）
  - 健康检查与监控：/health、/metrics（可选）
  - 国际化：i18n（可选）
  - 多租户（可选，后续版本）

- App/Modules（具体业务模块）
  - 电商模块：商品管理、订单管理、购物车、支付流程
  - CRM 模块：客户管理、销售线索、商机跟进
  - ERP 模块：库存管理、采购管理、财务管理
  - 其他业务模块：根据具体需求扩展

- Vendor（第三方适配层）
  - Redis 客户端、MySQL 连接适配（由 Core 调用）
  - 对象存储：Aliyun OSS / AWS S3 / Qiniu 等适配器
  - 邮件：Nodemailer/SES 适配器
  - 短信：Aliyun SMS / Tencent SMS 适配器
  - 支付：Alipay / WeChat Pay 适配器
  - 验证码：图形/短信验证码服务
  - 第三方 OAuth：GitHub/WeChat 等

- Addon（可选插件）
  - 雪花 ID / 分布式 ID
  - 审批流/流程引擎
  - 特性开关/灰度发布
  - 代码生成/脚手架

## 📁 完整目录规范（建议骨架）

```
src/
├─ addon/
│  ├─ feature-flags/
│  │  ├─ feature-flags.module.ts
│  │  └─ services/
│  ├─ id-generator/
│  │  ├─ id-generator.module.ts
│  │  └─ services/
│  └─ workflow/
│     ├─ workflow.module.ts
│     └─ services/
│
├─ app/
│  ├─ ecommerce/
│  │  ├─ product/
│  │  │  ├─ product.module.ts
│  │  │  ├─ product.controller.ts
│  │  │  ├─ product.service.ts
│  │  │  ├─ entities/
│  │  │  └─ dto/
│  │  ├─ order/
│  │  │  ├─ order.module.ts
│  │  │  ├─ order.controller.ts
│  │  │  ├─ order.service.ts
│  │  │  ├─ entities/
│  │  │  └─ dto/
│  │  └─ cart/
│  │     ├─ cart.module.ts
│  │     ├─ cart.controller.ts
│  │     ├─ cart.service.ts
│  │     ├─ entities/
│  │     └─ dto/
│  ├─ crm/
│  │  ├─ customer/
│  │  ├─ lead/
│  │  └─ opportunity/
│  └─ erp/
│     ├─ inventory/
│     ├─ procurement/
│     └─ finance/
│
├─ common/
│  ├─ auth/
│  │  ├─ auth.module.ts
│  │  ├─ auth.controller.ts
│  │  ├─ auth.service.ts
│  │  ├─ strategies/
│  │  └─ dto/
│  ├─ user/
│  │  ├─ user.module.ts
│  │  ├─ user.controller.ts
│  │  ├─ user.service.ts
│  │  ├─ entities/
│  │  └─ dto/
│  ├─ rbac/
│  │  ├─ rbac.module.ts
│  │  ├─ role.service.ts
│  │  ├─ permission.service.ts
│  │  ├─ menu.service.ts
│  │  ├─ entities/
│  │  └─ dto/
│  ├─ settings/
│  │  ├─ settings.module.ts
│  │  ├─ email/
│  │  ├─ sms/
│  │  ├─ storage/
│  │  ├─ payment/
│  │  └─ login/
│  ├─ dict/
│  ├─ file/
│  ├─ notify/
│  ├─ audit/
│  ├─ schedule/
│  ├─ health/
│  ├─ i18n/
│  └─ shared/
│     ├─ dto/
│     ├─ constants/
│     └─ utils/
│
├─ core/
│  ├─ config/
│  │  ├─ config.module.ts
│  │  └─ schemas/
│  ├─ database/
│  │  ├─ database.module.ts
│  │  ├─ base.entity.ts
│  │  └─ base.repository.ts
│  ├─ logger/
│  │  └─ logger.module.ts
│  ├─ cache/
│  │  ├─ cache.module.ts
│  │  └─ ports/
│  │     └─ cache.port.ts
│  ├─ queue/
│  │  ├─ queue.module.ts
│  │  └─ ports/
│  │     └─ queue.port.ts
│  ├─ http/
│  │  └─ http.module.ts
│  ├─ security/
│  │  ├─ security.module.ts
│  │  ├─ guards/
│  │  └─ strategies/
│  ├─ exception/
│  │  └─ filters/
│  ├─ interceptor/
│  │  ├─ logging.interceptor.ts
│  │  └─ transform.interceptor.ts
│  ├─ validation/
│  │  └─ pipes/
│  └─ context/
│     └─ cls.module.ts
│
├─ vendor/
│  ├─ redis/
│  │  ├─ redis.module.ts
│  │  └─ redis.provider.ts
│  ├─ mailer/
│  │  ├─ mailer.module.ts
│  │  └─ nodemailer.adapter.ts
│  ├─ sms/
│  │  └─ aliyun-sms.adapter.ts
│  ├─ storage/
│  │  ├─ oss.adapter.ts
│  │  └─ s3.adapter.ts
│  ├─ payment/
│  │  ├─ alipay.adapter.ts
│  │  └─ wechatpay.adapter.ts
│  ├─ captcha/
│  │  └─ captcha.adapter.ts
│  └─ http/
│     └─ axios.adapter.ts
│
├─ config/
│  ├─ database.config.ts
│  ├─ redis.config.ts
│  └─ app.config.ts
│
└─ main.ts
```

## 🔌 依赖倒置与适配器模式约定

- Core 只定义 Port/Token（接口/抽象）与领域无关的基础能力
- Vendor 负责第三方实现（Adapter），通过 Provider 绑定到 Core 的 Token
- Common 仅通过 Core 暴露的 Token 使用能力，禁止直接引用具体 Adapter

## 🔔 事件与跨层通信

- 领域事件优先，使用 EventEmitter；禁止同步强耦合调用导致循环依赖
- 对跨系统/异步任务，统一走队列（Bull）或消息（后续可扩展）

## ⚙️ 配置命名约定（节选）

- LOG_LEVEL、THROTTLE_TTL、THROTTLE_LIMIT
- DB_HOST、DB_PORT、DB_USER、DB_PASS、DB_NAME
- REDIS_HOST、REDIS_PORT、REDIS_DB、REDIS_PASS
- JWT_SECRET、JWT_EXPIRES_IN

## 🛠️ 待落实的工程化检查（后续可执行）

- ESLint import 方向约束规则落地
- tsconfig 路径别名（@app/@common/@core/@vendor）
- 各层 index.ts 统一导出公共 API

---


## 🎨 前端开发规范（Vben Admin）

本项目前端基于 **Vben Admin** 框架，参考 **Niucloud** 的业务模式进行开发。前端位于 `admin/` 目录，采用 Vue 3 + TypeScript + Vite 技术栈。

**参考目录：**
- Niucloud 前端参考：`g:\wwjcloud-nestjs\reference\niucloud-php\admin\`
- 本项目前端目录：`g:\wwjcloud-nestjs\admin\apps\web-ele\`

### 1) 前端目录结构规范

```
admin/
├─ apps/
│  └─ web-ele/                    # 主应用
│     ├─ src/
│     │  ├─ addon/                # 插件扩展层（参考 Niucloud）
│     │  │  ├─ shop/              # 商城插件
│     │  │  ├─ cms/               # 内容管理插件
│     │  │  └─ marketing/         # 营销插件
│     │  ├─ app/                  # 应用业务层（对应后端 app）
│     │  │  ├─ ecommerce/         # 电商模块
│     │  │  │  ├─ product/        # 商品管理
│     │  │  │  ├─ order/          # 订单管理
│     │  │  │  └─ cart/           # 购物车
│     │  │  ├─ crm/               # CRM 模块
│     │  │  │  ├─ customer/       # 客户管理
│     │  │  │  └─ lead/           # 销售线索
│     │  │  └─ erp/               # ERP 模块
│     │  │     ├─ inventory/      # 库存管理
│     │  │     └─ finance/        # 财务管理
│     │  ├─ common/               # 通用业务功能（对应后端 common）
│     │  │  ├─ user/              # 用户管理
│     │  │  │  ├─ api/            # 用户相关 API
│     │  │  │  └─ views/          # 用户页面
│     │  │  ├─ auth/              # 认证授权
│     │  │  │  ├─ api/            # 认证相关 API
│     │  │  │  └─ views/          # 认证页面
│     │  │  ├─ settings/          # 系统设置
│     │  │  │  ├─ api/            # 设置相关 API
│     │  │  │  │  ├─ email.ts
│     │  │  │  │  ├─ login.ts
│     │  │  │  │  ├─ sms.ts
│     │  │  │  │  └─ storage.ts
│     │  │  │  └─ views/          # 设置页面
│     │  │  │     ├─ email/
│     │  │  │     │  └─ index.vue
│     │  │  │     ├─ login/
│     │  │  │     │  └─ index.vue
│     │  │  │     ├─ sms/
│     │  │  │     │  └─ index.vue
│     │  │  │     └─ storage/
│     │  │  │        └─ index.vue
│     │  │  ├─ menu/              # 菜单管理
│     │  │  │  ├─ api/            # 菜单相关 API
│     │  │  │  └─ views/          # 菜单页面
│     │  │  ├─ upload/            # 文件上传
│     │  │  │  ├─ api/            # 上传相关 API
│     │  │  │  └─ views/          # 上传页面
│     │  │  └─ rbac/              # 角色权限管理
│     │  │     ├─ api/            # 权限相关 API
│     │  │     └─ views/          # 权限页面
│     │  ├─ api/                  # API 接口层（Vben 规范）
│     │  │  └─ request.ts         # 请求客户端配置
│     │  ├─ views/                # 页面视图层（Vben 规范）
│     │  │  └─ dashboard/         # 仪表板
│     │  ├─ router/               # 路由配置（Vben 规范）
│     │  │  └─ routes/
│     │  │     └─ modules/
│     │  │        ├─ settings.ts
│     │  │        └─ auth.ts
│     │  ├─ stores/               # 状态管理（Vben 规范）
│     │  ├─ components/           # 公共组件（Vben 规范）
│     │  ├─ composables/          # 组合式函数（Vben 规范）
│     │  ├─ utils/                # 工具函数（Vben 规范）
│     │  └─ types/                # 类型定义（Vben 规范）
│     ├─ package.json
│     └─ vite.config.ts
├─ packages/                      # 共享包（Vben 规范）
└─ docs/                         # 文档
```

### 2) 前端分层架构

前端采用分层架构设计，参考 Niucloud 业务模式并结合 Vben 框架规范：

```
┌─────────────────┐
│     Addon       │  ← 插件扩展层（参考 Niucloud）
│   (插件扩展)     │    可插拔功能模块，如商城、CMS等
└─────────────────┘
         ↓
┌─────────────────┐
│      App        │  ← 应用业务层（对应后端 app 层）
│   (业务应用)     │    电商、CRM、ERP 等具体业务模块
└─────────────────┘
         ↓
┌─────────────────┐
│     Common      │  ← 通用功能层（对应后端 common 层）
│   (通用功能)     │    用户、认证、设置、菜单、权限等
└─────────────────┘
         ↓
┌─────────────────┐
│     Views       │  ← 视图层（页面组件，Vben 规范）
│   (页面视图)     │    负责用户界面展示和交互
└─────────────────┘
          ↓
┌─────────────────┐
│   Composables   │  ← 逻辑层（组合式函数，Vben 规范）
│   (业务逻辑)     │    封装业务逻辑和状态管理
└─────────────────┘
          ↓
┌─────────────────┐
│      API        │  ← 接口层（API 调用，Vben 规范）
│   (数据接口)     │    封装后端接口调用
└─────────────────┘
          ↓
┌─────────────────┐
│     Utils       │  ← 工具层（通用工具，Vben 规范）
│   (工具函数)     │    提供通用工具和辅助函数
└─────────────────┘
```

#### 2.1 分层架构详细说明

- **插件扩展层 (addon/)**: 可插拔功能模块，参考 Niucloud 插件架构
- **应用业务层 (app/)**: 对应后端 app 层，具体业务模块
  - **电商模块 (app/ecommerce/)**: 商品、订单、购物车等
  - **CRM 模块 (app/crm/)**: 客户管理、销售线索等
  - **ERP 模块 (app/erp/)**: 库存、财务等
- **通用功能层 (common/)**: 对应后端 common 层，框架通用功能
  - **用户管理 (common/user/)**: 用户相关功能
  - **认证授权 (common/auth/)**: 登录、权限等
  - **系统设置 (common/settings/)**: 邮件、短信、存储等配置
  - **菜单管理 (common/menu/)**: 菜单配置
  - **文件上传 (common/upload/)**: 文件处理
  - **角色权限 (common/rbac/)**: RBAC 权限管理
- **API 接口层 (api/)**: 统一管理后端接口调用（Vben 规范）
- **页面视图层 (views/)**: 业务页面组件（Vben 规范）
- **路由配置层 (router/)**: 页面路由管理（Vben 规范）
- **状态管理层 (stores/)**: 全局状态管理（Vben 规范）
- **组件层 (components/)**: 可复用组件（Vben 规范）
- **工具层 (utils/)**: 通用工具函数（Vben 规范）

### 3) API 接口层规范

#### 3.1 接口文件组织
- 按业务模块划分：`api/settings/`、`api/auth/`、`api/user/` 等
- 每个模块包含：接口函数、类型定义、响应处理
- 统一使用 `requestClient` 进行 HTTP 请求

#### 3.2 接口命名约定
```typescript
// 获取数据：get{Module}Api 或 get{Module}{Action}Api
export const getEmailSettingsApi = () => requestClient.get<EmailSettingsVo>('/settings/email')

// 更新数据：update{Module}Api 或 update{Module}{Action}Api
export const updateEmailSettingsApi = (data: UpdateEmailSettingsDto) => 
  requestClient.put<EmailSettingsVo>('/settings/email', data)

// 创建数据：create{Module}Api
export const createUserApi = (data: CreateUserDto) => 
  requestClient.post<UserVo>('/users', data)

// 删除数据：delete{Module}Api
export const deleteUserApi = (id: string) => 
  requestClient.delete(`/users/${id}`)
```

#### 3.3 类型定义规范
```typescript
// 响应类型以 Vo 结尾（View Object）
export interface EmailSettingsVo {
  host: string
  port: number
  username: string
  password: string
  encryption: string
  fromAddress: string
  fromName: string
}

// 请求类型以 Dto 结尾（Data Transfer Object）
export interface UpdateEmailSettingsDto {
  host?: string
  port?: number
  username?: string
  password?: string
  encryption?: string
  fromAddress?: string
  fromName?: string
}
```

### 4) 页面组件规范

#### 4.1 页面结构模板（Vben Admin + Element Plus 规范）
```vue
<template>
  <div class="p-4">
    <!-- 页面标题和描述 -->
    <div class="mb-4">
      <h1 class="text-2xl font-bold mb-2">{{ pageTitle }}</h1>
      <p class="text-gray-600">{{ pageDescription }}</p>
    </div>

    <!-- 主要内容区域 -->
    <el-card :header="cardTitle" shadow="hover">
      <template #header>
        <div class="flex justify-between items-center">
          <span>{{ cardTitle }}</span>
          <el-button type="primary" @click="handleSave" :loading="loading">
            保存
          </el-button>
        </div>
      </template>
      
      <!-- Vben 表单内容 -->
      <VbenForm ref="formRef" @submit="handleSubmit" />
    </el-card>
    
    <!-- 页面底部操作栏（可选） -->
    <div class="flex justify-end gap-2 mt-4">
      <el-button @click="handleCancel">取消</el-button>
      <el-button type="primary" @click="handleSave" :loading="loading">
        保存
      </el-button>
    </div>
  </div>
</template>
```

#### 4.2 组件脚本结构（Vben Admin + Element Plus 规范）
```vue
<script lang="ts" setup>
// 1. Vue 相关导入
import { ref, reactive, computed, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'

// 2. Element Plus 组件导入
import { ElCard, ElButton, ElMessage } from 'element-plus'

// 3. Vben 表单组件导入
import { useVbenForm, z } from '#/adapter/form'

// 4. 项目内部导入
import { $t } from '#/locales'
import { getEmailSettingsApi, updateEmailSettingsApi } from '#/api/settings/email'
import type { EmailSettingsVo, UpdateEmailSettingsDto } from '#/api/settings/email'

// 5. 页面基础信息
const pageTitle = '邮件设置'
const pageDescription = '配置系统邮件发送相关参数'
const cardTitle = '邮件服务器配置'

// 6. 路由和状态
const route = useRoute()
const router = useRouter()
const loading = ref(false)

// 7. Vben 表单配置（适配 Element Plus）
const [EmailForm, emailFormApi] = useVbenForm({
  // 表单布局
  layout: 'horizontal',
  // 表单项通用配置
  commonConfig: {
    componentProps: {
      class: 'w-full',
    },
  },
  // 表单提交处理
  handleSubmit: handleFormSubmit,
  // 表单结构定义（使用 Element Plus 组件）
  schema: [
    {
      component: 'Input', // 对应 el-input
      fieldName: 'host',
      label: 'SMTP服务器',
      rules: z.string().min(1, '请输入SMTP服务器地址'),
      componentProps: {
        placeholder: '请输入SMTP服务器地址',
      },
    },
    {
      component: 'InputNumber', // 对应 el-input-number
      fieldName: 'port',
      label: '端口号',
      rules: z.number().min(1, '请输入端口号'),
      componentProps: {
        placeholder: '请输入端口号',
        min: 1,
        max: 65535,
      },
    },
    {
      component: 'Input',
      fieldName: 'username',
      label: '用户名',
      rules: z.string().min(1, '请输入用户名'),
      componentProps: {
        placeholder: '请输入邮箱用户名',
      },
    },
    {
      component: 'InputPassword', // 对应 el-input type="password"
      fieldName: 'password',
      label: '密码',
      rules: z.string().min(1, '请输入密码'),
      componentProps: {
        placeholder: '请输入邮箱密码或授权码',
        showPassword: true,
      },
    },
  ],
})

// 8. 方法定义
const fetchData = async () => {
  loading.value = true
  try {
    const data = await getEmailSettingsApi()
    emailFormApi.setValues(data)
  } catch (error) {
    console.error('Failed to fetch email settings:', error)
    ElMessage.error('获取邮件设置失败')
  } finally {
    loading.value = false
  }
}

async function handleFormSubmit(values: UpdateEmailSettingsDto) {
  loading.value = true
  try {
    await updateEmailSettingsApi(values)
    ElMessage.success('保存成功')
    router.back()
  } catch (error) {
    console.error('Failed to save email settings:', error)
    ElMessage.error('保存失败')
  } finally {
    loading.value = false
  }
}

const handleSave = () => {
  emailFormApi.submitForm()
}

const handleCancel = () => {
  router.back()
}

const handleAction = () => {
  // 自定义操作逻辑
}

// 9. 生命周期
onMounted(() => {
  fetchData()
})
</script>
```

### 5) 路由配置规范（Vben Admin 规范）

#### 5.1 路由文件组织
- 按模块划分：`src/router/routes/modules/settings.ts`
- 路由配置遵循 Vben 路由规范
- 使用懒加载方式导入组件
- 路由权限通过 `meta.authority` 配置

#### 5.2 路由配置示例
```typescript
import type { RouteRecordRaw } from 'vue-router'

const routes: RouteRecordRaw[] = [
  {
    path: '/settings',
    name: 'Settings',
    component: '#/layouts/index.vue',
    meta: {
      title: '系统设置',
      icon: 'lucide:settings',
      order: 1000,
    },
    children: [
      {
        path: '/settings/email',
        name: 'EmailSettings',
        component: () => import('#/views/settings/email/index.vue'),
        meta: {
          title: '邮件设置',
          icon: 'lucide:mail',
          authority: ['admin', 'super'],
        },
      },
      {
        path: '/settings/sms',
        name: 'SmsSettings',
        component: () => import('#/views/settings/sms/index.vue'),
        meta: {
          title: '短信设置',
          icon: 'lucide:message-square',
          authority: ['admin', 'super'],
        },
      },
      {
        path: '/settings/storage',
        name: 'StorageSettings',
        component: () => import('#/views/settings/storage/index.vue'),
        meta: {
          title: '存储设置',
          icon: 'lucide:hard-drive',
          authority: ['admin', 'super'],
        },
      },
    ],
  },
]

export default routes
```

#### 5.3 路由权限配置
- 使用 `meta.authority` 配置页面访问权限
- 支持角色权限：`['admin', 'super']`
- 支持权限码：`['settings:email:read', 'settings:email:write']`
- 无权限配置表示公开访问

### 6) 状态管理规范（Vben Admin 规范）

#### 6.1 使用 Pinia 进行状态管理
- 按业务模块划分 Store：`src/stores/modules/`
- 优先使用 Composition API 风格
- 合理使用持久化存储
- 遵循 Vben 状态管理模式

#### 6.2 Store 示例
```typescript
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import type { EmailSettingsVo } from '#/api/settings/email'
import { getEmailSettingsApi, updateEmailSettingsApi } from '#/api/settings/email'

export const useSettingsStore = defineStore(
  'settings',
  () => {
    // 状态
    const emailSettings = ref<EmailSettingsVo | null>(null)
    const smsSettings = ref<any>(null)
    const storageSettings = ref<any>(null)
    const loading = ref(false)

    // 计算属性
    const isEmailConfigured = computed(() => {
      return emailSettings.value?.host && emailSettings.value?.username
    })

    const isAnySettingLoading = computed(() => loading.value)

    // 方法
    const fetchEmailSettings = async () => {
      loading.value = true
      try {
        const data = await getEmailSettingsApi()
        emailSettings.value = data
        return data
      } catch (error) {
        console.error('Failed to fetch email settings:', error)
        throw error
      } finally {
        loading.value = false
      }
    }

    const updateEmailSettings = async (settings: EmailSettingsVo) => {
      loading.value = true
      try {
        await updateEmailSettingsApi(settings)
        emailSettings.value = settings
        return settings
      } catch (error) {
        console.error('Failed to update email settings:', error)
        throw error
      } finally {
        loading.value = false
      }
    }

    const resetEmailSettings = () => {
      emailSettings.value = null
    }

    return {
      // 状态
      emailSettings,
      smsSettings,
      storageSettings,
      loading,
      // 计算属性
      isEmailConfigured,
      isAnySettingLoading,
      // 方法
      fetchEmailSettings,
      updateEmailSettings,
      resetEmailSettings,
    }
  },
  {
    // 持久化配置
    persist: {
      key: 'settings-store',
      storage: localStorage,
      paths: ['emailSettings', 'smsSettings', 'storageSettings'],
    },
  },
)
```

### 7) 组件开发规范（Vben Admin 规范）

#### 7.1 组件命名
- 使用 PascalCase 命名
- 组件文件名与组件名保持一致
- 页面组件放在 `views/` 目录
- 公共组件放在 `components/` 目录
- 遵循 Vben 组件命名约定

#### 7.2 组件使用优先级（基于 Vben Admin 官方规范）

**组件选择原则：**
1. **Vben 封装组件**（最高优先级）：如 `VbenForm`、`VbenModal`、`VbenDrawer`、`VbenVxeTable` 等
2. **适配器组件**（中等优先级）：通过 `src/adapter/component` 和 `src/adapter/form` 适配的组件
3. **原生 UI 库组件**（最低优先级）：如 Element Plus 的 `el-card`、`el-button` 等

**官方指导原则：**
> "如果你觉得现有组件的封装不够理想，或者不完全符合你的需求，大可以直接使用原生组件，亦或亲手封装一个适合的组件。框架提供的组件并非束缚，使用与否，完全取决于你的需求与自由。" —— Vben Admin 官方文档

**具体使用指导：**
- **表单开发**：**必须优先使用** `useVbenForm` 和 `VbenForm`，提供完整的表单解决方案，支持动态表单、验证、联动等高级功能
- **模态框**：**必须优先使用** `useVbenModal` 和 `VbenModal`，支持拖拽、全屏、自动高度等功能，提供统一的交互体验
- **抽屉**：**必须优先使用** `useVbenDrawer` 和 `VbenDrawer`，提供更好的用户体验和统一的样式
- **表格**：优先使用 `VbenVxeTable`，基于 vxe-table 封装，结合 VbenForm 搜索；简单展示可使用 Element Plus 的 `ElTable`
- **基础组件**：可根据需求选择 Vben 组件或通过适配器使用 Element Plus 组件

**适配器配置要求：**
- Element Plus 组件适配：在 `src/adapter/component/index.ts` 中配置组件映射
- 表单适配：在 `src/adapter/form.ts` 中配置表单验证、国际化等
- 适配器处理：v-model 属性映射、国际化、主题适配、验证规则等
- 灵活使用：可根据具体需求选择 Vben 组件、适配器组件或原生组件

#### 7.3 组件结构模板（Vben 组件优先）
```vue
<template>
  <Page>
    <!-- 页面头部 -->
    <PageHeader :title="title" :description="description">
      <template #extra>
        <VbenButton @click="handleReset" :disabled="loading">
          重置
        </VbenButton>
      </template>
    </PageHeader>

    <!-- 主要内容卡片 -->
    <Card title="基本设置">
      <VbenForm
        ref="formRef"
        :schema="formSchema"
        @submit="handleSubmit"
      />
      
      <!-- 底部操作栏 -->
      <template #footer>
        <div class="flex justify-end gap-2">
          <VbenButton @click="handleCancel" :disabled="loading">
            取消
          </VbenButton>
          <VbenButton
            type="primary"
            @click="handleSave"
            :loading="loading"
          >
            保存
          </VbenButton>
        </div>
      </template>
    </Card>
  </Page>
</template>

<script setup lang="ts">
// 导入
import { ref, onMounted } from 'vue'
import { Page, PageHeader, Card, VbenButton } from '@vben/common-ui'
import { useVbenForm } from '#/adapter/form'
import type { VbenFormSchema } from '#/components/form'
import type { EmailSettingsVo } from '#/api/settings/email'
import { getEmailSettingsApi, updateEmailSettingsApi } from '#/api/settings/email'

// 接口定义
interface Props {
  title?: string
  description?: string
  disabled?: boolean
}

// Props
const props = withDefaults(defineProps<Props>(), {
  title: '邮件设置',
  description: '配置系统邮件发送相关参数',
  disabled: false
})

// Emits
const emit = defineEmits<{
  save: [settings: EmailSettingsVo]
  cancel: []
}>()

// 响应式数据
const loading = ref(false)
const formRef = ref()

// 表单配置
const formSchema: VbenFormSchema[] = [
  {
    fieldName: 'host',
    label: 'SMTP服务器',
    component: 'Input',
    rules: [{ required: true, message: '请输入SMTP服务器地址' }],
  },
  {
    fieldName: 'port',
    label: '端口',
    component: 'InputNumber',
    componentProps: {
      min: 1,
      max: 65535,
    },
    rules: [{ required: true, message: '请输入端口号' }],
  },
  {
    fieldName: 'username',
    label: '用户名',
    component: 'Input',
    rules: [{ required: true, message: '请输入用户名' }],
  },
  {
    fieldName: 'password',
    label: '密码',
    component: 'InputPassword',
    rules: [{ required: true, message: '请输入密码' }],
  },
]

// 生命周期
onMounted(async () => {
  await fetchSettings()
})

// 方法
const fetchSettings = async () => {
  loading.value = true
  try {
    const data = await getEmailSettingsApi()
    formRef.value?.setFieldsValue(data)
  } catch (error) {
    message.error('获取设置失败')
  } finally {
    loading.value = false
  }
}

const handleSubmit = async (values: EmailSettingsVo) => {
  loading.value = true
  try {
    await updateEmailSettingsApi(values)
    message.success('保存成功')
    emit('save', values)
  } catch (error) {
    message.error('保存失败')
  } finally {
    loading.value = false
  }
}

const handleSave = () => {
  formRef.value?.submit()
}

const handleCancel = () => {
  emit('cancel')
}

const handleReset = () => {
  formRef.value?.resetFields()
}
</script>

<style scoped>
/* 使用 Tailwind CSS 类名，避免自定义样式 */
</style>
```

#### 7.3 组件 Props 定义
```typescript
interface Props {
  title?: string
  loading?: boolean
  data?: Record<string, any>
}

const props = withDefaults(defineProps<Props>(), {
  title: '',
  loading: false,
  data: () => ({})
})
```

#### 7.4 组件事件定义
```typescript
interface Emits {
  save: [data: Record<string, any>]
  cancel: []
  change: [value: string]
}

const emit = defineEmits<Emits>()
```

### 8) 样式规范（Vben Admin 规范）

#### 8.1 样式系统
- 优先使用 Tailwind CSS 工具类
- 使用 CSS Variables 进行主题定制
- 避免编写自定义 CSS，除非必要
- 遵循 Vben 设计系统

#### 8.2 Tailwind CSS 使用
```vue
<template>
  <!-- 使用 Tailwind 工具类 -->
  <div class="flex items-center justify-between p-4 bg-white rounded-lg shadow-sm">
    <h2 class="text-lg font-semibold text-gray-900">
      邮件设置
    </h2>
    <Button class="ml-4" type="primary">
      保存
    </Button>
  </div>

  <!-- 响应式设计 -->
  <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
    <Card class="p-6">
      <!-- 卡片内容 -->
    </Card>
  </div>

  <!-- 状态样式 -->
  <Button 
    :class="[
      'px-4 py-2 rounded-md transition-colors',
      loading ? 'opacity-50 cursor-not-allowed' : 'hover:bg-blue-600'
    ]"
  >
    {{ loading ? '保存中...' : '保存' }}
  </Button>
</template>
```

#### 8.3 主题定制
```css
/* 在 tailwind.config.js 中定义主题 */
module.exports = {
  theme: {
    extend: {
      colors: {
        primary: {
          50: '#eff6ff',
          500: '#3b82f6',
          600: '#2563eb',
          700: '#1d4ed8',
        },
        gray: {
          50: '#f9fafb',
          100: '#f3f4f6',
          900: '#111827',
        },
      },
      spacing: {
        '18': '4.5rem',
        '88': '22rem',
      },
    },
  },
}
```

#### 8.4 自定义样式（仅在必要时使用）
```vue
<style scoped>
/* 仅在 Tailwind 无法满足需求时使用 */
.custom-scrollbar::-webkit-scrollbar {
  width: 6px;
}

.custom-scrollbar::-webkit-scrollbar-thumb {
  background-color: theme('colors.gray.300');
  border-radius: 3px;
}

/* 使用 CSS Variables 保持主题一致性 */
.custom-component {
  background-color: var(--vben-color-bg-container);
  border: 1px solid var(--vben-color-border);
}
</style>
```

### 9) 国际化规范（Vben Admin 规范）

#### 9.1 语言文件组织
```
src/locales/
├── langs/
│   ├── zh-CN/
│   │   ├── common.json
│   │   ├── settings.json
│   │   ├── validation.json
│   │   └── index.ts
│   ├── en-US/
│   │   ├── common.json
│   │   ├── settings.json
│   │   ├── validation.json
│   │   └── index.ts
│   └── index.ts
├── helper.ts
└── index.ts
```

#### 9.2 语言文件示例
```json
// src/locales/langs/zh-CN/settings.json
{
  "title": "系统设置",
  "email": {
    "title": "邮件设置",
    "description": "配置系统邮件发送相关参数",
    "form": {
      "host": "SMTP服务器",
      "port": "端口",
      "username": "用户名",
      "password": "密码",
      "encryption": "加密方式",
      "fromName": "发件人名称",
      "fromEmail": "发件人邮箱"
    },
    "placeholder": {
      "host": "请输入SMTP服务器地址",
      "port": "请输入端口号",
      "username": "请输入用户名",
      "password": "请输入密码"
    },
    "validation": {
      "hostRequired": "请输入SMTP服务器地址",
      "portRequired": "请输入端口号",
      "usernameRequired": "请输入用户名",
      "passwordRequired": "请输入密码"
    }
  },
  "sms": {
    "title": "短信设置",
    "description": "配置短信发送服务商参数",
    "form": {
      "provider": "服务商",
      "accessKey": "Access Key",
      "secretKey": "Secret Key",
      "signName": "签名"
    }
  },
  "storage": {
    "title": "存储设置",
    "description": "配置文件存储相关参数",
    "form": {
      "driver": "存储驱动",
      "bucket": "存储桶",
      "region": "地域",
      "endpoint": "访问域名"
    }
  }
}
```

#### 9.3 在组件中使用
```vue
<template>
  <Page :title="$t('settings.email.title')">
    <template #description>
      <span>{{ $t('settings.email.description') }}</span>
    </template>

    <Card :title="$t('settings.email.title')">
      <VbenForm
        ref="formRef"
        :schema="formSchema"
        @submit="handleSubmit"
      />
    </Card>
  </Page>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import { useI18n } from '#/hooks/useI18n'
import type { VbenFormSchema } from '#/components/form'

const { t } = useI18n()

// 表单配置使用国际化
const formSchema = computed<VbenFormSchema[]>(() => [
  {
    fieldName: 'host',
    label: t('settings.email.form.host'),
    component: 'Input',
    componentProps: {
      placeholder: t('settings.email.placeholder.host'),
    },
    rules: [
      { 
        required: true, 
        message: t('settings.email.validation.hostRequired') 
      },
    ],
  },
  {
    fieldName: 'port',
    label: t('settings.email.form.port'),
    component: 'InputNumber',
    componentProps: {
      placeholder: t('settings.email.placeholder.port'),
      min: 1,
      max: 65535,
    },
    rules: [
      { 
        required: true, 
        message: t('settings.email.validation.portRequired') 
      },
    ],
  },
])

// 在方法中使用
const handleSubmit = async (values: any) => {
  try {
    // 处理提交逻辑
    message.success(t('common.saveSuccess'))
  } catch (error) {
    message.error(t('common.saveFailed'))
  }
}
</script>
```

#### 9.4 国际化配置
```typescript
// src/locales/index.ts
import { createI18n } from 'vue-i18n'
import { getLocale, setLocale } from './helper'

// 导入语言包
import zhCN from './langs/zh-CN'
import enUS from './langs/en-US'

const messages = {
  'zh-CN': zhCN,
  'en-US': enUS,
}

export const i18n = createI18n({
  legacy: false,
  locale: getLocale(),
  fallbackLocale: 'zh-CN',
  messages,
  globalInjection: true,
})

export { setLocale, getLocale }
```

### 10) 错误处理规范（Vben Admin 规范）

#### 10.1 API 错误处理
```typescript
// src/api/request.ts
import { requestClient } from '#/api/request'
import { useAuthStore } from '#/stores/auth'
import { message } from '#/components'
import { $t } from '#/locales'

// 请求拦截器
requestClient.interceptors.request.use(
  (config) => {
    const authStore = useAuthStore()
    const token = authStore.accessToken
    
    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }
    
    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)

// 响应拦截器
requestClient.interceptors.response.use(
  (response) => {
    const { code, data, message: msg } = response.data
    
    // 根据业务状态码处理
    if (code === 200 || code === 0) {
      return data
    } else {
      const errorMessage = msg || $t('common.requestFailed')
      message.error(errorMessage)
      return Promise.reject(new Error(errorMessage))
    }
  },
  (error) => {
    const { response } = error
    
    if (response) {
      const { status, data } = response
      
      switch (status) {
        case 401:
          const authStore = useAuthStore()
          authStore.logout()
          message.error($t('common.tokenExpired'))
          break
        case 403:
          message.error($t('common.noPermission'))
          break
        case 404:
          message.error($t('common.notFound'))
          break
        case 500:
          message.error($t('common.serverError'))
          break
        default:
          message.error(data?.message || $t('common.requestFailed'))
      }
    } else {
      // 网络错误
      message.error($t('common.networkError'))
    }
    
    return Promise.reject(error)
  }
)
```

#### 10.2 组件错误处理
```vue
<script setup lang="ts">
import { ref } from 'vue'
import { message } from '#/components'
import { useI18n } from '#/hooks/useI18n'
import { getEmailSettingsApi, updateEmailSettingsApi } from '#/api/settings/email'
import type { EmailSettingsVo } from '#/api/settings/email'

const { t } = useI18n()
const loading = ref(false)
const emailSettings = ref<EmailSettingsVo | null>(null)

// 获取设置
const fetchEmailSettings = async () => {
  loading.value = true
  try {
    const data = await getEmailSettingsApi()
    emailSettings.value = data
  } catch (error) {
    console.error('Failed to fetch email settings:', error)
    // 错误信息已在拦截器中处理，这里只需记录日志
  } finally {
    loading.value = false
  }
}

// 更新设置
const updateEmailSettings = async (values: EmailSettingsVo) => {
  loading.value = true
  try {
    await updateEmailSettingsApi(values)
    emailSettings.value = values
    message.success(t('common.saveSuccess'))
  } catch (error) {
    console.error('Failed to update email settings:', error)
    // 具体错误处理
    if (error instanceof Error) {
      message.error(error.message)
    } else {
      message.error(t('common.saveFailed'))
    }
  } finally {
    loading.value = false
  }
}

// 表单提交错误处理
const handleSubmit = async (values: EmailSettingsVo) => {
  try {
    await updateEmailSettings(values)
  } catch (error) {
    // 错误已在 updateEmailSettings 中处理
    // 可以在这里添加额外的错误处理逻辑
  }
}
</script>
```

#### 10.3 全局错误处理
```typescript
// src/main.ts
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

// 全局错误处理
app.config.errorHandler = (error, instance, info) => {
  console.error('Global error:', error)
  console.error('Component instance:', instance)
  console.error('Error info:', info)
  
  // 发送错误到监控服务
  // reportError(error, { instance, info })
}

// 未捕获的 Promise 错误
window.addEventListener('unhandledrejection', (event) => {
  console.error('Unhandled promise rejection:', event.reason)
  // reportError(event.reason)
})

app.mount('#app')
```

### 11) 性能优化规范（Vben Admin 规范）

#### 11.1 组件懒加载
```typescript
// 路由懒加载
const routes: RouteRecordRaw[] = [
  {
    path: '/settings',
    name: 'Settings',
    component: () => import('#/views/settings/index.vue'),
    meta: {
      title: '系统设置',
    },
  },
]

// 组件懒加载
import { defineAsyncComponent } from 'vue'

const AsyncHeavyComponent = defineAsyncComponent({
  loader: () => import('./HeavyComponent.vue'),
  loadingComponent: () => import('#/components/Loading.vue'),
  errorComponent: () => import('#/components/Error.vue'),
  delay: 200,
  timeout: 3000,
})
```

#### 11.2 虚拟滚动
```vue
<template>
  <VbenVirtualList
    :data="largeDataList"
    :height="400"
    :item-height="50"
    :buffer="5"
  >
    <template #default="{ item, index }">
      <div class="flex items-center p-4 border-b">
        <span class="text-sm text-gray-600 mr-2">{{ index + 1 }}</span>
        <span class="font-medium">{{ item.name }}</span>
      </div>
    </template>
  </VbenVirtualList>
</template>

<script setup lang="ts">
import { VbenVirtualList } from '#/components'

interface ListItem {
  id: string
  name: string
}

const largeDataList = ref<ListItem[]>([])

// 生成大量数据
const generateLargeData = () => {
  const data: ListItem[] = []
  for (let i = 0; i < 10000; i++) {
    data.push({
      id: `item-${i}`,
      name: `Item ${i}`,
    })
  }
  return data
}

onMounted(() => {
  largeDataList.value = generateLargeData()
})
</script>
```

#### 11.3 图片优化
```vue
<template>
  <!-- 图片懒加载 -->
  <VbenImage
    :src="imageUrl"
    :alt="imageAlt"
    :lazy="true"
    :preview="true"
    class="w-full h-48 object-cover rounded-lg"
    loading="lazy"
  />

  <!-- 响应式图片 -->
  <picture>
    <source
      media="(min-width: 768px)"
      :srcset="largeImageUrl"
    >
    <source
      media="(min-width: 480px)"
      :srcset="mediumImageUrl"
    >
    <img
      :src="smallImageUrl"
      :alt="imageAlt"
      class="w-full h-auto"
      loading="lazy"
    >
  </picture>
</template>

<script setup lang="ts">
import { VbenImage } from '#/components'

interface Props {
  imageUrl: string
  imageAlt: string
  largeImageUrl?: string
  mediumImageUrl?: string
  smallImageUrl?: string
}

const props = defineProps<Props>()
</script>
```

#### 11.4 状态管理优化
```typescript
// 使用 computed 缓存计算结果
import { computed, ref } from 'vue'

const expensiveData = ref([])

// 缓存计算结果
const processedData = computed(() => {
  return expensiveData.value
    .filter(item => item.active)
    .map(item => ({
      ...item,
      displayName: `${item.firstName} ${item.lastName}`,
    }))
    .sort((a, b) => a.displayName.localeCompare(b.displayName))
})

// 使用 shallowRef 优化大对象
import { shallowRef, triggerRef } from 'vue'

const largeObject = shallowRef({
  // 大量数据
})

// 更新时手动触发响应
const updateLargeObject = (newData: any) => {
  largeObject.value = { ...largeObject.value, ...newData }
  triggerRef(largeObject)
}
```

#### 11.5 网络请求优化
```typescript
// 请求去重
import { ref } from 'vue'

const requestCache = new Map<string, Promise<any>>()

const cachedRequest = async (url: string, options?: any) => {
  const cacheKey = `${url}-${JSON.stringify(options)}`
  
  if (requestCache.has(cacheKey)) {
    return requestCache.get(cacheKey)
  }
  
  const promise = fetch(url, options).then(res => res.json())
  requestCache.set(cacheKey, promise)
  
  // 请求完成后清除缓存
  promise.finally(() => {
    requestCache.delete(cacheKey)
  })
  
  return promise
}

// 请求防抖
import { debounce } from 'lodash-es'

const searchKeyword = ref('')
const searchResults = ref([])

const debouncedSearch = debounce(async (keyword: string) => {
  if (!keyword.trim()) {
    searchResults.value = []
    return
  }
  
  try {
    const results = await searchApi(keyword)
    searchResults.value = results
  } catch (error) {
    console.error('Search failed:', error)
  }
}, 300)

watch(searchKeyword, (newKeyword) => {
  debouncedSearch(newKeyword)
})
```

### 12) 测试规范（Vben Admin 规范）

#### 12.1 单元测试
```typescript
// tests/unit/components/EmailSettings.spec.ts
import { mount } from '@vue/test-utils'
import { describe, it, expect, beforeEach, vi } from 'vitest'
import { createTestingPinia } from '@pinia/testing'
import EmailSettings from '#/views/settings/email/index.vue'
import { VbenForm } from '#/components/form'

// Mock API
vi.mock('#/api/settings/email', () => ({
  getEmailSettingsApi: vi.fn(),
  updateEmailSettingsApi: vi.fn(),
}))

describe('EmailSettings', () => {
  let wrapper: any
  
  beforeEach(() => {
    wrapper = mount(EmailSettings, {
      global: {
        plugins: [
          createTestingPinia({
            createSpy: vi.fn,
          }),
        ],
        components: {
          VbenForm,
        },
      },
    })
  })
  
  it('renders correctly', () => {
    expect(wrapper.find('[data-testid="email-settings-title"]').text())
      .toBe('邮件设置')
  })
  
  it('displays form fields correctly', () => {
    const formFields = wrapper.findAll('.vben-form-item')
    expect(formFields.length).toBeGreaterThan(0)
  })
  
  it('handles form submission', async () => {
    const mockUpdateApi = vi.mocked(updateEmailSettingsApi)
    mockUpdateApi.mockResolvedValue({})
    
    const formData = {
      host: 'smtp.test.com',
      port: 587,
      username: 'test@test.com',
      password: 'password123',
    }
    
    await wrapper.vm.handleSubmit(formData)
    
    expect(mockUpdateApi).toHaveBeenCalledWith(formData)
    // 验证 Element Plus 消息提示
    expect(ElMessage.success).toHaveBeenCalledWith('保存成功')
  })
})
```

#### 12.2 API 测试
```typescript
// tests/api/settings.spec.ts
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { getEmailSettingsApi, updateEmailSettingsApi } from '#/api/settings/email'
import { requestClient } from '#/api/request'
import type { EmailSettingsVo } from '#/api/settings/email'

// Mock request client
vi.mock('#/api/request', () => ({
  requestClient: {
    get: vi.fn(),
    put: vi.fn(),
  },
}))

describe('Settings API', () => {
  beforeEach(() => {
    vi.clearAllMocks()
  })
  
  describe('getEmailSettingsApi', () => {
    it('should fetch email settings successfully', async () => {
      const mockData: EmailSettingsVo = {
        host: 'smtp.example.com',
        port: 587,
        username: 'test@example.com',
        password: 'password123',
        encryption: 'tls',
        fromName: 'System',
        fromEmail: 'noreply@example.com',
      }
      
      vi.mocked(requestClient.get).mockResolvedValue(mockData)
      
      const result = await getEmailSettingsApi()
      
      expect(requestClient.get).toHaveBeenCalledWith('/settings/email')
      expect(result).toEqual(mockData)
    })
  })
})
```

#### 12.3 E2E 测试
```typescript
// tests/e2e/settings.spec.ts
import { test, expect } from '@playwright/test'

test.describe('Settings Page', () => {
  test.beforeEach(async ({ page }) => {
    // 登录
    await page.goto('/login')
    await page.fill('[data-testid="username-input"]', 'admin')
    await page.fill('[data-testid="password-input"]', 'password')
    await page.click('[data-testid="login-button"]')
    
    // 等待登录完成
    await page.waitForURL('/dashboard')
  })
  
  test('should navigate to email settings', async ({ page }) => {
    await page.goto('/settings/email')
    
    await expect(page.locator('[data-testid="email-settings-title"]'))
      .toHaveText('邮件设置')
  })
  
  test('should update email settings', async ({ page }) => {
    await page.goto('/settings/email')
    
    // 填写表单（Element Plus 输入框）
    await page.fill('[data-testid="host-input"]', 'smtp.test.com')
    await page.fill('[data-testid="port-input"]', '587')
    
    // 提交表单（Element Plus 按钮）
    await page.click('[data-testid="save-button"]')
    
    // 验证 Element Plus 成功消息
    await expect(page.locator('.el-message--success'))
      .toHaveText('保存成功')
  })
})
```

#### 12.4 测试配置
```typescript
// vitest.config.ts
import { defineConfig } from 'vitest/config'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'

export default defineConfig({
  plugins: [vue()],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: ['./tests/setup.ts'],
  },
  resolve: {
    alias: {
      '#': resolve(__dirname, './src'),
    },
  },
})
```

### 13) 开发工具配置

#### 13.1 必要的 VSCode 插件
- Vue Language Features (Volar)
- TypeScript Vue Plugin (Volar)
- Tailwind CSS IntelliSense
- ESLint
- Prettier

#### 13.2 代码质量检查
```bash
# 代码格式化
pnpm format

# 代码检查
pnpm lint

# 类型检查
pnpm type-check

# 构建检查
pnpm build
```

### 14) 与后端协作规范

#### 14.1 接口约定
- 前端接口路径与后端保持一致
- 使用 TypeScript 类型定义确保类型安全
- 统一错误码和响应格式

#### 14.2 数据流约定
```typescript
// 后端响应格式
interface ApiResponse<T> {
  code: number
  data: T
  message: string
}

// 前端自动解包 data 字段
const data = await getEmailSettingsApi() // 直接返回 EmailSettingsVo
```

---

## 📖 重要开发说明

### Vben Admin 官方文档参考

本项目基于 **Vben Admin** 框架开发，所有前端开发规范均应严格遵循 Vben Admin 官方文档：

- **官方文档地址**: https://doc.vben.pro/
- **当前使用版本**: Element Plus 适配版本
- **表单组件**: 使用 Vben Form，支持多种 UI 库适配
- **组件库**: Element Plus（项目已配置）

### 开发约束

1. **禁止自创规范**: 所有前端开发必须参考 Vben Admin 官方文档，禁止自创或假设性开发
2. **参考项目文档**: 可参考项目 `docs/` 目录下的代码规范和示例

#### 组件使用优先级（基于项目实际代码示例）

**组件选择原则：**
1. **Element Plus 原生组件**（最高优先级）：如 `ElCard`、`ElButton`、`ElTable`、`ElMessage` 等
2. **Vben 封装组件**（中等优先级）：如 `WorkbenchHeader`、`WorkbenchProject`、`AnalysisChartCard`、`Page` 等业务组件
3. **适配器组件**（最低优先级）：自定义适配器组件，仅在特殊需求时使用

**实际使用示例：**

**基础 UI 组件**：直接使用 Element Plus
```vue
<template>
  <!-- 卡片容器 -->
  <ElCard class="mb-5 w-auto">
    <template #header>按钮</template>
    <!-- 按钮组 -->
    <ElSpace>
      <ElButton type="primary">Primary</ElButton>
      <ElButton type="success">Success</ElButton>
    </ElSpace>
  </ElCard>
  
  <!-- 表格 -->
  <ElTable :data="tableData" stripe>
    <ElTable.TableColumn label="测试列1" prop="prop1" />
    <ElTable.TableColumn label="测试列2" prop="prop2" />
  </ElTable>
</template>

<script setup>
import { ElCard, ElButton, ElSpace, ElTable } from 'element-plus';
</script>
```

**业务组件**：使用 Vben 封装组件
```vue
<template>
  <!-- 页面容器 -->
  <Page title="页面标题" description="页面描述">
    <!-- 工作台头部 -->
    <WorkbenchHeader :avatar="userInfo.avatar">
      <template #title>欢迎回来</template>
    </WorkbenchHeader>
    
    <!-- 业务组件 -->
    <WorkbenchProject :items="projectItems" @click="navTo" />
    <AnalysisChartCard title="图表标题">
      <CustomChart />
    </AnalysisChartCard>
  </Page>
</template>

<script setup>
import {
  Page,
  WorkbenchHeader,
  WorkbenchProject,
  AnalysisChartCard
} from '@vben/common-ui';
</script>
```

**官方指导原则：**
> "如果你觉得现有组件的封装不够理想，或者不完全符合你的需求，大可以直接使用原生组件，亦或亲手封装一个适合的组件。框架提供的组件并非束缚，使用与否，完全取决于你的需求与自由。" —— Vben Admin 官方文档

**具体使用指导：**
- **基础 UI**：优先使用 Element Plus 原生组件（`ElCard`、`ElButton`、`ElTable`、`ElForm` 等）
- **页面布局**：使用 Vben 的 `Page` 组件作为页面容器
- **业务组件**：使用 Vben 封装的业务组件（`WorkbenchHeader`、`WorkbenchProject` 等）
- **表单开发**：可选择 Element Plus 的 `ElForm` 或 Vben 的表单组件，根据复杂度决定
- **消息提示**：直接使用 Element Plus 的 `ElMessage`、`ElNotification`
- **数据展示**：直接使用 Element Plus 的 `ElTable`、图表组件等

### 协同开发要求

开发步骤，要前后端一起协同开发，项目的数据库账号、密码、库表均为wwjcloud。前端和后端项目均有规范工具，开发前一定要检查工具是否配置正确，是否有必要的插件，是否正常运行状态。前端开发进行修改框架核心内容，可以参考前端docs目录参考代码规范禁止自创和假设造成，没有规范的去写。

### 技术栈确认

- **前端框架**: Vue 3 + TypeScript + Vite
- **UI 组件库**: Element Plus
- **表单解决方案**: Vben Form（支持 Element Plus 适配）
- **状态管理**: Pinia
- **路由**: Vue Router
- **构建工具**: Vite
- **包管理器**: pnpm