Files
cms-SiteForge/scripts/hesupipe_v8331_preview.py
T
浅念 e21dbb6518 upgrade: adopt V8.33.1 — final merge, our patches upstreamed natively
V8.33.0 absorbed our entire platform patch set as native features
(discovery/env_for macro override/blocks.css priority/type-mapping fix/
frontend entries/locale override) and synced trade-pro from our remote;
V8.33.1 adds HESU PIPE industrial-theme home fixes (1.3.1).

Zero patch re-application this round — all verified native. Theme
suites 35/35; full run 428 passed + same 10 known Windows env fails
(FAILED set unchanged). Live: container 8.33.1-dev.1 healthy, hesupipe
192 entries intact, trade-pro build 203 pages 0 errors.

Patch registry retired to archive — future upgrades are plain overlay.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-26 14:27:17 +08:00

63 lines
6.9 KiB
Python

"""Make a fully offline industrial-theme homepage preview from the real static builder."""
import os,sys,json,html,re,tempfile
from pathlib import Path
ROOT=Path(__file__).resolve().parents[1]
sys.path[:0]=[str(ROOT),str(ROOT/'tests')]
from tests.legacy import LegacyTestClient
from app import db,theme_store
from app.main import app
def generate():
target=ROOT/'examples'; target.mkdir(exist_ok=True)
with tempfile.TemporaryDirectory() as temporary:
db.DATA=Path(temporary);db.DB_FILE=db.DATA/'data.sqlite3';theme_store.THEME_ROOT=db.DATA/'theme_packages'
os.environ['SITEFORGE_ALLOW_LEGACY_DIRECT_DESIGN_WRITE']='1'
os.environ['SITEFORGE_ADMIN_PASSWORD']='demo-test-admin-secret-2026'
os.environ['SITEFORGE_SESSION_SECRET']='demo-secret-not-for-use-outside-test-2026'
with LegacyTestClient(app) as c:
assert c.post('/api/auth/login',json={'username':'admin','password':os.environ['SITEFORGE_ADMIN_PASSWORD']}).status_code==200
c.headers.update({'X-SiteForge-CSRF':c.get('/api/auth/me').json()['csrf']})
r=c.post('/api/sites',json={'name':'HESU PIPE · 排版验证样站','theme':'industrial','domain':'https://example.test','mode':'migration','tagline':'工业管道与工程材料 · 完整产品方案'})
assert r.status_code==201,r.text; sid=r.json()['id']
home=next(e for e in c.get(f'/api/sites/{sid}/entries').json() if e['route']=='/')
assert c.put(f'/api/factory/sites/{sid}/theme',json={'theme':'industrial','version':'1.3.1'}).status_code==200
products=[('HDPE 给水管','适用于市政给水及工业供水管网。'),('双壁波纹排水管','适用于市政雨污水管网和地下排水工程。'),('PVC-U 排水管','耐腐蚀、规格丰富的塑料管材系统。'),('PPR 冷热水管','建筑冷热水输送常用管道系列。'),('钢丝网骨架复合管','适用于承压输水与工程管线系统。'),('HDPE 管道连接件','用于热熔及电熔连接的各类管件。')]
for i,(title,summary) in enumerate(products,1):
res=c.post(f'/api/sites/{sid}/entries',json={'type':'product','title':title,'route':f'/products/pipe-{i}/','summary':summary})
assert res.status_code==201,res.text
blocks=[{'id':'features-hp-v8331','type':'features','title':'核心优势','items':[
{'title':'管道产品供应','text':'覆盖多种工程管材和配件,便于项目集中采购。'},
{'title':'规格与质量管理','text':'根据实际应用提供产品选型和规格资料。'},
{'title':'工程应用支持','text':'面向供水、排水及工业管网项目的应用场景。'},
{'title':'全球交付服务','text':'从订单沟通到物流交付,提供清晰的合作流程。'},
]}, {'id':'collection-hp-v8331','type':'collection','title':'动态内容列表 · 精选产品',
'subtitle':'PRODUCT COLLECTION','source':'product','limit':6,'columns':3,
'href':'/products/','button':'查看全部产品'}]
saved=c.put(f'/api/sites/{sid}/pages/{home["id"]}/blueprint',json={'blocks':blocks,'page_template':'home'})
assert saved.status_code==200,saved.text
built=c.post(f'/api/sites/{sid}/builds',json={})
assert built.status_code==200,built.text
bid=built.json()['version']; dist=db.DATA/'builds'/sid/bid/'dist'
assert (dist/'index.html').exists(),dist
source=(dist/'index.html').read_text()
# Inline exact packaged CSS/JS, so the demo is readable without a server or external requests.
def stylesheet(m):
path=m.group(1)
local=dist/path
return '<style>\n'+local.read_text(encoding='utf-8')+'\n</style>' if local.is_file() else ''
source=re.sub(r'<link rel="stylesheet" href="(assets/[A-Za-z0-9._-]+\.css)">',stylesheet,source)
def script(m):
local=dist/m.group(1)
if local.is_file():
return '<script>\n'+local.read_text(encoding='utf-8').replace('</script','<\\/script')+'\n</script>'
return ''
source=re.sub(r'<script defer src="(assets/[A-Za-z0-9._-]+\.js)"></script>',script,source)
# These paths are demonstrative and intentionally not published.
isolated=target/'V8_33_1_HesuPipe_首页布局真实构建预览.html'
snippet=json.dumps(source,ensure_ascii=False).replace('<','\\u003c')
wrapper='''<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>HesuPipe · 首页核心优势与产品列表</title><style>*{box-sizing:border-box}body{margin:0;background:#eef2f5;color:#1d3344;font-family:system-ui,-apple-system,sans-serif}.bar{display:flex;gap:15px;align-items:center;justify-content:space-between;padding:14px 23px;background:#fff;border-bottom:1px solid #dce4e9;flex-wrap:wrap}.bar strong{font-size:16px}.bar small{display:block;font-size:11px;color:#657a89;margin-top:4px}.buttons{display:flex;gap:6px}.buttons button{border:1px solid #cbdce4;background:#f6f9fa;padding:9px 14px;border-radius:6px;font-weight:650;color:#1e4359;cursor:pointer}.buttons button[aria-pressed=true]{background:#0f5e78;color:#fff}iframe{border:0;width:100%;height:calc(100vh - 74px);min-height:550px;background:#fff;display:block;margin:auto;transition:width .15s}.note{position:fixed;right:20px;bottom:18px;border:1px solid #d0dce3;border-radius:9px;background:#fff;padding:10px 13px;font-size:12px;box-shadow:0 4px 15px #0001}</style></head><body><div class="bar"><div><strong>HESU PIPE · 核心优势 / 动态内容列表</strong><small>V8.33.1 从实际静态构建生成的离线页面 · 示范文字与占位产品图</small></div><div class="buttons"><button data-size="100%" aria-pressed="true">电脑版</button><button data-size="820px" aria-pressed="false">平板</button><button data-size="390px" aria-pressed="false">手机版</button></div></div><iframe title="工业建材主题首页实际构建预览" sandbox="allow-scripts" id="preview"></iframe><span class="note">仅检查预览 · 不连接线上网站</span><script id="payload" type="application/json">PAYLOAD</script><script>const raw=JSON.parse(document.getElementById('payload').textContent);const target=document.getElementById('preview');target.srcdoc=raw;document.querySelectorAll('[data-size]').forEach(btn=>btn.addEventListener('click',()=>{target.style.width=btn.dataset.size;document.querySelectorAll('[data-size]').forEach(item=>item.setAttribute('aria-pressed',String(item===btn)));}));</script></body></html>'''
isolated.write_text(wrapper.replace('PAYLOAD',snippet),encoding='utf-8')
(target/'v8331-real-built-page.html').write_text(source,encoding='utf-8')
print('generated',isolated,'bytes',isolated.stat().st_size,'build',bid)
if __name__=='__main__':generate()