shop-web/doc/开发指南.md

529 lines
11 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.

# 开发指南
## 开发环境设置
### 1. 环境要求
- **Node.js**: 20.x 或 22+
- **包管理器**: pnpm 9.x 或 10+
- **编辑器**: Visual Studio Code (推荐)
- **浏览器**: Chrome 或 Safari (移动端调试)
### 2. 推荐 VS Code 插件
- Vue Language Features (Volar)
- TypeScript Vue Plugin (Volar)
- ESLint
- UnoCSS
- Auto Rename Tag
- GitLens
### 3. 项目初始化
```bash
# 克隆项目
git clone <repository-url>
# 安装依赖
pnpm i
# 启动开发服务器
pnpm dev
```
## 项目架构
### 目录结构详解
```
src/
├── common/ # 通用模块
│ ├── apis/ # API 接口定义
│ │ ├── users/ # 用户相关接口
│ │ ├── shop/ # 店铺相关接口
│ │ ├── cabinet/ # 柜机相关接口
│ │ ├── approval/ # 审批相关接口
│ │ └── ab98/ # AB98系统接口
│ ├── assets/ # 静态资源
│ │ └── styles/ # 样式文件
│ ├── composables/ # 组合式函数
│ │ ├── useDark.ts # 暗黑模式
│ │ ├── useWatermark.ts # 水印功能
│ │ └── useGrayscaleAndColorblind.ts # 无障碍模式
│ ├── components/ # 通用组件
│ └── utils/ # 工具函数
│ ├── cache/ # 缓存工具
│ ├── permission.ts # 权限工具
│ └── wx.ts # 微信工具
├── layout/ # 布局组件
│ ├── index.vue # 主布局
│ ├── components/
│ │ ├── NavBar.vue # 导航栏
│ │ ├── Tabbar.vue # 标签栏
│ │ └── Footer.vue # 底部
├── pages/ # 页面组件
│ ├── product/ # 商品相关页面
│ ├── order/ # 订单相关页面
│ ├── cabinet/ # 柜机相关页面
│ ├── approval/ # 审批相关页面
│ ├── me/ # 个人中心
│ └── error/ # 错误页面
├── pinia/ # 状态管理
│ ├── index.ts # Pinia 实例
│ └── stores/ # Store 定义
│ ├── user.ts # 用户状态
│ ├── ab98-user.ts # AB98用户状态
│ ├── wx.ts # 微信状态
│ ├── product.ts # 商品状态
│ ├── cart.ts # 购物车状态
│ ├── order.ts # 订单状态
│ └── approval.ts # 审批状态
├── router/ # 路由配置
│ ├── index.ts # 路由定义
│ ├── guard.ts # 路由守卫
│ └── whitelist.ts # 白名单
├── http/ # HTTP 请求
│ └── axios.ts # Axios 配置
└── plugins/ # 插件配置
├── index.ts # 插件安装
├── permission-directive.ts # 权限指令
└── console.ts # 控制台工具
```
## 开发规范
### 1. 代码风格
#### TypeScript 规范
- 使用严格模式,避免 `any` 类型
- 为所有函数和变量提供明确的类型定义
- 使用接口定义复杂的数据结构
```typescript
// ✅ 推荐
interface UserInfo {
id: number;
name: string;
email: string;
}
const getUserInfo = async (id: number): Promise<UserInfo> => {
// ...
}
// ❌ 避免
const getUserInfo = async (id: any): Promise<any> => {
// ...
}
```
#### Vue 组件规范
- 使用 script setup 语法
- 组件名使用 PascalCase
- Props 和 Emits 使用 TypeScript 定义
```vue
<script setup lang="ts">
interface Props {
title: string;
count?: number;
}
interface Emits {
(e: 'update:count', value: number): void;
}
const props = defineProps<Props>();
const emit = defineEmits<Emits>();
const handleClick = () => {
emit('update:count', (props.count || 0) + 1);
};
</script>
<template>
<div class="my-component">
<h3>{{ title }}</h3>
<button @click="handleClick">
点击 {{ count }}
</button>
</div>
</template>
```
### 2. 状态管理规范
#### Store 定义
- Store 名使用 camelCase
- 使用组合式 API 风格
- 提供清晰的类型定义
```typescript
import { pinia } from "@/pinia";
export const useProductStore = defineStore("product", () => {
// State
const products = ref<Product[]>([]);
const loading = ref(false);
// Getters
const availableProducts = computed(() =>
products.value.filter(p => p.stock > 0)
);
// Actions
const fetchProducts = async () => {
loading.value = true;
try {
const response = await getProductListApi();
if (response.code === 0) {
products.value = response.data.products;
}
} finally {
loading.value = false;
}
};
return {
products,
loading,
availableProducts,
fetchProducts
};
});
```
### 3. API 开发规范
#### API 文件结构
```typescript
// src/common/apis/product/index.ts
import { request } from "@/http/axios";
import type { ProductListResponse, ProductDetailResponse } from "./type";
export const getProductListApi = (params?: { page?: number; size?: number }) => {
return request<ProductListResponse>({
url: "/api/v1/product/list",
method: "GET",
params
});
};
export const getProductDetailApi = (id: number) => {
return request<ProductDetailResponse>({
url: `/api/v1/product/${id}`,
method: "GET"
});
};
```
#### 类型定义文件
```typescript
// src/common/apis/product/type.ts
export interface Product {
id: number;
name: string;
price: number;
image: string;
description: string;
stock: number;
category: string;
}
export interface ProductListResponse {
products: Product[];
total: number;
page: number;
size: number;
}
export interface ProductDetailResponse extends Product {
specifications: Specification[];
images: string[];
details: string;
}
```
### 4. 路由配置规范
#### 路由定义
```typescript
// src/router/index.ts
export const routes: RouteRecordRaw[] = [
{
path: "/product/:id",
component: () => import("@/pages/product/ProductDetail.vue"),
name: "ProductDetail",
meta: {
title: "商品详情",
keepAlive: true,
layout: {
navBar: {
showNavBar: true,
showLeftArrow: true
},
tabbar: {
showTabbar: false
}
},
requiresAuth: true
}
}
];
```
### 5. 样式开发规范
#### UnoCSS 使用
- 优先使用预设的原子类
- 自定义规则在 `uno.config.ts` 中定义
- 使用属性化模式un-前缀)
```vue
<template>
<div class="product-card un-p-4 un-bg-white un-rounded-lg un-shadow-sm">
<img
:src="product.image"
class="un-w-full un-h-40 un-object-cover un-rounded"
/>
<h3 class="un-text-lg un-font-medium un-mt-2 un-text-gray-900">
{{ product.name }}
</h3>
<p class="un-text-primary un-font-bold un-mt-1">
¥{{ product.price }}
</p>
</div>
</template>
```
#### CSS 变量
`src/common/assets/styles/variables.css` 中定义主题变量:
```css
:root {
--mobvue-primary-color: #1989fa;
--mobvue-bg-color: #ffffff;
--mobvue-text-color: #323233;
}
html.dark {
--mobvue-primary-color: #2d8cf0;
--mobvue-bg-color: #1a1a1a;
--mobvue-text-color: #e5e5e5;
}
```
## 功能开发指南
### 1. 添加新页面
#### 步骤 1: 创建页面组件
```vue
<!-- src/pages/example/ExamplePage.vue -->
<script setup lang="ts">
import { useRoute } from "vue-router";
const route = useRoute();
// 页面逻辑...
</script>
<template>
<div class="example-page">
<h1>示例页面</h1>
<!-- 页面内容 -->
</div>
</template>
<style scoped>
.example-page {
padding: 16px;
}
</style>
```
#### 步骤 2: 配置路由
```typescript
// src/router/index.ts
export const routes: RouteRecordRaw[] = [
{
path: "/example",
component: () => import("@/pages/example/ExamplePage.vue"),
name: "ExamplePage",
meta: {
title: "示例页面",
layout: {
navBar: {
showNavBar: true,
showLeftArrow: true
}
}
}
}
];
```
### 2. 添加新 Store
```typescript
// src/pinia/stores/example.ts
import { pinia } from "@/pinia";
export const useExampleStore = defineStore("example", () => {
const data = ref<string[]>([]);
const loading = ref(false);
const fetchData = async () => {
loading.value = true;
try {
// API 调用...
} finally {
loading.value = false;
}
};
return {
data,
loading,
fetchData
};
});
```
### 3. 添加新 API
```typescript
// src/common/apis/example/index.ts
import { request } from "@/http/axios";
import type { ExampleResponse } from "./type";
export const getExampleDataApi = () => {
return request<ExampleResponse>({
url: "/api/v1/example/data",
method: "GET"
});
};
// src/common/apis/example/type.ts
export interface ExampleResponse {
data: string[];
}
```
## 调试技巧
### 1. 移动端调试
- 使用 Chrome DevTools 的设备模拟
- 启用移动端触摸模拟
- 测试不同屏幕尺寸
### 2. 微信调试
- 使用微信开发者工具
- 配置正确的回调域名
- 检查 openid 获取逻辑
### 3. 状态调试
- 使用 Vue DevTools
- 查看 Pinia Store 状态
- 监控组件生命周期
## 性能优化
### 1. 代码分割
- 路由级别的懒加载
- 组件按需导入
- 第三方库独立打包
### 2. 图片优化
- 使用 WebP 格式
- 实现懒加载
- 压缩图片大小
### 3. 缓存策略
- 合理使用浏览器缓存
- API 响应缓存
- 组件 keep-alive
## 测试指南
### 1. 单元测试
```typescript
// tests/example.test.ts
import { describe, it, expect } from "vitest";
import { mount } from "@vue/test-utils";
import ExampleComponent from "@/components/ExampleComponent.vue";
describe("ExampleComponent", () => {
it("renders correctly", () => {
const wrapper = mount(ExampleComponent, {
props: {
title: "Test Title"
}
});
expect(wrapper.text()).toContain("Test Title");
});
});
```
### 2. E2E 测试
- 使用 Playwright 或 Cypress
- 模拟用户操作流程
- 测试关键业务路径
## 部署指南
### 1. 环境变量配置
```env
# .env.production
VITE_BASE_URL=https://api.example.com
VITE_PUBLIC_PATH=/
VITE_ROUTER_HISTORY=hash
```
### 2. 构建优化
```bash
# 生产环境构建
pnpm build
# 预发布环境构建
pnpm build:staging
```
### 3. 部署检查清单
- [ ] 环境变量配置正确
- [ ] 静态资源路径正确
- [ ] API 接口可访问
- [ ] 路由配置正确
- [ ] 移动端适配正常
## 常见问题解决
### 1. 微信认证失败
- 检查回调域名配置
- 验证 corpid 和 secret
- 查看网络请求日志
### 2. 路由跳转问题
- 检查路由守卫逻辑
- 验证权限配置
- 查看路由历史模式
### 3. 样式显示异常
- 检查 UnoCSS 配置
- 验证 CSS 变量定义
- 测试不同主题模式
## 贡献指南
### 1. 代码提交
- 遵循提交信息规范
- 一个功能一个提交
- 提供清晰的提交描述
### 2. 代码审查
- 检查代码规范
- 验证功能完整性
- 测试边界情况
### 3. 文档更新
- 更新相关文档
- 添加使用示例
- 记录变更内容