release 1.31
This commit is contained in:
@@ -1,113 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from PIL import Image, ImageDraw, ImageFilter
|
||||
import os
|
||||
|
||||
def add_border_and_resize(input_path, output_path, target_size=(1920, 1080), border_color=(255, 255, 255), border_width=20):
|
||||
img = Image.open(input_path)
|
||||
original_width, original_height = img.size
|
||||
aspect_ratio = original_width / original_height
|
||||
target_aspect = target_size[0] / target_size[1]
|
||||
|
||||
if aspect_ratio > target_aspect:
|
||||
new_width = target_size[0] - border_width * 2
|
||||
new_height = int(new_width / aspect_ratio)
|
||||
else:
|
||||
new_height = target_size[1] - border_width * 2
|
||||
new_width = int(new_height * aspect_ratio)
|
||||
|
||||
img_resized = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
|
||||
output_img = Image.new('RGB', target_size, border_color)
|
||||
paste_x = (target_size[0] - new_width) // 2
|
||||
paste_y = (target_size[1] - new_height) // 2
|
||||
|
||||
shadow_offset = 8
|
||||
shadow_rect = [
|
||||
paste_x + shadow_offset,
|
||||
paste_y + shadow_offset,
|
||||
paste_x + new_width + shadow_offset,
|
||||
paste_y + new_height + shadow_offset
|
||||
]
|
||||
shadow_layer = Image.new('RGBA', target_size, (0, 0, 0, 0))
|
||||
shadow_draw = ImageDraw.Draw(shadow_layer)
|
||||
shadow_draw.rectangle(shadow_rect, fill=(0, 0, 0, 60))
|
||||
shadow_blurred = shadow_layer.filter(ImageFilter.GaussianBlur(radius=10))
|
||||
|
||||
final_image = Image.new('RGB', target_size, border_color)
|
||||
|
||||
if shadow_blurred.mode == 'RGBA':
|
||||
final_image.paste(shadow_blurred, (0, 0), shadow_blurred)
|
||||
else:
|
||||
final_rgb_shadow = shadow_blurred.convert('RGB')
|
||||
final_image.paste(final_rgb_shadow, (0, 0))
|
||||
|
||||
final_image.paste(img_resized, (paste_x, paste_y))
|
||||
|
||||
draw = ImageDraw.Draw(final_image)
|
||||
rect = [paste_x - 2, paste_y - 2, paste_x + new_width + 2, paste_y + new_height + 2]
|
||||
for i in range(3):
|
||||
offset = i + 1
|
||||
current_rect = [
|
||||
rect[0] - offset,
|
||||
rect[1] - offset,
|
||||
rect[2] + offset,
|
||||
rect[3] + offset
|
||||
]
|
||||
draw.rectangle(current_rect, outline=(180, 200, 220))
|
||||
|
||||
for i in range(border_width):
|
||||
current_rect = [
|
||||
rect[0] - i - 3,
|
||||
rect[1] - i - 3,
|
||||
rect[2] + i + 3,
|
||||
rect[3] + i + 3
|
||||
]
|
||||
alpha = int(255 * (1 - i / border_width))
|
||||
color_with_alpha = (200 + i*2, 210 + i*2, 230 + i*2)
|
||||
draw.rectangle(current_rect, outline=color_with_alpha)
|
||||
|
||||
final_image.save(output_path, quality=95)
|
||||
print(f'[OK] Processed: {os.path.basename(input_path)} -> {output_path}')
|
||||
return True
|
||||
|
||||
def main():
|
||||
input_files = [
|
||||
r'e:\project\flutter\f\mom_kitchen\docs\design\1.jpg',
|
||||
r'e:\project\flutter\f\mom_kitchen\docs\design\2.jpg',
|
||||
r'e:\project\flutter\f\mom_kitchen\docs\design\3.jpg',
|
||||
r'e:\project\flutter\f\mom_kitchen\docs\design\4.jpg',
|
||||
r'e:\project\flutter\f\mom_kitchen\docs\design\5.jpg',
|
||||
]
|
||||
|
||||
output_dir = r'e:\project\flutter\f\mom_kitchen\docs\design\processed'
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
print('='*50)
|
||||
print('Image Border Processing Script')
|
||||
print(f'Target Size: 1920 x 1080 px')
|
||||
print(f'Processing: {len(input_files)} images')
|
||||
print('='*50)
|
||||
print()
|
||||
|
||||
success_count = 0
|
||||
for input_file in input_files:
|
||||
if os.path.exists(input_file):
|
||||
filename = os.path.basename(input_file)
|
||||
output_path = os.path.join(output_dir, f'bordered_{filename}')
|
||||
try:
|
||||
add_border_and_resize(input_file, output_path)
|
||||
success_count += 1
|
||||
except Exception as e:
|
||||
print(f'[ERROR] Failed to process: {filename} - {str(e)}')
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
else:
|
||||
print(f'[WARNING] File not found: {input_file}')
|
||||
|
||||
print()
|
||||
print('='*50)
|
||||
print(f'[DONE] Processed {success_count}/{len(input_files)} images successfully!')
|
||||
print(f'Output directory: {output_dir}')
|
||||
print('='*50)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,111 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from PIL import Image, ImageDraw, ImageFilter
|
||||
import os
|
||||
|
||||
def add_border_and_resize(input_path, output_path, target_size=(1080, 1920), border_color=(255, 255, 255), border_width=20):
|
||||
img = Image.open(input_path)
|
||||
original_width, original_height = img.size
|
||||
aspect_ratio = original_width / original_height
|
||||
target_aspect = target_size[0] / target_size[1]
|
||||
|
||||
if aspect_ratio > target_aspect:
|
||||
new_width = target_size[0] - border_width * 2
|
||||
new_height = int(new_width / aspect_ratio)
|
||||
else:
|
||||
new_height = target_size[1] - border_width * 2
|
||||
new_width = int(new_height * aspect_ratio)
|
||||
|
||||
img_resized = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
|
||||
paste_x = (target_size[0] - new_width) // 2
|
||||
paste_y = (target_size[1] - new_height) // 2
|
||||
|
||||
shadow_offset = 8
|
||||
shadow_rect = [
|
||||
paste_x + shadow_offset,
|
||||
paste_y + shadow_offset,
|
||||
paste_x + new_width + shadow_offset,
|
||||
paste_y + new_height + shadow_offset
|
||||
]
|
||||
shadow_layer = Image.new('RGBA', target_size, (0, 0, 0, 0))
|
||||
shadow_draw = ImageDraw.Draw(shadow_layer)
|
||||
shadow_draw.rectangle(shadow_rect, fill=(0, 0, 0, 60))
|
||||
shadow_blurred = shadow_layer.filter(ImageFilter.GaussianBlur(radius=10))
|
||||
|
||||
final_image = Image.new('RGB', target_size, border_color)
|
||||
|
||||
if shadow_blurred.mode == 'RGBA':
|
||||
final_image.paste(shadow_blurred, (0, 0), shadow_blurred)
|
||||
else:
|
||||
final_rgb_shadow = shadow_blurred.convert('RGB')
|
||||
final_image.paste(final_rgb_shadow, (0, 0))
|
||||
|
||||
final_image.paste(img_resized, (paste_x, paste_y))
|
||||
|
||||
draw = ImageDraw.Draw(final_image)
|
||||
rect = [paste_x - 2, paste_y - 2, paste_x + new_width + 2, paste_y + new_height + 2]
|
||||
for i in range(3):
|
||||
offset = i + 1
|
||||
current_rect = [
|
||||
rect[0] - offset,
|
||||
rect[1] - offset,
|
||||
rect[2] + offset,
|
||||
rect[3] + offset
|
||||
]
|
||||
draw.rectangle(current_rect, outline=(180, 200, 220))
|
||||
|
||||
for i in range(border_width):
|
||||
current_rect = [
|
||||
rect[0] - i - 3,
|
||||
rect[1] - i - 3,
|
||||
rect[2] + i + 3,
|
||||
rect[3] + i + 3
|
||||
]
|
||||
color_with_alpha = (200 + i*2, 210 + i*2, 230 + i*2)
|
||||
draw.rectangle(current_rect, outline=color_with_alpha)
|
||||
|
||||
final_image.save(output_path, quality=95)
|
||||
print(f'[OK] Processed: {os.path.basename(input_path)} -> {output_path}')
|
||||
return True
|
||||
|
||||
def main():
|
||||
input_files = [
|
||||
r'e:\project\flutter\f\mom_kitchen\docs\design\1.jpg',
|
||||
r'e:\project\flutter\f\mom_kitchen\docs\design\2.jpg',
|
||||
r'e:\project\flutter\f\mom_kitchen\docs\design\3.jpg',
|
||||
r'e:\project\flutter\f\mom_kitchen\docs\design\4.jpg',
|
||||
r'e:\project\flutter\f\mom_kitchen\docs\design\5.jpg',
|
||||
]
|
||||
|
||||
output_dir = r'e:\project\flutter\f\mom_kitchen\docs\design\processed\portrait'
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
print('='*50)
|
||||
print('Image Border Processing Script (Portrait Mode)')
|
||||
print(f'Target Size: 1080 x 1920 px (Vertical)')
|
||||
print(f'Processing: {len(input_files)} images')
|
||||
print('='*50)
|
||||
print()
|
||||
|
||||
success_count = 0
|
||||
for input_file in input_files:
|
||||
if os.path.exists(input_file):
|
||||
filename = os.path.basename(input_file)
|
||||
output_path = os.path.join(output_dir, f'bordered_portrait_{filename}')
|
||||
try:
|
||||
add_border_and_resize(input_file, output_path)
|
||||
success_count += 1
|
||||
except Exception as e:
|
||||
print(f'[ERROR] Failed to process: {filename} - {str(e)}')
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
else:
|
||||
print(f'[WARNING] File not found: {input_file}')
|
||||
|
||||
print()
|
||||
print('='*50)
|
||||
print(f'[DONE] Processed {success_count}/{len(input_files)} images successfully!')
|
||||
print(f'Output directory: {output_dir}')
|
||||
print('='*50)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,64 +0,0 @@
|
||||
// 2026-04-13 | test_detail_id.dart | 详情页ID测试 | 验证详情页API返回数据
|
||||
// 运行: dart run scripts/test_detail_id.dart
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
const String baseUrl = 'https://eat.wktyl.com/api';
|
||||
|
||||
Future<void> main() async {
|
||||
print('=== 详情页ID测试 ===\n');
|
||||
|
||||
// 测试ID 32390(从日志中获取)
|
||||
const testId = 32390;
|
||||
|
||||
print('📡 测试ID: $testId');
|
||||
await testDetailApi(testId);
|
||||
|
||||
// 再测试一个有效的ID
|
||||
print('\n📡 测试另一个ID: 46518');
|
||||
await testDetailApi(46518);
|
||||
}
|
||||
|
||||
Future<void> testDetailApi(int id) async {
|
||||
final client = HttpClient();
|
||||
try {
|
||||
final url = Uri.parse('$baseUrl/api.php?act=full&id=$id&_refresh=1');
|
||||
print(' 请求URL: $url');
|
||||
|
||||
final request = await client.getUrl(url);
|
||||
request.headers.set('Accept', 'application/json');
|
||||
|
||||
final response = await request.close();
|
||||
final body = await response.transform(utf8.decoder).join();
|
||||
|
||||
print(' 状态码: ${response.statusCode}');
|
||||
print(' 响应长度: ${body.length}');
|
||||
|
||||
if (body.isEmpty) {
|
||||
print(' ❌ 响应体为空');
|
||||
return;
|
||||
}
|
||||
|
||||
final json = jsonDecode(body) as Map<String, dynamic>;
|
||||
print(' code: ${json['code']}');
|
||||
print(' message: ${json['message']}');
|
||||
|
||||
final data = json['data'] as Map<String, dynamic>?;
|
||||
if (data == null) {
|
||||
print(' ❌ data字段为null');
|
||||
return;
|
||||
}
|
||||
|
||||
print(' ✅ 数据加载成功');
|
||||
print(' id: ${data['id']}');
|
||||
print(' title: ${data['title']}');
|
||||
print(' pic_id: ${data['pic_id']}');
|
||||
print(' cover: ${data['cover']}');
|
||||
print(' intro: ${(data['intro'] as String?)?.substring(0, (data['intro'] as String?)?.length.clamp(0, 50) ?? 0)}...');
|
||||
} catch (e) {
|
||||
print(' ❌ 请求错误: $e');
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
// 2026-04-14 | test_discover_image.dart | Discover图片数据验证 | 验证api_discover.php返回的cover/picId字段
|
||||
// 运行: dart run scripts/test_discover_image.dart
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
const String baseUrl = 'https://eat.wktyl.com/api';
|
||||
|
||||
Future<void> main() async {
|
||||
print('=== Discover 图片数据验证 ===\n');
|
||||
|
||||
await testDiscoverApi();
|
||||
await testDetailApi();
|
||||
await testImageUrl();
|
||||
}
|
||||
|
||||
Future<void> testDiscoverApi() async {
|
||||
print('📡 测试 api_discover.php 接口');
|
||||
final client = HttpClient();
|
||||
try {
|
||||
final url = Uri.parse('$baseUrl/api_discover.php?total=10');
|
||||
print(' 请求URL: $url');
|
||||
|
||||
final request = await client.getUrl(url);
|
||||
request.headers.set('Accept', 'application/json');
|
||||
|
||||
final response = await request.close();
|
||||
final body = await response.transform(utf8.decoder).join();
|
||||
|
||||
if (body.isEmpty) {
|
||||
print(' ❌ 响应体为空');
|
||||
return;
|
||||
}
|
||||
|
||||
final json = jsonDecode(body) as Map<String, dynamic>;
|
||||
print(' code: ${json['code']}');
|
||||
|
||||
final data = json['data'] as Map<String, dynamic>?;
|
||||
if (data == null) {
|
||||
print(' ❌ data字段为null');
|
||||
return;
|
||||
}
|
||||
|
||||
final recipes = data['recipes'] as List?;
|
||||
if (recipes == null || recipes.isEmpty) {
|
||||
print(' ❌ recipes为空');
|
||||
return;
|
||||
}
|
||||
|
||||
print(' 菜谱数量: ${recipes.length}');
|
||||
print('');
|
||||
|
||||
for (int i = 0; i < recipes.length && i < 5; i++) {
|
||||
final recipe = recipes[i] as Map<String, dynamic>;
|
||||
print(' ─── 菜谱 #${i + 1} ───');
|
||||
print(' id: ${recipe['id']}');
|
||||
print(' title: ${recipe['title']}');
|
||||
print(' cover: ${recipe['cover']}');
|
||||
print(' pic_id: ${recipe['pic_id']}');
|
||||
print(' picId: ${recipe['picId']}');
|
||||
print(' pic: ${recipe['pic']}');
|
||||
|
||||
final allKeys = recipe.keys.toList();
|
||||
print(' 所有字段: $allKeys');
|
||||
|
||||
final cover = recipe['cover'] ?? '';
|
||||
if (cover.isNotEmpty) {
|
||||
final regex = RegExp(r'/pic/(\d+)[ab]?\.(jpg|png|webp)$');
|
||||
final match = regex.firstMatch(cover.toString());
|
||||
if (match != null) {
|
||||
print(' ✅ 从cover提取picId: ${match.group(1)}');
|
||||
} else {
|
||||
print(' ⚠️ cover不匹配picId正则: $cover');
|
||||
}
|
||||
} else {
|
||||
print(' ❌ cover为空');
|
||||
}
|
||||
print('');
|
||||
}
|
||||
} catch (e) {
|
||||
print(' ❌ 请求失败: $e');
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> testDetailApi() async {
|
||||
print('\n📡 测试 api.php?act=detail 接口(对比picId字段)');
|
||||
final client = HttpClient();
|
||||
try {
|
||||
final url = Uri.parse('$baseUrl/api.php?act=detail&id=32390');
|
||||
print(' 请求URL: $url');
|
||||
|
||||
final request = await client.getUrl(url);
|
||||
request.headers.set('Accept', 'application/json');
|
||||
|
||||
final response = await request.close();
|
||||
final body = await response.transform(utf8.decoder).join();
|
||||
|
||||
if (body.isEmpty) return;
|
||||
|
||||
final json = jsonDecode(body) as Map<String, dynamic>;
|
||||
final data = json['data'] as Map<String, dynamic>?;
|
||||
if (data == null) return;
|
||||
|
||||
print(' id: ${data['id']}');
|
||||
print(' title: ${data['title']}');
|
||||
print(' cover: ${data['cover']}');
|
||||
print(' pic_id: ${data['pic_id']}');
|
||||
print(' picId: ${data['picId']}');
|
||||
print(' pic: ${data['pic']}');
|
||||
|
||||
final allKeys = data.keys.toList();
|
||||
print(' 所有字段: $allKeys');
|
||||
} catch (e) {
|
||||
print(' ❌ 请求失败: $e');
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> testImageUrl() async {
|
||||
print('\n📡 测试图片URL可访问性');
|
||||
final client = HttpClient();
|
||||
try {
|
||||
final testUrls = [
|
||||
'https://eat.wktyl.com/api/assets/pic/32390a.jpg',
|
||||
'https://eat.wktyl.com/api/assets/pic/32390b.jpg',
|
||||
'https://eat.wktyl.com/api/assets/pic/32390.jpg',
|
||||
];
|
||||
|
||||
for (final url in testUrls) {
|
||||
try {
|
||||
final request = await client.getUrl(Uri.parse(url));
|
||||
final response = await request.close();
|
||||
print(
|
||||
' $url → ${response.statusCode} (${response.contentLength} bytes)',
|
||||
);
|
||||
} catch (e) {
|
||||
print(' $url → ❌ $e');
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
// 2026-04-20 | test_filter_steps.dart | 动态筛选接口测试 | 验证filter_steps动态筛选+api_filter分类
|
||||
// 运行: dart run scripts/test_filter_steps.dart
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
const String baseUrl = 'https://eat.wktyl.com/api';
|
||||
|
||||
Future<void> main() async {
|
||||
print('=== 动态筛选接口测试 ===\n');
|
||||
|
||||
print('━━━ 1. api_filter: 获取菜谱大类 ━━━');
|
||||
final mainCats = await getJson('api_filter.php', {'act': 'recipe_main_categories'});
|
||||
if (mainCats != null) {
|
||||
final list = mainCats['data']?['list'] as List? ?? [];
|
||||
print(' 大类数量: ${list.length}');
|
||||
for (final c in list) {
|
||||
final m = c as Map;
|
||||
print(' 📂 ${m['name']} (ID:${m['id']}): ${m['recipe_count']}道');
|
||||
}
|
||||
}
|
||||
|
||||
print('\n━━━ 2. api_filter: 获取中国菜子类 ━━━');
|
||||
final subCats = await getJson('api_filter.php', {'act': 'recipe_sub_categories', 'parent_id': '12'});
|
||||
if (subCats != null) {
|
||||
final list = subCats['data']?['list'] as List? ?? [];
|
||||
print(' 子类数量: ${list.length}');
|
||||
for (final c in list.take(5)) {
|
||||
final m = c as Map;
|
||||
print(' 📂 ${m['name']} (ID:${m['id']}): ${m['recipe_count']}道');
|
||||
}
|
||||
}
|
||||
|
||||
print('\n━━━ 3. filter_steps: 无筛选条件 ━━━');
|
||||
final fs1 = await fetchFilterSteps();
|
||||
if (fs1 != null) {
|
||||
print(' 匹配菜谱数: ${fs1['matched_count']}');
|
||||
final opts = fs1['available_options'] as List? ?? [];
|
||||
print(' 可用分类数: ${opts.length}');
|
||||
for (final o in opts.take(3)) {
|
||||
final m = o as Map;
|
||||
print(' 📂 ${m['name']}: ${m['count']}道 (${(m['children'] as List?)?.length ?? 0}子类)');
|
||||
}
|
||||
final tags1 = fs1['available_tags'] as List? ?? [];
|
||||
print(' 可用标签数: ${tags1.length}');
|
||||
for (final t in tags1.take(5)) {
|
||||
final tm = t as Map;
|
||||
print(' 🏷️ ${tm['name']}: ${tm['count']}道');
|
||||
}
|
||||
}
|
||||
|
||||
print('\n━━━ 4. filter_steps: 选分类[12] ━━━');
|
||||
final fs2 = await fetchFilterSteps(categories: [12]);
|
||||
if (fs2 != null) {
|
||||
print(' 匹配菜谱数: ${fs2['matched_count']}');
|
||||
final tags2 = fs2['available_tags'] as List? ?? [];
|
||||
print(' 可用标签数: ${tags2.length}');
|
||||
for (final t in tags2.take(5)) {
|
||||
final tm = t as Map;
|
||||
print(' 🏷️ ${tm['name']}: ${tm['count']}道');
|
||||
}
|
||||
}
|
||||
|
||||
print('\n━━━ 5. filter_steps: 分类[12]+标签[1] ━━━');
|
||||
final fs3 = await fetchFilterSteps(categories: [12], tags: [1]);
|
||||
if (fs3 != null) {
|
||||
print(' 匹配菜谱数: ${fs3['matched_count']}');
|
||||
final tags3 = fs3['available_tags'] as List? ?? [];
|
||||
print(' 可用标签数: ${tags3.length}');
|
||||
for (final t in tags3.take(5)) {
|
||||
final tm = t as Map;
|
||||
print(' 🏷️ ${tm['name']}: ${tm['count']}道');
|
||||
}
|
||||
}
|
||||
|
||||
print('\n━━━ 6. 验证动态筛选效果 ━━━');
|
||||
final c1 = fs1?['matched_count'] ?? 0;
|
||||
final c2 = fs2?['matched_count'] ?? 0;
|
||||
final c3 = fs3?['matched_count'] ?? 0;
|
||||
print(' 无筛选: $c1 道');
|
||||
print(' 选分类: $c2 道');
|
||||
print(' 分类+标签: $c3 道');
|
||||
if (c2 < c1 && c3 < c2) {
|
||||
print(' ✅ 动态筛选正常:选项越多,匹配越少');
|
||||
} else if (c2 <= c1 && c3 <= c2) {
|
||||
print(' ⚠️ 动态筛选部分正常');
|
||||
} else {
|
||||
print(' ❌ 动态筛选异常');
|
||||
}
|
||||
|
||||
print('\n━━━ 7. filter_apply: 获取推荐菜谱 ━━━');
|
||||
final applyResult = await fetchFilterApply(categories: [12], tags: [1], count: 3);
|
||||
if (applyResult != null) {
|
||||
final recipes = applyResult['recipes'] as List? ?? [];
|
||||
print(' 返回菜谱数: ${recipes.length}');
|
||||
print(' 总匹配数: ${applyResult['total_matched']}');
|
||||
for (final r in recipes) {
|
||||
final rm = r as Map;
|
||||
print(' 🍳 ${rm['title']} (ID: ${rm['id']})');
|
||||
}
|
||||
}
|
||||
|
||||
print('\n=== 测试完成 ===');
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>?> getJson(String endpoint, Map<String, String> params) async {
|
||||
try {
|
||||
final uri = Uri.parse('$baseUrl/$endpoint').replace(queryParameters: params);
|
||||
final response = await HttpClient()
|
||||
.getUrl(uri)
|
||||
.then((r) => r.close())
|
||||
.timeout(const Duration(seconds: 15));
|
||||
final body = await response.transform(utf8.decoder).join();
|
||||
return json.decode(body) as Map<String, dynamic>;
|
||||
} catch (e) {
|
||||
print(' ❌ 请求失败: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>?> fetchFilterSteps({
|
||||
List<int>? categories,
|
||||
List<int>? tags,
|
||||
}) async {
|
||||
final params = <String, String>{'act': 'filter_steps'};
|
||||
if (categories != null && categories.isNotEmpty) {
|
||||
params['category'] = categories.join(',');
|
||||
}
|
||||
if (tags != null && tags.isNotEmpty) {
|
||||
params['tag'] = tags.join(',');
|
||||
}
|
||||
final data = await getJson('api_what_to_eat.php', params);
|
||||
if (data != null && data['code'] == 200) {
|
||||
return data['data'] as Map<String, dynamic>?;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>?> fetchFilterApply({
|
||||
List<int>? categories,
|
||||
List<int>? tags,
|
||||
int count = 5,
|
||||
}) async {
|
||||
final params = <String, String>{'act': 'filter_apply', 'count': '$count'};
|
||||
if (categories != null && categories.isNotEmpty) {
|
||||
params['category'] = categories.join(',');
|
||||
}
|
||||
if (tags != null && tags.isNotEmpty) {
|
||||
params['tag'] = tags.join(',');
|
||||
}
|
||||
final data = await getJson('api_what_to_eat.php', params);
|
||||
if (data != null && data['code'] == 200) {
|
||||
return data['data'] as Map<String, dynamic>?;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 文件: test_ingredient_cache.dart
|
||||
* 名称: 食材缓存测试脚本
|
||||
* 作用: 验证食材缓存服务的读写功能
|
||||
* 创建: 2026-04-14
|
||||
*/
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
void main() async {
|
||||
print('========================================');
|
||||
print('食材缓存测试脚本');
|
||||
print('========================================\n');
|
||||
|
||||
// 测试 API 接口
|
||||
await testIngredientApi();
|
||||
|
||||
print('\n========================================');
|
||||
print('测试完成');
|
||||
print('========================================');
|
||||
}
|
||||
|
||||
Future<void> testIngredientApi() async {
|
||||
final testIds = [849, 1248, 1, 1206, 1209];
|
||||
|
||||
for (final id in testIds) {
|
||||
print('\n--- 测试食材 ID: $id ---');
|
||||
|
||||
try {
|
||||
final client = HttpClient();
|
||||
final request = await client.getUrl(
|
||||
Uri.parse('https://eat.wktyl.com/api/api.php?act=ingredient_detail&id=$id'),
|
||||
);
|
||||
|
||||
final response = await request.close();
|
||||
final body = await response.transform(const SystemEncoding().decoder).join();
|
||||
|
||||
print('状态码: ${response.statusCode}');
|
||||
print('响应长度: ${body.length} 字符');
|
||||
|
||||
if (body.isNotEmpty && body.startsWith('{')) {
|
||||
print('✅ API 响应正常');
|
||||
} else {
|
||||
print('❌ API 响应异常');
|
||||
}
|
||||
|
||||
client.close();
|
||||
} catch (e) {
|
||||
print('❌ 请求失败: $e');
|
||||
}
|
||||
|
||||
// 延迟避免请求过快
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user