# 零食商城 Snack Mall

> 毕业设计 · 前后端分离的 B2C 电商平台，覆盖用户端、管理端、客服、公告、优惠券、抢购六大模块。

仓库采用单仓多模块结构，包含两个前端项目（用户端 + 管理端）、一个 Spring Boot 后端服务，以及数据库脚本与设计文档。

## 模块概览

| 目录 | 角色 | 技术栈 |
|------|------|--------|
| [`server-snack/`](./server-snack/) | 后端 API 服务 | Spring Boot 4.0.6 · Java 21 · MyBatis-Plus 3.5 · Sa-Token 1.45 · Redis · MySQL 8 · Knife4j 4.6 |
| [`web-snack/`](./web-snack/) | 用户端 H5/PC 前端 | Vue 3.5 · Vite 8 · TypeScript 6 · Element Plus 2.14 · Pinia 3 |
| [`admin-snack/`](./admin-snack/) | 管理后台前端 | Vue 3.5 · Vite 6 · TypeScript 5 · Element Plus 2.9 · Pinia 2 · ECharts 5 |
| [`db/`](./db/) | 数据库脚本与设计文档 | `schema.sql` 建库 + 21 张表 DDL，`seed.sql` 演示数据 |
| [`功能设计文档.md`](./功能设计文档.md) | 完整功能与接口设计（v1.2） | 6 大模块业务与接口说明 |
| [`db/BUSINESS_DESIGN.md`](./db/BUSINESS_DESIGN.md) | 核心业务设计 | WebSocket 客服 + Redis 防超卖方案 |
| [`admin-snack/design-system/`](./design-system/) | 设计系统资源 | 视觉令牌与组件规范 |

## 业务功能

- **用户端**：注册登录、收货地址、购物车、收藏、订单、支付、抢购、客服聊天
- **管理端**：仪表盘、商品 / 分类 / SKU 管理、订单处理、用户管理、优惠券、抢购活动、公告、客服会话
- **跨端共享**：系统公告、用户优惠券、限时抢购（Redis 原子扣减防超卖）

## 快速开始

### 环境要求

| 工具 | 版本 |
|------|------|
| JDK | 21 |
| Maven | 3.8+ |
| Node.js | ≥ 20.19 |
| MySQL | 8.0+ |
| Redis | 6.0+ |

### 1. 初始化数据库

```bash
mysql -u root -p < db/schema.sql   # 建库 + 21 张表
mysql -u root -p < db/seed.sql     # 演示数据（可选）
```

### 2. 启动后端

```bash
cd server-snack
mvn spring-boot:run
# 监听 http://localhost:8080
# 接口文档 http://localhost:8080/doc.html
```

修改 `server-snack/src/main/resources/application.yml` 中的 MySQL / Redis 配置以匹配本地环境。

### 3. 启动管理端

```bash
cd admin-snack
npm install
npm run dev
# 访问 http://localhost:5173
```

### 4. 启动用户端

```bash
cd web-snack
npm install
npm run dev
```

> Vite 已将 `/api` 与 `/uploads` 代理到 `http://localhost:8080`，联调时确认后端已启动。

## 默认账号

| 角色 | 用户名 | 密码 |
|------|--------|------|
| 管理员 | `admin` | `123456` |
| 管理员 | `manager` | `123456` |
| 管理员 | `operator` | `123456` |
| 普通用户 | `user001` ~ `user005` | `123456` |

## 架构与约定

### 后端分层

每个业务模块位于 `server-snack/src/main/java/com/snack/server/module/<name>/`：

```
module/<name>/
├── controller/   # @RestController，用户端 / 管理端分文件
├── service/      # 业务接口
│   └── impl/     # 业务实现
├── mapper/       # MyBatis-Plus BaseMapper
├── entity/       # 数据库表实体
├── dto/req       # 入参（带 jakarta.validation 注解）
├── vo/           # 出参（视图对象）
├── enums/        # 模块内枚举
└── constant/     # 模块内常量
```

跨模块共享：`com.snack.server.{common,config,constant,exception,handler,utils,enums,websocket}`。

### 关键技术点

1. **认证** — Sa-Token（非 JWT），用户端与管理端走两套登录体系（`LoginType.USER` / `LoginType.ADMIN`），通过 `SaRouter.match` 按 URL 区分
2. **统一响应** — `Result<T>` 封装 `{ code, message, data }`，前端 axios 拦截器在 `code === 200` 时直接返回 `data`（已解包约定）
3. **MyBatis-Plus** — 逻辑删除字段 `deleted`（0/1）、主键自增、`createTime`/`updateTime` 自动填充、复杂 SQL 走 XML
4. **防超卖** — Redis `DECR` 原子扣减库存 → 失败返回"已抢完" → 写入异步队列 → 消费端落 MySQL
5. **WebSocket 客服** — Spring WebSocket + STOMP，握手时验证 Token，消息全量落库 `chat_message`

### 前端约定

- **路径别名**：`@` → `src/`
- **自动导入**：`unplugin-auto-import` + `unplugin-vue-components` 处理 Vue / Vue Router / Pinia / Element Plus
- **状态管理**：Pinia + 持久化（管理端 key 为 `snack-admin-user`）
- **请求层**：`utils/request.ts` 已解包响应，401 自动清空登录态并跳登录页
- **设计系统**：主色 `#1E40AF` / `#3B82F6`，圆角 6/10px，背景 `#F8FAFC`

更多细节参见 [`CLAUDE.md`](./CLAUDE.md)。

## 目录结构

```
snack-mall/
├── server-snack/                # 后端服务
├── web-snack/                   # 用户端
├── admin-snack/                 # 管理端
├── db/                          # 数据库脚本与业务设计
│   ├── schema.sql               # 建库 + 21 张表
│   ├── seed.sql                 # 演示数据
│   ├── README.md
│   └── BUSINESS_DESIGN.md       # WebSocket + 防超卖设计
├── 功能设计文档.md               # 完整功能与接口设计
├── design-system/               # 设计系统资源
├── CLAUDE.md                    # Claude Code 项目指引
└── README.md                    # 本文件
```

## 常用命令速查

### 后端

```bash
mvn clean package              # 构建（首次较慢）
mvn spring-boot:run            # 启动
mvn test                       # 跑测试
mvn test -Dtest=类名#方法名    # 单个测试方法
```

### 前端

```bash
npm install
npm run dev                    # 开发服务器
npm run build                  # 类型检查 + 生产构建
npm run type-check             # vue-tsc 类型检查
npm run lint                   # ESLint --fix
npm run format                 # Prettier 格式化
```

## 文档索引

| 文档 | 路径 | 何时读 |
|------|------|--------|
| Claude Code 项目指引 | [`CLAUDE.md`](./CLAUDE.md) | 使用 Claude Code 协助开发前 |
| 功能设计总览 | [`功能设计文档.md`](./功能设计文档.md) | 任何新模块开发前 |
| 业务核心设计 | [`db/BUSINESS_DESIGN.md`](./db/BUSINESS_DESIGN.md) | 客服 / 抢购相关开发前 |
| 数据库表结构 | [`db/schema.sql`](./db/schema.sql) + [`db/README.md`](./db/README.md) | 新增 / 修改实体前 |
| 管理端技术栈 | [`admin-snack/README.md`](./admin-snack/README.md) | 前端环境问题排查 |
| 用户端说明 | [`web-snack/README.md`](./web-snack/README.md) | 用户端环境问题排查 |

## 调试与排错

- **后端启动失败** — 检查 MySQL / Redis 是否启动、端口是否被占用、Knife4j 文档能否打开
- **前端 401 风暴** — 检查 `VITE_API_BASE_URL`、浏览器是否带了 `Authorization` 头、Sa-Token 拦截器路径配置
- **抢购超卖** — 查看 Redis 中 `seckill:stock:*` 键值，对照 [`db/BUSINESS_DESIGN.md`](./db/BUSINESS_DESIGN.md) 流程
- **类型错误** — 运行 `npm run type-check`，不要绕过 `vue-tsc` 直接 build
- **本地上传文件访问不到** — 确认 `WebMvcConfig.addResourceHandlers` 中 `/uploads/**` 映射正确

## 浏览器支持

现代浏览器 + ES2020（Chrome 90+、Edge 90+、Firefox 90+、Safari 14+）

## License

仅用于学习与毕业设计用途。
