feat(design): 全站配图重新设计为极简现代中式纯视觉艺术,彻底移除文字介绍与密集说明

这个提交包含在:
wikiboss
2026-10-09 13:58:15 +08:00
父节点 47ec398cab
当前提交 157e5f4a40
共有 23 个文件被更改,包括 1912 次插入 和 2597 次删除

查看文件

@@ -1,7 +1,8 @@
# -*- coding: utf-8 -*-
"""
生成文章资讯专属现代中式浅色专业风矢量封面图 (SVG)
尺寸 600x380,浅色专业背景、科技蓝与中国印章点缀、窗棂细线、无 emoji
生成文章资讯专属现代中式极简矢量封面图 (Concise Article Covers Generator)
彻底杜绝文字介绍类图片,纯粹以现代中式浅色专业风空间几何、流光、细线窗棂与单字印章呈现。
尺寸 600x380,浅色专业底色 #FFFFFF / #F8FAFC,主色 #2563EB,辅色 #06B6D4 / #7C3AED。
"""
import os
@@ -9,310 +10,217 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
TARGET_DIR = os.path.join(BASE_DIR, 'public', 'assets', 'addons', 'official', 'images', 'articles')
os.makedirs(TARGET_DIR, exist_ok=True)
# 模板定义
def create_article_svg(title_cn, subtitle_en, tag_text, badge_label, content_elements):
return f'''<svg width="600" height="380" viewBox="0 0 600 380" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="bgGrad" x1="0%" y1="0%" x2="100%" y2="100%">
COMMON_DEFS = '''
<linearGradient id="artBgGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#FFFFFF"/>
<stop offset="100%" stop-color="#F8FAFC"/>
</linearGradient>
<linearGradient id="primaryGrad" x1="0%" y1="0%" x2="100%" y2="0%">
<linearGradient id="artBlue" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#2563EB"/>
<stop offset="100%" stop-color="#3B82F6"/>
<stop offset="100%" stop-color="#1D4ED8"/>
</linearGradient>
<pattern id="latticeGrid" width="24" height="24" patternUnits="userSpaceOnUse">
<path d="M 24 0 L 0 0 0 24" fill="none" stroke="#E2E8F0" stroke-width="0.75" stroke-dasharray="2,2"/>
<linearGradient id="artCyan" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#06B6D4"/>
<stop offset="100%" stop-color="#0EA5E9"/>
</linearGradient>
<linearGradient id="artPurple" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#7C3AED"/>
<stop offset="100%" stop-color="#6366F1"/>
</linearGradient>
<linearGradient id="artGlass" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#FFFFFF" stop-opacity="0.85"/>
<stop offset="100%" stop-color="#F1F5F9" stop-opacity="0.6"/>
</linearGradient>
<pattern id="artLattice" width="24" height="24" patternUnits="userSpaceOnUse">
<path d="M 24 0 L 0 0 0 24" fill="none" stroke="#E2E8F0" stroke-width="0.75" stroke-dasharray="3,3"/>
</pattern>
<filter id="artShadow" x="-10%" y="-10%" width="120%" height="120%">
<feDropShadow dx="0" dy="6" stdDeviation="10" flood-color="#0F172A" flood-opacity="0.06"/>
</filter>
<filter id="artGlow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="10" result="blur"/>
<feComposite in="SourceGraphic" in2="blur" operator="over"/>
</filter>
'''
def make_art_seal(x, y, char):
return f'''
<g transform="translate({x}, {y})">
<rect width="24" height="24" rx="4" fill="#FEF2F2" stroke="#DC2626" stroke-width="1.2"/>
<rect x="2" y="2" width="20" height="20" rx="2" fill="none" stroke="#DC2626" stroke-width="0.5" stroke-opacity="0.5"/>
<text x="12" y="17" fill="#DC2626" font-family="'Noto Serif SC', 'SimSun', serif" font-size="12" font-weight="700" text-anchor="middle">{char}</text>
</g>
'''
def create_base_svg(seal_char, visual_elements):
return f'''<svg width="600" height="380" viewBox="0 0 600 380" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
{COMMON_DEFS}
</defs>
<!-- 背景卡片与淡雅窗棂网格 -->
<rect width="600" height="380" rx="8" fill="url(#bgGrad)"/>
<rect width="600" height="380" rx="8" fill="url(#latticeGrid)" opacity="0.6"/>
<rect width="600" height="380" rx="8" fill="url(#artBgGrad)"/>
<rect width="600" height="380" rx="8" fill="url(#artLattice)" opacity="0.6"/>
<rect x="1" y="1" width="598" height="378" rx="7" fill="none" stroke="#E2E8F0" stroke-width="1.5"/>
<!-- 顶部控制台标题栏 -->
<rect x="20" y="20" width="560" height="36" rx="4" fill="#FFFFFF" stroke="#E2E8F0"/>
<circle cx="36" cy="38" r="4.5" fill="#EF4444"/>
<circle cx="50" cy="38" r="4.5" fill="#F59E0B"/>
<circle cx="64" cy="38" r="4.5" fill="#10B981"/>
<text x="84" y="42" fill="#334155" font-family="'Inter', 'Noto Sans SC', sans-serif" font-size="12" font-weight="600">{subtitle_en}</text>
<!-- 中式印章 -->
<rect x="495" y="26" width="72" height="22" rx="2" fill="#FEF2F2" stroke="#EF4444" stroke-width="1"/>
<text x="502" y="42" fill="#DC2626" font-family="'Noto Serif SC', 'SimSun', serif" font-size="11" font-weight="700">{badge_label}</text>
{make_art_seal(554, 20, seal_char)}
<!-- 核心图解视窗区域 -->
{content_elements}
<!-- 底部文章标签条 -->
<rect x="20" y="324" width="560" height="36" rx="4" fill="#F1F5F9" stroke="#E2E8F0"/>
<rect x="32" y="332" width="76" height="20" rx="2" fill="#EFF6FF" stroke="#BFDBFE"/>
<text x="40" y="346" fill="#1D4ED8" font-family="'Inter', 'Noto Sans SC', sans-serif" font-size="11" font-weight="600">{tag_text}</text>
<text x="120" y="347" fill="#64748B" font-family="'Noto Serif SC', 'SimSun', serif" font-size="12">{title_cn}</text>
<text x="480" y="346" fill="#2563EB" font-family="'Inter', sans-serif" font-size="11" font-weight="600">NAHAICHUAN TECH</text>
<g transform="translate(300, 190)">
{visual_elements}
</g>
</svg>'''
articles = [
{
'file': 'article_microservice.svg',
'title': '高并发商城微服务中台分布式事务与分库分表实践',
'sub': 'Engineering Insight · High-Concurrency Mall Architecture',
'tag': '技术洞察',
'badge': '高可用中台',
'content': '''
<rect x="30" y="75" width="250" height="230" rx="6" fill="#FFFFFF" stroke="#E2E8F0"/>
<rect x="30" y="75" width="250" height="32" rx="6 6 0 0" fill="#F8FAFC"/>
<text x="44" y="96" fill="#0F172A" font-family="'Inter', 'Noto Sans SC', sans-serif" font-size="12" font-weight="700">分布式核心拓扑 (Distributed Mesh)</text>
<rect x="44" y="120" width="222" height="36" rx="4" fill="#EFF6FF" stroke="#BFDBFE"/>
<text x="54" y="142" fill="#1E40AF" font-family="'Inter', sans-serif" font-size="11">API 网关 · 限流熔断与路由分发</text>
<rect x="44" y="166" width="222" height="36" rx="4" fill="#F8FAFC" stroke="#CBD5E1"/>
<text x="54" y="188" fill="#334155" font-family="'Inter', sans-serif" font-size="11">交易订单集群 · RocketMQ 事务消息</text>
<rect x="44" y="212" width="222" height="36" rx="4" fill="#F8FAFC" stroke="#CBD5E1"/>
<text x="54" y="234" fill="#334155" font-family="'Inter', sans-serif" font-size="11">库存防超卖 · Redis RedLock + Lua 脚本</text>
<rect x="44" y="258" width="222" height="32" rx="4" fill="#ECFDF5" stroke="#A7F3D0"/>
<text x="54" y="278" fill="#065F46" font-family="'Inter', sans-serif" font-size="11">压测吞吐量: 8,500+ TPS · 延迟 &lt; 35ms</text>
articles = {
# 1. 微服务分布式事务
'article_microservice.svg': ('枢', '''
<ellipse cx="0" cy="50" rx="190" ry="75" fill="none" stroke="#E2E8F0" stroke-width="1.2" stroke-dasharray="5,4"/>
<g transform="translate(-70, 0)" filter="url(#artShadow)">
<polygon points="0,-28 35,-10 0,10 -35,-10" fill="url(#artBlue)"/>
<polygon points="-35,-10 0,10 0,34 -35,14" fill="#1D4ED8"/>
<polygon points="0,10 35,-10 35,14 0,34" fill="#1E40AF"/>
</g>
<g transform="translate(70, 0)" filter="url(#artShadow)">
<polygon points="0,-28 35,-10 0,10 -35,-10" fill="url(#artCyan)"/>
<polygon points="-35,-10 0,10 0,34 -35,14" fill="#0891B2"/>
<polygon points="0,10 35,-10 35,14 0,34" fill="#0E7490"/>
</g>
<g transform="translate(0, -50)" filter="url(#artShadow)">
<polygon points="0,-24 28,-8 0,8 -28,-8" fill="url(#artGlass)" stroke="#2563EB" stroke-width="1.2"/>
<circle cx="0" cy="0" r="4" fill="#2563EB"/>
</g>
<path d="M -70 0 Q 0 -40 70 0" fill="none" stroke="url(#artBlue)" stroke-width="2" stroke-linecap="round"/>
<path d="M 70 15 Q 0 55 -70 15" fill="none" stroke="url(#artCyan)" stroke-width="1.8" stroke-dasharray="4,3"/>
'''),
<rect x="300" y="75" width="270" height="230" rx="6" fill="#FFFFFF" stroke="#E2E8F0"/>
<rect x="300" y="75" width="270" height="32" rx="6 6 0 0" fill="#F8FAFC"/>
<text x="314" y="96" fill="#0F172A" font-family="'Inter', 'Noto Sans SC', sans-serif" font-size="12" font-weight="700">数据一致性与多租户分片</text>
<path d="M 320 135 L 550 135 M 320 180 L 550 180 M 320 225 L 550 225" stroke="#F1F5F9" stroke-width="1"/>
<text x="320" y="125" fill="#64748B" font-family="'Inter', sans-serif" font-size="10">分库分表策略 (Sharding-Sphere)</text>
<text x="320" y="150" fill="#0F172A" font-family="'Inter', sans-serif" font-size="12" font-weight="600">按商户ID哈希分区 + 订单月份归档</text>
<text x="320" y="195" fill="#64748B" font-family="'Inter', sans-serif" font-size="10">分布式事务协调 (Seata AT 模式)</text>
<text x="320" y="220" fill="#0F172A" font-family="'Inter', sans-serif" font-size="12" font-weight="600">两阶段提交 · 自动全局锁回滚机制</text>
<rect x="320" y="248" width="230" height="42" rx="4" fill="#F8FAFC" stroke="#E2E8F0"/>
<text x="330" y="274" fill="#475569" font-family="'Noto Serif SC', 'SimSun', serif" font-size="11">严谨设计:双向对账机制与死信队列自动报警</text>
'''
},
{
'file': 'article_ai_agent.svg',
'title': '企业私域AI智能体落地:RAG本地知识库与安全隔离工程',
'sub': 'AI Engineering · Private RAG & Knowledge Governance',
'tag': '技术洞察',
'badge': '私域智能体',
'content': '''
<rect x="30" y="75" width="260" height="230" rx="6" fill="#FFFFFF" stroke="#E2E8F0"/>
<rect x="30" y="75" width="260" height="32" rx="6 6 0 0" fill="#F8FAFC"/>
<text x="44" y="96" fill="#0F172A" font-family="'Inter', 'Noto Sans SC', sans-serif" font-size="12" font-weight="700">RAG 双路检索与溯源流水线</text>
<rect x="44" y="120" width="232" height="36" rx="4" fill="#EFF6FF" stroke="#BFDBFE"/>
<text x="54" y="142" fill="#1E40AF" font-family="'Inter', sans-serif" font-size="11">密集向量检索 (Milvus) + BM25 稀疏全文</text>
<rect x="44" y="166" width="232" height="36" rx="4" fill="#F8FAFC" stroke="#CBD5E1"/>
<text x="54" y="188" fill="#334155" font-family="'Inter', sans-serif" font-size="11">跨编码器 Rerank 重排序引擎 (Top-5)</text>
<rect x="44" y="212" width="232" height="36" rx="4" fill="#F8FAFC" stroke="#CBD5E1"/>
<text x="54" y="234" fill="#334155" font-family="'Inter', sans-serif" font-size="11">原文章节双向锚定 (章节溯源防幻觉)</text>
<rect x="44" y="258" width="232" height="32" rx="4" fill="#ECFDF5" stroke="#A7F3D0"/>
<text x="54" y="278" fill="#065F46" font-family="'Inter', sans-serif" font-size="11">检索命中准确率: 95.8% · 响应 &lt; 1.2s</text>
# 2. 跨端APP与小程序
'article_cross_app.svg': ('端', '''
<ellipse cx="0" cy="60" rx="180" ry="65" fill="none" stroke="#E2E8F0" stroke-width="1.2" stroke-dasharray="4,4"/>
<g transform="translate(-65, -10)" filter="url(#artShadow)">
<rect x="-45" y="-65" width="90" height="130" rx="6" fill="url(#artGlass)" stroke="#CBD5E1" stroke-width="1.2"/>
<rect x="-35" y="-55" width="70" height="95" rx="3" fill="#FFFFFF" stroke="#E2E8F0"/>
<circle cx="0" cy="52" r="3" fill="#94A3B8"/>
</g>
<g transform="translate(65, 10)" filter="url(#artShadow)">
<rect x="-32" y="-70" width="64" height="140" rx="10" fill="#FFFFFF" stroke="#2563EB" stroke-width="1.5"/>
<rect x="-26" y="-55" width="52" height="110" rx="5" fill="url(#artBgGrad)"/>
<circle cx="0" cy="-20" r="14" fill="url(#artPurple)"/>
</g>
<path d="M -20 -15 C 10 -40 30 -30 65 -15" fill="none" stroke="url(#artCyan)" stroke-width="2" stroke-linecap="round"/>
<circle cx="20" cy="-25" r="4" fill="#06B6D4" filter="url(#artGlow)"/>
'''),
<rect x="310" y="75" width="260" height="230" rx="6" fill="#FFFFFF" stroke="#E2E8F0"/>
<rect x="310" y="75" width="260" height="32" rx="6 6 0 0" fill="#F8FAFC"/>
<text x="324" y="96" fill="#0F172A" font-family="'Inter', 'Noto Sans SC', sans-serif" font-size="12" font-weight="700">纯内网物理隔离安全沙箱</text>
<rect x="324" y="120" width="232" height="48" rx="4" fill="#FEF2F2" stroke="#FECACA"/>
<text x="334" y="142" fill="#991B1B" font-family="'Inter', sans-serif" font-size="11" font-weight="600">物理隔离隔离域 · 零外网数据外泄</text>
<text x="334" y="158" fill="#B91C1C" font-family="'Inter', sans-serif" font-size="10">私有算力服务器量化部署 · 内网专网运行</text>
<rect x="324" y="178" width="232" height="42" rx="4" fill="#F8FAFC" stroke="#E2E8F0"/>
<text x="334" y="196" fill="#334155" font-family="'Inter', sans-serif" font-size="11" font-weight="600">企业角色级敏感数据脱敏 (RBAC)</text>
<text x="334" y="210" fill="#64748B" font-family="'Inter', sans-serif" font-size="10">动态字段脱敏 · 问答审计日志永久加密归档</text>
<rect x="324" y="230" width="232" height="60" rx="4" fill="#F1F5F9" stroke="#E2E8F0"/>
<text x="334" y="254" fill="#475569" font-family="'Noto Serif SC', 'SimSun', serif" font-size="11">工程交付:提供完整微调脚本、</text>
<text x="334" y="272" fill="#475569" font-family="'Noto Serif SC', 'SimSun', serif" font-size="11">向量分块策略与内网环境 Docker 镜像包</text>
'''
},
{
'file': 'article_erp_bom.svg',
'title': '全链路进销存系统的业财一体化构建与动态BOM算法',
'sub': 'Enterprise Systems · Multi-Level BOM & Financial Cohesion',
'tag': '技术洞察',
'badge': '进销存架构',
'content': '''
<rect x="30" y="75" width="260" height="230" rx="6" fill="#FFFFFF" stroke="#E2E8F0"/>
<rect x="30" y="75" width="260" height="32" rx="6 6 0 0" fill="#F8FAFC"/>
<text x="44" y="96" fill="#0F172A" font-family="'Inter', 'Noto Sans SC', sans-serif" font-size="12" font-weight="700">多级动态 BOM 树状递归模型</text>
<rect x="44" y="120" width="232" height="34" rx="4" fill="#EFF6FF" stroke="#BFDBFE"/>
<text x="54" y="141" fill="#1E40AF" font-family="'Inter', sans-serif" font-size="11">成品装配节点 · 动态工时与损耗率核算</text>
<rect x="44" y="162" width="232" height="34" rx="4" fill="#F8FAFC" stroke="#CBD5E1"/>
<text x="54" y="183" fill="#334155" font-family="'Inter', sans-serif" font-size="11">半成品自递归拆解 · 齐套率缺料实时预警</text>
<rect x="44" y="204" width="232" height="34" rx="4" fill="#F8FAFC" stroke="#CBD5E1"/>
<text x="54" y="225" fill="#334155" font-family="'Inter', sans-serif" font-size="11">原料批次批号绑定 · 一物一码全流程溯源</text>
<rect x="44" y="246" width="232" height="44" rx="4" fill="#ECFDF5" stroke="#A7F3D0"/>
<text x="54" y="265" fill="#065F46" font-family="'Inter', sans-serif" font-size="11">35,000+ SKU 大数据量下</text>
<text x="54" y="280" fill="#065F46" font-family="'Inter', sans-serif" font-size="10">生产需求计算 (MRP) 耗时稳定在 1.8 秒内</text>
# 3. 私域AI智能体落地
'article_ai_agent.svg': ('智', '''
<circle cx="0" cy="0" r="100" fill="#FAF5FF" opacity="0.7"/>
<ellipse cx="0" cy="0" rx="150" ry="60" fill="none" stroke="#E2E8F0" stroke-width="1.2" stroke-dasharray="5,4" transform="rotate(-30)"/>
<ellipse cx="0" cy="0" rx="150" ry="60" fill="none" stroke="#E2E8F0" stroke-width="1.2" stroke-dasharray="5,4" transform="rotate(30)"/>
<polygon points="0,-50 45,-20 45,25 0,55 -45,25 -45,-20" fill="none" stroke="#93C5FD" stroke-width="1.2"/>
<circle cx="0" cy="0" r="24" fill="url(#artPurple)" filter="url(#artShadow)"/>
<circle cx="0" cy="0" r="15" fill="url(#artBlue)"/>
<circle cx="0" cy="0" r="6" fill="#FFFFFF"/>
<circle cx="-130" cy="0" r="5" fill="#7C3AED" transform="rotate(-30)"/>
<circle cx="130" cy="0" r="5" fill="#06B6D4" transform="rotate(30)"/>
'''),
<rect x="310" y="75" width="260" height="230" rx="6" fill="#FFFFFF" stroke="#E2E8F0"/>
<rect x="310" y="75" width="260" height="32" rx="6 6 0 0" fill="#F8FAFC"/>
<text x="324" y="96" fill="#0F172A" font-family="'Inter', 'Noto Sans SC', sans-serif" font-size="12" font-weight="700">业务与财务闭环核算引擎</text>
<text x="324" y="125" fill="#64748B" font-family="'Inter', sans-serif" font-size="10">三单智能自动匹配 (Three-Way Match)</text>
<text x="324" y="148" fill="#0F172A" font-family="'Inter', sans-serif" font-size="12" font-weight="600">采购订单 = 验收送货单 = 进项发票</text>
<text x="324" y="185" fill="#64748B" font-family="'Inter', sans-serif" font-size="10">不停产动态快照盘点 (Dynamic Stocktake)</text>
<text x="324" y="208" fill="#0F172A" font-family="'Inter', sans-serif" font-size="12" font-weight="600">基于快照时点 + 增量出入库流水对冲</text>
<rect x="324" y="235" width="232" height="55" rx="4" fill="#F8FAFC" stroke="#E2E8F0"/>
<text x="334" y="258" fill="#475569" font-family="'Noto Serif SC', 'SimSun', serif" font-size="11">消除信息孤岛:财务科目凭证自动生成,</text>
<text x="334" y="275" fill="#475569" font-family="'Noto Serif SC', 'SimSun', serif" font-size="11">应收应付账期与信用额度实时联锁控制</text>
'''
},
{
'file': 'article_cross_app.svg',
'title': '跨端移动开发工程化实践:Flutter与Uni-app选型与调优',
'sub': 'Mobile & IoT · Cross-Platform Rendering & Bluetooth BLE',
'tag': '技术洞察',
'badge': '跨端开发',
'content': '''
<rect x="30" y="75" width="260" height="230" rx="6" fill="#FFFFFF" stroke="#E2E8F0"/>
<rect x="30" y="75" width="260" height="32" rx="6 6 0 0" fill="#F8FAFC"/>
<text x="44" y="96" fill="#0F172A" font-family="'Inter', 'Noto Sans SC', sans-serif" font-size="12" font-weight="700">架构选型决策矩阵</text>
<rect x="44" y="120" width="232" height="50" rx="4" fill="#EFF6FF" stroke="#BFDBFE"/>
<text x="54" y="142" fill="#1E40AF" font-family="'Inter', sans-serif" font-size="11" font-weight="600">Flutter 自绘引擎 (iOS / Android)</text>
<text x="54" y="158" fill="#2563EB" font-family="'Inter', sans-serif" font-size="10">Skia/Impeller 底层渲染 · 稳定 60fps 高帧率</text>
<rect x="44" y="178" width="232" height="50" rx="4" fill="#F8FAFC" stroke="#CBD5E1"/>
<text x="54" y="200" fill="#334155" font-family="'Inter', sans-serif" font-size="11" font-weight="600">Uni-app 全生态 (微信 / 支付宝 / 抖音)</text>
<text x="54" y="216" fill="#64748B" font-family="'Inter', sans-serif" font-size="10">轻量跨小程序运行环境 · 微信生态无缝裂变</text>
<rect x="44" y="236" width="232" height="54" rx="4" fill="#ECFDF5" stroke="#A7F3D0"/>
<text x="54" y="258" fill="#065F46" font-family="'Inter', sans-serif" font-size="11">首屏启动性能冷启动优化</text>
<text x="54" y="274" fill="#065F46" font-family="'Inter', sans-serif" font-size="10">分包预加载 + 异步骨架屏,启动压缩至 680ms</text>
# 4. 断网离线收银
'article_pos_offline.svg': ('笃', '''
<circle cx="0" cy="0" r="120" fill="none" stroke="#E2E8F0" stroke-width="1" stroke-dasharray="4,4"/>
<circle cx="0" cy="0" r="90" fill="none" stroke="#CBD5E1" stroke-width="1.2"/>
<path d="M 0 -70 L 45 -45 V 0 C 45 35 0 70 0 70 C 0 70 -45 35 -45 0 V -45 Z" fill="url(#artGlass)" stroke="#CBD5E1" stroke-width="1.5" filter="url(#artShadow)"/>
<circle cx="0" cy="0" r="22" fill="url(#artBlue)" filter="url(#artGlow)"/>
<circle cx="0" cy="0" r="10" fill="#FFFFFF"/>
<line x1="-90" y1="0" x2="-22" y2="0" stroke="url(#artCyan)" stroke-width="2" stroke-linecap="round"/>
<line x1="22" y1="0" x2="90" y2="0" stroke="url(#artBlue)" stroke-width="2" stroke-linecap="round"/>
<circle cx="-90" cy="0" r="4.5" fill="#06B6D4"/>
<circle cx="90" cy="0" r="4.5" fill="#2563EB"/>
'''),
<rect x="310" y="75" width="260" height="230" rx="6" fill="#FFFFFF" stroke="#E2E8F0"/>
<rect x="310" y="75" width="260" height="32" rx="6 6 0 0" fill="#F8FAFC"/>
<text x="324" y="96" fill="#0F172A" font-family="'Inter', 'Noto Sans SC', sans-serif" font-size="12" font-weight="700">低功耗蓝牙 (BLE) 工业外设直连</text>
<text x="324" y="125" fill="#64748B" font-family="'Inter', sans-serif" font-size="10">状态机自动重连与心跳保活机制</text>
<text x="324" y="148" fill="#0F172A" font-family="'Inter', sans-serif" font-size="12" font-weight="600">扫描 -> GATT握手 -> 特征订阅 -> 丢包重传</text>
<text x="324" y="185" fill="#64748B" font-family="'Inter', sans-serif" font-size="10">原生平台通道双向通信 (MethodChannel)</text>
<text x="324" y="208" fill="#0F172A" font-family="'Inter', sans-serif" font-size="12" font-weight="600">热敏打印机 / 工业手持扫码枪指令秒级解析</text>
<rect x="324" y="235" width="232" height="55" rx="4" fill="#F8FAFC" stroke="#E2E8F0"/>
<text x="334" y="258" fill="#475569" font-family="'Noto Serif SC', 'SimSun', serif" font-size="11">内存优化实录:大图纹理缓存精细回收,</text>
<text x="334" y="275" fill="#475569" font-family="'Noto Serif SC', 'SimSun', serif" font-size="11">连续操作 8 小时无卡顿与 OOM 闪退</text>
'''
},
{
'file': 'article_pos_offline.svg',
'title': '新零售商业收银系统容灾:弱网断网离线记账机制解析',
'sub': 'POS Reliability · Offline Transactions & Queue Recovery',
'tag': '技术洞察',
'badge': '收银容灾',
'content': '''
<rect x="30" y="75" width="260" height="230" rx="6" fill="#FFFFFF" stroke="#E2E8F0"/>
<rect x="30" y="75" width="260" height="32" rx="6 6 0 0" fill="#F8FAFC"/>
<text x="44" y="96" fill="#0F172A" font-family="'Inter', 'Noto Sans SC', sans-serif" font-size="12" font-weight="700">门店离线记账沙箱架构</text>
<rect x="44" y="120" width="232" height="36" rx="4" fill="#EFF6FF" stroke="#BFDBFE"/>
<text x="54" y="142" fill="#1E40AF" font-family="'Inter', sans-serif" font-size="11">本地 SQLite 离线存储 · 全加密暂存凭单</text>
<rect x="44" y="166" width="232" height="36" rx="4" fill="#F8FAFC" stroke="#CBD5E1"/>
<text x="54" y="188" fill="#334155" font-family="'Inter', sans-serif" font-size="11">后厨 ESC/POS 打印机双网口局域网直连</text>
<rect x="44" y="212" width="232" height="36" rx="4" fill="#F8FAFC" stroke="#CBD5E1"/>
<text x="54" y="234" fill="#334155" font-family="'Inter', sans-serif" font-size="11">断网期间保障点单、出票、挂账平稳运行</text>
<rect x="44" y="258" width="232" height="32" rx="4" fill="#ECFDF5" stroke="#A7F3D0"/>
<text x="54" y="278" fill="#065F46" font-family="'Inter', sans-serif" font-size="11">离线丢单率: 0% · 扫码付响应 &lt; 0.3s</text>
# 5. 进销存BOM物料匹配
'article_erp_bom.svg': ('准', '''
<ellipse cx="0" cy="55" rx="170" ry="60" fill="none" stroke="#E2E8F0" stroke-width="1.2" stroke-dasharray="4,4"/>
<g transform="translate(-65, 15)" filter="url(#artShadow)">
<polygon points="0,-25 30,-8 0,8 -30,-8" fill="url(#artGlass)" stroke="#CBD5E1" stroke-width="1.2"/>
<polygon points="-30,-8 0,8 0,28 -30,12" fill="#E2E8F0"/>
<polygon points="0,8 30,-8 30,12 0,28" fill="#F1F5F9"/>
</g>
<g transform="translate(65, 15)" filter="url(#artShadow)">
<polygon points="0,-25 30,-8 0,8 -30,-8" fill="url(#artGlass)" stroke="#CBD5E1" stroke-width="1.2"/>
<polygon points="-30,-8 0,8 0,28 -30,12" fill="#E2E8F0"/>
<polygon points="0,8 30,-8 30,12 0,28" fill="#F1F5F9"/>
</g>
<g transform="translate(0, -30)" filter="url(#artShadow)">
<circle cx="0" cy="0" r="32" fill="none" stroke="#2563EB" stroke-width="1.2" stroke-dasharray="4,4"/>
<circle cx="0" cy="0" r="22" fill="url(#artBlue)"/>
<circle cx="0" cy="0" r="8" fill="#FFFFFF"/>
</g>
<path d="M -65 5 Q 0 -15 65 5" fill="none" stroke="url(#artCyan)" stroke-width="2" stroke-linecap="round"/>
'''),
<rect x="310" y="75" width="260" height="230" rx="6" fill="#FFFFFF" stroke="#E2E8F0"/>
<rect x="310" y="75" width="260" height="32" rx="6 6 0 0" fill="#F8FAFC"/>
<text x="324" y="96" fill="#0F172A" font-family="'Inter', 'Noto Sans SC', sans-serif" font-size="12" font-weight="700">网络恢复幂等自动同步状态机</text>
<text x="324" y="125" fill="#64748B" font-family="'Inter', sans-serif" font-size="10">幂等性与重试控制 (Idempotency Engine)</text>
<text x="324" y="148" fill="#0F172A" font-family="'Inter', sans-serif" font-size="12" font-weight="600">全局雪花ID防重校验 · 事务幂等入库</text>
<text x="324" y="185" fill="#64748B" font-family="'Inter', sans-serif" font-size="10">增量冲突消解策略 (Conflict Resolution)</text>
<text x="324" y="208" fill="#0F172A" font-family="'Inter', sans-serif" font-size="12" font-weight="600">版本号时钟排序 · 差异对账自动生成补差单</text>
<rect x="324" y="235" width="232" height="55" rx="4" fill="#F8FAFC" stroke="#E2E8F0"/>
<text x="334" y="258" fill="#475569" font-family="'Noto Serif SC', 'SimSun', serif" font-size="11">经受 300+ 实体门店连续 720 天生产考验,</text>
<text x="334" y="275" fill="#475569" font-family="'Noto Serif SC', 'SimSun', serif" font-size="11">高可靠断网防御与零财务差错保障</text>
'''
},
{
'file': 'article_tdd_standards.svg',
'title': '贵阳纳海川科技全线推行规范工程与完整源码交付标准',
'sub': 'Quality Assurance · Engineering Standards & Full Source Code Delivery',
'tag': '公司动态',
'badge': '交付规范',
'content': '''
<rect x="30" y="75" width="260" height="230" rx="6" fill="#FFFFFF" stroke="#E2E8F0"/>
<rect x="30" y="75" width="260" height="32" rx="6 6 0 0" fill="#F8FAFC"/>
<text x="44" y="96" fill="#0F172A" font-family="'Inter', 'Noto Sans SC', sans-serif" font-size="12" font-weight="700">规范化持续集成与自动化测试</text>
<rect x="44" y="120" width="232" height="36" rx="4" fill="#FEF2F2" stroke="#FECACA"/>
<text x="54" y="142" fill="#991B1B" font-family="'Inter', sans-serif" font-size="11">1. 编写业务需求与接口自动化用例</text>
<rect x="44" y="166" width="232" height="36" rx="4" fill="#ECFDF5" stroke="#A7F3D0"/>
<text x="54" y="188" fill="#065F46" font-family="'Inter', sans-serif" font-size="11">2. 规范化高质量代码实现与接口对接</text>
<rect x="44" y="212" width="232" height="36" rx="4" fill="#EFF6FF" stroke="#BFDBFE"/>
<text x="54" y="234" fill="#1E40AF" font-family="'Inter', sans-serif" font-size="11">3. 多轮代码审查与自动化回归测试</text>
<rect x="44" y="258" width="232" height="32" rx="4" fill="#F8FAFC" stroke="#CBD5E1"/>
<text x="54" y="278" fill="#334155" font-family="'Inter', sans-serif" font-size="11">核心接口自动化测试覆盖率 &gt; 85%</text>
# 6. 安全合规白皮书
'article_security_whitepaper.svg': ('安', '''
<polygon points="0,-95 82,-47 82,47 0,95 -82,47 -82,-47" fill="none" stroke="#E2E8F0" stroke-width="1.2" stroke-dasharray="4,4"/>
<polygon points="0,-75 65,-37 65,37 0,75 -65,37 -65,-37" fill="url(#artGlass)" stroke="#CBD5E1" stroke-width="1.5" filter="url(#artShadow)"/>
<circle cx="0" cy="0" r="26" fill="url(#artPurple)"/>
<circle cx="0" cy="0" r="14" fill="url(#artBlue)"/>
<circle cx="0" cy="0" r="6" fill="#FFFFFF"/>
<circle cx="0" cy="-75" r="4" fill="#2563EB"/>
<circle cx="65" cy="-37" r="4" fill="#7C3AED"/>
<circle cx="65" cy="37" r="4" fill="#06B6D4"/>
<circle cx="0" cy="75" r="4" fill="#2563EB"/>
<circle cx="-65" cy="37" r="4" fill="#7C3AED"/>
<circle cx="-65" cy="-37" r="4" fill="#06B6D4"/>
'''),
<rect x="310" y="75" width="260" height="230" rx="6" fill="#FFFFFF" stroke="#E2E8F0"/>
<rect x="310" y="75" width="260" height="32" rx="6 6 0 0" fill="#F8FAFC"/>
<text x="324" y="96" fill="#0F172A" font-family="'Inter', 'Noto Sans SC', sans-serif" font-size="12" font-weight="700">100% 完整工程源码交付清单</text>
<text x="324" y="125" fill="#64748B" font-family="'Inter', sans-serif" font-size="10">工程可控资产 (Engineering Assets)</text>
<text x="324" y="148" fill="#0F172A" font-family="'Inter', sans-serif" font-size="12" font-weight="600">完整无加密 Git 源码仓库与提交历史</text>
<text x="324" y="185" fill="#64748B" font-family="'Inter', sans-serif" font-size="10">设计与架构文档 (Documentation)</text>
<text x="324" y="208" fill="#0F172A" font-family="'Inter', sans-serif" font-size="12" font-weight="600">数据库字典 + 拓扑蓝图 + 运维部署手册</text>
<rect x="324" y="235" width="232" height="55" rx="4" fill="#F8FAFC" stroke="#E2E8F0"/>
<text x="334" y="258" fill="#475569" font-family="'Noto Serif SC', 'SimSun', serif" font-size="11">坚决杜绝外包套壳模板代码,</text>
<text x="334" y="275" fill="#475569" font-family="'Noto Serif SC', 'SimSun', serif" font-size="11">确保企业客户对数字资产拥有完整掌控权</text>
'''
},
{
'file': 'article_security_whitepaper.svg',
'title': '纳海川发布《企业级微服务安全审计与合规防护白皮书》',
'sub': 'Security Whitepaper · Microservice Defense & Cryptography',
'tag': '公司动态',
'badge': '安全合规',
'content': '''
<rect x="30" y="75" width="260" height="230" rx="6" fill="#FFFFFF" stroke="#E2E8F0"/>
<rect x="30" y="75" width="260" height="32" rx="6 6 0 0" fill="#F8FAFC"/>
<text x="44" y="96" fill="#0F172A" font-family="'Inter', 'Noto Sans SC', sans-serif" font-size="12" font-weight="700">微服务零信任纵深防御模型</text>
<rect x="44" y="120" width="232" height="36" rx="4" fill="#EFF6FF" stroke="#BFDBFE"/>
<text x="54" y="142" fill="#1E40AF" font-family="'Inter', sans-serif" font-size="11">mTLS 双向证书通信 · 服务间调用零信任</text>
<rect x="44" y="166" width="232" height="36" rx="4" fill="#F8FAFC" stroke="#CBD5E1"/>
<text x="54" y="188" fill="#334155" font-family="'Inter', sans-serif" font-size="11">国密 SM4 敏感信息加密存储与脱敏传输</text>
<rect x="44" y="212" width="232" height="36" rx="4" fill="#F8FAFC" stroke="#CBD5E1"/>
<text x="54" y="234" fill="#334155" font-family="'Inter', sans-serif" font-size="11">SQL 预编译防注入 + XSS 白名单严格转义</text>
<rect x="44" y="258" width="232" height="32" rx="4" fill="#ECFDF5" stroke="#A7F3D0"/>
<text x="54" y="278" fill="#065F46" font-family="'Inter', sans-serif" font-size="11">国家信息系统安全等级保护三级对照设计</text>
# 7. 数字化转型路径
'article_southwest_digital.svg': ('融', '''
<ellipse cx="0" cy="20" rx="180" ry="80" fill="none" stroke="#E2E8F0" stroke-width="1.2" stroke-dasharray="5,4"/>
<g filter="url(#artShadow)">
<circle cx="0" cy="0" r="28" fill="url(#artBlue)"/>
<circle cx="0" cy="0" r="12" fill="#FFFFFF"/>
</g>
<g transform="translate(-110, -25)">
<circle cx="0" cy="0" r="16" fill="url(#artGlass)" stroke="#2563EB" stroke-width="1.2"/>
<circle cx="0" cy="0" r="5" fill="#2563EB"/>
<line x1="0" y1="0" x2="85" y2="20" stroke="#93C5FD" stroke-width="1.5" stroke-dasharray="3,3"/>
</g>
<g transform="translate(110, -25)">
<circle cx="0" cy="0" r="16" fill="url(#artGlass)" stroke="#06B6D4" stroke-width="1.2"/>
<circle cx="0" cy="0" r="5" fill="#06B6D4"/>
<line x1="0" y1="0" x2="-85" y2="20" stroke="#93C5FD" stroke-width="1.5" stroke-dasharray="3,3"/>
</g>
<g transform="translate(0, 70)">
<circle cx="0" cy="0" r="14" fill="url(#artGlass)" stroke="#7C3AED" stroke-width="1"/>
<circle cx="0" cy="0" r="4.5" fill="#7C3AED"/>
<line x1="0" y1="0" x2="0" y2="-42" stroke="#CBD5E1" stroke-width="1.2"/>
</g>
'''),
<rect x="310" y="75" width="260" height="230" rx="6" fill="#FFFFFF" stroke="#E2E8F0"/>
<rect x="310" y="75" width="260" height="32" rx="6 6 0 0" fill="#F8FAFC"/>
<text x="324" y="96" fill="#0F172A" font-family="'Inter', 'Noto Sans SC', sans-serif" font-size="12" font-weight="700">全链路审计闭环与合规追溯</text>
<text x="324" y="125" fill="#64748B" font-family="'Inter', sans-serif" font-size="10">全链路跟踪 (Distributed TraceID)</text>
<text x="324" y="148" fill="#0F172A" font-family="'Inter', sans-serif" font-size="12" font-weight="600">网关到存储统一链路标识,毫秒级定位异常</text>
<text x="324" y="185" fill="#64748B" font-family="'Inter', sans-serif" font-size="10">不可篡改审计日志 (Tamper-Proof Audit)</text>
<text x="324" y="208" fill="#0F172A" font-family="'Inter', sans-serif" font-size="12" font-weight="600">管理端关键动作数字签名存证归档</text>
<rect x="324" y="235" width="232" height="55" rx="4" fill="#F8FAFC" stroke="#E2E8F0"/>
<text x="334" y="258" fill="#475569" font-family="'Noto Serif SC', 'SimSun', serif" font-size="11">白皮书全面总结政企系统交付经验,</text>
<text x="334" y="275" fill="#475569" font-family="'Noto Serif SC', 'SimSun', serif" font-size="11">赋能实体企业低成本达成数据安全法规合规</text>
'''
},
{
'file': 'article_southwest_digital.svg',
'title': '立足贵阳服务全国:纳海川助力数十家实体企业数字化转型纪实',
'sub': 'Regional Practice · Southwest Digital Middle Platform Realization',
'tag': '公司动态',
'badge': '本地服务',
'content': '''
<rect x="30" y="75" width="260" height="230" rx="6" fill="#FFFFFF" stroke="#E2E8F0"/>
<rect x="30" y="75" width="260" height="32" rx="6 6 0 0" fill="#F8FAFC"/>
<text x="44" y="96" fill="#0F172A" font-family="'Inter', 'Noto Sans SC', sans-serif" font-size="12" font-weight="700">贵阳本土驻场服务技术优势</text>
<rect x="44" y="120" width="232" height="36" rx="4" fill="#EFF6FF" stroke="#BFDBFE"/>
<text x="54" y="142" fill="#1E40AF" font-family="'Inter', sans-serif" font-size="11">自有本地研发团队 · 资深架构师面对面沟通</text>
<rect x="44" y="166" width="232" height="36" rx="4" fill="#F8FAFC" stroke="#CBD5E1"/>
<text x="54" y="188" fill="#334155" font-family="'Inter', sans-serif" font-size="11">深入车间、门店与仓库现场梳理真实业务逻辑</text>
<rect x="44" y="212" width="232" height="36" rx="4" fill="#F8FAFC" stroke="#CBD5E1"/>
<text x="54" y="234" fill="#334155" font-family="'Inter', sans-serif" font-size="11">拒绝二次转包 · 杜绝异地沟通信息失真</text>
<rect x="44" y="258" width="232" height="32" rx="4" fill="#ECFDF5" stroke="#A7F3D0"/>
<text x="54" y="278" fill="#065F46" font-family="'Inter', sans-serif" font-size="11">响应时效: &lt;15分钟响应 · 紧急现场2小时内到达</text>
# 8. TDD 工程规范
'article_tdd_standards.svg': ('律', '''
<circle cx="0" cy="0" r="110" fill="none" stroke="#E2E8F0" stroke-width="1" stroke-dasharray="5,5"/>
<g transform="translate(-60, 0)" filter="url(#artShadow)">
<circle cx="0" cy="0" r="30" fill="url(#artBlue)"/>
<circle cx="0" cy="0" r="12" fill="#FFFFFF"/>
<circle cx="0" cy="0" r="5" fill="#1D4ED8"/>
</g>
<g transform="translate(60, 0)" filter="url(#artShadow)">
<circle cx="0" cy="0" r="30" fill="url(#artCyan)"/>
<circle cx="0" cy="0" r="12" fill="#FFFFFF"/>
<circle cx="0" cy="0" r="5" fill="#0891B2"/>
</g>
<path d="M -30 -15 C 0 -35 0 -35 30 -15" fill="none" stroke="url(#artBlue)" stroke-width="2.2" stroke-linecap="round"/>
<path d="M 30 15 C 0 35 0 35 -30 15" fill="none" stroke="url(#artCyan)" stroke-width="2.2" stroke-linecap="round"/>
<circle cx="0" cy="-26" r="4" fill="#2563EB" filter="url(#artGlow)"/>
<circle cx="0" cy="26" r="4" fill="#06B6D4" filter="url(#artGlow)"/>
''')
}
<rect x="310" y="75" width="260" height="230" rx="6" fill="#FFFFFF" stroke="#E2E8F0"/>
<rect x="310" y="75" width="260" height="32" rx="6 6 0 0" fill="#F8FAFC"/>
<text x="324" y="96" fill="#0F172A" font-family="'Inter', 'Noto Sans SC', sans-serif" font-size="12" font-weight="700">实体企业转型标杆收益矩阵</text>
<text x="324" y="125" fill="#64748B" font-family="'Inter', sans-serif" font-size="10">生产周转效率 (Operational Velocity)</text>
<text x="324" y="148" fill="#0F172A" font-family="'Inter', sans-serif" font-size="12" font-weight="600">库存物料占用压降 35% · 交付周期缩短 40%</text>
<text x="324" y="185" fill="#64748B" font-family="'Inter', sans-serif" font-size="10">售后与维保承诺 (Warranty & SLA)</text>
<text x="324" y="208" fill="#0F172A" font-family="'Inter', sans-serif" font-size="12" font-weight="600">首年 365 天免费运维 · 终身技术架构咨询支持</text>
<rect x="324" y="235" width="232" height="55" rx="4" fill="#F8FAFC" stroke="#E2E8F0"/>
<text x="334" y="258" fill="#475569" font-family="'Noto Serif SC', 'SimSun', serif" font-size="11">立足贵阳研发优势,以严谨务实技术态度,</text>
<text x="334" y="275" fill="#475569" font-family="'Noto Serif SC', 'SimSun', serif" font-size="11">为实体企业交付扎实稳固的数字化业务系统</text>
'''
}
]
def generate_all_articles():
for fname, (seal, vis) in articles.items():
content = create_base_svg(seal, vis)
path = os.path.join(TARGET_DIR, fname)
with open(path, 'w', encoding='utf-8') as f:
f.write(content.strip())
print(f"Generated concise article cover: {fname} ({len(content)} bytes)")
for a in articles:
svg_code = create_article_svg(a['title'], a['sub'], a['tag'], a['badge'], a['content'])
file_path = os.path.join(TARGET_DIR, a['file'])
with open(file_path, 'w', encoding='utf-8') as f:
f.write(svg_code)
print(f"Generated: {a['file']}")
print("All 8 article covers successfully generated!")
if __name__ == '__main__':
generate_all_articles()

文件差异内容过多而无法显示 加载差异

查看文件

@@ -279,6 +279,15 @@ def test_dedicated_service_pages_suite():
res.assert_true(test_result.wasSuccessful(), f"三大服务独立页断言全部通过 (共 {test_result.testsRun} 项)")
return res.summary()
def test_concise_showcase_images_suite():
res = TestResult("配图简洁性与去文字化专项测试 (ConciseShowcaseImages)")
from tests.test_concise_showcase_images import ConciseShowcaseImagesTest
suite = unittest.TestLoader().loadTestsFromTestCase(ConciseShowcaseImagesTest)
runner = unittest.TextTestRunner(verbosity=0)
test_result = runner.run(suite)
res.assert_true(test_result.wasSuccessful(), f"配图简洁性与去文字化断言全部通过 (共 {test_result.testsRun} 项)")
return res.summary()
def main():
import unittest
results = [
@@ -294,7 +303,8 @@ def main():
test_natural_copywriting_suite(),
test_homepage_button_links_suite(),
test_journalism_and_articles_suite(),
test_dedicated_service_pages_suite()
test_dedicated_service_pages_suite(),
test_concise_showcase_images_suite()
]
sys.exit(0 if all(results) else 1)

查看文件

@@ -0,0 +1,128 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
配图简洁性与去文字化自动化测试 (TDD - Test-Driven Development)
验证要求:
1. 网站配图必须简洁高质感,绝不能是文字介绍类的图片(无冗余业务文字、功能列表、参数指标等)。
2. showcases 核心配图(服务3张、产品4张、案例4张)必须为纯粹的高端视觉图形或概念拓扑,text 标签数量严格限制(≤ 1,仅允许极简中式印章微标如单字印文或纯图形无文字)。
3. articles 封面配图必须为极简抽象科技艺术构图,杜绝长篇标题与说明文字堆砌(text 标签 ≤ 1)。
4. 严格遵循现代中式浅色专业风规范(背景 #FFFFFF / #F8FAFC,主色 #2563EB 科技蓝,辅色 #06B6D4 青 / #7C3AED 紫,细线与留白)。
5. 配图文件完整存在且大小合理,SVG 语法严格闭合。
"""
import os
import re
import unittest
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
class ConciseShowcaseImagesTest(unittest.TestCase):
def setUp(self):
self.showcases_dir = os.path.join(BASE_DIR, 'public', 'assets', 'addons', 'official', 'images', 'showcases')
self.articles_dir = os.path.join(BASE_DIR, 'public', 'assets', 'addons', 'official', 'images', 'articles')
self.core_showcase_files = [
# 服务类
'service_middle.svg',
'service_app.svg',
'service_agent.svg',
# 产品类
'product_mall.svg',
'product_pos.svg',
'product_erp.svg',
'product_saas.svg',
# 案例类
'case_distrib.svg',
'case_catering.svg',
'case_gov_agent.svg',
'case_manufacture.svg'
]
self.article_files = [
'article_microservice.svg',
'article_cross_app.svg',
'article_ai_agent.svg',
'article_pos_offline.svg',
'article_erp_bom.svg',
'article_security_whitepaper.svg',
'article_southwest_digital.svg',
'article_tdd_standards.svg'
]
def test_01_showcases_are_concise_not_text_intro(self):
"""核心业务配图必须简洁纯粹,杜绝文字介绍类图片(text 标签不超过1个,严禁包含业务功能段落)"""
self.assertTrue(os.path.isdir(self.showcases_dir), "showcases 目录必须存在")
text_regex = re.compile(r'<text[^>]*>(.*?)</text>', re.DOTALL | re.IGNORECASE)
for fname in self.core_showcase_files:
fpath = os.path.join(self.showcases_dir, fname)
self.assertTrue(os.path.isfile(fpath), f"配图 {fname} 必须存在")
with open(fpath, 'r', encoding='utf-8') as f:
content = f.read()
# 提取所有 <text> 标签中实际显示的文字
matches = text_regex.findall(content)
clean_texts = [re.sub(r'<[^>]+>', '', m).strip() for m in matches if m.strip()]
# 简洁要求:可见文字数量 ≤ 1(纯图形无文字,或最多仅含极简单字印章如'研'/'商'/'通'等)
self.assertLessEqual(
len(clean_texts), 1,
f"配图 {fname} 必须简洁,不能是文字介绍类图片!当前检测到 {len(clean_texts)} 处文字: {clean_texts[:5]}"
)
# 严禁在可见文本中出现功能描述词、参数指标词、业务列表等
forbidden_intro_words = [
'控制台', '架构', '文档分块', '向量化', '网关', '订单', '履约', '调度',
'分销', '营销', '收银', '核销', '物料', '进销存', 'SaaS', '多租户', 'API'
]
all_visible_text = ' '.join(clean_texts)
for word in forbidden_intro_words:
self.assertNotIn(word, all_visible_text, f"配图 {fname} 中严禁出现业务介绍文字: '{word}'")
def test_02_articles_are_concise_artwork(self):
"""文章封面必须简洁大气,不能包含大段标题或业务文字(text 标签不超过1个)"""
if os.path.isdir(self.articles_dir):
text_regex = re.compile(r'<text[^>]*>(.*?)</text>', re.DOTALL | re.IGNORECASE)
for fname in self.article_files:
fpath = os.path.join(self.articles_dir, fname)
if os.path.isfile(fpath):
with open(fpath, 'r', encoding='utf-8') as f:
content = f.read()
matches = text_regex.findall(content)
clean_texts = [re.sub(r'<[^>]+>', '', m).strip() for m in matches if m.strip()]
self.assertLessEqual(
len(clean_texts), 1,
f"文章配图 {fname} 必须简洁,不能堆砌冗长介绍文字!当前有 {len(clean_texts)} 处文字: {clean_texts[:5]}"
)
def test_03_color_palette_and_modern_style(self):
"""配图必须符合浅色专业风现代中式设计规范(含 #2563EB 科技蓝与浅色背景)"""
for fname in self.core_showcase_files:
fpath = os.path.join(self.showcases_dir, fname)
with open(fpath, 'r', encoding='utf-8') as f:
content = f.read()
# 浅色系与主色
self.assertTrue(
'#2563EB' in content or '#1D4ED8' in content or '#3B82F6' in content,
f"配图 {fname} 必须包含主色科技蓝 (#2563EB)"
)
self.assertTrue(
'#FFFFFF' in content or '#F8FAFC' in content or '#EFF6FF' in content,
f"配图 {fname} 必须为浅色专业风底色"
)
def test_04_svg_structure_validity(self):
"""SVG 必须具有合法闭合结构与合理的 viewBox"""
for fname in self.core_showcase_files:
fpath = os.path.join(self.showcases_dir, fname)
with open(fpath, 'r', encoding='utf-8') as f:
content = f.read()
self.assertTrue(content.strip().startswith('<svg'), f"{fname} 必须以 <svg 开头")
self.assertTrue(content.strip().endswith('</svg>'), f"{fname} 必须以 </svg> 闭合")
self.assertIn('viewBox', content, f"{fname} 必须指定 viewBox 属性以确保自适应")
if __name__ == '__main__':
unittest.main()