Files
frontend/API_GUIDE.md

697 lines
19 KiB
Markdown
Raw Permalink Normal View History

# 云印享 - 前端 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