Files
kitchen/scripts/verify_what_to_eat_api.dart
Developer 346fc795f7 完善
2026-04-11 06:05:12 +08:00

186 lines
6.8 KiB
Dart

// 2026-04-11 | verify_what_to_eat_api.dart | 今天吃什么接口验证脚本 | 验证filter_apply/categories/tags接口连通性和数据格式
import 'dart:async';
import 'dart:convert';
import 'dart:io';
const String baseUrl = 'http://eat.wktyl.com/api';
const int timeoutSeconds = 12;
const String reset = '\x1B[0m';
const String green = '\x1B[32m';
const String red = '\x1B[31m';
const String yellow = '\x1B[33m';
const String blue = '\x1B[34m';
const String cyan = '\x1B[36m';
void main() async {
printHeader();
await testFilterApply();
await testCategories();
await testTags();
await testFilterSteps();
await testFilterApplyWithCategory();
printSummary();
}
void printHeader() {
print('$cyan═══════════════════════════════════════════════════$reset');
print('$cyan 🎲 今天吃什么 API 接口验证$reset');
print('$cyan═══════════════════════════════════════════════════$reset');
print('');
}
Future<Map<String, dynamic>?> apiGet(String endpoint, Map<String, String> params) async {
final uri = Uri.parse('$baseUrl$endpoint').replace(queryParameters: params);
final stopwatch = Stopwatch()..start();
try {
final client = HttpClient();
client.connectionTimeout = Duration(seconds: timeoutSeconds);
final request = await client.getUrl(uri);
final response = await request.close();
final body = await response.transform(utf8.decoder).join();
stopwatch.stop();
client.close();
if (response.statusCode != 200) {
print('$red ❌ HTTP ${response.statusCode} (${stopwatch.elapsedMilliseconds}ms)$reset');
return null;
}
final json = jsonDecode(body) as Map<String, dynamic>;
print('$green${stopwatch.elapsedMilliseconds}ms | code=${json['code']}$reset');
return json;
} on TimeoutException {
stopwatch.stop();
print('$red ❌ 超时 (${stopwatch.elapsedMilliseconds}ms)$reset');
return null;
} catch (e) {
stopwatch.stop();
print('$red ❌ 错误: $e (${stopwatch.elapsedMilliseconds}ms)$reset');
return null;
}
}
Future<void> testFilterApply() async {
print('$yellow▶ 测试 1: filter_apply (无筛选随机推荐)$reset');
final result = await apiGet('/api_what_to_eat.php', {'act': 'filter_apply', 'count': '5'});
if (result != null) {
final data = result['data'];
if (data is Map) {
final recipes = data['recipes'] as List?;
print(' recipes count: ${recipes?.length ?? 0}');
if (recipes != null && recipes.isNotEmpty) {
final first = recipes.first as Map<String, dynamic>;
print(' first recipe: id=${first['id']}, title=${first['title']}');
print(' fields: ${first.keys.take(15).join(', ')}...');
}
print(' total_matched: ${data['total_matched']}');
print(' filters_applied: ${data['filters_applied']}');
} else if (data is List) {
print(' data is List, count: ${data.length}');
if (data.isNotEmpty) {
final first = data.first as Map<String, dynamic>;
print(' first: id=${first['id']}, title=${first['title']}');
}
}
}
print('');
}
Future<void> testCategories() async {
print('$yellow▶ 测试 2: categories (分类列表)$reset');
final result = await apiGet('/api.php', {'act': 'categories'});
if (result != null) {
final data = result['data'];
if (data is List) {
print(' categories count: ${data.length}');
for (final cat in data.take(5)) {
final m = cat as Map<String, dynamic>;
print(' - id=${m['id'] ?? m['cate_id']}, name=${m['name'] ?? m['cate_name']}, parent_id=${m['parent_id']}');
final children = m['children'] as List?;
if (children != null && children.isNotEmpty) {
print(' children: ${children.length}');
for (final child in children.take(3)) {
final cm = child as Map<String, dynamic>;
print(' - id=${cm['id'] ?? cm['cate_id']}, name=${cm['name'] ?? cm['cate_name']}');
}
}
}
} else {
print(' data type: ${data.runtimeType}');
}
}
print('');
}
Future<void> testTags() async {
print('$yellow▶ 测试 3: tags (标签列表)$reset');
final result = await apiGet('/api.php', {'act': 'tags'});
if (result != null) {
final data = result['data'];
if (data is List) {
print(' tags count: ${data.length}');
for (final tag in data.take(5)) {
final m = tag as Map<String, dynamic>;
print(' - id=${m['id'] ?? m['tag_id']}, name=${m['name'] ?? m['tag_name']}');
}
} else {
print(' data type: ${data.runtimeType}');
}
}
print('');
}
Future<void> testFilterSteps() async {
print('$yellow▶ 测试 4: filter_steps (筛选步骤)$reset');
final result = await apiGet('/api_what_to_eat.php', {'act': 'filter_steps'});
if (result != null) {
final data = result['data'];
if (data is Map) {
print(' keys: ${data.keys.join(', ')}');
final steps = data['steps'] as List?;
if (steps != null) {
print(' steps count: ${steps.length}');
for (final step in steps.take(3)) {
final m = step as Map<String, dynamic>;
print(' - step: ${m['step']}, title: ${m['title']}, type: ${m['type']}');
final options = m['options'] as List? ?? m['available_options'] as List? ?? [];
print(' options: ${options.length}');
}
}
final available = data['available_options'] as List?;
if (available != null) {
print(' available_options count: ${available.length}');
}
}
}
print('');
}
Future<void> testFilterApplyWithCategory() async {
print('$yellow▶ 测试 5: filter_apply (带分类筛选)$reset');
final result = await apiGet('/api_what_to_eat.php', {'act': 'filter_apply', 'category': '1', 'count': '3'});
if (result != null) {
final data = result['data'];
if (data is Map) {
final recipes = data['recipes'] as List?;
print(' recipes count: ${recipes?.length ?? 0}');
if (recipes != null && recipes.isNotEmpty) {
for (final r in recipes.take(3)) {
final m = r as Map<String, dynamic>;
print(' - id=${m['id']}, title=${m['title']}');
}
}
} else if (data is List) {
print(' data is List, count: ${data.length}');
}
}
print('');
}
void printSummary() {
print('$cyan═══════════════════════════════════════════════════$reset');
print('$cyan 验证完成$reset');
print('$cyan═══════════════════════════════════════════════════$reset');
}