# 开发指南

## 开发环境设置

### 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. 文档更新
- 更新相关文档
- 添加使用示例
- 记录变更内容