# 点餐小程序

基于 uni-app 框架开发的微信点餐小程序，使用 Vue 3 + Pinia 构建。

## 📋 项目简介

这是一个功能完善的微信点餐小程序，提供完整的点餐流程，包括菜品浏览、购物车管理、优惠券使用、订单确认等功能。项目采用现代化的前端技术栈，代码结构清晰，易于维护和扩展。

### 主要业务场景

- 🍽️ **扫码点餐**: 用户扫描桌码进入点餐页面
- 🛒 **购物车管理**: 实时管理已选菜品，支持增减数量
- 🎫 **优惠券系统**: 优惠券领取和使用
- 📝 **订单确认**: 确认订单信息并提交
- 👤 **个人中心**: 用户信息管理和设置

## 🛠 技术栈

- **框架**: uni-app
- **Vue 版本**: Vue 3
- **状态管理**: Pinia
- **构建工具**: HBuilderX / Vite
- **主要依赖**:
  - `@vueuse/core`: Vue Composition API 工具库
  - `dayjs`: 日期处理库
  - `lodash-es`: JavaScript 工具库
  - `uqrcodejs`: 二维码生成库

## 📁 项目结构

```
WechatApp/
├── api/                    # API 接口定义
│   ├── index.js           # 通用接口
│   ├── dining.js          # 点餐相关接口
│   └── login.js           # 登录相关接口
├── components/             # 公共组件
│   ├── Modal/             # 弹窗组件
│   │   ├── BasicModal.vue
│   │   └── ScrollPopup.vue
│   ├── NavBar/            # 导航栏组件
│   │   ├── index.vue
│   │   └── StatusBar.vue
│   ├── Share/             # 分享组件
│   │   ├── hook.js
│   │   └── ShareBtn.vue
│   ├── TabBar.vue         # 底部导航栏（首页/扫码点餐/我的）
│   └── Upload/            # 文件上传组件
│       ├── index.vue
│       └── upload.js
├── hooks/                  # 自定义 Hooks
│   ├── libs/              # 第三方库
│   │   └── qqmap-wx-jssdk.min.js  # 腾讯地图 SDK
│   └── usePay.js          # 支付相关 Hook
├── pages/                  # 页面目录
│   ├── index/             # 首页（菜品展示）
│   │   └── index.vue
│   ├── numberOfDiners/    # 扫码点餐（选择就餐人数）
│   │   └── index.vue
│   ├── orderFood/         # 点餐页面
│   │   ├── index.vue
│   │   └── components/    # 点餐相关组件
│   │       ├── FoodCard.vue        # 菜品卡片
│   │       ├── BottomActionBar.vue # 底部操作栏
│   │       ├── CartModal.vue       # 购物车弹窗
│   │       ├── CouponModal.vue     # 优惠券弹窗
│   │       └── SelectCouponModal.vue # 选择优惠券弹窗
│   ├── foodDetail/        # 菜品详情页
│   │   └── index.vue
│   ├── placeOrder/        # 确认订单页
│   │   └── index.vue
│   ├── result/            # 订单结果页
│   │   └── index.vue
│   ├── personal/          # 个人中心
│   │   ├── index.vue      # 个人中心首页
│   │   ├── userInfo.vue   # 个人信息
│   │   └── setPhone.vue   # 设置手机号
│   ├── webview/           # WebView 页面
│   │   └── index.vue
│   └── components/        # 页面级组件
│       └── LoginModal.vue # 登录弹窗
├── settings/              # 配置文件
│   ├── enums.js           # 枚举常量（存储键名等）
│   └── siteSetting.js     # 站点配置（API地址、CDN地址等）
├── store/                 # 状态管理（Pinia）
│   ├── app.js             # 应用状态
│   └── user.js            # 用户状态（登录、用户信息等）
├── utils/                 # 工具函数
│   ├── index.js           # 工具函数入口
│   ├── request.js         # HTTP 请求封装
│   ├── utils.js           # 通用工具函数
│   ├── share.js           # 分享工具
│   ├── file.js            # 文件处理（CDN地址处理等）
│   ├── is.js              # 类型判断工具
│   └── uuid.js            # UUID 生成
├── static/                # 静态资源
│   └── img/               # 图片资源
│       ├── tabbar/        # 底部导航图标
│       └── orderFood/     # 点餐相关图片
├── uni_modules/           # uni-app 插件模块
│   ├── uni-popup/         # 弹窗组件
│   ├── uni-scss/          # 样式工具
│   └── uni-transition/    # 过渡动画
├── App.vue                # 应用入口（全局样式、生命周期）
├── main.js                # 主入口文件（应用初始化）
├── initConfig.js          # 初始化配置（版本更新检测等）
├── routeInterceptor.js    # 路由拦截器（登录验证）
├── pages.json             # 页面路由配置
├── manifest.json          # 应用配置文件（AppID、权限等）
└── uni.scss               # 全局样式变量
```

## 🚀 功能特性

### 核心功能

- ✅ **用户认证**: 微信登录、手机号登录、token 管理、自动登录
- ✅ **路由拦截**: 自动检测登录状态，保护需要登录的页面
- ✅ **请求封装**: 统一的 HTTP 请求处理，自动处理 token、loading、错误提示
- ✅ **状态管理**: 基于 Pinia 的用户状态管理
- ✅ **小程序更新**: 自动检测并提示小程序版本更新
- ✅ **网络检测**: 启动时检测网络状态

### 业务功能

#### 点餐流程
- 🍽️ **扫码点餐**: 扫描桌码进入点餐流程
- 👥 **选择人数**: 选择就餐人数
- 🍜 **菜品浏览**: 分类浏览菜品，查看菜品详情
- 🛒 **购物车**: 实时管理已选菜品，支持增减数量
- 🎫 **优惠券**: 优惠券领取、选择和使用
- 📝 **订单确认**: 确认订单信息、桌号、人数、优惠等
- ✅ **订单提交**: 提交订单并查看结果

#### 其他功能
- 📱 **首页**: 店铺信息展示、菜品推荐、登录引导
- 👤 **个人中心**: 用户信息管理、手机号设置
- 📤 **文件上传**: 支持图片、文件上传到 OSS
- 📍 **地理位置**: 集成腾讯地图 SDK（H5端）
- 💰 **支付功能**: 微信支付集成（预留接口）

### UI 组件

- **自定义导航栏**: 支持状态栏适配，自定义样式
- **底部 TabBar**: 三栏导航（首页/扫码点餐/我的），中间为特殊圆形按钮
- **模态弹窗**: 基础弹窗、滚动弹窗组件
- **菜品卡片**: 菜品信息展示，支持加购操作
- **购物车弹窗**: 购物车管理，支持修改数量、清空
- **优惠券弹窗**: 优惠券列表展示和领取
- **登录弹窗**: 快速登录入口

## 📦 安装与运行

### 环境要求

- Node.js >= 14.0.0
- HBuilderX 或 支持 uni-app 的 IDE
- 微信开发者工具

### 安装依赖

```bash
# 使用 yarn
yarn install

# 或使用 npm
npm install
```

### 开发运行

1. 使用 HBuilderX 打开项目
2. 选择运行到微信小程序
3. 或使用命令行：

```bash
# 开发环境
npm run dev:mp-weixin

# 生产构建
npm run build:mp-weixin
```

### 配置说明

#### 1. 小程序配置 (`manifest.json`)

- **AppID**: `wxc9598c736783dfa9`（当前配置）
- **版本号**: `1.0.0` (versionName) / `100` (versionCode)
- **权限配置**:
  - `scope.userLocation`: 位置信息权限
  - `scope.record`: 录音权限
- **网络配置**: `urlCheck: false`（开发环境可关闭域名校验）

#### 2. API 配置

在 `settings/siteSetting.js` 中配置 API 基础地址：

```javascript
// 开发环境 / 生产环境 API 地址
export const BASE_API_URL = process.env.NODE_ENV === 'development' 
  ? 'http://192.168.1.91:8000/aliendining' 
  : 'http://192.168.1.91:8000/aliendining';

// 文件上传地址
export const UPLOAD_URL = 'https://api.xxxxxx.cn/File/UploadImg';

// CDN 地址
export const DEFAULT_CDN_URL = 'https://alien-volume.oss-cn-beijing.aliyuncs.com/';
export const UPLOAD = 'https://alien-volume.oss-cn-beijing.aliyuncs.com/';
```

#### 3. 腾讯地图配置

在 `manifest.json` 的 `h5.sdkConfigs.maps.qqmap` 中配置地图 Key（仅 H5 端使用）：

```json
{
  "h5": {
    "sdkConfigs": {
      "maps": {
        "qqmap": {
          "key": ""
        }
      }
    }
  }
}
```

#### 4. 页面路由配置 (`pages.json`)

主要页面路由：
- `/pages/index/index` - 首页
- `/pages/numberOfDiners/index` - 扫码点餐（选择人数）
- `/pages/orderFood/index` - 点餐页面
- `/pages/foodDetail/index` - 菜品详情
- `/pages/placeOrder/index` - 确认订单
- `/pages/result/index` - 订单结果
- `/pages/personal/index` - 个人中心
- `/pages/personal/userInfo` - 个人信息
- `/pages/personal/setPhone` - 设置手机号
- `/pages/webview/index` - WebView 页面

## 🔧 核心模块说明

### 路由拦截 (`routeInterceptor.js`)

自动拦截需要登录的页面访问，未登录用户将被引导至登录页，登录成功后自动跳转回原页面。

**拦截的路由方法**:
- `uni.navigateTo`
- `uni.reLaunch`
- `uni.redirectTo`

**需要登录的页面列表**（在 `routeInterceptor.js` 中配置）

**工作原理**:
1. 检测目标页面是否在登录列表中
2. 检查用户 token 是否存在
3. 未登录时弹出提示，用户确认后跳转登录页
4. 登录成功后从 `REDIRECT_KEY` 读取原目标地址并跳转

### 请求封装 (`utils/request.js`)

统一的 HTTP 请求处理类，提供以下特性：

- ✅ 自动添加 token 到请求头（Authorization）
- ✅ 自动显示/隐藏 loading（支持并发请求计数）
- ✅ 统一错误处理（根据 code 码处理）
- ✅ 请求超时处理（默认 180 秒）
- ✅ GET 请求自动添加时间戳防缓存
- ✅ 网络错误提示

**请求配置选项**:

```javascript
{
  url: string,              // 请求路径（相对路径）
  params: object,          // 请求参数
  headers: object,         // 自定义请求头
  loading: boolean,        // 是否显示 loading（默认 true）
  timeout: number,         // 超时时间（默认 180000ms）
  returnResponse: boolean, // 是否返回原生响应（默认 false）
  message: boolean,        // 是否显示消息提示（默认 true）
  hideErrorModal: boolean, // 是否隐藏错误弹窗（默认 false）
  customizeUrl: string     // 自定义完整 URL
}
```

**响应码处理**:
- `code: 200` - 成功，返回 `data` 字段
- `code: 400` - 系统异常，弹出错误提示
- 其他 code - 根据 `hideErrorModal` 决定是否弹出错误提示

**使用示例**:

```javascript
import { api } from '@/utils/request.js';

// GET 请求
const userInfo = await api.get({
  url: '/api/user/info',
  params: { id: 1 }
});

// POST 请求
const result = await api.post({
  url: '/api/user/update',
  params: { name: 'test' },
  loading: true,        // 显示 loading
  hideErrorModal: false // 显示错误弹窗
});

// 静默请求（不显示 loading 和错误提示）
const data = await api.get({
  url: '/api/check',
  loading: false,
  hideErrorModal: true
});
```

### 状态管理 (`store/user.js`)

用户状态管理 Store（基于 Pinia），提供以下功能：

- ✅ 用户信息管理（内存 + 本地存储）
- ✅ Token 管理（自动同步到本地存储）
- ✅ OpenId 管理
- ✅ SiteId 管理
- ✅ 登录/登出（带确认提示）
- ✅ 自动持久化（使用 `uni.setStorageSync`）

**State**:
```javascript
{
  userInfo: null,    // 用户信息对象
  token: undefined,  // 用户 token
  siteId: undefined, // 站点 ID
  openId: undefined  // 微信 OpenId
}
```

**Getters**:
- `getUserInfo` - 获取用户信息（优先内存，其次本地存储）
- `getToken` - 获取 token
- `getOpenId` - 获取 OpenId

**Actions**:
- `setUserInfo(e)` - 设置用户信息
- `login(e)` - 登录（保存用户信息、token、siteId，显示成功提示）
- `beforeLogout()` - 退出前确认
- `logout(option)` - 退出登录（清除存储，可配置是否跳转首页）

**使用示例**:

```javascript
import { useUserStore } from '@/store/user.js';

const userStore = useUserStore();

// 获取用户信息
const userInfo = userStore.getUserInfo;

// 获取 token
const token = userStore.getToken;

// 登录
userStore.login({
  token: 'xxx',
  siteId: 'xxx',
  ...userData
});

// 退出登录（带确认）
userStore.beforeLogout();

// 直接退出（不确认）
userStore.logout({ redirct: true });
```

### 初始化配置 (`initConfig.js`)

应用启动时的初始化逻辑（在 `App.vue` 的 `onLaunch` 中调用）：

**功能**:
1. **网络检测**: 检测当前网络状态
   - 无网络时提示用户开启网络
   - 有网络时继续后续流程
2. **版本更新检测**: 使用 `uni.getUpdateManager()` 检测小程序更新
   - 检测到新版本时自动下载
   - 下载完成后提示用户重启应用
   - 下载失败时提示用户卸载重装

**更新流程**:
```
启动 → 检测网络 → 检测更新 → 下载更新 → 提示重启 → 应用更新
```

**注意事项**:
- 仅在微信小程序环境执行（`#ifdef MP-WEIXIN`）
- 网络检测失败时不会阻止应用启动

## 🎨 样式规范

项目使用 SCSS，全局样式定义在 `App.vue` 和 `uni.scss` 中。

### 常用工具类

- `.flex`: Flex 布局
- `.flex-center`: 水平垂直居中
- `.flex-between`: 两端对齐
- `.ellipsis`: 单行省略
- `.ellipsis-2`: 两行省略（支持 2-10 行）
- `.safe-area`: 底部安全区适配

## 📱 页面说明

### 首页 (`pages/index/index`)

- **功能**: 店铺信息展示、菜品推荐、登录引导
- **特性**:
  - 支持下拉刷新
  - 自定义导航栏
  - 未登录时显示登录卡片
  - 菜品列表展示（图片、名称、价格、月售等）
  - 菜品加购功能

### 扫码点餐 (`pages/numberOfDiners/index`)

- **功能**: 选择就餐人数
- **入口**: 底部 TabBar 中间圆形按钮
- **流程**: 选择人数 → 进入点餐页面

### 点餐页面 (`pages/orderFood/index`)

- **功能**: 浏览菜品、管理购物车、使用优惠券
- **特性**:
  - 左侧分类导航
  - 右侧菜品列表
  - 实时购物车管理
  - 优惠券领取和使用
  - 底部操作栏（购物车、优惠券、下单）
- **组件**:
  - `FoodCard`: 菜品卡片
  - `BottomActionBar`: 底部操作栏
  - `CartModal`: 购物车弹窗
  - `CouponModal`: 优惠券弹窗
  - `SelectCouponModal`: 选择优惠券弹窗

### 菜品详情 (`pages/foodDetail/index`)

- **功能**: 查看菜品详细信息
- **特性**: 自定义导航栏、菜品详情展示

### 确认订单 (`pages/placeOrder/index`)

- **功能**: 确认订单信息并提交
- **内容**: 订单详情、桌号、人数、优惠信息等

### 订单结果 (`pages/result/index`)

- **功能**: 显示订单提交结果
- **状态**: 成功/失败提示

### 个人中心 (`pages/personal/index`)

- **功能**: 用户信息展示、功能入口
- **特性**: 自定义导航栏、用户信息卡片

### 个人信息 (`pages/personal/userInfo`)

- **功能**: 查看和编辑个人信息

### 设置手机号 (`pages/personal/setPhone`)

- **功能**: 设置或修改手机号

### WebView 页面 (`pages/webview/index`)

- **功能**: 内嵌网页展示
- **特性**: 自定义导航栏、支持外部链接加载

### 登录弹窗 (`pages/components/LoginModal.vue`)

- **功能**: 快速登录入口
- **使用**: 在需要登录的页面中调用

## 🔌 插件说明

### uni-popup 弹窗组件

uni-app 官方弹窗组件，用于各种弹窗场景。

**安装**: 通过 uni_modules 自动安装

**使用**:
```vue
<uni-popup ref="popup" type="bottom">
  <view>弹窗内容</view>
</uni-popup>
```

### uni-scss 样式工具

uni-app 官方样式工具库，提供统一的样式变量和工具类。

### uni-transition 过渡动画

uni-app 官方过渡动画组件，用于页面和组件过渡效果。

## 📦 依赖说明

### 核心依赖

- `@dcloudio/uni-ui`: uni-app UI 组件库
- `@vueuse/core`: Vue Composition API 工具库（Vue 3 版本）
- `dayjs`: 轻量级日期处理库
- `lodash-es`: JavaScript 工具库（ES 模块版本）
- `uqrcodejs`: 二维码生成库

### 开发依赖

项目使用 HBuilderX 或 Vite 进行构建，具体构建工具根据开发环境而定。

## 📝 开发规范

### 代码规范

#### Vue 组件规范
- ✅ 使用 Vue 3 Composition API (`<script setup>`)
- ✅ 组件命名采用 PascalCase（如 `FoodCard.vue`）
- ✅ 文件命名采用 camelCase（如 `userInfo.vue`）
- ✅ 使用 TypeScript 或 JSDoc 注释（可选）

#### 目录结构规范
- ✅ 工具函数统一放在 `utils` 目录
- ✅ API 接口统一放在 `api` 目录
- ✅ 公共组件放在 `components` 目录
- ✅ 页面组件放在对应页面的 `components` 目录

#### 样式规范
- ✅ 使用 SCSS 预处理器
- ✅ 使用 rpx 作为尺寸单位（适配不同屏幕）
- ✅ 使用全局样式类（`.flex`, `.ellipsis` 等）
- ✅ 组件样式使用 `scoped`

#### 命名规范
- ✅ 变量和函数使用 camelCase
- ✅ 常量使用 UPPER_SNAKE_CASE
- ✅ 组件名使用 PascalCase
- ✅ 文件名使用 camelCase

### 提交规范

建议使用约定式提交（Conventional Commits）：

- `feat`: 新功能
- `fix`: 修复 bug
- `docs`: 文档更新
- `style`: 代码格式调整（不影响代码运行）
- `refactor`: 代码重构
- `perf`: 性能优化
- `test`: 测试相关
- `chore`: 构建/工具相关
- `revert`: 回滚提交

**示例**:
```
feat: 添加优惠券选择功能
fix: 修复购物车数量计算错误
docs: 更新 README 文档
style: 调整菜品卡片样式
refactor: 重构请求封装代码
```

### 代码审查清单

提交代码前请检查：
- [ ] 代码格式正确，无语法错误
- [ ] 已测试功能正常
- [ ] 无控制台错误和警告
- [ ] 样式在不同设备上显示正常
- [ ] API 请求错误处理完善
- [ ] 登录状态检查正确
- [ ] 图片资源路径正确

## 🐛 常见问题

### 1. 小程序版本更新

**问题**: 小程序如何检测和更新版本？

**解答**: 
- 小程序会自动检测新版本并提示用户更新
- 更新逻辑在 `initConfig.js` 中实现
- 使用 `uni.getUpdateManager()` API
- 下载完成后会提示用户重启应用

### 2. 登录状态管理

**问题**: 如何判断用户是否已登录？

**解答**:
- 通过 `useUserStore().getToken` 获取 token
- token 存储在 Pinia store 和本地存储中
- 路由拦截器会自动检查需要登录的页面

### 3. 网络请求失败

**问题**: 网络请求失败时如何处理？

**解答**:
- 网络请求失败时会自动提示"网络不稳定，请稍后刷新重试"
- 自动隐藏 loading
- 不会阻止后续代码执行（需要自行处理 reject）

### 4. 图片资源加载

**问题**: 如何正确加载静态图片？

**解答**:
- 使用 `getFileUrl()` 工具函数处理图片路径
- 支持 CDN 地址和本地路径
- 示例: `getFileUrl('img/tabbar/index1.png')`

### 5. 底部 TabBar 不显示

**问题**: 为什么底部导航栏不显示？

**解答**:
- 检查页面中是否引入了 `TabBar` 组件
- 确认 `TabBar` 组件的 `fixed` 属性设置
- 检查页面样式是否遮挡了 TabBar

### 6. 路由跳转被拦截

**问题**: 为什么跳转到某些页面会被拦截？

**解答**:
- 检查目标页面是否在 `routeInterceptor.js` 的 `loginList` 中
- 确认用户是否已登录（token 是否存在）
- 未登录时会弹出提示，确认后跳转登录页

### 7. API 请求地址配置

**问题**: 如何修改 API 请求地址？

**解答**:
- 修改 `settings/siteSetting.js` 中的 `BASE_API_URL`
- 支持根据 `process.env.NODE_ENV` 区分开发/生产环境
- 修改后需要重新编译小程序

### 8. 微信开发者工具报错

**问题**: 在微信开发者工具中运行报错？

**解答**:
- 检查 `manifest.json` 中的 AppID 是否正确
- 确认网络请求域名是否在微信后台配置
- 开发环境可设置 `urlCheck: false` 关闭域名校验
- 检查是否有语法错误或缺少依赖

### 9. 样式不生效

**问题**: 为什么某些样式不生效？

**解答**:
- 检查是否使用了正确的选择器（小程序不支持部分 CSS 选择器）
- 确认样式作用域（scoped 样式）
- 检查全局样式是否被覆盖
- 使用 rpx 单位而非 px

### 10. 本地存储数据

**问题**: 如何管理本地存储数据？

**解答**:
- 使用 `uni.setStorageSync` 和 `uni.getStorageSync`
- 存储键名定义在 `settings/enums.js` 中
- 用户信息、token 等会自动同步到本地存储

## 🔐 环境变量

项目支持通过环境变量配置不同环境：

- `NODE_ENV`: 环境标识（`development` / `production`）
- API 地址根据环境自动切换（在 `settings/siteSetting.js` 中配置）

## 📊 项目信息

- **项目名称**: 点餐小程序
- **框架版本**: uni-app (Vue 3)
- **小程序 AppID**: `wxc9598c736783dfa9`
- **版本号**: 1.0.0
- **构建工具**: HBuilderX / Vite

## 🗺️ 开发路线图

- [ ] 完善支付功能集成
- [ ] 添加订单历史查询
- [ ] 优化购物车性能
- [ ] 添加菜品搜索功能
- [ ] 支持多店铺切换
- [ ] 添加评价功能

## 📄 许可证

MIT License

## 👥 贡献

欢迎提交 Issue 和 Pull Request。

### 贡献指南

1. Fork 本项目
2. 创建特性分支 (`git checkout -b feature/AmazingFeature`)
3. 提交更改 (`git commit -m 'feat: Add some AmazingFeature'`)
4. 推送到分支 (`git push origin feature/AmazingFeature`)
5. 开启 Pull Request

## 📞 联系方式

如有问题或建议，请联系项目维护者。

---

**注意**: 
- 本项目为微信小程序项目，部分功能仅在微信小程序环境中可用
- 开发时请使用微信开发者工具进行调试
- 生产环境部署前请确保所有配置正确（AppID、API 地址、权限等）

