feat(goods): 增加微信小程序审核专用真实3C产品与分类线上生成及验证脚本

这个提交包含在:
chen
2026-09-26 16:13:50 +08:00
父节点 e2ed46ba3d
当前提交 cacd1acac0
共有 3 个文件被更改,包括 1111 次插入 和 0 次删除

查看文件

@@ -0,0 +1,488 @@
<?php
/**
* 线上生成真实 3C 产品与分类维护脚本 (用于微信小程序上架审核)
*
* 包含:
* 1. 4 个真实的 3C 数码分类 (手机数码、智能影音、智能穿戴、电脑办公)
* 2. 8 款真实主流知名品牌 3C 商品 (倍思、漫步者、罗马仕、华为、小米、罗技、绿联、品胜)
* 3. 关联更新单规格 SKU 价格、库存与服务保障
* 4. 联动更新装修模板 5 (3C数码模板) 首页推荐商品与搜索热词
*/
// 载入 ThinkPHP 框架基础
define('APP_PATH', __DIR__ . '/../application/');
define('ROOT_PATH', dirname(realpath(APP_PATH)) . '/');
require_once __DIR__ . '/../thinkphp/base.php';
require_once __DIR__ . '/../thinkphp/helper.php';
require_once __DIR__ . '/../application/common.php';
if (is_file(ROOT_PATH . '.env')) {
$env = parse_ini_file(ROOT_PATH . '.env', true);
foreach ($env as $key => $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 = <<<HTML
<div style="padding:10px 0;text-align:center;">
<p style="font-size:15px;color:#1e293b;font-weight:bold;margin:8px 0;">{$item['title']}</p>
<p style="font-size:12px;color:#64748b;margin-bottom:14px;">{$item['subtitle']}</p>
<p><img src="/uploads/henglian_goods/3c/p_{$i}/detail_1.jpg" style="width:100%;max-width:750px;display:block;margin:0 auto 10px auto;border-radius:8px;" /></p>
<p><img src="/uploads/henglian_goods/3c/p_{$i}/detail_2.jpg" style="width:100%;max-width:750px;display:block;margin:0 auto 10px auto;border-radius:8px;" /></p>
<p><img src="/uploads/henglian_goods/3c/p_{$i}/detail_3.jpg" style="width:100%;max-width:750px;display:block;margin:0 auto 10px auto;border-radius:8px;" /></p>
<div style="background:#f8fafc;padding:16px;border-radius:8px;text-align:left;font-size:13px;color:#475569;line-height:1.8;margin-top:12px;">
<p style="font-weight:bold;color:#0f172a;margin-bottom:6px;">【正品保障与官方售后承诺】</p>
<p>1. 本品为正品行货,支持全国统一防伪验证,享受原厂保修及技术支持服务;</p>
<p>2. 签收之日起支持 7 天无理由退换货(需保持未激活、商品主体与包装完整未损);</p>
<p>3. 质量问题 30 天内包换,1 年内享受全国联合保修;</p>
<p>4. 每日 16:00 前完成支付的订单,当日顺丰/京东快递速发,全国顺畅直达。</p>
</div>
</div>
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();

查看文件

@@ -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()

查看文件

@@ -0,0 +1,199 @@
<?php
/**
* 线上 3C 商品与分类完整性校验测试脚本
*
* 覆盖:
* 1. 分类层级与权重测试
* 2. 8 款 3C 商品与 SKU 价格/库存数据完整性测试
* 3. 前端接口模拟测试 (正常场景、业务失败场景、参数错误场景)
* 4. 装修模板 5 首页推荐联动验证
*/
namespace tests\goods;
define('APP_PATH', __DIR__ . '/../application/');
define('ROOT_PATH', dirname(realpath(APP_PATH)) . '/');
require_once __DIR__ . '/../thinkphp/base.php';
require_once __DIR__ . '/../thinkphp/helper.php';
require_once __DIR__ . '/../application/common.php';
if (is_file(ROOT_PATH . '.env')) {
$env = parse_ini_file(ROOT_PATH . '.env', true);
foreach ($env as $key => $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();