feat: 新增口味偏好服务和菜谱分享功能

- 新增 TastePreferenceService 用于管理用户口味偏好设置
- 实现菜谱分享功能,包括 RecipeShareService 和分享页面
- 更新平台工具类以支持鸿蒙系统检测
- 优化收藏页和农场商店页面的UI交互
- 添加新的参考文献和关于页面内容
- 更新API文档至v3.3.0版本
This commit is contained in:
Developer
2026-04-18 08:29:31 +08:00
parent e347b3ca73
commit ceb11d9aac
27 changed files with 6063 additions and 816 deletions

View File

@@ -1,13 +1,18 @@
# 菜谱 API 接口文档
> **版本**: v3.2.1
> **更新日期**: 2026-04-13
> **版本**: v3.3.0
> **更新日期**: 2026-04-18
> **基础地址**: `http://eat.wktyl.com/api/`
---
## 📝 更新日志
### v3.3.0 (2026-04-18)
- **新增点餐助手接口**`kitchen.php` 支持点单CRUD操作JSON文件存储SSE实时推送
- **新增SSE推送端点**`kitchen_sse.php` 实现订单实时更新推送
- **新增菜谱分享页面**`recipe_share.php` 扫码展示菜谱详情,支持统计和管理
### v3.2.1 (2026-04-13)
- **文档同步更新**:完善发现页接口字段说明
- **分类字段补充**:添加 `id` 字段到分类返回结构
@@ -37,6 +42,9 @@
| `stats_full.php` | 全面统计 | 热门、在线、请求统计 |
| `api_check_duplicate.php` | 查重接口 | 菜品、食材、营养成分、内容查重 |
| `diagnose.php` | 诊断工具 | 数据库诊断、运维检查 |
| `kitchen.php` | 点餐助手 | 点单CRUD、JSON存储、过期清理 |
| `kitchen_sse.php` | SSE推送 | 订单实时更新推送 |
| `recipe_share.php` | 菜谱分享 | 扫码展示、访问统计、OG标签 |
| `cache.php` | 缓存系统 | 工具类 |
| `cache_manage.php` | 缓存管理 | 清理、统计、配置 |
| `response.php` | 响应格式 | 工具类 |
@@ -56,6 +64,9 @@
- [全面统计 stats_full.php](#全面统计-stats_fullphp)
- [查重接口 api_check_duplicate.php](#查重接口-api_check_duplicatephp)
- [发现页 api_discover.php](#发现页-api_discoverphp)
- [点餐助手 kitchen.php](#点餐助手-kitchenphp)
- [SSE推送 kitchen_sse.php](#sse推送-kitchen_ssephp)
- [菜谱分享 recipe_share.php](#菜谱分享-recipe_sharephp)
- [功能扩展指南](#功能扩展指南)
- [错误处理](#错误处理)
@@ -1793,6 +1804,479 @@ Widget buildCategoryCard(Map<String, dynamic> category) {
---
## 点餐助手 kitchen.php
### 📋 接口索引
```
GET kitchen.php?act=index
```
**功能**: 获取点餐助手API所有可用端点
**客户端实现**:
```dart
final response = await http.get(Uri.parse('$baseUrl/kitchen.php?act=index'));
```
---
### 创建点单
```
POST kitchen.php?act=create
Content-Type: application/json
{
"items": [{"id": "1", "name": "宫保鸡丁", "quantity": 1}],
"tableNo": "A01",
"peopleCount": 2
}
```
**功能**: 创建新点单
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| items | array | 是 | 菜品列表 |
| tableNo | string | 否 | 桌号 |
| peopleCount | int | 否 | 人数 |
| note | string | 否 | 备注 |
| type | int | 否 | 类型0=用户点餐1=商家推单 |
**返回字段**:
| 字段 | 说明 |
|------|------|
| `id` | 订单唯一ID自动生成 |
| `orderNo` | 订单号(自动生成,如 OD123456789 |
| `status` | 状态0=草稿1=进行中2=已完成3=已取消 |
| `createdAt` | 创建时间ISO 8601格式 |
| `updatedAt` | 更新时间 |
| `createdBy` | 创建者IP |
| `recordCount` | 全局订单计数 |
**客户端实现**:
```dart
final response = await http.post(
Uri.parse('$baseUrl/kitchen.php?act=create'),
headers: {'Content-Type': 'application/json'},
body: json.encode({
'items': [
{'id': '1', 'name': '宫保鸡丁', 'quantity': 1, 'price': 28.0}
],
'tableNo': 'A01',
'peopleCount': 2,
}),
);
```
---
### 📄 获取点单
```
GET kitchen.php?act=get&id=ord_xxx
```
**功能**: 根据订单ID获取点单详情
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| id | string | 是 | 订单ID |
**客户端实现**:
```dart
final response = await http.get(
Uri.parse('$baseUrl/kitchen.php?act=get&id=$orderId')
);
```
---
### ✏️ 更新点单
```
POST kitchen.php?act=update
Content-Type: application/json
{
"id": "ord_xxx",
"items": [...],
"status": 2
}
```
**功能**: 更新现有订单(如修改菜品、更改状态)
**客户端实现**:
```dart
final response = await http.post(
Uri.parse('$baseUrl/kitchen.php?act=update'),
headers: {'Content-Type': 'application/json'},
body: json.encode({
'id': orderId,
'status': 2, // 标记为已完成
}),
);
```
---
### 📋 点单列表
```
GET kitchen.php?act=list&page=1&limit=20&status=1
```
**功能**: 获取点单列表,支持分页和状态筛选
| 参数 | 类型 | 说明 |
|------|------|------|
| page | int | 页码默认1 |
| limit | int | 每页数量默认20最大100 |
| status | int | 状态筛选0=草稿1=进行中2=已完成3=已取消 |
| type | int | 类型筛选0=用户点餐1=商家推单 |
**返回字段**:
| 字段 | 说明 |
|------|------|
| `list` | 订单列表 |
| `total` | 总记录数 |
| `page` | 当前页码 |
| `limit` | 每页数量 |
| `pages` | 总页数 |
**客户端实现**:
```dart
final response = await http.get(
Uri.parse('$baseUrl/kitchen.php?act=list&page=$page&limit=$limit&status=$status')
);
```
---
### 🗑️ 删除点单
```
GET kitchen.php?act=delete&id=ord_xxx
```
**功能**: 删除指定订单
**客户端实现**:
```dart
final response = await http.get(
Uri.parse('$baseUrl/kitchen.php?act=delete&id=$orderId')
);
```
---
### 🧹 清理过期数据
```
GET kitchen.php?act=cleanup&days=30
```
**功能**: 清理超过指定天数的订单数据
| 参数 | 类型 | 说明 |
|------|------|------|
| days | int | 过期天数默认30 |
**返回字段**:
| 字段 | 说明 |
|------|------|
| `deleted_count` | 删除的记录数 |
| `remaining_count` | 剩余记录数 |
| `cutoff_date` | 截止日期 |
| `expire_days` | 过期天数设置 |
**客户端实现**:
```dart
final response = await http.get(
Uri.parse('$baseUrl/kitchen.php?act=cleanup&days=30')
);
```
---
### 🧨 清空全部数据
```
POST kitchen.php?act=clear_all&confirm=yes
```
**功能**: 清空所有点餐数据(需确认参数)
**客户端实现**:
```dart
final response = await http.post(
Uri.parse('$baseUrl/kitchen.php?act=clear_all&confirm=yes')
);
```
---
### 📊 统计信息
```
GET kitchen.php?act=stats
```
**功能**: 获取点餐统计信息
**返回字段**:
| 字段 | 说明 |
|------|------|
| `total_orders` | 历史总订单数 |
| `today_orders` | 今日订单数 |
| `stored_orders` | 当前存储订单数 |
| `by_status` | 按状态分类的订单数 |
| `by_type` | 按类型分类的订单数 |
**客户端实现**:
```dart
final response = await http.get(
Uri.parse('$baseUrl/kitchen.php?act=stats')
);
```
---
## SSE推送 kitchen_sse.php
### 📡 建立SSE连接
```
GET kitchen_sse.php?order_id=ord_xxx
```
**功能**: 建立Server-Sent Events连接实时接收订单更新推送
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| order_id | string | 否 | 监听的订单ID不传则监听全局 |
| last_timestamp | float | 否 | 上次已知时间戳 |
**事件类型**:
| 事件 | 说明 | 数据 |
|------|------|------|
| `connected` | 连接成功 | 连接信息 |
| `order_update` | 订单更新 | 最新订单数据 |
| `order_deleted` | 订单删除 | 删除的订单ID |
| `global_update` | 全局更新 | 时间戳信息 |
| `heartbeat` | 心跳包 | 时间戳和迭代次数 |
| `close` | 连接关闭 | 关闭原因 |
**JavaScript 客户端实现**:
```javascript
const evtSource = new EventSource('kitchen_sse.php?order_id=ord_xxx');
evtSource.addEventListener('connected', (e) => {
console.log('SSE连接已建立', JSON.parse(e.data));
});
evtSource.addEventListener('order_update', (e) => {
const order = JSON.parse(e.data);
console.log('订单更新:', order);
updateOrderUI(order);
});
evtSource.addEventListener('heartbeat', (e) => {
console.log('心跳包', JSON.parse(e.data));
});
evtSource.addEventListener('close', (e) => {
console.log('连接关闭,准备重连');
evtSource.close();
setTimeout(connectSSE, 3000);
});
```
**Dart 客户端实现**:
```dart
import 'package:sse/sse_client.dart';
final client = SseClient(Uri.parse('$baseUrl/kitchen_sse.php?order_id=$orderId'));
client.messages.listen((message) {
final data = json.decode(message);
if (data['event'] == 'order_update') {
updateOrderUI(data['data']);
}
});
```
**注意事项**:
- SSE连接最长保持2分钟超时后自动关闭
- 客户端断开后需重新连接
- 心跳包每10秒发送一次
- 订单更新通过 `kitchen.php` 的写操作触发
---
## 菜谱分享 recipe_share.php
### 📱 分享页面
```
GET recipe_share.php?code=CP032892
GET recipe_share.php?id=32892
```
**功能**: 渲染美观的菜谱分享页面iOS风格支持深色模式
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| code | string | 二选一 | 菜谱编码(如 CP032892 |
| id | int | 二选一 | 菜谱ID |
**页面特性**:
- 🎨 iOS风格设计深色模式自适应
- 📊 自动记录访问统计
- 🏷️ OG标签支持微信/社交媒体分享预览)
- 📱 响应式设计,移动端适配
**客户端实现**:
```dart
// 生成分享链接
String generateShareLink(Recipe recipe) {
if (recipe.code != null) {
return '$baseUrl/recipe_share.php?code=${recipe.code}';
}
return '$baseUrl/recipe_share.php?id=${recipe.id}';
}
// 在WebView中打开
WebView(
initialUrl: generateShareLink(recipe),
);
```
---
### 📊 分享统计
```
GET recipe_share.php?act=stats
```
**功能**: 获取菜谱分享的访问统计
**返回字段**:
| 字段 | 说明 |
|------|------|
| `total_views` | 总访问量 |
| `today_views` | 今日访问量 |
| `today_date` | 统计日期 |
| `recipes` | 各菜谱访问统计按菜谱ID分组 |
**返回示例**:
```json
{
"code": 200,
"data": {
"total_views": 1250,
"today_views": 85,
"today_date": "2026-04-18",
"recipes": {
"r_32892": {
"id": 32892,
"title": "三色玉米沙拉",
"code": "CP032892",
"views": 120,
"first_access": "2026-04-15T10:30:00+08:00",
"last_access": "2026-04-18T14:20:00+08:00"
}
}
}
}
```
**客户端实现**:
```dart
final response = await http.get(
Uri.parse('$baseUrl/recipe_share.php?act=stats')
);
```
---
### 📝 访问日志
```
GET recipe_share.php?act=log&page=1&limit=20
```
**功能**: 获取分享访问日志保留最近200条
| 参数 | 类型 | 说明 |
|------|------|------|
| page | int | 页码默认1 |
| limit | int | 每页数量默认20最大50 |
**返回字段**:
| 字段 | 说明 |
|------|------|
| `list` | 日志列表 |
| `total` | 总日志数 |
| `page` | 当前页码 |
| `limit` | 每页数量 |
**日志字段**:
| 字段 | 说明 |
|------|------|
| `time` | 访问时间 |
| `recipe_id` | 菜谱ID |
| `title` | 菜谱标题 |
| `code` | 菜谱编码 |
| `ip` | 访问者IP |
| `ua` | 用户代理 |
| `referer` | 来源页面 |
**客户端实现**:
```dart
final response = await http.get(
Uri.parse('$baseUrl/recipe_share.php?act=log&page=$page&limit=$limit')
);
```
---
### 🔌 JSON数据接口
```
GET recipe_share.php?act=api&code=CP032892
GET recipe_share.php?act=api&id=32892
```
**功能**: 返回菜谱JSON数据通过调用 api.php 获取,不直接查数据库)
**客户端实现**:
```dart
final response = await http.get(
Uri.parse('$baseUrl/recipe_share.php?act=api&code=$code')
);
```
---
### 📖 接口说明
```
GET recipe_share.php?act=index
```
**功能**: 获取菜谱分享API所有可用端点
---
## 功能扩展指南
本章节详细介绍每个接口返回字段的具体用途、应用场景和可实现的功能。

1401
docs/api/recipe_share.php Normal file

File diff suppressed because it is too large Load Diff