From c86f92bb94a49e34d117be28ed7b23cd04a6adba Mon Sep 17 00:00:00 2001 From: chen Date: Thu, 17 Sep 2026 17:53:38 +0800 Subject: [PATCH] =?UTF-8?q?feat(decorate):=20=E5=BD=92=E6=A1=A3=E6=81=92?= =?UTF-8?q?=E9=93=BE=E6=95=B0=E9=80=9A=E6=97=97=E8=88=B0=E5=95=86=E5=9F=8E?= =?UTF-8?q?=E8=A3=85=E4=BF=AE=E6=A8=A1=E6=9D=BF=E8=BF=81=E7=A7=BB=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E4=B8=8E=E8=A7=86=E8=A7=89=E6=B5=B7=E6=8A=A5=E6=9E=84?= =?UTF-8?q?=E5=BB=BA=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/sql/decorate-template-henglian-2026.sql | 25 ++ scripts/generate_banners.py | 315 +++++++++++++++++++ 2 files changed, 340 insertions(+) create mode 100644 docs/sql/decorate-template-henglian-2026.sql create mode 100644 scripts/generate_banners.py diff --git a/docs/sql/decorate-template-henglian-2026.sql b/docs/sql/decorate-template-henglian-2026.sql new file mode 100644 index 0000000..f343989 --- /dev/null +++ b/docs/sql/decorate-template-henglian-2026.sql @@ -0,0 +1,25 @@ +-- ============================================================================== +-- 恒链数通商城 - 旗舰主营产品装修模板与分类校准迁移脚本 +-- 归档时间: 2026-09-17 +-- 适用平台: WechatOfficialAccount, WechatMiniProgram, H5, App +-- ============================================================================== + +-- 1. 商品分类绑定关系校准(白酒:154,155,158;美护:163,164) +UPDATE `hla_shopro_goods` SET `category_ids` = '153,154,155,158' WHERE `id` IN (34, 35); +UPDATE `hla_shopro_goods` SET `category_ids` = '153,163,164' WHERE `id` IN (32, 33); + +-- 2. 分类横幅与封面更新 +UPDATE `hla_shopro_category` SET `image` = '/uploads/henglian_goods/20260917/ff1b5f21/cc03fa9120352080.jpg' WHERE `id` = 154; +UPDATE `hla_shopro_category` SET `image` = '/uploads/henglian_goods/20260917/c76a38b6/0a6fed04b792a271.png' WHERE `id` = 163; +UPDATE `hla_shopro_category` SET `image` = '/uploads/henglian_goods/20260917/3a0470ce/e335dc712cf6d84a.jpg' WHERE `id` = 167; + +-- 3. 启用模板2(恒链数通 · 旗舰臻选),清除软删除标记,全平台发布 +UPDATE `hla_shopro_decorate` +SET `name` = '恒链数通 · 旗舰臻选', + `status` = 'enable', + `platform` = 'WechatOfficialAccount,WechatMiniProgram,H5,App', + `deletetime` = NULL +WHERE `id` = 2; + +-- 4. 禁用其他冲突模板 +UPDATE `hla_shopro_decorate` SET `status` = 'disabled' WHERE `id` != 2; diff --git a/scripts/generate_banners.py b/scripts/generate_banners.py new file mode 100644 index 0000000..f8f91ab --- /dev/null +++ b/scripts/generate_banners.py @@ -0,0 +1,315 @@ +import math +from PIL import Image, ImageDraw, ImageFont, ImageFilter + +W, H = 1420, 640 +font_title = "/System/Library/Fonts/Supplemental/Songti.ttc" +font_text = "/System/Library/Fonts/STHeiti Medium.ttc" + +def create_gradient(w, h, c1, c2, horizontal=True): + base = Image.new('RGBA', (w, h), c1) + top = Image.new('RGBA', (w, h), c2) + mask = Image.new('L', (w, h)) + for y in range(h): + for x in range(w): + ratio = x / w if horizontal else y / h + mask.putpixel((x, y), int(255 * ratio)) + base.paste(top, (0, 0), mask) + return base + +def draw_pill(draw, xy, fill, outline=None, width=1): + draw.rounded_rectangle(xy, radius=xy[3]-xy[1], fill=fill, outline=outline, width=width) + +# ==================== BANNER 1: WINE ==================== +def build_wine_banner(): + # Base background: dark luxury burgundy + bg = create_gradient(W, H, (35, 12, 14, 255), (15, 6, 8, 255), horizontal=True) + draw = ImageDraw.Draw(bg) + + # Ambient gold glow circle + glow = Image.new('RGBA', (W, H), (0, 0, 0, 0)) + g_draw = ImageDraw.Draw(glow) + g_draw.ellipse([900, -100, 1600, 700], fill=(212, 160, 89, 40)) + glow = glow.filter(ImageFilter.GaussianBlur(80)) + bg = Image.alpha_composite(bg, glow) + draw = ImageDraw.Draw(bg) + + # Border & frame accents + draw.rounded_rectangle([16, 16, W-16, H-16], radius=24, outline=(212, 175, 110, 80), width=2) + + # Tag + font_tag = ImageFont.truetype(font_text, 28) + tag_text = "✦ 国酿琼浆 · 东方名酒专区 ✦" + draw.rounded_rectangle([80, 80, 520, 130], radius=25, fill=(60, 20, 24, 200), outline=(212, 175, 110, 200), width=2) + draw.text((105, 92), tag_text, font=font_tag, fill=(245, 215, 160)) + + # Title + font_t = ImageFont.truetype(font_title, 68) + draw.text((80, 165), "贵州飞天盛世 · 龙抬头", font=font_t, fill=(255, 235, 195)) + + # Subtitle + font_s = ImageFont.truetype(font_text, 34) + draw.text((80, 265), "古法大曲坤沙足年窖藏 | 传世名酿 · 宴饮礼遇", font=font_s, fill=(210, 185, 170)) + + font_s2 = ImageFont.truetype(font_text, 28) + draw.text((80, 325), "陶坛封坛 · 酱香幽雅 · 回味悠长 · 祥瑞尊享", font=font_s2, fill=(160, 140, 135)) + + # CTA Button + draw.rounded_rectangle([80, 420, 460, 500], radius=40, fill=(197, 160, 89, 255)) + font_btn = ImageFont.truetype(font_text, 32) + draw.text((120, 442), "官方尊享价 ¥1398 立即品鉴 →", font=font_btn, fill=(25, 10, 12)) + + # Trust chips + font_chip = ImageFont.truetype(font_text, 24) + draw.text((80, 540), "✔ 官方正品保真 ✔ 原厂陶坛直采 ✔ 顺丰保价尊享配", font=font_chip, fill=(180, 155, 130)) + + # Right products: wine_blue & wine_red + img_red = Image.open('/tmp/henglian_assets/wine_red.jpg').convert('RGBA') + img_blue = Image.open('/tmp/henglian_assets/wine_blue.jpg').convert('RGBA') + + # Resize & crop + red_w, red_h = 460, int(460 * (img_red.height / img_red.width)) + img_red_r = img_red.resize((red_w, red_h), Image.Resampling.LANCZOS) + + blue_w, blue_h = 420, int(420 * (img_blue.height / img_blue.width)) + img_blue_r = img_blue.resize((blue_w, blue_h), Image.Resampling.LANCZOS) + + # Crop to neat card style on right + card_right = Image.new('RGBA', (W, H), (0, 0, 0, 0)) + + # Make rounded masks for product cards + def rounded_card(img, size, radius=20): + c = img.resize(size, Image.Resampling.LANCZOS) + mask = Image.new('L', size, 0) + m_draw = ImageDraw.Draw(mask) + m_draw.rounded_rectangle([0, 0, size[0], size[1]], radius=radius, fill=255) + res = Image.new('RGBA', size, (0, 0, 0, 0)) + res.paste(c, (0, 0), mask) + return res + + p1 = rounded_card(img_red, (380, 460), radius=24) + p2 = rounded_card(img_blue, (360, 420), radius=24) + + # Border for product cards + def add_border(img, radius=24): + border = Image.new('RGBA', img.size, (0, 0, 0, 0)) + b_draw = ImageDraw.Draw(border) + b_draw.rounded_rectangle([0, 0, img.size[0]-1, img.size[1]-1], radius=radius, outline=(212, 175, 110, 180), width=3) + return Image.alpha_composite(img, border) + + p1 = add_border(p1) + p2 = add_border(p2) + + # Shadow for p1, p2 + shadow = Image.new('RGBA', (W, H), (0, 0, 0, 0)) + s_draw = ImageDraw.Draw(shadow) + s_draw.rounded_rectangle([650, 110, 650+360, 110+420], radius=24, fill=(0, 0, 0, 120)) + s_draw.rounded_rectangle([970, 80, 970+380, 80+460], radius=24, fill=(0, 0, 0, 150)) + shadow = shadow.filter(ImageFilter.GaussianBlur(30)) + bg = Image.alpha_composite(bg, shadow) + + bg.paste(p2, (660, 110), p2) + bg.paste(p1, (980, 80), p1) + + bg.convert('RGB').save('/tmp/henglian_assets/banner_wine.jpg', quality=95) + print("banner_wine.jpg generated") + +# ==================== BANNER 2: SKINCARE ==================== +def build_skincare_banner(): + # Base background: luxury emerald / jade green + bg = create_gradient(W, H, (14, 38, 32, 255), (6, 18, 15, 255), horizontal=True) + draw = ImageDraw.Draw(bg) + + # Ambient mint/teal glow + glow = Image.new('RGBA', (W, H), (0, 0, 0, 0)) + g_draw = ImageDraw.Draw(glow) + g_draw.ellipse([900, -100, 1600, 700], fill=(64, 180, 140, 45)) + glow = glow.filter(ImageFilter.GaussianBlur(80)) + bg = Image.alpha_composite(bg, glow) + draw = ImageDraw.Draw(bg) + + # Frame + draw.rounded_rectangle([16, 16, W-16, H-16], radius=24, outline=(100, 200, 165, 80), width=2) + + # Tag + font_tag = ImageFont.truetype(font_text, 28) + tag_text = "✦ 极光凝时 · 医研美护专区 ✦" + draw.rounded_rectangle([80, 80, 520, 130], radius=25, fill=(20, 55, 45, 200), outline=(100, 200, 165, 200), width=2) + draw.text((105, 92), tag_text, font=font_tag, fill=(180, 240, 220)) + + # Title + font_t = ImageFont.truetype(font_title, 68) + draw.text((80, 165), "润泽优选 · 轻盈赋活系列", font=font_t, fill=(235, 255, 248)) + + # Subtitle + font_s = ImageFont.truetype(font_text, 34) + draw.text((80, 265), "医研级西林瓶锁鲜 | 一秒赋活 · 紧致淡纹抗皱", font=font_s, fill=(185, 225, 215)) + + font_s2 = ImageFont.truetype(font_text, 28) + draw.text((80, 325), "高纯活性精粹 · 密集修护赋能 · 水润焕亮无负担", font=font_s2, fill=(130, 180, 168)) + + # CTA Button + draw.rounded_rectangle([80, 420, 460, 500], radius=40, fill=(50, 150, 120, 255)) + font_btn = ImageFont.truetype(font_text, 32) + draw.text((120, 442), "官方尊享价 ¥1398 焕活美肌 →", font=font_btn, fill=(255, 255, 255)) + + # Trust chips + font_chip = ImageFont.truetype(font_text, 24) + draw.text((80, 540), "✔ 医研级鲜活锁鲜 ✔ 多维抗皱淡纹 ✔ 院线赋能滋养", font=font_chip, fill=(160, 215, 200)) + + # Right products: skincare_runze & skincare_qingying + img_runze = Image.open('/tmp/henglian_assets/skincare_runze.png').convert('RGBA') + img_qing = Image.open('/tmp/henglian_assets/skincare_qingying.png').convert('RGBA') + + def rounded_card(img, size, radius=20): + c = img.resize(size, Image.Resampling.LANCZOS) + mask = Image.new('L', size, 0) + m_draw = ImageDraw.Draw(mask) + m_draw.rounded_rectangle([0, 0, size[0], size[1]], radius=radius, fill=255) + res = Image.new('RGBA', size, (0, 0, 0, 0)) + res.paste(c, (0, 0), mask) + return res + + def add_border(img, radius=24): + border = Image.new('RGBA', img.size, (0, 0, 0, 0)) + b_draw = ImageDraw.Draw(border) + b_draw.rounded_rectangle([0, 0, img.size[0]-1, img.size[1]-1], radius=radius, outline=(100, 200, 165, 180), width=3) + return Image.alpha_composite(img, border) + + p1 = add_border(rounded_card(img_runze, (380, 440), radius=24)) + p2 = add_border(rounded_card(img_qing, (360, 420), radius=24)) + + shadow = Image.new('RGBA', (W, H), (0, 0, 0, 0)) + s_draw = ImageDraw.Draw(shadow) + s_draw.rounded_rectangle([660, 110, 660+360, 110+420], radius=24, fill=(0, 0, 0, 100)) + s_draw.rounded_rectangle([980, 90, 980+380, 90+440], radius=24, fill=(0, 0, 0, 120)) + shadow = shadow.filter(ImageFilter.GaussianBlur(30)) + bg = Image.alpha_composite(bg, shadow) + + bg.paste(p2, (660, 110), p2) + bg.paste(p1, (980, 90), p1) + + bg.convert('RGB').save('/tmp/henglian_assets/banner_skincare.jpg', quality=95) + print("banner_skincare.jpg generated") + +# ==================== BANNER 3: PARTNER ==================== +def build_partner_banner(): + # Base background: prestige navy & gold + bg = create_gradient(W, H, (12, 24, 45, 255), (5, 10, 20, 255), horizontal=True) + draw = ImageDraw.Draw(bg) + + # Warm gold aura + glow = Image.new('RGBA', (W, H), (0, 0, 0, 0)) + g_draw = ImageDraw.Draw(glow) + g_draw.ellipse([800, -50, 1500, 650], fill=(212, 175, 110, 40)) + glow = glow.filter(ImageFilter.GaussianBlur(80)) + bg = Image.alpha_composite(bg, glow) + draw = ImageDraw.Draw(bg) + + draw.rounded_rectangle([16, 16, W-16, H-16], radius=24, outline=(212, 175, 110, 80), width=2) + + # Tag + font_tag = ImageFont.truetype(font_text, 28) + tag_text = "✦ 恒链合伙人 · 共享新零售红利 ✦" + draw.rounded_rectangle([80, 80, 560, 130], radius=25, fill=(25, 40, 70, 200), outline=(212, 175, 110, 200), width=2) + draw.text((105, 92), tag_text, font=font_tag, fill=(245, 220, 165)) + + # Title + font_t = ImageFont.truetype(font_title, 68) + draw.text((80, 165), "聚势共赢 · 开启数字化财富新篇", font=font_t, fill=(255, 240, 205)) + + # Subtitle + font_s = ImageFont.truetype(font_text, 34) + draw.text((80, 265), "零门槛赋能体系 | 高额佣金 · 裂变倍增 · 团队管理", font=font_s, fill=(195, 210, 235)) + + font_s2 = ImageFont.truetype(font_text, 28) + draw.text((80, 325), "全链路数字分销 · 私域专属顾问 · 收益实时明细透明", font=font_s2, fill=(140, 165, 195)) + + # CTA Button + draw.rounded_rectangle([80, 420, 460, 500], radius=40, fill=(212, 175, 110, 255)) + font_btn = ImageFont.truetype(font_text, 32) + draw.text((120, 442), "立即进入团队中心 · 查阅权益 →", font=font_btn, fill=(15, 25, 45)) + + # Trust chips + font_chip = ImageFont.truetype(font_text, 24) + draw.text((80, 540), "✔ 专属推广海报 ✔ 团队收益实时结算 ✔ 尊崇合伙人礼遇", font=font_chip, fill=(185, 200, 225)) + + # Right graphic: Golden geometric emblem / shield + emblem = Image.new('RGBA', (480, 480), (0, 0, 0, 0)) + e_draw = ImageDraw.Draw(emblem) + + # Concentric rings & diamond + e_draw.ellipse([40, 40, 440, 440], outline=(212, 175, 110, 160), width=4) + e_draw.ellipse([80, 80, 400, 400], outline=(212, 175, 110, 100), width=2) + e_draw.ellipse([120, 120, 360, 360], fill=(30, 50, 85, 180), outline=(212, 175, 110, 220), width=4) + + font_emb = ImageFont.truetype(font_title, 48) + font_emb_sub = ImageFont.truetype(font_text, 26) + + e_draw.text((150, 180), "恒链合伙", font=font_emb, fill=(255, 235, 185)) + e_draw.text((170, 250), "VIP PARTNER", font=font_emb_sub, fill=(212, 175, 110)) + e_draw.text((160, 290), "共创 · 共享 · 共赢", font=font_emb_sub, fill=(180, 200, 230)) + + bg.paste(emblem, (850, 80), emblem) + + bg.convert('RGB').save('/tmp/henglian_assets/banner_partner.jpg', quality=95) + print("banner_partner.jpg generated") + +if __name__ == '__main__': + build_wine_banner() + build_skincare_banner() + build_partner_banner() + +def build_menu_icons(): + font_menu = ImageFont.truetype(font_title, 42) + font_sub = ImageFont.truetype(font_text, 22) + + menus = [ + ("menu_wine.png", "白酒", "典藏", (85, 25, 25), (212, 175, 110)), + ("menu_skincare.png", "美护", "赋活", (25, 65, 50), (130, 220, 185)), + ("menu_partner.png", "合伙", "中心", (25, 45, 80), (230, 200, 130)), + ("menu_gift.png", "尊享", "礼盒", (95, 45, 20), (245, 210, 150)), + ("menu_coupon.png", "领券", "福利", (90, 30, 60), (250, 180, 200)), + ] + + for filename, t1, t2, bg_c, fg_c in menus: + size = (160, 160) + img = Image.new('RGBA', size, (0, 0, 0, 0)) + d = ImageDraw.Draw(img) + + # Soft background circle with border + d.ellipse([6, 6, 154, 154], fill=(*bg_c, 240), outline=(*fg_c, 200), width=3) + d.ellipse([14, 14, 146, 146], outline=(*fg_c, 80), width=1) + + # Text + d.text((40, 42), t1, font=font_menu, fill=(*fg_c, 255)) + d.text((58, 96), t2, font=font_sub, fill=(240, 240, 240, 220)) + + img.save('/tmp/henglian_assets/' + filename) + print(filename, "generated") + +build_menu_icons() + +def build_trust_bar(): + size = (1420, 110) + img = Image.new('RGBA', size, (0, 0, 0, 0)) + d = ImageDraw.Draw(img) + + # Rounded card background + d.rounded_rectangle([4, 4, 1416, 106], radius=20, fill=(255, 255, 255, 255), outline=(230, 215, 190, 200), width=2) + + font_bar = ImageFont.truetype(font_text, 28) + + items = [ + ("✦ 100% 官方正品", 120, (197, 160, 89)), + ("✦ 产地源头直采", 480, (197, 160, 89)), + ("✦ 顺丰冷链速达", 830, (197, 160, 89)), + ("✦ 尊崇私享服务", 1160, (197, 160, 89)), + ] + + for text, x, col in items: + d.text((x, 38), text, font=font_bar, fill=(50, 40, 35)) + + img.save('/tmp/henglian_assets/trust_bar.png') + print("trust_bar.png generated") + +build_trust_bar()