# 前端技术设计规范
## 目录
1. [项目概述](#项目概述)
2. [技术栈](#技术栈)
3. [项目架构](#项目架构)
4. [页面结构规范](#页面结构规范)
5. [组件使用规范](#组件使用规范)
6. [业务组件规范](#业务组件规范)
7. [图标使用规范](#图标使用规范)
8. [样式规范](#样式规范)
9. [文件预览规范](#文件预览规范)
10. [路由规范](#路由规范)
11. [状态管理规范](#状态管理规范)
12. [接口处理规范](#接口处理规范)
13. [最佳实践](#最佳实践)
## 项目概述
本项目是一个企业智能运营管理系统(Smart Ops Front),采用 Vue 3 + Vite + Element Plus 技术栈构建,提供完整的权限管理、知识库管理、CRM管理、OA审批等功能模块。
### 设计原则
- **统一性**:所有页面采用相同的布局结构和交互模式
- **简洁性**:基于Element Plus组件库,避免重度定制样式
- **可维护性**:使用composable模式和组件分离提高代码质量
- **可扩展性**:模块化设计,支持功能快速迭代
## 技术栈
### 核心框架
- **Vue 3.3.4** - 渐进式JavaScript框架
- **Vite 4.4.9** - 下一代前端构建工具
- **Vue Router 4.2.4** - 官方路由管理器
- **Pinia 2.1.6** - Vue状态管理库
### UI组件库
- **Element Plus 2.10.4** - 基于Vue 3的组件库
- **@element-plus/icons-vue 2.1.0** - Element Plus图标库
### 表格组件
- **vxe-table 4.14.1** - 高性能表格组件
- **xe-utils 3.7.6** - 表格工具库
### 编辑器组件
- **@umoteam/editor 7.0.1** - 富文本编辑器
- **@vueup/vue-quill 1.2.0** - Quill编辑器Vue组件
- **@vue-office/** - Office文档预览组件
### 工具库
- **@vueuse/core 13.1.0** - Vue组合式API工具集
- **axios 1.5.0** - HTTP客户端
- **crypto-js 4.2.0** - 加密库
- **echarts 5.6.0** - 数据可视化图表库
## 项目架构
### 目录结构
```
src/
├── api/ # API接口层
├── assets/ # 静态资源
│ ├── images/ # 图片资源
│ └── styles/ # 样式文件
│ ├── index.scss # 主样式文件(设计令牌)
│ └── common.scss # 公共页面样式
├── components/ # 公共组件
├── composables/ # 组合式函数
├── layout/ # 布局组件
├── router/ # 路由配置
├── stores/ # 状态管理
├── utils/ # 工具函数
└── views/ # 页面组件
├── account/ # 账户管理
├── crm/ # CRM管理
├── knowledge/ # 知识库管理
├── oa-approval/ # OA审批
├── org/ # 组织管理
└── system/ # 系统管理
```
### 架构特点
- **分层架构**: API层、组件层、页面层清晰分离
- **模块化设计**: 按业务功能模块组织代码
- **组件化开发**: 可复用的公共组件和业务组件
- **状态管理**: 使用Pinia进行全局状态管理
- **Composable模式**: 使用composable函数实现逻辑复用
- **动态组件**: 支持按需加载和动态组件管理
## 页面结构规范
### 1. 页面容器规范
#### 必须使用 PageContainer 包裹
所有页面必须使用 `PageContainer` 组件作为根容器:
```vue
```
### 2. 标准页面结构
#### 普通列表页面结构
```vue
```
#### 一级菜单首页结构(模块Dashboard)
**重要说明**:一级菜单的首页(如 `/email`、`/crm`、`/knowledge` 等路由的根页面)必须采用特殊的模块首页布局,不能使用普通列表页面结构:
**标准首页结构(带动画效果)** - **推荐使用**:
```vue
```
**简化首页结构(无动画效果)**:
```vue
```
**关键区别**:
- **模块首页**:使用 `
` 直接包裹内容区域
- **普通列表页**:使用 `
` 包裹内容区域
**样式选择**:
- **`module-home-header`**:华丽的动画效果,适合重要的模块首页(推荐)
- **`page-header`**:简洁的渐变样式,适合功能型页面或简化的首页
**类名对照表**:
| 用途 | 类名 | 说明 |
|------|------|------|
| 模块首页容器 | `module-dashboard-container` | 统一的模块首页容器 |
| 动画头部 | `module-home-header` | 带背景动画的头部样式 |
| 简化头部 | `page-header` | 简洁的渐变头部样式 |
| 模块图片 | `module-image` | 模块banner图片容器 |
| 文字内容 | `header-text` | 头部文字内容区域 |
| 状态指示器 | `status-indicator` | 系统状态显示 |
**应用场景**:
- **模块首页**:如 `/email`、`/crm`、`/knowledge` 等一级菜单的入口页面
- **普通列表页**:如 `/email/management`、`/crm/customer`、`/knowledge/repository` 等功能页面
**识别规则**:
1. **路由层级**:一级菜单的根路由页面(如 `/email/index/Dashboard.vue`)
2. **页面性质**:展示模块概览、统计数据、功能入口的首页
3. **文件位置**:通常位于 `views/模块名/index/Dashboard.vue` 或 `views/模块名/Dashboard.vue`
4. **菜单结构**:在左侧菜单中作为一级菜单的主页面
**样式文件优化**:
- ✅ **统一封装**:所有首页样式都在 `src/assets/styles/common.scss` 中定义
- ✅ **完整动画**:包含流星漂移、浮动形状、呼吸状态指示器等动画效果
- ✅ **响应式设计**:自动适配移动端和桌面端
- ✅ **模块特定样式**:各模块只需要在自己的文件中添加特定样式
- ✅ **性能优化**:避免重复代码,减少CSS体积
**使用指南**:
1. **导入样式**:在Vue文件中使用 `@import '@/assets/styles/common.scss'`
2. **统一结构**:使用标准的模板结构和类名
3. **内容区域**:使用 `.module-content` 包裹所有模块内容
4. **首页布局**:在 `.module-content` 内使用 `.dashboard-layout` 进行布局
5. **模块特定样式**:在模块的style中添加特定的内容样式
6. **图片资源**:将模块banner图片放在 `src/assets/images/模块名/banner.png`
**正确的首页布局结构**:
```vue
```
**层级说明**:
- `module-dashboard-container`:模块首页的根容器
- `module-home-header`:带动画效果的模块头部
- `module-content`:模块内容区域(所有模块页面的标准容器)
- `dashboard-layout`:首页专用的布局容器(只在Dashboard页面使用)
- `dashboard-row-1/2`:首页布局的行容器
**动画效果**:
- `meteor-drift`:流星漂移动画,3个不同延迟的流星在XY平面内移动
- `float`:装饰形状的旋转和缩放动画(**已优化:移除上下浮动**)
- `pulse`:状态指示器的呼吸灯效果
- **交互动画**:使用阴影、亮度、边框等效果替代Y轴位移
- 所有动画都经过性能优化,使用硬件加速
**设计原则**:
- ❌ **禁止使用** `translateY` 进行上下浮动动画
- ✅ **推荐使用** 阴影变化、颜色过渡、缩放、旋转等效果
- ✅ **保持稳定** 所有元素位置固定,避免页面跳动
- ✅ **流畅体验** 使用平滑的视觉反馈替代位移动画
### 动画设计规范
**推荐的悬停效果**:
```scss
// ✅ 推荐:使用阴影和亮度变化
&:hover {
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
filter: brightness(1.05);
border-color: #primary-color;
}
// ✅ 推荐:使用缩放和旋转
&:hover {
transform: scale(1.05) rotate(2deg);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
}
// ❌ 禁止:使用Y轴位移
&:hover {
transform: translateY(-5px); // 不要使用这种效果
}
```
**装饰性动画原则**:
- 旋转动画:`transform: rotate(0deg to 360deg)`
- 缩放动画:`transform: scale(0.9 to 1.1)`
- 透明度变化:`opacity: 0.3 to 0.8`
- 颜色渐变:`background`, `border-color`, `color` 过渡
- 禁止位移:避免 `translateX`, `translateY` 造成的位置跳动
### 快捷操作组件封装
**快捷操作区域**已在 `common.scss` 中统一封装,支持自适应布局和多种样式:
```vue
```
**自适应特性**:
- **最小宽度控制**:每个操作项最小宽度 `120px`
- **自动换行**:使用 `grid-template-columns: repeat(auto-fit, minmax(120px, 1fr))`
- **响应式布局**:
- 桌面端:最多8列
- 平板端:自动适应
- 手机端:最少2列,最小宽度100px
**预设颜色系统**:
| 类名 | 颜色 | 图标渐变 | 悬停背景 |
|------|------|----------|----------|
| `color-0` | 蓝色 | `#6366f1 → #4f46e5` | 紫蓝色浅色 |
| `color-1` | 绿色 | `#10b981 → #059669` | 绿色浅色 |
| `color-2` | 橙色 | `#f59e0b → #d97706` | 橙色浅色 |
| `color-3` | 红色 | `#ef4444 → #dc2626` | 红色浅色 |
| `color-4` | 紫色 | `#8b5cf6 → #7c3aed` | 紫色浅色 |
| `color-5` | 青色 | `#06b6d4 → #0891b2` | 青色浅色 |
| `color-6` | 粉色 | `#ec4899 → #db2777` | 粉色浅色 |
| `color-7` | 草绿色 | `#84cc16 → #65a30d` | 草绿色浅色 |
| `color-8` | 灰色 | `#6b7280 → #4b5563` | 灰色浅色 |
| `color-9` | 深橙色 | `#f97316 → #ea580c` | 深橙色浅色 |
**使用规则**:
- **顺序分配**:按照操作项的顺序依次使用 `color-0` 到 `color-9`
- **循环使用**:超过10个操作时,重新从 `color-0` 开始循环
- **主要操作**:仍可使用 `primary-action` 类来突出显示最重要的操作
- **视觉一致**:所有颜色都经过精心调配,确保视觉和谐
**布局规则**:
1. **网格优先**:优先显示更多列,到达最小宽度后自动换行
2. **均匀分布**:使用 `1fr` 确保每项宽度相等
3. **最小保证**:极小屏幕下确保至少显示2列
4. **最大限制**:大屏幕下限制最大8列,避免过度拉伸
## 组件使用规范
### 1. 表格组件使用规范
#### 使用场景
- **数据列表展示**: 用户列表、文件列表、订单列表等
- **数据筛选排序**: 需要分页、搜索、排序的数据表格
- **复杂数据操作**: 批量操作、行内编辑、树形数据等
#### 技术选型
**必须使用 vxe-table 作为表格组件**
```vue
编辑
```
#### 表格配置规范
```javascript
// 标准分页配置
const pagerConfig = {
currentPage: 1,
pageSize: 20,
total: 0,
layouts: ['PrevPage', 'JumpNumber', 'NextPage', 'FullJump', 'Sizes', 'Total']
}
```
### 2. 按钮组件使用规范
#### 按钮类型和使用场景
```vue
确认
取消
删除
新增
```
### 3. 表单组件使用规范
```vue
```
### 4. 卡片组件使用规范
```vue
```
### 5. 统计卡片组件规范
#### 统计卡片标准结构
项目已在 `src/assets/styles/common.scss` 中封装了统一的统计卡片样式,支持多种布局和主题:
```vue
```
#### 布局类型
| 类名 | 布局 | 响应式断点 | 使用场景 |
|------|------|------------|----------|
| `grid-4` | 4列布局 | 1200px→2列, 768px→1列 | 完整的统计面板 |
| `grid-3` | 3列布局 | 900px→2列, 768px→1列 | 知识库风格布局 |
| `grid-2` | 2列布局 | 768px→1列 | 简化的统计展示 |
#### 主题颜色
| 主题类名 | 颜色系 | 渐变色 | 适用场景 |
|----------|--------|--------|----------|
| `theme-blue` | 蓝色 | `#3b82f6 → #1d4ed8` | 主要数据、消息类 |
| `theme-red` | 红色 | `#ef4444 → #dc2626` | 紧急、警告类 |
| `theme-orange` | 橙色 | `#f59e0b → #d97706` | 待处理、提醒类 |
| `theme-green` | 绿色 | `#10b981 → #059669` | 完成、成功类 |
| `theme-purple` | 紫色 | `#a855f7 → #7c3aed` | 特殊、高级功能 |
| `theme-cyan` | 青色 | `#06b6d4 → #0891b2` | 活动、记录类 |
| `theme-pink` | 粉色 | `#ec4899 → #db2777` | 收藏、喜欢类 |
| `theme-lime` | 草绿 | `#84cc16 → #65a30d` | 新增、增长类 |
#### CountUp数字动画组件
统计卡片配合使用CountUp组件实现数字滚动动画效果:
```vue
GB
```
#### 完整示例
```vue
```
#### 设计原则
1. **视觉一致性**:所有统计卡片使用相同的尺寸和样式
2. **颜色语义化**:根据数据类型选择合适的主题颜色
3. **纯展示功能**:统计卡片仅用于数据展示,不支持点击交互
4. **动画增强**:使用CountUp组件提升用户体验
5. **响应式设计**:自动适配不同屏幕尺寸
6. **悬浮反馈**:支持轻微的阴影变化,但不包含Y轴移动效果
## 业务组件规范
### 1. 组件文件组织结构
#### 业务模块组件结构
```
views/
├── module-name/ # 业务模块
│ ├── stores/ # 模块状态管理
│ │ └── useModuleStore.js
│ ├── components/ # 模块内组件
│ │ ├── ComponentA.vue
│ │ └── ComponentB.vue
│ ├── composables/ # 业务逻辑函数
│ │ ├── useModuleData.js
│ │ └── useModuleOperations.js
│ ├── utils/ # 模块工具函数
│ │ └── moduleUtils.js
│ ├── api/ # 模块API
│ │ └── moduleApi.js
│ ├── Dashboard.vue # 模块首页
│ └── index.vue # 模块入口
```
### 2. Composable 设计模式
#### 推荐使用 Composable 分离业务逻辑
```javascript
// composables/useTableOperations.js
export function useTableOperations() {
const loading = ref(false)
const tableData = ref([])
const loadData = async () => {
loading.value = true
try {
// 数据加载逻辑
} finally {
loading.value = false
}
}
return {
loading,
tableData,
loadData
}
}
```
## 图标使用规范
### 必须使用 Element Plus 图标库
**基础操作图标**
```javascript
import {
// 基础操作
Plus, // 新增
Edit, // 编辑
Delete, // 删除
Search, // 搜索
Refresh, // 刷新
View, // 查看
Setting, // 设置
// 文件操作
Download, // 下载
Upload, // 上传
Document, // 文档
Folder, // 文件夹
FolderOpened, // 打开的文件夹
// 导航和布局
Home, // 首页
ArrowLeft, // 左箭头
ArrowRight, // 右箭头
ArrowUp, // 上箭头
ArrowDown, // 下箭头
// 状态指示
Check, // 成功/确认
Close, // 关闭/失败
Warning, // 警告
Info, // 信息
Success, // 成功
Error, // 错误
// 用户和权限
User, // 用户
UserFilled, // 用户(填充)
Lock, // 锁定
Unlock, // 解锁
// 通信和分享
Message, // 消息
Phone, // 电话
Email, // 邮件
Share, // 分享
Link, // 链接
// 媒体类型
Picture, // 图片
Video, // 视频
Audio, // 音频
// 业务功能
Management, // 管理
DataBoard, // 数据看板
Grid, // 网格
List, // 列表
Calendar, // 日历
Clock, // 时钟
Location, // 位置
// 交互反馈
Star, // 星标
StarFilled, // 星标(填充)
Heart, // 喜欢
HeartFilled, // 喜欢(填充)
// 圆形图标变体
CircleCheck, // 圆形确认
CircleClose, // 圆形关闭
CirclePlus, // 圆形加号
// 更多操作
More, // 更多
MoreFilled, // 更多(填充)
// 展开收起
Expand, // 展开
Fold, // 收起
// 其他常用
Filter, // 筛选
Sort, // 排序
Export, // 导出
Import, // 导入
Copy, // 复制
Files, // 文件集合
Histogram, // 柱状图
PieChart, // 饼图
TrendCharts // 趋势图
} from '@element-plus/icons-vue'
```
### 图标使用原则
1. **统一性**:同一功能在不同页面必须使用相同图标
2. **语义性**:图标含义要与功能匹配
3. **一致性**:图标大小和颜色保持项目统一风格
### 常用图标映射
| 功能 | 图标 | 使用场景 |
|------|------|----------|
| 新增 | Plus | 新建数据、添加项目 |
| 编辑 | Edit | 修改数据、编辑内容 |
| 删除 | Delete | 删除数据、移除项目 |
| 搜索 | Search | 搜索框、查询功能 |
| 刷新 | Refresh | 重新加载数据 |
| 下载 | Download | 文件下载、数据导出 |
| 上传 | Upload | 文件上传、导入数据 |
| 查看 | View | 查看详情、预览 |
| 设置 | Setting | 配置、参数设置 |
| 首页 | Home | 返回首页、主页导航 |
## 样式规范
### 1. 样式架构
项目采用分层样式架构:
- `src/assets/styles/index.scss` - 设计令牌和全局变量
- `src/assets/styles/common.scss` - 公共页面样式
### 2. 间距规范
#### 统一Padding标准
为确保界面的一致性和视觉平衡,项目采用统一的padding规范:
**默认padding值:16px**
```scss
// 标准间距规范
.default-padding {
padding: 16px; // 默认内边距16px
}
// 卡片组件标准间距
.dashboard-card {
:deep(.el-card__body) {
padding: 16px !important; // 卡片内容区域16px
}
.card-header {
padding: 16px 16px 12px; // 卡片头部:水平16px,底部12px
}
}
// 统计卡片间距
.stat-card {
padding: 16px; // 统计卡片16px
}
```
#### 特殊情况说明
以下情况可根据设计需求调整:
| 场景 | Padding值 | 说明 |
|------|-----------|------|
| **密集信息展示** | `12px` | 需要显示更多内容时 |
| **强调内容区域** | `20px` | 需要突出显示的重要内容 |
| **移动端适配** | `12px` | 小屏幕下的紧凑布局 |
| **表单输入区域** | `16px` | 保持与默认值一致 |
| **列表项内容** | `12px - 16px` | 根据列表密度调整 |
#### 间距层级系统
```scss
// 间距变量定义
:root {
--padding-xs: 8px; // 极小间距
--padding-sm: 12px; // 小间距
--padding-md: 16px; // 默认间距(推荐)
--padding-lg: 20px; // 大间距
--padding-xl: 24px; // 超大间距
}
// 使用示例
.content-area {
padding: var(--padding-md); // 使用默认16px
}
.compact-list {
padding: var(--padding-sm); // 使用紧凑12px
}
```
### 3. 全局样式规范
#### 使用 common.scss 统一样式
项目已在 `src/assets/styles/common.scss` 中定义了页面头部样式,所有页面应使用统一的样式类:
- `.page-header` - 页面头部容器
- `.header-content` - 头部内容区域
- `.header-left` - 头部左侧区域
- `.page-title` - 页面标题
- `.page-description` - 页面描述
- `.header-actions` - 头部操作区域
- `.add-btn` - 特殊的新增按钮样式
#### CSS 变量和设计令牌
项目已在 `src/assets/styles/index.scss` 中定义了完整的设计令牌系统:
- **颜色系统**: `--primary-color`, `--success-color` 等
- **间距系统**: `--spacing-small`, `--spacing-medium` 等
- **高度系统**: `--full-content-height`, `--card-content-height` 等
- **阴影系统**: `--shadow-light`, `--shadow-medium` 等
- **Z-Index层级**: `--z-index-header`, `--z-index-modal` 等
### 3. 边框颜色规范
#### 统一边框颜色使用
为确保界面的一致性和品牌统一性,项目采用统一的边框颜色规范:
**标准边框颜色:`var(--customer-board-color)`**
```scss
// 标准边框样式
.standard-border {
border: 1px solid var(--customer-board-color);
}
// 卡片边框
.card-container {
border: 1px solid var(--customer-board-color);
border-radius: 8px;
}
// 分割线边框
.divider-line {
border-bottom: 1px solid var(--customer-board-color);
}
// 输入框边框
.input-field {
border: 1px solid var(--customer-board-color);
border-radius: 4px;
}
```
#### 边框使用场景
| 场景 | 边框样式 | 说明 |
|------|----------|------|
| **容器边框** | `1px solid var(--customer-board-color)` | 卡片、面板、弹窗等容器 |
| **分割线** | `1px solid var(--customer-board-color)` | 列表项、内容区域之间的分割 |
| **输入框** | `1px solid var(--customer-board-color)` | 表单输入框、选择器等 |
| **表格边框** | `1px solid var(--customer-board-color)` | 表格单元格、表头等 |
| **悬浮状态** | `1px solid var(--customer-board-color)` | 按钮、链接等悬浮时的边框 |
#### 禁止使用的边框颜色
- ❌ 硬编码的颜色值:`#e4e7ed`, `#f1f5f9`, `#e5e7eb` 等
- ❌ 直接使用 Element Plus 默认边框色
- ❌ 使用不统一的颜色变量
#### 正确示例
```scss
// ✅ 正确:使用统一的边框颜色变量
.email-list {
border-bottom: 1px solid var(--customer-board-color);
}
// ✅ 正确:使用统一的边框颜色变量
.sidebar-section {
border-bottom: 1px solid var(--customer-board-color);
}
// ✅ 正确:使用统一的边框颜色变量
.dialog-content {
border: 1px solid var(--customer-board-color);
}
```
#### 错误示例
```scss
// ❌ 错误:使用硬编码颜色值
.email-list {
border-bottom: 1px solid #e4e7ed;
}
// ❌ 错误:使用不统一的颜色变量
.sidebar-section {
border-bottom: 1px solid #f1f5f9;
}
```
### 4. 组件样式规范
#### Element Plus 组件样式增强
项目已对 Element Plus 组件进行了样式增强:
- **卡片组件**: 统一圆角和阴影
- **抽屉组件**: 标准化头部和底部样式
- **对话框组件**: 统一边框和间距
- **滚动条**: 自定义滚动条样式
#### 页面布局类
- `.main-card` - 主要内容卡片
- `.search-section` - 搜索区域
- `.table-section` - 表格区域
- `.stats-section` - 统计区域
- `.feature-section` - 功能区域
## 文件预览规范
### 使用 FileViewer 组件
**统一使用 FileViewer 组件处理文件预览**
```vue
```
### 支持的文件类型
- **Office文档**: DOC, DOCX, XLS, XLSX, PPT, PPTX
- **PDF文档**: PDF
- **图片文件**: JPG, PNG, GIF, BMP, SVG
- **文本文件**: TXT, MD, JSON, XML
- **视频文件**: MP4, AVI, MOV
- **音频文件**: MP3, WAV, OGG
- **在线文档**: 富文本内容
### FileViewer 组件特性
- 自动识别文件类型
- 支持在线预览
- 统一的预览界面
- 不支持预览的文件显示下载提示
## 路由规范
### 1. 路由配置规范
#### 路由命名规范
```javascript
// 路由命名遵循以下规则:
// 1. 使用 kebab-case 格式
// 2. 层级结构清晰
// 3. 名称具有语义性
const routes = [
{
path: '/crm',
name: 'Crm',
component: Layout,
meta: {
title: 'CRM',
icon: 'UserFilled',
permission: 'crm'
},
children: [
{
path: 'customer',
name: 'CrmCustomer',
component: () => import('@/views/crm/CustomerInfo.vue'),
meta: {
title: '客户信息',
icon: 'User',
permission: 'crm:customer',
cache: true
}
}
]
}
]
```
#### 路由 Meta 信息规范
```javascript
// Meta 字段标准定义
meta: {
title: '页面标题', // 必填:页面标题
icon: 'ElementIcon', // 可选:菜单图标
permission: 'module:action', // 可选:权限标识
cache: true, // 可选:是否缓存页面
hidden: false, // 可选:是否隐藏菜单
```
### 2. 路由守卫规范
#### 权限检查流程
```javascript
// 统一的路由守卫逻辑
router.beforeEach(async (to, from, next) => {
const userStore = useUserStore()
const permissionStore = usePermissionStore()
// 1. 公开页面直接放行
if (PUBLIC_PAGES.has(to.path)) {
next()
return
}
// 2. 登录状态检查
if (!userStore.isLoggedIn) {
userStore.redirectToLoginWithUrl(to.fullPath, router)
return
}
// 3. 权限检查
if (to.meta.permission && !permissionStore.hasPermission(to.meta.permission)) {
next('/403')
return
}
next()
})
```
### 3. 路由跳转规范
#### 编程式导航
```javascript
// 推荐:使用命名路由
router.push({ name: 'CrmCustomer', params: { id: '123' } })
// 推荐:带查询参数
router.push({
name: 'CrmCustomer',
query: { tab: 'projects', status: 'active' }
})
// 避免:硬编码路径
// router.push('/crm/customer/123')
```
#### 路由参数处理
```javascript
// 在组件中获取路由参数
const route = useRoute()
const router = useRouter()
// 获取路径参数
const customerId = route.params.id
// 获取查询参数
const activeTab = route.query.tab || 'basic'
// 监听路由变化
watch(() => route.params.id, (newId) => {
if (newId) {
loadCustomerData(newId)
}
})
```
## 状态管理规范
### 1. Store 组织结构
#### Store 命名和文件组织
```
# 全局状态管理
stores/
├── user.js # 用户状态
├── permission.js # 权限状态
├── app.js # 应用全局状态
└── utils/ # 状态工具
└── storeHelpers.js
# 业务模块状态管理(放在各自模块内)
views/
├── crm/
│ ├── stores/
│ │ └── useCrmStore.js # CRM模块状态
│ ├── components/
│ └── ...
├── knowledge/
│ ├── stores/
│ │ └── useKnowledgeStore.js # 知识库模块状态
│ ├── components/
│ └── ...
└── email/
├── stores/
│ └── useEmailStore.js # 邮件模块状态
├── components/
└── ...
```
### 2. Store 设计规范
#### 标准 Store 结构
```javascript
// views/crm/stores/useCrmStore.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import * as crmApi from '../api/crmApi'
export const useCrmStore = defineStore('crm', () => {
// ========== 状态定义 ==========
const customers = ref([])
const projects = ref([])
const loading = ref(false)
const error = ref(null)
// ========== 计算属性 ==========
const activeCustomers = computed(() =>
customers.value.filter(customer => customer.status === 'active')
)
const totalProjects = computed(() => projects.value.length)
// ========== Actions ==========
const loadCustomers = async (params = {}) => {
loading.value = true
error.value = null
try {
const response = await crmApi.getCustomerPage(params)
customers.value = response.records || []
return response
} catch (err) {
error.value = err.message
throw err
} finally {
loading.value = false
}
}
const addCustomer = async (customerData) => {
try {
const newCustomer = await crmApi.createCustomer(customerData)
customers.value.unshift(newCustomer)
return newCustomer
} catch (err) {
error.value = err.message
throw err
}
}
const updateCustomer = async (id, customerData) => {
try {
const updatedCustomer = await crmApi.updateCustomer(id, customerData)
const index = customers.value.findIndex(c => c.id === id)
if (index !== -1) {
customers.value[index] = updatedCustomer
}
return updatedCustomer
} catch (err) {
error.value = err.message
throw err
}
}
const removeCustomer = async (id) => {
try {
await crmApi.deleteCustomer(id)
customers.value = customers.value.filter(c => c.id !== id)
} catch (err) {
error.value = err.message
throw err
}
}
// ========== 工具方法 ==========
const resetState = () => {
customers.value = []
projects.value = []
loading.value = false
error.value = null
}
const findCustomerById = (id) => {
return customers.value.find(customer => customer.id === id)
}
return {
// 状态
customers,
projects,
loading,
error,
// 计算属性
activeCustomers,
totalProjects,
// 方法
loadCustomers,
addCustomer,
updateCustomer,
removeCustomer,
resetState,
findCustomerById
}
})
```
### 3. Store 使用规范
#### 在组件中使用 Store
```javascript
// 组件中的标准用法
```
#### 跨 Store 通信
```javascript
// 在业务模块 Store 中使用全局 Store
export const useCrmStore = defineStore('crm', () => {
const userStore = useUserStore() // 全局用户状态
const permissionStore = usePermissionStore() // 全局权限状态
const loadCustomers = async () => {
// 检查权限
if (!permissionStore.hasPermission('crm:customer:read')) {
throw new Error('没有访问权限')
}
// 使用用户信息
const params = {
userId: userStore.userId,
tenantId: userStore.currentTenant?.id
}
// API调用...
}
})
```
### 4. 状态持久化
#### 使用 localStorage 持久化
```javascript
import { defineStore } from 'pinia'
export const useAppStore = defineStore('app', () => {
// 从 localStorage 恢复状态
const sidebarCollapsed = ref(
localStorage.getItem('sidebarCollapsed') === 'true'
)
const toggleSidebar = () => {
sidebarCollapsed.value = !sidebarCollapsed.value
// 持久化到 localStorage
localStorage.setItem('sidebarCollapsed', sidebarCollapsed.value.toString())
}
return {
sidebarCollapsed,
toggleSidebar
}
})
```
## 接口处理规范
### 1. 接口调用规范
#### 基于 http.js 的统一调用
项目已使用 `src/utils/http.js` 进行 Ajax 响应封装,所有接口调用必须使用统一的 request 方法:
```javascript
// 正确:使用统一的 http 实例
import request from '@/utils/http'
export function getCustomerList(params) {
return request({
url: '/smart-ops/crm/customer/page',
method: 'post',
data: params
})
}
// 错误:直接使用 axios
// import axios from 'axios'
// axios.post('/api/customer', data)
```
### 2. 接口文件组织规范
#### API 文件结构
```
# 全局API接口
api/
├── index.js # API 统一导出
├── user.js # 用户相关接口
├── permission.js # 权限相关接口
└── wiki/ # Wiki相关接口
├── comment.js
├── favorite.js
└── version.js
# 业务模块API接口(放在各自模块内)
views/
├── crm/
│ └── api/
│ └── crmApi.js # CRM模块接口
├── email/
│ └── api/
│ └── emailApi.js # 邮件模块接口
└── knowledge/
└── api/
└── knowledgeApi.js # 知识库模块接口
```
#### 接口命名规范
```javascript
// 命名规范:动词 + 资源名 + 操作类型
// CRUD 操作标准命名
export function getCustomerList(params) // 获取列表
export function getCustomerPage(params) // 分页查询
export function getCustomerDetail(id) // 获取详情
export function createCustomer(data) // 创建
export function updateCustomer(id, data) // 更新
export function deleteCustomer(id) // 删除
// 特殊操作命名
export function exportCustomers(params) // 导出
export function importCustomers(file) // 导入
export function batchDeleteCustomers(ids) // 批量删除
export function enableCustomer(id) // 启用
export function disableCustomer(id) // 禁用
```
### 3. 接口文档规范
#### 标准接口注释
```javascript
/**
* 获取客户分页列表
* @param {Object} params - 查询参数
* @param {number} params.pageNo - 页码(从1开始)
* @param {number} params.pageSize - 每页大小
* @param {string} [params.keyword] - 搜索关键词
* @param {string} [params.status] - 客户状态:active|inactive
* @param {string} [params.createTimeStart] - 创建时间开始
* @param {string} [params.createTimeEnd] - 创建时间结束
* @returns {Promise