diff --git a/scripts/create_3c_products_and_categories.php b/scripts/create_3c_products_and_categories.php
new file mode 100644
index 0000000..39ab6ad
--- /dev/null
+++ b/scripts/create_3c_products_and_categories.php
@@ -0,0 +1,488 @@
+ $val) {
+ $name = 'PHP_' . strtoupper($key);
+ if (is_array($val)) {
+ foreach ($val as $k => $v) {
+ putenv("{$name}_" . strtoupper($k) . "={$v}");
+ }
+ } else {
+ putenv("{$name}={$val}");
+ }
+ }
+}
+
+\think\Config::set(\think\Config::load(APP_PATH . 'config.php'));
+$dbConfig = [
+ 'type' => 'mysql',
+ 'hostname' => '127.0.0.1',
+ 'database' => 'henglianshutong',
+ 'username' => 'henglianshutong',
+ 'password' => 'henglianshutong',
+ 'hostport' => '3306',
+ 'prefix' => 'hla_',
+];
+\think\Config::set('database', $dbConfig);
+
+use think\Db;
+
+class Create3CProducts
+{
+ public function run()
+ {
+ echo "====================================================\n";
+ echo "开始执行 3C 分类与真实商品线上数据生成...\n";
+ echo "====================================================\n\n";
+
+ Db::startTrans();
+ try {
+ $now = time();
+
+ // 1. 确认父分类 153 (恒链甄选)
+ $parentCategory = Db::name('shopro_category')->where('id', 153)->find();
+ if (!$parentCategory) {
+ throw new \Exception("未找到主分类 ID: 153");
+ }
+ echo "[1] 主分类校验成功: ID 153 ({$parentCategory['name']})\n";
+
+ // 调整原酒水分类权重,让 3C 分类排在最前
+ Db::name('shopro_category')->where('id', 154)->update(['weigh' => 50, 'updatetime' => $now]);
+
+ // 2. 创建/更新 4 个 3C 二级分类
+ $categoriesDef = [
+ 'mobile' => [
+ 'name' => '手机数码',
+ 'parent_id' => 153,
+ 'style' => null,
+ 'image' => '/uploads/henglian_goods/3c/categories/cat_mobile.png',
+ 'description' => '精选智能手机、高能移动电源、高速快充及数据传输配件',
+ 'status' => 'normal',
+ 'weigh' => 110
+ ],
+ 'audio' => [
+ 'name' => '智能影音',
+ 'parent_id' => 153,
+ 'style' => null,
+ 'image' => '/uploads/henglian_goods/3c/categories/cat_audio.png',
+ 'description' => '真无线蓝牙耳机、头戴降噪耳机与高保真便携音箱',
+ 'status' => 'normal',
+ 'weigh' => 109
+ ],
+ 'wearable' => [
+ 'name' => '智能穿戴',
+ 'parent_id' => 153,
+ 'style' => null,
+ 'image' => '/uploads/henglian_goods/3c/categories/cat_wearable.png',
+ 'description' => '智能运动健康手环、全天候心率血氧监测智能通话手表',
+ 'status' => 'normal',
+ 'weigh' => 108
+ ],
+ 'computer' => [
+ 'name' => '电脑办公',
+ 'parent_id' => 153,
+ 'style' => null,
+ 'image' => '/uploads/henglian_goods/3c/categories/cat_computer.png',
+ 'description' => '人体工学静音无线鼠标、多功能扩展坞与数码办公外设',
+ 'status' => 'normal',
+ 'weigh' => 107
+ ]
+ ];
+
+ $categoryMap = [];
+ foreach ($categoriesDef as $key => $cat) {
+ $existCat = Db::name('shopro_category')
+ ->where('parent_id', 153)
+ ->where('name', $cat['name'])
+ ->find();
+ if ($existCat) {
+ Db::name('shopro_category')->where('id', $existCat['id'])->update([
+ 'image' => $cat['image'],
+ 'description' => $cat['description'],
+ 'status' => 'normal',
+ 'weigh' => $cat['weigh'],
+ 'updatetime' => $now
+ ]);
+ $catId = $existCat['id'];
+ echo " - 已更新分类: {$cat['name']} (ID: {$catId})\n";
+ } else {
+ $catId = Db::name('shopro_category')->insertGetId(array_merge($cat, [
+ 'createtime' => $now,
+ 'updatetime' => $now
+ ]));
+ echo " + 新增分类: {$cat['name']} (ID: {$catId})\n";
+ }
+ $categoryMap[$key] = $catId;
+ }
+
+ // 3. 准备 8 款真实 3C 商品
+ $products = [
+ [
+ 'num' => 1,
+ 'title' => '倍思 65W GaN氮化镓多口快充充电器',
+ 'subtitle' => 'GaN5 Pro 氮化镓快充 / 2C1A多口盲插 / 智能温控不烫机',
+ 'cat_key' => 'mobile',
+ 'sn' => '3C-BASEUS-GAN65',
+ 'weight' => 0.25,
+ 'original_price' => 149.00,
+ 'price' => 119.00,
+ 'cost_price' => 68.00,
+ 'params' => [
+ ["title" => "品牌", "content" => "倍思 (Baseus)"],
+ ["title" => "型号", "content" => "CCGAN65S5"],
+ ["title" => "接口类型", "content" => "Type-C1 + Type-C2 + USB-A"],
+ ["title" => "最大输出功率", "content" => "65W Max"],
+ ["title" => "输入规格", "content" => "AC 100-240V~, 50/60Hz, 1.5A Max"],
+ ["title" => "适用机型", "content" => "iPhone / 华为 / 小米 / MacBook / 笔记本电脑"],
+ ["title" => "质保期限", "content" => "12个月官方全国联保"]
+ ]
+ ],
+ [
+ 'num' => 2,
+ 'title' => '漫步者 LolliPods 真无线立体声蓝牙耳机',
+ 'subtitle' => '半入耳舒适佩戴 / AptX高清音频解码 / CVC双麦通话降噪 / 24小时综合续航',
+ 'cat_key' => 'audio',
+ 'sn' => '3C-EDIFIER-LP2026',
+ 'weight' => 0.18,
+ 'original_price' => 199.00,
+ 'price' => 149.00,
+ 'cost_price' => 88.00,
+ 'params' => [
+ ["title" => "品牌", "content" => "漫步者 (EDIFIER)"],
+ ["title" => "型号", "content" => "LolliPods 2026款"],
+ ["title" => "佩戴方式", "content" => "半入耳式"],
+ ["title" => "蓝牙版本", "content" => "Bluetooth 5.3"],
+ ["title" => "发声单元", "content" => "13mm大尺寸高解析复合振膜"],
+ ["title" => "单次续航", "content" => "约 6 小时"],
+ ["title" => "配合充电盒", "content" => "约 24 小时长续航"],
+ ["title" => "防尘防水", "content" => "IP54级专业防护"]
+ ]
+ ],
+ [
+ 'num' => 3,
+ 'title' => '罗马仕 20000mAh 22.5W超级快充移动电源',
+ 'subtitle' => '智能LED数显大容量充电宝 / 支持SCP/PD3.0快充 / 三入三出全兼容',
+ 'cat_key' => 'mobile',
+ 'sn' => '3C-ROMOSS-SW20',
+ 'weight' => 0.46,
+ 'original_price' => 129.00,
+ 'price' => 89.00,
+ 'cost_price' => 52.00,
+ 'params' => [
+ ["title" => "品牌", "content" => "罗马仕 (ROMOSS)"],
+ ["title" => "型号", "content" => "SW20 Pro"],
+ ["title" => "电池容量", "content" => "20000mAh / 74Wh (符合民航登机要求)"],
+ ["title" => "额定容量", "content" => "12000mAh (5V/3A)"],
+ ["title" => "输入接口", "content" => "Type-C 18W / Micro-USB 18W / Lightning"],
+ ["title" => "输出接口", "content" => "Type-C 20W / USB-A1 22.5W / USB-A2 22.5W"],
+ ["title" => "电量显示", "content" => "LED精准百分比数字屏幕"]
+ ]
+ ],
+ [
+ 'num' => 4,
+ 'title' => '华为手环 8 智能运动健康手环 曜石黑',
+ 'subtitle' => '8.99mm超薄机身 / 1.47英寸无界大屏 / TruSleep 3.0科学睡眠 / 14天长续航',
+ 'cat_key' => 'wearable',
+ 'sn' => '3C-HUAWEI-BAND8',
+ 'weight' => 0.12,
+ 'original_price' => 269.00,
+ 'price' => 199.00,
+ 'cost_price' => 135.00,
+ 'params' => [
+ ["title" => "品牌", "content" => "华为 (HUAWEI)"],
+ ["title" => "型号", "content" => "ASK-B19"],
+ ["title" => "机身厚度", "content" => "8.99 mm (超薄机身设计)"],
+ ["title" => "屏幕规格", "content" => "1.47英寸 AMOLED炫彩全面屏"],
+ ["title" => "健康监测", "content" => "全天候血氧心率监测 / 睡眠管理 / 压力检测"],
+ ["title" => "防水等级", "content" => "5ATM专业防水 (支持游泳)"],
+ ["title" => "续航能力", "content" => "最长可达14天超长续航"]
+ ]
+ ],
+ [
+ 'num' => 5,
+ 'title' => '小米Redmi Watch 3 青春版 智能蓝牙通话手表',
+ 'subtitle' => '1.83英寸超大高清屏 / 蓝牙高清语音通话 / 12天持久续航 / 200+个性表盘',
+ 'cat_key' => 'wearable',
+ 'sn' => '3C-REDMI-WATCH3',
+ 'weight' => 0.15,
+ 'original_price' => 299.00,
+ 'price' => 229.00,
+ 'cost_price' => 150.00,
+ 'params' => [
+ ["title" => "品牌", "content" => "小米 (Redmi)"],
+ ["title" => "型号", "content" => "M2247W1"],
+ ["title" => "屏幕尺寸", "content" => "1.83英寸高保真触控彩屏"],
+ ["title" => "通话功能", "content" => "支持蓝牙双向免提高清语音通话"],
+ ["title" => "运动模式", "content" => "100+种专业运动健康监测模式"],
+ ["title" => "防水等级", "content" => "5ATM专业防水"],
+ ["title" => "典型续航", "content" => "典型使用12天 / 重度使用8天"]
+ ]
+ ],
+ [
+ 'num' => 6,
+ 'title' => '罗技 M330 降噪静音无线鼠标 曜石黑',
+ 'subtitle' => '90%降噪静音微动 / 人体工学舒适右手握感 / 2.4G即插即用 / 24个月超长续航',
+ 'cat_key' => 'computer',
+ 'sn' => '3C-LOGI-M330',
+ 'weight' => 0.16,
+ 'original_price' => 119.00,
+ 'price' => 89.00,
+ 'cost_price' => 55.00,
+ 'params' => [
+ ["title" => "品牌", "content" => "罗技 (Logitech)"],
+ ["title" => "型号", "content" => "M330 Silent Plus"],
+ ["title" => "连接方式", "content" => "2.4GHz 无线USB微型接收器 (10米有效)"],
+ ["title" => "传感器", "content" => "1000 DPI 高精度先进光学追踪"],
+ ["title" => "降噪技术", "content" => "静音微动技术,减少90%以上点击噪音"],
+ ["title" => "电池寿命", "content" => "1节AA五号电池,最长可达24个月续航"]
+ ]
+ ],
+ [
+ 'num' => 7,
+ 'title' => '绿联 六合一Type-C多功能扩展坞',
+ 'subtitle' => '4K@30Hz HDMI高清投屏 / PD 100W大功率闪充 / USB3.0*3 5Gbps高速传输',
+ 'cat_key' => 'computer',
+ 'sn' => '3C-UGREEN-HUB6',
+ 'weight' => 0.22,
+ 'original_price' => 159.00,
+ 'price' => 119.00,
+ 'cost_price' => 72.00,
+ 'params' => [
+ ["title" => "品牌", "content" => "绿联 (UGREEN)"],
+ ["title" => "型号", "content" => "CM475"],
+ ["title" => "端口扩展", "content" => "HDMI 4K + USB 3.0*3 + PD 100W供电 + SD/TF槽"],
+ ["title" => "材质工艺", "content" => "深空灰阳极氧化铝合金一体散热机身"],
+ ["title" => "线身材质", "content" => "15cm 高密抗折弯编织线身"],
+ ["title" => "兼容平台", "content" => "MacBook / iPad / 华为 / 联想 / 戴尔等全功能Type-C"]
+ ]
+ ],
+ [
+ 'num' => 8,
+ 'title' => '品胜 苹果PD 20W快充编织数据线 1.2米',
+ 'subtitle' => '智能低温快充芯片 / 加粗镀锡铜芯 / 强韧高密度尼龙编织线身 / 充放提速60%',
+ 'cat_key' => 'mobile',
+ 'sn' => '3C-PISEN-CABLE20',
+ 'weight' => 0.08,
+ 'original_price' => 49.00,
+ 'price' => 29.00,
+ 'cost_price' => 12.00,
+ 'params' => [
+ ["title" => "品牌", "content" => "品胜 (PISEN)"],
+ ["title" => "接口类型", "content" => "Type-C 转 Lightning / C to C"],
+ ["title" => "支持功率", "content" => "最高支持 PD 20W / 27W 闪电快充"],
+ ["title" => "传输速率", "content" => "USB 2.0 480Mbps 稳定数据传输"],
+ ["title" => "线长规格", "content" => "1.2 米 (黄金便携使用长度)"],
+ ["title" => "适用机型", "content" => "iPhone 8-15 全系 / iPad / AirPods 系列"]
+ ]
+ ]
+ ];
+
+ $createdGoodsIds = [];
+
+ foreach ($products as $idx => $item) {
+ $i = $item['num'];
+ $catId = $categoryMap[$item['cat_key']];
+ $categoryIds = "153,{$catId}";
+
+ $mainImg = "/uploads/henglian_goods/3c/p_{$i}/cover.jpg";
+ $banners = [
+ "/uploads/henglian_goods/3c/p_{$i}/banner_1.jpg",
+ "/uploads/henglian_goods/3c/p_{$i}/banner_2.jpg",
+ "/uploads/henglian_goods/3c/p_{$i}/banner_3.jpg"
+ ];
+
+ $contentHtml = <<
+
{$item['title']}
+ {$item['subtitle']}
+ 
+ 
+ 
+
+
【正品保障与官方售后承诺】
+
1. 本品为正品行货,支持全国统一防伪验证,享受原厂保修及技术支持服务;
+
2. 签收之日起支持 7 天无理由退换货(需保持未激活、商品主体与包装完整未损);
+
3. 质量问题 30 天内包换,1 年内享受全国联合保修;
+
4. 每日 16:00 前完成支付的订单,当日顺丰/京东快递速发,全国顺畅直达。
+
+
+HTML;
+
+ $goodsData = [
+ 'type' => 'normal',
+ 'title' => $item['title'],
+ 'subtitle' => $item['subtitle'],
+ 'category_ids' => $categoryIds,
+ 'image' => $mainImg,
+ 'images' => json_encode($banners, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
+ 'params' => json_encode($item['params'], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
+ 'content' => $contentHtml,
+ 'original_price' => $item['original_price'],
+ 'price' => $item['price'],
+ 'is_sku' => 0,
+ 'limit_type' => 'none',
+ 'limit_num' => 0,
+ 'likes' => 120 + $i * 18,
+ 'views' => 1500 + $i * 120,
+ 'sales' => 88 + $i * 15,
+ 'sales_show_type' => 'exact',
+ 'stock_show_type' => 'exact',
+ 'show_sales' => 88 + $i * 15,
+ 'service_ids' => '1,2,3,4', // 正品保障、7天退换、运费险、极速退款
+ 'dispatch_type' => 'express',
+ 'dispatch_id' => 1, // 全国包邮
+ 'is_offline' => 0,
+ 'status' => 'up',
+ 'weigh' => 200 - $i,
+ 'updatetime' => $now
+ ];
+
+ $existGoods = Db::name('shopro_goods')->where('title', $item['title'])->find();
+ if ($existGoods) {
+ Db::name('shopro_goods')->where('id', $existGoods['id'])->update($goodsData);
+ $goodsId = $existGoods['id'];
+ echo "[2] 更新商品: {$item['title']} (ID: {$goodsId})\n";
+ } else {
+ $goodsData['createtime'] = $now;
+ $goodsId = Db::name('shopro_goods')->insertGetId($goodsData);
+ echo "[2] 新增商品: {$item['title']} (ID: {$goodsId})\n";
+ }
+
+ $createdGoodsIds[] = $goodsId;
+
+ // 维护单规格 SKU 价格记录
+ $skuData = [
+ 'goods_sku_ids' => null,
+ 'goods_sku_text' => null,
+ 'goods_id' => $goodsId,
+ 'image' => null,
+ 'stock' => 1000,
+ 'stock_warning' => 20,
+ 'sn' => $item['sn'],
+ 'weight' => $item['weight'],
+ 'cost_price' => $item['cost_price'],
+ 'original_price' => $item['original_price'],
+ 'price' => $item['price'],
+ 'status' => 'up',
+ 'weigh' => 0,
+ 'updatetime' => $now
+ ];
+
+ $existSku = Db::name('shopro_goods_sku_price')->where('goods_id', $goodsId)->find();
+ if ($existSku) {
+ Db::name('shopro_goods_sku_price')->where('id', $existSku['id'])->update($skuData);
+ } else {
+ $skuData['createtime'] = $now;
+ Db::name('shopro_goods_sku_price')->insert($skuData);
+ }
+ }
+
+ // 4. 联动更新装修模板 5 (3C数码模板) 首页推荐与搜索关键词
+ $decorPage = Db::name('shopro_decorate_page')
+ ->where('decorate_id', 5)
+ ->where('type', 'home')
+ ->find();
+
+ if ($decorPage) {
+ $pageConfig = json_decode($decorPage['page'], true);
+ if (isset($pageConfig['data']) && is_array($pageConfig['data'])) {
+ foreach ($pageConfig['data'] as &$block) {
+ // 更新搜索框关键词
+ if ($block['type'] === 'searchBlock') {
+ $block['data']['placeholder'] = '搜索 65W氮化镓快充 · 蓝牙耳机 · 智能手表 · 移动电源';
+ $block['data']['keywords'] = ['65W快充', '漫步者耳机', '华为手环', '罗技鼠标', '罗马仕充电宝', '绿联扩展坞'];
+ }
+ // 更新首页轮播图
+ if ($block['type'] === 'imageBanner') {
+ $block['data']['list'] = [
+ [
+ 'title' => '倍思 65W 氮化镓快充 · 闪速满电',
+ 'type' => 'image',
+ 'src' => '/uploads/henglian_goods/3c/banners/banner_home_1.jpg',
+ 'poster' => '',
+ 'url' => '/pages/goods/index?id=' . $createdGoodsIds[0]
+ ],
+ [
+ 'title' => '漫步者 LolliPods 真无线 · 纯粹原声',
+ 'type' => 'image',
+ 'src' => '/uploads/henglian_goods/3c/banners/banner_home_2.jpg',
+ 'poster' => '',
+ 'url' => '/pages/goods/index?id=' . $createdGoodsIds[1]
+ ],
+ [
+ 'title' => 'Redmi Watch 3 智能手表 · 运动健康',
+ 'type' => 'image',
+ 'src' => '/uploads/henglian_goods/3c/banners/banner_home_3.jpg',
+ 'poster' => '',
+ 'url' => '/pages/goods/index?id=' . $createdGoodsIds[4]
+ ]
+ ];
+ }
+ // 更新头条通知公告
+ if ($block['type'] === 'noticeBlock') {
+ $block['data']['title']['text'] = '数码狂欢季,全场精选大牌 3C 正品行货,顺丰包邮极速达!';
+ }
+ // 更新专区标题栏
+ if ($block['type'] === 'titleBlock') {
+ $block['data']['title']['text'] = '热门数码甄选';
+ $block['data']['subtitle']['text'] = '精选大牌 · 官方正品';
+ $block['data']['more']['url'] = '/pages/index/category?id=153';
+ }
+ // 更新商品推荐卡片
+ if ($block['type'] === 'goodsCard') {
+ if (isset($block['data']['goodsIds'])) {
+ // 推荐前 2 或剩余 3C 商品
+ if (count($block['data']['goodsIds']) <= 2) {
+ $block['data']['goodsIds'] = array_slice($createdGoodsIds, 0, 2);
+ } else {
+ $block['data']['goodsIds'] = array_slice($createdGoodsIds, 2, 6);
+ }
+ }
+ }
+ }
+ unset($block);
+
+ Db::name('shopro_decorate_page')
+ ->where('id', $decorPage['id'])
+ ->update([
+ 'page' => json_encode($pageConfig, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
+ ]);
+ echo "[3] 装修模板 5 (3C数码) 首页推荐商品与搜索关键词已成功联动更新!\n";
+ }
+ }
+
+ Db::commit();
+ echo "\n====================================================\n";
+ echo "3C 分类与商品数据生成成功!事务已提交!\n";
+ echo "本次涉及 3C 分类 ID: " . implode(', ', array_values($categoryMap)) . "\n";
+ echo "本次涉及 3C 商品 ID: " . implode(', ', $createdGoodsIds) . "\n";
+ echo "====================================================\n";
+
+ } catch (\Exception $e) {
+ Db::rollback();
+ echo "\n[ERROR] 执行失败,事务已回滚: " . $e->getMessage() . "\n";
+ echo $e->getTraceAsString() . "\n";
+ exit(1);
+ }
+ }
+}
+
+$task = new Create3CProducts();
+$task->run();
diff --git a/scripts/generate_3c_assets.py b/scripts/generate_3c_assets.py
new file mode 100644
index 0000000..164376c
--- /dev/null
+++ b/scripts/generate_3c_assets.py
@@ -0,0 +1,424 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+生成腾讯小程序审核专用的真实 3C 数码产品素材:
+包含:
+1. 4 大类目分类图标
+2. 8 款主流爆款 3C 商品的主图、轮播图 (3张/款)、详情长图切片 (3张/款)
+"""
+
+import os
+import sys
+from PIL import Image, ImageDraw, ImageFont, ImageFilter
+
+FONT_PATH = "/System/Library/Fonts/STHeiti Light.ttc"
+if not os.path.exists(FONT_PATH):
+ FONT_PATH = "/System/Library/Fonts/PingFang.ttc"
+if not os.path.exists(FONT_PATH):
+ FONT_PATH = "/Library/Fonts/Arial Unicode.ttf"
+
+def get_font(size):
+ try:
+ return ImageFont.truetype(FONT_PATH, size)
+ except Exception:
+ return ImageFont.load_default()
+
+BASE_DIR = "/Users/chen/Desktop/xbiuld/henglianshutong"
+SOURCE_IMG_DIR = "/Users/chen/.gemini/antigravity/brain/a8c097d8-307e-4c94-b68c-7d7aeaa89eee"
+OUTPUT_DIR = os.path.join(BASE_DIR, "scratch/3c_assets")
+
+PRODUCTS = [
+ {
+ "id": 1,
+ "key": "gan_charger",
+ "raw_img": "baseus_gan_charger_1790409638528.jpg",
+ "title": "倍思 65W GaN氮化镓多口快充充电器",
+ "brand": "倍思 (Baseus)",
+ "model": "CCGAN65S5",
+ "subtitle": "GaN5 Pro 氮化镓快充 / 2C1A多口盲插 / 智能温控不伤机",
+ "features": ["65W大功率氮化镓", "2C+1A三口盲插", "BPS II充电技术", "低温快充安全不烫"],
+ "specs": [
+ ("品名", "倍思 65W GaN5 Pro 多口快充头"),
+ ("接口", "Type-C1 + Type-C2 + USB-A"),
+ ("输入", "AC 100-240V~, 50/60Hz, 1.5A Max"),
+ ("C1/C2输出", "5V/3A, 9V/3A, 12V/3A, 15V/3A, 20V/3.25A (65W Max)"),
+ ("USB-A输出", "5V/3A, 9V/3A, 12V/2.5A, 20V/1.5A (30W Max)"),
+ ("产品尺寸", "65 x 36 x 32 mm"),
+ ("净重", "约 120g"),
+ ("质保服务", "1年全国联保")
+ ],
+ "package": ["65W氮化镓充电器主机 * 1", "双Type-C 100W快充数据线 * 1", "产品说明书 & 保修卡 * 1", "品牌贴纸 * 1"]
+ },
+ {
+ "id": 2,
+ "key": "tws_earbuds",
+ "raw_img": "tws_earbuds_1790409653035.jpg",
+ "title": "漫步者 LolliPods 真无线立体声蓝牙耳机",
+ "brand": "漫步者 (EDIFIER)",
+ "model": "LolliPods 2026款",
+ "subtitle": "半入耳舒适佩戴 / AptX高清音频解码 / CVC双麦通话降噪 / 24小时综合续航",
+ "features": ["13mm大尺寸复合振膜", "高通QCC低延迟芯片", "CVC8.0双麦通话降噪", "24小时复合长续航"],
+ "specs": [
+ ("品名", "漫步者 LolliPods 真无线立体声耳机"),
+ ("蓝牙版本", "Bluetooth V5.3"),
+ ("音频解码", "AptX / SBC"),
+ ("有效距离", "10m 无障碍传输"),
+ ("耳机续航", "约 6小时 (单次)"),
+ ("配合充电仓", "约 24小时"),
+ ("充电接口", "Type-C 高速充电"),
+ ("防水等级", "IP54级防尘防水")
+ ],
+ "package": ["蓝牙耳机本体 * 1对", "便携式无线充电仓 * 1", "Type-C充电线 * 1", "用户手册与保修凭证 * 1"]
+ },
+ {
+ "id": 3,
+ "key": "power_bank",
+ "raw_img": "power_bank_1790409670628.jpg",
+ "title": "罗马仕 20000mAh 22.5W超级快充移动电源",
+ "brand": "罗马仕 (ROMOSS)",
+ "model": "SW20 Pro",
+ "subtitle": "智能LED数显大容量充电宝 / 支持SCP/PD3.0快充 / 三入三出全兼容",
+ "features": ["20000mAh大容量", "22.5W超级闪充", "LED百分比数显屏", "三入三出高效充放"],
+ "specs": [
+ ("品名", "罗马仕 20000mAh 双向快充移动电源"),
+ ("额定容量", "12000mAh (5V/3A)"),
+ ("电池能量", "20000mAh / 74Wh (符合民航登机标准)"),
+ ("输入接口", "Type-C 18W / Micro-USB 18W / Lightning"),
+ ("输出接口", "Type-C 20W / USB-A1 22.5W / USB-A2 22.5W"),
+ ("电量显示", "LED数字智能精准显示"),
+ ("尺寸重量", "168 x 82 x 23 mm / 约 460g"),
+ ("安全保护", "过流/过压/短路/过充等10重安全防护")
+ ],
+ "package": ["20000mAh移动电源主机 * 1", "USB转Type-C快充线 * 1", "快速使用指南 * 1", "防伪质保卡 * 1"]
+ },
+ {
+ "id": 4,
+ "key": "fitness_band",
+ "raw_img": "fitness_band_1790409752424.jpg",
+ "title": "华为手环 8 智能运动健康手环 曜石黑",
+ "brand": "华为 (HUAWEI)",
+ "model": "ASK-B19",
+ "subtitle": "8.99mm超薄机身 / 1.47英寸无界大屏 / TruSleep 3.0科学睡眠 / 14天长续航",
+ "features": ["8.99mm轻薄无感佩戴", "1.47英寸全面彩屏", "全天候血氧心率监测", "100+种专业运动模式"],
+ "specs": [
+ ("品名", "华为手环 8 标准版"),
+ ("机身厚度", "8.99 mm (不含传感器凸起)"),
+ ("机身重量", "约 14 g (不含表带)"),
+ ("屏幕规格", "1.47英寸 AMOLED炫彩触摸屏 (194x368)"),
+ ("健康管理", "睡眠监测 / 连续血氧 / 智能心率 / 压力检测"),
+ ("防水等级", "5 ATM 防水等级 (支持泳池游泳)"),
+ ("典型续航", "最长续航14天 / 常规使用9天"),
+ ("连接技术", "BLE 5.0,支持Android 6.0 / iOS 9.0及以上")
+ ],
+ "package": ["手环主机含表带 * 1", "专用磁吸充电底座线缆 * 1", "快速入门及安全信息手册 * 1", "三包凭证 * 1"]
+ },
+ {
+ "id": 5,
+ "key": "smart_watch",
+ "raw_img": "smart_watch_1790409770345.jpg",
+ "title": "小米Redmi Watch 3 青春版 智能蓝牙通话手表",
+ "brand": "小米 (Redmi)",
+ "model": "M2247W1",
+ "subtitle": "1.83英寸超大高清屏 / 蓝牙高清语音通话 / 12天持久续航 / 200+个性表盘",
+ "features": ["1.83英寸全贴合大屏", "支持蓝牙高清通话", "全天心率血氧监测", "12天长效超强续航"],
+ "specs": [
+ ("品名", "Redmi Watch 3 青春版 智能手表"),
+ ("屏幕尺寸", "1.83英寸高清触控彩屏 (240x280)"),
+ ("表框材质", "高强度高光金属质感中框"),
+ ("通话功能", "内置高灵敏降噪麦克风与独立扬声器"),
+ ("运动模式", "100+种运动模式,自动识别跑步步行"),
+ ("防水等级", "5ATM专业防水"),
+ ("电池容量", "289mAh锂聚合物电池"),
+ ("续航时间", "典型模式12天 / 重度使用8天")
+ ],
+ "package": ["智能手表主机 * 1", "亲肤硅胶表带 * 1", "专用磁吸充电线 * 1", "使用说明书 * 1"]
+ },
+ {
+ "id": 6,
+ "key": "wireless_mouse",
+ "raw_img": "wireless_mouse_1790409787831.jpg",
+ "title": "罗技 M330 降噪静音无线鼠标 曜石黑",
+ "brand": "罗技 (Logitech)",
+ "model": "M330 Silent Plus",
+ "subtitle": "90%降噪静音微动 / 人体工学舒适右手握感 / 2.4G即插即用 / 24个月超长续航",
+ "features": ["静音降噪静音点击", "人体工学仿生曲线", "微型USB无线接收器", "24个月超长电池续航"],
+ "specs": [
+ ("品名", "罗技 M330 Silent Plus 无线静音鼠标"),
+ ("连接方式", "2.4 GHz 无线连接技术 (微型USB Nano接收器)"),
+ ("有效距离", "约 10 米"),
+ ("传感器类型", "罗技先进光学追踪技术"),
+ ("传感器分辨率", "1000 DPI 精准定位"),
+ ("按键数量", "3个 (左键、右键、滚轮中键)"),
+ ("供电电池", "1节 AA 五号电池 (出厂预装)"),
+ ("支持系统", "Windows 10/11, macOS, ChromeOS, Linux")
+ ],
+ "package": ["M330 无线鼠标 * 1", "Nano 微型无线接收器 * 1", "AA 电池 (已预装) * 1", "用户文档 * 1"]
+ },
+ {
+ "id": 7,
+ "key": "usbc_hub",
+ "raw_img": "usbc_hub_1790409804480.jpg",
+ "title": "绿联 六合一Type-C多功能扩展坞",
+ "brand": "绿联 (UGREEN)",
+ "model": "CM475",
+ "subtitle": "4K@30Hz HDMI高清投屏 / PD 100W大功率闪充 / USB3.0*3 5Gbps高速传输",
+ "features": ["4K高清HDMI输出", "PD 100W边充边玩", "3口USB3.0 5Gbps", "铝合金一体高效散热"],
+ "specs": [
+ ("品名", "绿联 Type-C 六合一多功能扩展坞"),
+ ("输入端口", "Type-C (兼容雷电3/4, USB4)"),
+ ("视频端口", "HDMI 支持 4K*2K@30Hz / 1080P@60Hz"),
+ ("数据端口", "USB 3.0 * 3 (传输速率最高 5Gbps)"),
+ ("供电端口", "Type-C PD 3.0 (最高支持 100W 快速充电)"),
+ ("外壳材质", "深空灰阳极氧化铝合金"),
+ ("线身工艺", "高密度尼龙精编,抗弯折寿命10000+次"),
+ ("兼容平台", "MacBook / iPad / 华为 / 联想 / 戴尔等全功能Type-C设备")
+ ],
+ "package": ["六合一多功能扩展坞 * 1", "产品快速使用手册 * 1", "产品保修凭证 * 1"]
+ },
+ {
+ "id": 8,
+ "key": "fast_cable",
+ "raw_img": "fast_cable_1790409818654.jpg",
+ "title": "品胜 苹果PD 20W快充编织数据线 1.2米",
+ "brand": "品胜 (PISEN)",
+ "model": "AL10-1200",
+ "subtitle": "智能低温快充芯片 / 加粗镀锡铜芯 / 强韧高密度尼龙编织线身 / 充放提速60%",
+ "features": ["PD 20W急速快充", "高密度尼龙防断编织", "加粗五股纯铜线芯", "充电传输二合一"],
+ "specs": [
+ ("品名", "品胜 Type-C 转 Lightning / C to C 快充线"),
+ ("接口规格", "Type-C to Lightning / Type-C (兼容PD快充)"),
+ ("最大输出", "20W / 27W Max (向下兼容标准充电)"),
+ ("数据传输", "USB 2.0 480Mbps 稳定互传"),
+ ("线身长度", "1.2 米 (黄金日用长度)"),
+ ("线身材质", "精工高密尼龙双色编织 + 铝合金端子外壳"),
+ ("弯折测试", "经过 20000+ 次SR摇摆弯折抗疲劳测试"),
+ ("适用机型", "iPhone 8-15全系 / iPad / AirPods 系列设备")
+ ],
+ "package": ["快充编织数据线 1.2米 * 1", "硅胶收纳绑带 * 1", "产品合格证 & 质保卡 * 1"]
+ }
+]
+
+def create_banner_2(prod, raw_img_path, out_path):
+ """生成轮播图2:性能特性/场景解析"""
+ canvas = Image.new("RGB", (800, 800), (248, 250, 252))
+ raw = Image.open(raw_img_path).convert("RGBA").resize((560, 560), Image.Resampling.LANCZOS)
+ canvas.paste(raw, (120, 180), raw)
+
+ draw = ImageDraw.Draw(canvas)
+ # 顶部标签
+ font_tag = get_font(26)
+ font_sub = get_font(20)
+ draw.rounded_rectangle([(40, 40), (220, 85)], radius=8, fill=(30, 41, 59))
+ draw.text((60, 48), "核心性能解析", fill=(255, 255, 255), font=font_tag)
+ draw.text((240, 52), prod["brand"] + " · 原厂正品", fill=(100, 116, 139), font=font_sub)
+
+ # 底部核心特性芯片卡片
+ features = prod["features"]
+ card_w = 345
+ card_h = 44
+ coords = [
+ (40, 680), (415, 680),
+ (40, 735), (415, 735)
+ ]
+ font_f = get_font(20)
+ for i, f in enumerate(features[:4]):
+ x, y = coords[i]
+ draw.rounded_rectangle([(x, y), (x + card_w, y + card_h)], radius=6, fill=(241, 245, 249), outline=(226, 232, 240))
+ draw.ellipse([(x + 14, y + 16), (x + 24, y + 26)], fill=(37, 99, 235))
+ draw.text((x + 36, y + 10), f, fill=(15, 23, 42), font=font_f)
+
+ canvas.save(out_path, "JPEG", quality=92)
+
+def create_banner_3(prod, raw_img_path, out_path):
+ """生成轮播图3:做工细节与设计质感"""
+ canvas = Image.new("RGB", (800, 800), (255, 255, 255))
+ raw = Image.open(raw_img_path).convert("RGBA").resize((600, 600), Image.Resampling.LANCZOS)
+ canvas.paste(raw, (100, 80), raw)
+
+ draw = ImageDraw.Draw(canvas)
+ # 底部质感横幅
+ draw.rectangle([(0, 680), (800, 800)], fill=(15, 23, 42))
+ font_title = get_font(28)
+ font_desc = get_font(20)
+ draw.text((50, 705), "极简精工美学 · 严苛品质出厂质检", fill=(255, 255, 255), font=font_title)
+ draw.text((50, 748), prod["subtitle"][:32], fill=(148, 163, 184), font=font_desc)
+
+ canvas.save(out_path, "JPEG", quality=92)
+
+def create_detail_1(prod, raw_img_path, out_path):
+ """生成详情切片1:产品核心卖点海报长图 (750 x 1000)"""
+ w, h = 750, 1000
+ canvas = Image.new("RGB", (w, h), (248, 250, 252))
+ draw = ImageDraw.Draw(canvas)
+
+ # 顶部品牌条
+ draw.rectangle([(0, 0), (w, 140)], fill=(15, 23, 42))
+ font_brand = get_font(22)
+ font_title = get_font(32)
+ draw.text((40, 30), prod["brand"].upper(), fill=(148, 163, 184), font=font_brand)
+ draw.text((40, 70), prod["title"][:16], fill=(255, 255, 255), font=font_title)
+
+ # 主体产品图片
+ raw = Image.open(raw_img_path).convert("RGBA").resize((480, 480), Image.Resampling.LANCZOS)
+ canvas.paste(raw, (135, 170), raw)
+
+ # 4大卖点模块
+ draw.rectangle([(30, 680), (720, 960)], fill=(255, 255, 255), outline=(226, 232, 240))
+ font_block_t = get_font(24)
+ font_block_c = get_font(20)
+ draw.text((55, 705), "产品核心亮点", fill=(15, 23, 42), font=font_block_t)
+ draw.line([(55, 745), (695, 745)], fill=(241, 245, 249), width=2)
+
+ feats = prod["features"]
+ for i, ft in enumerate(feats):
+ fy = 765 + i * 44
+ draw.ellipse([(60, fy + 8), (72, fy + 20)], fill=(37, 99, 235))
+ draw.text((85, fy + 4), ft, fill=(51, 65, 85), font=font_block_c)
+
+ canvas.save(out_path, "JPEG", quality=92)
+
+def create_detail_2(prod, out_path):
+ """生成详情切片2:标准技术参数表格长图 (750 x 900)"""
+ w, h = 750, 900
+ canvas = Image.new("RGB", (w, h), (255, 255, 255))
+ draw = ImageDraw.Draw(canvas)
+
+ # 顶部标题栏
+ draw.rectangle([(0, 0), (w, 90)], fill=(241, 245, 249))
+ font_t = get_font(30)
+ draw.text((40, 28), "详细规格参数与技术指标", fill=(15, 23, 42), font=font_t)
+
+ # 表格
+ specs = prod["specs"]
+ table_top = 120
+ row_h = 75
+ font_k = get_font(22)
+ font_v = get_font(20)
+
+ for i, (k, v) in enumerate(specs):
+ curr_y = table_top + i * row_h
+ bg_col = (248, 250, 252) if i % 2 == 0 else (255, 255, 255)
+ draw.rectangle([(30, curr_y), (720, curr_y + row_h)], fill=bg_col, outline=(226, 232, 240))
+ # 键列
+ draw.text((50, curr_y + 25), k, fill=(100, 116, 139), font=font_k)
+ # 值列 (换行处理)
+ if len(v) > 28:
+ draw.text((220, curr_y + 12), v[:28], fill=(15, 23, 42), font=font_v)
+ draw.text((220, curr_y + 40), v[28:], fill=(15, 23, 42), font=font_v)
+ else:
+ draw.text((220, curr_y + 26), v, fill=(15, 23, 42), font=font_v)
+
+ canvas.save(out_path, "JPEG", quality=92)
+
+def create_detail_3(prod, out_path):
+ """生成详情切片3:包装清单与正品保障售后承诺长图 (750 x 850)"""
+ w, h = 750, 850
+ canvas = Image.new("RGB", (w, h), (248, 250, 252))
+ draw = ImageDraw.Draw(canvas)
+
+ # 包装清单部分
+ draw.rectangle([(30, 40), (720, 360)], fill=(255, 255, 255), outline=(226, 232, 240))
+ font_sec = get_font(26)
+ font_item = get_font(21)
+ draw.text((55, 65), "包装清单 (Standard Package)", fill=(15, 23, 42), font=font_sec)
+ draw.line([(55, 110), (695, 110)], fill=(241, 245, 249), width=2)
+
+ for i, item in enumerate(prod["package"]):
+ iy = 135 + i * 48
+ draw.ellipse([(60, iy + 8), (70, iy + 18)], fill=(16, 185, 129))
+ draw.text((85, iy + 4), item, fill=(51, 65, 85), font=font_item)
+
+ # 服务保障部分
+ draw.rectangle([(30, 400), (720, 800)], fill=(255, 255, 255), outline=(226, 232, 240))
+ draw.text((55, 425), "正品承诺与售后保障说明", fill=(15, 23, 42), font=font_sec)
+ draw.line([(55, 470), (695, 470)], fill=(241, 245, 249), width=2)
+
+ guarantees = [
+ ("官方正品", "100% 正品行货,支持全国防伪验证查询,假一赔十"),
+ ("七天无理由", "支持 7 天无理由退换货(保持商品包装完好未激活)"),
+ ("一年全国联保", "自购买之日起享受 365 天官方全国联合保修服务"),
+ ("极速闪电发货", "每日16点前订单顺丰/京东快递当日发出,全场包邮")
+ ]
+ font_gt = get_font(22)
+ font_gc = get_font(18)
+ for j, (gt, gc) in enumerate(guarantees):
+ gy = 495 + j * 72
+ draw.rounded_rectangle([(55, gy), (180, gy + 36)], radius=6, fill=(238, 242, 255))
+ draw.text((65, gy + 6), gt, fill=(79, 70, 229), font=font_gt)
+ draw.text((200, gy + 8), gc, fill=(71, 85, 105), font=font_gc)
+
+ canvas.save(out_path, "JPEG", quality=92)
+
+def create_category_icon(title, subtitle, icon_color, out_path, sample_img_path):
+ """生成 200x200 分类图标"""
+ canvas = Image.new("RGBA", (200, 200), (0, 0, 0, 0))
+ draw = ImageDraw.Draw(canvas)
+
+ # 渐变或圆角卡片底色
+ draw.rounded_rectangle([(10, 10), (190, 190)], radius=36, fill=(245, 247, 250), outline=(226, 232, 240))
+
+ # 贴上该类目产品的居中缩略图
+ sample = Image.open(sample_img_path).convert("RGBA").resize((130, 130), Image.Resampling.LANCZOS)
+ canvas.paste(sample, (35, 35), sample)
+
+ canvas.save(out_path, "PNG")
+
+def main():
+ os.makedirs(OUTPUT_DIR, exist_ok=True)
+ os.makedirs(os.path.join(OUTPUT_DIR, "categories"), exist_ok=True)
+
+ print("开始生成 3C 分类与商品图片素材...")
+
+ # 1. 生成商品素材
+ for p in PRODUCTS:
+ p_dir = os.path.join(OUTPUT_DIR, f"p_{p['id']}")
+ os.makedirs(p_dir, exist_ok=True)
+ raw_path = os.path.join(SOURCE_IMG_DIR, p["raw_img"])
+
+ # main/cover (800x800)
+ img_main = Image.open(raw_path).convert("RGB").resize((800, 800), Image.Resampling.LANCZOS)
+ main_path = os.path.join(p_dir, "cover.jpg")
+ img_main.save(main_path, "JPEG", quality=94)
+
+ # banner 1 (800x800)
+ banner1_path = os.path.join(p_dir, "banner_1.jpg")
+ img_main.save(banner1_path, "JPEG", quality=94)
+
+ # banner 2
+ banner2_path = os.path.join(p_dir, "banner_2.jpg")
+ create_banner_2(p, raw_path, banner2_path)
+
+ # banner 3
+ banner3_path = os.path.join(p_dir, "banner_3.jpg")
+ create_banner_3(p, raw_path, banner3_path)
+
+ # detail 1
+ detail1_path = os.path.join(p_dir, "detail_1.jpg")
+ create_detail_1(p, raw_path, detail1_path)
+
+ # detail 2
+ detail2_path = os.path.join(p_dir, "detail_2.jpg")
+ create_detail_2(p, detail2_path)
+
+ # detail 3
+ detail3_path = os.path.join(p_dir, "detail_3.jpg")
+ create_detail_3(p, detail3_path)
+
+ print(f"商品 {p['id']} [{p['title']}] 素材生成完成。")
+
+ # 2. 生成 4 个分类图标
+ cat_items = [
+ ("手机数码", "充电/配件/外设", (37, 99, 235), "cat_mobile.png", os.path.join(SOURCE_IMG_DIR, PRODUCTS[0]["raw_img"])),
+ ("智能影音", "耳机/音箱/降噪", (124, 58, 237), "cat_audio.png", os.path.join(SOURCE_IMG_DIR, PRODUCTS[1]["raw_img"])),
+ ("智能穿戴", "手环/手表/健康", (225, 29, 72), "cat_wearable.png", os.path.join(SOURCE_IMG_DIR, PRODUCTS[3]["raw_img"])),
+ ("电脑办公", "鼠标/键鼠/扩展坞", (13, 148, 136), "cat_computer.png", os.path.join(SOURCE_IMG_DIR, PRODUCTS[5]["raw_img"]))
+ ]
+ for c_title, c_sub, c_col, c_name, sample_path in cat_items:
+ c_path = os.path.join(OUTPUT_DIR, "categories", c_name)
+ create_category_icon(c_title, c_sub, c_col, c_path, sample_path)
+ print(f"分类图标 [{c_title}] 生成完成: {c_name}")
+
+ print("全部素材生成完毕!输出目录:", OUTPUT_DIR)
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/verify_3c_online_data.php b/tests/verify_3c_online_data.php
new file mode 100644
index 0000000..6d702af
--- /dev/null
+++ b/tests/verify_3c_online_data.php
@@ -0,0 +1,199 @@
+ $val) {
+ $name = 'PHP_' . strtoupper($key);
+ if (is_array($val)) {
+ foreach ($val as $k => $v) {
+ putenv("{$name}_" . strtoupper($k) . "={$v}");
+ }
+ } else {
+ putenv("{$name}={$val}");
+ }
+ }
+}
+
+\think\Config::set(\think\Config::load(APP_PATH . 'config.php'));
+$dbConfig = [
+ 'type' => 'mysql',
+ 'hostname' => '127.0.0.1',
+ 'database' => 'henglianshutong',
+ 'username' => 'henglianshutong',
+ 'password' => 'henglianshutong',
+ 'hostport' => '3306',
+ 'prefix' => 'hla_',
+];
+\think\Config::set('database', $dbConfig);
+
+use think\Db;
+
+class Verify3COnlineData
+{
+ private $passed = 0;
+ private $failed = 0;
+
+ private function assert($condition, $message)
+ {
+ if ($condition) {
+ echo " [PASS] {$message}\n";
+ $this->passed++;
+ } else {
+ echo " [FAIL] {$message}\n";
+ $this->failed++;
+ }
+ }
+
+ public function run()
+ {
+ echo "====================================================\n";
+ echo "开始验证 3C 商品与分类线上数据及 API 接口...\n";
+ echo "====================================================\n\n";
+
+ // 1. 分类检验
+ echo "--- 场景 1: 分类层级与权重检验 ---\n";
+ $categories = Db::name('shopro_category')
+ ->where('parent_id', 153)
+ ->where('status', 'normal')
+ ->order('weigh', 'desc')
+ ->select();
+
+ $catNames = array_column($categories, 'name');
+ $this->assert(in_array('手机数码', $catNames), "分类列表中包含 '手机数码'");
+ $this->assert(in_array('智能影音', $catNames), "分类列表中包含 '智能影音'");
+ $this->assert(in_array('智能穿戴', $catNames), "分类列表中包含 '智能穿戴'");
+ $this->assert(in_array('电脑办公', $catNames), "分类列表中包含 '电脑办公'");
+
+ // 校验权重排在酒水之前
+ $top4Names = array_slice($catNames, 0, 4);
+ $this->assert(
+ in_array('手机数码', $top4Names) && in_array('智能影音', $top4Names),
+ "前 4 大展示分类全部为 3C 核心品类"
+ );
+
+ // 2. 商品检验
+ echo "\n--- 场景 2: 8 款主流 3C 商品及 SKU 检验 ---\n";
+ $titles = [
+ '倍思 65W GaN氮化镓多口快充充电器',
+ '漫步者 LolliPods 真无线立体声蓝牙耳机',
+ '罗马仕 20000mAh 22.5W超级快充移动电源',
+ '华为手环 8 智能运动健康手环 曜石黑',
+ '小米Redmi Watch 3 青春版 智能蓝牙通话手表',
+ '罗技 M330 降噪静音无线鼠标 曜石黑',
+ '绿联 六合一Type-C多功能扩展坞',
+ '品胜 苹果PD 20W快充编织数据线 1.2米'
+ ];
+
+ $goodsList = Db::name('shopro_goods')
+ ->whereIn('title', $titles)
+ ->whereNull('deletetime')
+ ->select();
+
+ $this->assert(count($goodsList) === 8, "8 款 3C 商品均已完整入库并正常启用 (实际: " . count($goodsList) . ")");
+
+ $goodsIds = [];
+ foreach ($goodsList as $goods) {
+ $goodsIds[] = $goods['id'];
+ $this->assert($goods['status'] === 'up', "商品 [{$goods['title']}] 状态为正常上架 (up)");
+ $this->assert(!empty($goods['image']), "商品 [{$goods['title']}] 配备高清封面图");
+
+ $images = json_decode($goods['images'], true);
+ $this->assert(is_array($images) && count($images) >= 3, "商品 [{$goods['title']}] 包含 3 张高清轮播图");
+
+ $params = json_decode($goods['params'], true);
+ $this->assert(is_array($params) && count($params) >= 5, "商品 [{$goods['title']}] 包含完整规格参数指标 (≥5项)");
+
+ $this->assert(strpos($goods['content'], '正品保障') !== false, "商品 [{$goods['title']}] 详情包含正品与官方售后承诺");
+
+ // SKU 价格与库存
+ $sku = Db::name('shopro_goods_sku_price')->where('goods_id', $goods['id'])->find();
+ $this->assert(!empty($sku), "商品 [{$goods['title']}] 存在有效 SKU 价格记录");
+ $this->assert($sku['stock'] >= 1000, "商品 [{$goods['title']}] 库存充足 (当前库存: {$sku['stock']})");
+ $this->assert($sku['price'] > 0 && $sku['price'] == $goods['price'], "商品 [{$goods['title']}] 售价核验一致 ({$sku['price']}元)");
+ }
+
+ // 3. API 模拟测试
+ echo "\n--- 场景 3: API 模拟测试 (覆盖正常/业务失败/参数异常) ---\n";
+
+ // 3.1 正常场景: 查询分类下的商品
+ $mobileCat = Db::name('shopro_category')->where('parent_id', 153)->where('name', '手机数码')->find();
+ $mobileGoods = Db::name('shopro_goods')
+ ->whereRaw("find_in_set({$mobileCat['id']}, category_ids)")
+ ->where('status', 'up')
+ ->whereNull('deletetime')
+ ->select();
+ $this->assert(count($mobileGoods) >= 3, "API 模拟: 查询 [手机数码] 分类成功返回对应商品 (返回: " . count($mobileGoods) . "款)");
+
+ // 3.2 正常场景: 商品详情查询
+ $firstGoodsId = $goodsIds[0];
+ $detail = Db::name('shopro_goods')->where('id', $firstGoodsId)->where('status', 'up')->find();
+ $this->assert(!empty($detail) && $detail['id'] == $firstGoodsId, "API 模拟: 获取商品 ID [{$firstGoodsId}] 详情成功");
+
+ // 3.3 业务失败场景: 查询下架或不存在的商品
+ $nonExistDetail = Db::name('shopro_goods')->where('id', 999999)->where('status', 'up')->find();
+ $this->assert(empty($nonExistDetail), "API 模拟: 查询不存在商品 ID [999999] 正确返回空 (业务预期失败)");
+
+ // 3.4 参数异常场景: 空参数或非法分类 ID
+ $invalidCatGoods = Db::name('shopro_goods')
+ ->whereRaw("find_in_set(-1, category_ids)")
+ ->select();
+ $this->assert(empty($invalidCatGoods), "API 模拟: 传入非法分类 ID [-1] 正确返回空列表");
+
+ // 4. 装修模板 5 首页联动校验
+ echo "\n--- 场景 4: 装修模板 5 (3C数码) 首页配置联动检验 ---\n";
+ $decorPage = Db::name('shopro_decorate_page')
+ ->where('decorate_id', 5)
+ ->where('type', 'home')
+ ->find();
+ $this->assert(!empty($decorPage), "装修模板 5 (3C数码) home 页面记录存在");
+
+ if ($decorPage) {
+ $pageConfig = json_decode($decorPage['page'], true);
+ $found3CSearch = false;
+ $found3CGoods = false;
+
+ foreach ($pageConfig['data'] as $block) {
+ if ($block['type'] === 'searchBlock') {
+ if (strpos($block['data']['placeholder'], '65W') !== false || in_array('65W快充', $block['data']['keywords'])) {
+ $found3CSearch = true;
+ }
+ }
+ if ($block['type'] === 'goodsCard') {
+ if (isset($block['data']['goodsIds']) && !empty(array_intersect($block['data']['goodsIds'], $goodsIds))) {
+ $found3CGoods = true;
+ }
+ }
+ }
+ $this->assert($found3CSearch, "首页搜索框关键词已更新为 3C 数码热词");
+ $this->assert($found3CGoods, "首页推荐商品卡片已关联新生成的 3C 数码爆品");
+ }
+
+ echo "\n====================================================\n";
+ echo "测试执行完成: 通过 {$this->passed} 项, 失败 {$this->failed} 项\n";
+ echo "====================================================\n";
+
+ if ($this->failed > 0) {
+ exit(1);
+ }
+ }
+}
+
+$verifier = new Verify3COnlineData();
+$verifier->run();