diff --git a/core/frontend/src/ai-tools-page.css b/core/frontend/src/ai-tools-page.css index f8c871b..3450a01 100644 --- a/core/frontend/src/ai-tools-page.css +++ b/core/frontend/src/ai-tools-page.css @@ -38,6 +38,8 @@ flex-direction: column; gap: 18px; height: 100%; + /* 盖掉旧全局 .factory-body(styles.css) 漏进来的 align-items:center —— 否则内容被居中、宽卡里偏离左边老远 */ + align-items: stretch; } .asset-factory .factory-text { display: flex; flex-direction: column; min-width: 0; } diff --git a/core/qa/visual-parity/_measure-factory.mjs b/core/qa/visual-parity/_measure-factory.mjs new file mode 100644 index 0000000..f3ede2d --- /dev/null +++ b/core/qa/visual-parity/_measure-factory.mjs @@ -0,0 +1,19 @@ +import { chromium } from "playwright"; +const b=await chromium.launch({headless:true}); +async function measure(w){ + const ctx=await b.newContext({viewport:{width:w,height:900}}); + const p=await ctx.newPage(); + await p.goto("http://localhost:5200/login"); await p.waitForTimeout(300); + await p.fill("#auth-username","airshelf"); await p.fill("#auth-pwd","Restraint2026"); + await p.click("button.btn-cta"); await p.waitForFunction(()=>!location.pathname.startsWith("/login"),{timeout:12000}); + await p.goto("http://localhost:5200/asset-factory"); await p.waitForTimeout(1500); + const card=await p.locator(".factory-card").first().boundingBox(); + const tag=await p.locator(".factory-card").first().locator(".factory-tag").boundingBox(); + const title=await p.locator(".factory-card").first().locator(".factory-title").boundingBox(); + if(w===1200) await p.locator(".factory-card").first().screenshot({path:"../../../_qa_shots/factory-fixed.png"}); + await ctx.close(); + return {viewport:w, cardW:Math.round(card.width), tag_offset:Math.round(tag.x-card.x), title_offset:Math.round(title.x-card.x)}; +} +console.log(JSON.stringify(await measure(1440))); +console.log(JSON.stringify(await measure(1200))); +await b.close();