Files
frontend/API_GUIDE.md

697 lines
19 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.
# 云印享 - 前端 API 使用指南
本文档面向前端开发者,详细说明如何调用云印享后端 API 接口。后端基于 gRPC 构建,前端通过 HTTP RESTful 风格接口进行通信。
## 目录
- [基础配置](#基础配置)
- [认证服务 (Auth)](#认证服务-auth)
- [文件管理服务 (File)](#文件管理服务-file)
- [订单服务 (Order)](#订单服务-order)
- [打印服务 (Print)](#打印服务-print)
- [支付服务 (Pay)](#支付服务-pay)
- [价目表服务 (Price)](#价目表服务-price)
- [错误处理](#错误处理)
- [注意事项](#注意事项)
---
## 基础配置
### API 基础地址
API 地址配置在 [`src/config/api.ts`](src/config/api.ts:1) 中:
```typescript
const DEV_API_URL = "http://localhost:8080";
const PROD_API_URL = "http://localhost:8080";
export const API_BASE_URL =
process.env.NODE_ENV === "development" ? DEV_API_URL : PROD_API_URL;
```
### 请求封装
项目已封装统一的请求工具 [`src/utils/request.ts`](src/utils/request.ts:1),自动处理:
- Token 注入Bearer 认证)
- 401 未授权处理(自动登出)
- 错误捕获
```typescript
// 使用示例
import { request } from "../utils/request";
const response = await request({
url: "/auth/userinfo",
method: "GET",
});
```
### 统一响应格式
所有 API 返回遵循统一格式:
```typescript
interface ApiResponse<T = any> {
code: number; // 状态码0 表示成功
message: string; // 响应消息
data: T; // 实际数据
}
```
---
## 认证服务 (Auth)
**基础路径**: `/auth`
### 1. 微信登录
获取用户访问令牌。
| 项目 | 说明 |
| ------------ | ------------------------------------------------------------------- |
| **接口地址** | `POST /auth/login` |
| **请求参数** | `{ code: string }` - 微信登录凭证 code |
| **返回数据** | `{ accessToken: string; refreshToken: string; userInfo: UserInfo }` |
**代码示例**
```typescript
import { authApi } from "./api/auth";
// 调用登录接口
const response = await authApi.login(wxCode);
// response.accessToken // 访问令牌
// response.refreshToken // 刷新令牌
// response.userInfo // 用户信息
```
**响应示例**
```json
{
"accessToken": "eyJhbGciOiJIUzI1NiIs...",
"refreshToken": "dGhpcyBpcyBhIHJlZnJl...",
"userInfo": {
"id": 1,
"openid": "oXXXX-xxxxx",
"nickname": "用户昵称",
"avatar": "https://xxx.com/avatar.jpg",
"balance": 10.5,
"createdAt": "2024-01-01T00:00:00Z"
}
}
```
### 2. 刷新 Token
使用刷新令牌获取新的访问令牌。
| 项目 | 说明 |
| ------------ | -------------------------- |
| **接口地址** | `POST /auth/refresh` |
| **请求参数** | `{ refreshToken: string }` |
| **返回数据** | `{ accessToken: string }` |
**代码示例**
```typescript
const { accessToken } = await authApi.refreshToken(refreshToken);
```
### 3. 获取用户信息
获取当前登录用户的详细信息。
| 项目 | 说明 |
| ------------ | --------------------------------- |
| **接口地址** | `GET /auth/userinfo` |
| **请求参数** | 无 |
| **返回数据** | [`UserInfo`](src/types/user.ts:1) |
**代码示例**
```typescript
const userInfo = await authApi.getUserInfo();
console.log(userInfo.nickname, userInfo.balance);
```
### 4. 更新用户信息
更新用户昵称和头像。
| 项目 | 说明 |
| ------------ | ---------------------------------------- |
| **接口地址** | `POST /auth/update` |
| **请求参数** | `{ nickname?: string; avatar?: string }` |
| **返回数据** | [`UserInfo`](src/types/user.ts:1) |
**代码示例**
```typescript
const updatedUser = await authApi.updateUser({
nickname: "新昵称",
avatar: "https://new-avatar.jpg",
});
```
### 5. 手机号登录
使用手机号和短信验证码登录。
| 项目 | 说明 |
| ------------ | ------------------------------------------------------------------- |
| **接口地址** | `POST /auth/phone/login` |
| **请求参数** | `{ phone: string; code: string }` |
| **返回数据** | `{ accessToken: string; refreshToken: string; userInfo: UserInfo }` |
**代码示例**
```typescript
import { authApi } from "./api/auth";
// 调用手机号登录接口
const response = await authApi.phoneLogin({
phone: "13800138000",
code: "123456",
});
```
### 6. 发送短信验证码
发送短信验证码到指定手机号。
| 项目 | 说明 |
| ------------ | --------------------- |
| **接口地址** | `POST /auth/sms/code` |
| **请求参数** | `{ phone: string }` |
| **返回数据** | `void` |
**代码示例**
```typescript
import { authApi } from "./api/auth";
// 发送短信验证码
await authApi.sendSmsCode({ phone: "13800138000" });
```
---
## 文件管理服务 (File)
**基础路径**: `/file`
### 1. 上传文件
支持分片上传,使用 Taro 原生上传能力。
| 项目 | 说明 |
| ------------ | ------------------------------------- |
| **接口地址** | `POST /file/upload` |
| **请求参数** | `filePath: string` - 本地文件路径 |
| **返回数据** | `{ fileId: number; fileUrl: string }` |
**代码示例**
```typescript
import { fileApi } from "./api/file";
// 上传文件
const result = await fileApi.upload(tempFilePath);
console.log(result.fileId, result.fileUrl);
```
### 2. 获取文件列表
分页获取用户上传的文件列表。
| 项目 | 说明 |
| ------------ | ----------------------------------------------------------------- |
| **接口地址** | `GET /file/list` |
| **请求参数** | `{ page?: number; pageSize?: number }` - 默认 page=1, pageSize=20 |
| **返回数据** | `{ files: FileInfo[]; total: number }` |
**代码示例**
```typescript
const { files, total } = await fileApi.getFileList(1, 20);
```
### 3. 获取文件详情
| 项目 | 说明 |
| ------------ | --------------------------------- |
| **接口地址** | `GET /file/:fileId` |
| **请求参数** | `fileId: number` |
| **返回数据** | [`FileInfo`](src/types/file.ts:1) |
**代码示例**
```typescript
const fileInfo = await fileApi.getFile(123);
```
### 4. 删除文件
| 项目 | 说明 |
| ------------ | ---------------------- |
| **接口地址** | `DELETE /file/:fileId` |
| **请求参数** | `fileId: number` |
| **返回数据** | `void` |
**代码示例**
```typescript
await fileApi.deleteFile(123);
```
### 5. 添加水印
| 项目 | 说明 |
| ------------ | ----------------------------------------- |
| **接口地址** | `POST /file/:fileId/watermark` |
| **请求参数** | `fileId: number`, `{ watermark: string }` |
| **返回数据** | `{ watermarkUrl: string }` |
**代码示例**
```typescript
const { watermarkUrl } = await fileApi.addWatermark(123, "仅供打印使用");
```
---
## 订单服务 (Order)
**基础路径**: `/order`
### 1. 创建订单
| 项目 | 说明 |
| ------------ | --------------------------------------------- |
| **接口地址** | `POST /order/create` |
| **请求参数** | [`CreateOrderRequest`](src/types/order.ts:22) |
| **返回数据** | [`Order`](src/types/order.ts:4) |
**请求参数结构**
```typescript
{
fileId: number; // 文件ID
printerId: number; // 打印机ID
printType: "A4" | "A3" | "照片"; // 打印类型
colorType: "黑白" | "彩色"; // 颜色类型
copies: number; // 份数
}
```
**代码示例**
```typescript
import { orderApi } from "./api/order";
const order = await orderApi.createOrder({
fileId: 123,
printerId: 1,
printType: "A4",
colorType: "黑白",
copies: 2,
});
```
### 2. 获取订单详情
| 项目 | 说明 |
| ------------ | ------------------------------- |
| **接口地址** | `GET /order/:orderId` |
| **请求参数** | `orderId: number` |
| **返回数据** | [`Order`](src/types/order.ts:4) |
**代码示例**
```typescript
const order = await orderApi.getOrder(456);
```
### 3. 获取订单列表
| 项目 | 说明 |
| ------------ | -------------------------------------- |
| **接口地址** | `GET /order/list` |
| **请求参数** | `{ page?: number; pageSize?: number }` |
| **返回数据** | `{ orders: Order[]; total: number }` |
**代码示例**
```typescript
const { orders, total } = await orderApi.getOrderList(1, 10);
```
### 4. 更新订单状态
| 项目 | 说明 |
| ------------ | --------------------------------------- |
| **接口地址** | `PUT /order/:orderId/status` |
| **请求参数** | `orderId: number`, `{ status: number }` |
| **返回数据** | [`Order`](src/types/order.ts:4) |
**订单状态枚举**
| 值 | 状态 |
|----|------|
| 0 | 待支付 |
| 1 | 已支付 |
| 2 | 打印中 |
| 3 | 已完成 |
| 4 | 已取消 |
**代码示例**
```typescript
await orderApi.updateOrderStatus(456, 1); // 标记为已支付
```
### 5. 取消订单
| 项目 | 说明 |
| ------------ | ------------------------------- |
| **接口地址** | `PUT /order/:orderId/cancel` |
| **请求参数** | `orderId: number` |
| **返回数据** | [`Order`](src/types/order.ts:4) |
**代码示例**
```typescript
await orderApi.cancelOrder(456);
```
---
## 打印服务 (Print)
**基础路径**: `/print`
### 1. 获取打印机列表
| 项目 | 说明 |
| ------------ | ------------------------------------- |
| **接口地址** | `GET /print/printers` |
| **请求参数** | 无 |
| **返回数据** | [`Printer[]`](src/types/printer.ts:3) |
**代码示例**
```typescript
import { printerApi } from "./api/printer";
const printers = await printerApi.getPrinters();
```
### 2. 获取打印机状态
| 项目 | 说明 |
| ------------ | -------------------------------------- |
| **接口地址** | `GET /print/printer/:printerId/status` |
| **请求参数** | `printerId: number` |
| **返回数据** | [`Printer`](src/types/printer.ts:3) |
**打印机状态枚举**
| 值 | 状态 |
|----|------|
| 0 | 空闲 |
| 1 | 打印中 |
| 2 | 离线 |
**代码示例**
```typescript
const printer = await printerApi.getPrinterStatus(1);
```
### 3. 注册打印机
| 项目 | 说明 |
| ------------ | ------------------------------------ |
| **接口地址** | `POST /print/printer/register` |
| **请求参数** | `{ name: string; location: string }` |
| **返回数据** | [`Printer`](src/types/printer.ts:3) |
**代码示例**
```typescript
const printer = await printerApi.registerPrinter("打印机1", "一楼大厅");
```
### 4. 提交打印任务
| 项目 | 说明 |
| ------------ | ---------------------------------------- |
| **接口地址** | `POST /print/job/submit` |
| **请求参数** | `{ orderId: number; printerId: number }` |
| **返回数据** | `{ jobId: number }` |
**代码示例**
```typescript
const { jobId } = await printerApi.submitPrintJob(456, 1);
```
### 5. 取消打印任务
| 项目 | 说明 |
| ------------ | ------------------------------ |
| **接口地址** | `PUT /print/job/:jobId/cancel` |
| **请求参数** | `jobId: number` |
| **返回数据** | `void` |
**代码示例**
```typescript
await printerApi.cancelPrintJob(789);
```
---
## 支付服务 (Pay)
**基础路径**: `/pay`
### 1. 创建微信支付订单
| 项目 | 说明 |
| ------------ | ---------------------------------------------------------------------------------------------- |
| **接口地址** | `POST /pay/create` |
| **请求参数** | `{ orderId: number }` |
| **返回数据** | `{ prepayId: string; paySign: string; timeStamp: string; nonceStr: string; signType: string }` |
**代码示例**
```typescript
import { payApi } from "./api/pay";
const payParams = await payApi.createWxPayOrder(456);
// 使用返回参数调起微信支付
```
### 2. 查询支付状态
| 项目 | 说明 |
| ------------ | ------------------------- |
| **接口地址** | `GET /pay/query/:orderId` |
| **请求参数** | `orderId: number` |
| **返回数据** | `{ status: number }` |
**支付状态枚举**
| 值 | 状态 |
|----|------|
| 0 | 待支付 |
| 1 | 支付中 |
| 2 | 成功 |
| 3 | 失败 |
**代码示例**
```typescript
const { status } = await payApi.queryPayStatus(456);
```
### 3. 余额支付
| 项目 | 说明 |
| ------------ | ---------------------- |
| **接口地址** | `POST /pay/balance` |
| **请求参数** | `{ orderId: number }` |
| **返回数据** | `{ success: boolean }` |
**代码示例**
```typescript
const { success } = await payApi.payByBalance(456);
```
---
## 价目表服务 (Price)
**基础路径**: `/price`
### 1. 获取价目表
| 项目 | 说明 |
| ------------ | ------------------------------------- |
| **接口地址** | `GET /price/list` |
| **请求参数** | 无 |
| **返回数据** | [`PriceItem[]`](src/types/price.ts:3) |
**代码示例**
```typescript
import { priceApi } from "./api/price";
const priceList = await priceApi.getPriceList();
```
**价目表示例**
```json
[
{ "id": 1, "name": "A4黑白打印", "type": "A4", "price": 0.1, "unit": "页" },
{ "id": 2, "name": "A4彩色打印", "type": "A4", "price": 0.3, "unit": "页" },
{ "id": 3, "name": "A3黑白打印", "type": "A3", "price": 0.2, "unit": "页" },
{ "id": 4, "name": "A3彩色打印", "type": "A3", "price": 0.6, "unit": "页" },
{ "id": 5, "name": "照片打印", "type": "照片", "price": 2.0, "unit": "张" }
]
```
---
## 错误处理
### HTTP 状态码
| 状态码 | 说明 | 处理建议 |
| ------ | -------------- | ---------------------------- |
| 200 | 请求成功 | 正常处理响应数据 |
| 400 | 请求参数错误 | 检查请求参数格式 |
| 401 | 未授权 | Token 过期或无效,需重新登录 |
| 403 | 禁止访问 | 权限不足 |
| 404 | 资源不存在 | 检查请求的资源 ID |
| 500 | 服务器内部错误 | 联系后端排查 |
### 统一错误处理
[`request.ts`](src/utils/request.ts:1) 已封装错误处理逻辑:
```typescript
try {
const result = await orderApi.createOrder(orderData);
} catch (error) {
if (error.message === "Unauthorized") {
// 处理未授权,跳转登录
Taro.redirectTo({ url: "/pages/login/index" });
} else {
// 显示错误提示
Taro.showToast({ title: error.message, icon: "none" });
}
}
```
---
## 注意事项
### 1. 认证机制
- 所有需要用户身份的接口都需要在请求头中携带 `Authorization: Bearer <token>`
- Token 由 [`request.ts`](src/utils/request.ts:16) 自动注入,无需手动处理
- Token 过期时,服务器返回 401前端自动触发登出
### 2. 文件上传
- 使用 Taro 原生 `uploadFile` API支持断点续传
- 上传成功后返回 `fileId``fileUrl`,用于后续订单创建
### 3. 分页查询
- 文件列表和订单列表接口支持分页
- 默认 `page=1`, `pageSize=20`
- 响应中包含 `total` 字段表示总记录数
### 4. 状态枚举
- 订单状态、支付状态、打印机状态均使用数字枚举
- 类型定义文件(如 [`order.ts`](src/types/order.ts:1))中提供了状态映射表,便于显示
### 5. 数据格式
- 所有时间字段使用 ISO 8601 格式字符串(如 `"2024-01-01T12:00:00Z"`
- 价格字段使用数字类型,单位为元(如 `0.10` 表示 0.1 元)
### 6. 开发环境配置
- 开发环境 API 地址:`http://localhost:8080`
- 确保后端服务已启动且端口正确
- 如需修改地址,编辑 [`src/config/api.ts`](src/config/api.ts:1)
### 7. 类型安全
- 所有 API 接口都有完整的 TypeScript 类型定义
- 导入对应的类型文件(如 `import type { Order } from '../types'`
- 使用类型提示可以减少运行时错误
---
## 快速开始示例
以下是一个完整的打印流程示例:
```typescript
import { authApi } from "./api/auth";
import { fileApi } from "./api/file";
import { orderApi } from "./api/order";
import { printerApi } from "./api/printer";
import { payApi } from "./api/pay";
// 1. 登录
const { accessToken, userInfo } = await authApi.login(wxCode);
// 2. 上传文件
const { fileId } = await fileApi.upload(tempFilePath);
// 3. 获取打印机列表
const printers = await printerApi.getPrinters();
const availablePrinter = printers.find((p) => p.status === 0);
// 4. 创建订单
const order = await orderApi.createOrder({
fileId,
printerId: availablePrinter.id,
printType: "A4",
colorType: "黑白",
copies: 2,
});
// 5. 发起支付
const payParams = await payApi.createWxPayOrder(order.id);
// 调起微信支付...
// 6. 查询支付状态
const { status } = await payApi.queryPayStatus(order.id);
if (status === 2) {
// 支付成功,提交打印任务
await printerApi.submitPrintJob(order.id, availablePrinter.id);
}
```
---
## 更新日志
- 2024-01-01: 初始版本,基于后端 README 和前端现有实现整理
---
**文档维护**: 前端开发团队
**最后更新**: 2024-01-01