fix: 效果图渲染歪斜线(Canvas stroke落错路径, 高光四边形被误描边), RenderCanvas/variantRenderer/photoCompose 三处同型缺陷修复
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
- [2026-10-05 06:11] FIX: v2.37 效果图渲染歪斜线修复——Canvas stroke 落错路径。根因: 玻璃多边形 fill 后叠加高光四边形(beginPath 新路径), 其后 ctx.stroke() 描的是最后构建的高光斜四边形而非玻璃多边形, 型材线全部变成斜线; 同型缺陷 3 处一并修复: RenderCanvas.vue(效果图渲染, stroke 移至高光前)+variantRenderer.ts renderAI(AI 炫图本地渲染, restore 后重建玻璃多边形路径再 stroke)+photoCompose.ts(照片式 AI 合成, 同 RenderCanvas 改法); 排查方法: 无头浏览器 hook moveTo/lineTo/beginPath 还原绘制序列, 证实矩形区域路径全部轴对齐、歪线恰为 3 个高光平行四边形; 高光斜带本为设计效果(clip 玻璃内)保留不变; 巡检 24 页 0 异常 (Files: frontend/src/components/RenderCanvas.vue, frontend/src/components/variantRenderer.ts, frontend/src/components/photoCompose.ts)
|
||||||
- [2026-10-05 05:58] FEAT: v2.36 成本核算模块——鲁铭成本核算 Excel 全量适配。解析 12 表工作簿(铝成本/铝计算/木成本+价格库 8 表): 价格库 580 条(华健型材模具 397/丝吉利娅 207/索宾柯 52/隔热条 42/胶条 56/赛遨 54/螺丝 39/其他 23)导入产品价格本(同名更新/异名新建, material 按 sheet 语义映射 profile/hardware/addon/glass); 「铝成本」页→CostSeriesTemplate 系列成本模板(75框扇齐平1.4/85框扇齐平1.8/95窗纱一体1.8, data JSON 八分区: window/profile/addon/strip/seal/glass/extra/hardware/labor); 估算器口径对齐核算表(固定类料随固定面积/开启类随开启面积/once 按樘数缩放, 人工+其他成本优先用核算表每平实际口径, 毛利阶梯 10%~70%); 75 系列基准窗估算 total=1118.20 与核算表成本合计完全一致(85/95 同样精确还原); API: /api/costbook import-excel/series/estimate CRUD; 前端 /cost_estimate 页(系列卡片+参数估算+八分区明细+毛利阶梯+价格库 Tab+Excel 上传导入); 种子脚本 seed_costbook.py; 修复 6 处解析缺陷(95系列号格式/隔热条total字段/胶条辅材辅件编号列空漏采/玻璃面积重复乘块数/once分支漏加total/基准窗面积等效); 回归: 冒烟 60/60(新增 COST-1~9)+24 页巡检 0 异常+深度审计 16/16 (Files: src/huamenchuang/services/costbook_service.py, src/huamenchuang/api/costbook.py, src/huamenchuang/api/router.py, src/huamenchuang/models/business.py, src/huamenchuang/models/__init__.py, src/huamenchuang/scripts/seed_costbook.py, src/huamenchuang/scripts/smoke_all.py, frontend/src/views/CostEstimateView.vue, frontend/src/views/LayoutView.vue, frontend/src/router/index.ts, frontend/scripts/verify-pages.mjs, doc/API.md)
|
- [2026-10-05 05:58] FEAT: v2.36 成本核算模块——鲁铭成本核算 Excel 全量适配。解析 12 表工作簿(铝成本/铝计算/木成本+价格库 8 表): 价格库 580 条(华健型材模具 397/丝吉利娅 207/索宾柯 52/隔热条 42/胶条 56/赛遨 54/螺丝 39/其他 23)导入产品价格本(同名更新/异名新建, material 按 sheet 语义映射 profile/hardware/addon/glass); 「铝成本」页→CostSeriesTemplate 系列成本模板(75框扇齐平1.4/85框扇齐平1.8/95窗纱一体1.8, data JSON 八分区: window/profile/addon/strip/seal/glass/extra/hardware/labor); 估算器口径对齐核算表(固定类料随固定面积/开启类随开启面积/once 按樘数缩放, 人工+其他成本优先用核算表每平实际口径, 毛利阶梯 10%~70%); 75 系列基准窗估算 total=1118.20 与核算表成本合计完全一致(85/95 同样精确还原); API: /api/costbook import-excel/series/estimate CRUD; 前端 /cost_estimate 页(系列卡片+参数估算+八分区明细+毛利阶梯+价格库 Tab+Excel 上传导入); 种子脚本 seed_costbook.py; 修复 6 处解析缺陷(95系列号格式/隔热条total字段/胶条辅材辅件编号列空漏采/玻璃面积重复乘块数/once分支漏加total/基准窗面积等效); 回归: 冒烟 60/60(新增 COST-1~9)+24 页巡检 0 异常+深度审计 16/16 (Files: src/huamenchuang/services/costbook_service.py, src/huamenchuang/api/costbook.py, src/huamenchuang/api/router.py, src/huamenchuang/models/business.py, src/huamenchuang/models/__init__.py, src/huamenchuang/scripts/seed_costbook.py, src/huamenchuang/scripts/smoke_all.py, frontend/src/views/CostEstimateView.vue, frontend/src/views/LayoutView.vue, frontend/src/router/index.ts, frontend/scripts/verify-pages.mjs, doc/API.md)
|
||||||
- [2026-09-26 08:30] CHORE: v2.35 系统更名"华门窗"→"定兴门窗"。替换全部用户可见名称: 侧边栏 logo(折叠态 定)/面包屑/登录页标题/分享页 logo 与页脚/页面 title(index.html)/FastAPI title(/docs Swagger)/Dockerfile 注释/各包 docstring; 代码标识符(包名 huamenchuang/数据表/JWT iss)不变; 全仓库 0 处残留, vue-tsc 0 错+构建通过, 无头浏览器验证 logo/面包屑/页面标题生效 (Files: frontend/src/views/LayoutView.vue, frontend/src/views/LoginView.vue, frontend/src/views/ShareView.vue, frontend/index.html, src/huamenchuang/main.py, src/huamenchuang/*/…)__
|
- [2026-09-26 08:30] CHORE: v2.35 系统更名"华门窗"→"定兴门窗"。替换全部用户可见名称: 侧边栏 logo(折叠态 定)/面包屑/登录页标题/分享页 logo 与页脚/页面 title(index.html)/FastAPI title(/docs Swagger)/Dockerfile 注释/各包 docstring; 代码标识符(包名 huamenchuang/数据表/JWT iss)不变; 全仓库 0 处残留, vue-tsc 0 错+构建通过, 无头浏览器验证 logo/面包屑/页面标题生效 (Files: frontend/src/views/LayoutView.vue, frontend/src/views/LoginView.vue, frontend/src/views/ShareView.vue, frontend/index.html, src/huamenchuang/main.py, src/huamenchuang/*/…)__
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,11 @@ function render() {
|
|||||||
ctx.closePath()
|
ctx.closePath()
|
||||||
ctx.fillStyle = grad
|
ctx.fillStyle = grad
|
||||||
ctx.fill()
|
ctx.fill()
|
||||||
// 玻璃斜向高光
|
// 型材线(先于高光描边:stroke 针对当前路径=玻璃多边形)
|
||||||
|
ctx.strokeStyle = '#5c6166'
|
||||||
|
ctx.lineWidth = 2.2
|
||||||
|
ctx.stroke()
|
||||||
|
// 玻璃斜向高光(clip 内绘制,不复用其后路径)
|
||||||
ctx.save()
|
ctx.save()
|
||||||
ctx.clip()
|
ctx.clip()
|
||||||
ctx.globalAlpha = 0.16
|
ctx.globalAlpha = 0.16
|
||||||
@@ -76,10 +80,6 @@ function render() {
|
|||||||
ctx.closePath()
|
ctx.closePath()
|
||||||
ctx.fill()
|
ctx.fill()
|
||||||
ctx.restore()
|
ctx.restore()
|
||||||
// 型材线
|
|
||||||
ctx.strokeStyle = '#5c6166'
|
|
||||||
ctx.lineWidth = 2.2
|
|
||||||
ctx.stroke()
|
|
||||||
}
|
}
|
||||||
// 外框
|
// 外框
|
||||||
const all = dd.sm.flatMap(s => replayShape(s).regions.flat().map(seg => seg.ps))
|
const all = dd.sm.flatMap(s => replayShape(s).regions.flat().map(seg => seg.ps))
|
||||||
|
|||||||
@@ -60,6 +60,10 @@ export function renderWindowOnly(w: number, h: number, drawingRaw: string | obje
|
|||||||
ctx.closePath()
|
ctx.closePath()
|
||||||
ctx.fillStyle = grad
|
ctx.fillStyle = grad
|
||||||
ctx.fill()
|
ctx.fill()
|
||||||
|
// 型材线(先于高光描边:stroke 针对当前路径=玻璃多边形)
|
||||||
|
ctx.strokeStyle = 'rgba(70,76,84,0.9)'
|
||||||
|
ctx.lineWidth = 2
|
||||||
|
ctx.stroke()
|
||||||
ctx.save()
|
ctx.save()
|
||||||
ctx.clip()
|
ctx.clip()
|
||||||
ctx.globalAlpha = 0.2
|
ctx.globalAlpha = 0.2
|
||||||
@@ -72,9 +76,6 @@ export function renderWindowOnly(w: number, h: number, drawingRaw: string | obje
|
|||||||
ctx.closePath()
|
ctx.closePath()
|
||||||
ctx.fill()
|
ctx.fill()
|
||||||
ctx.restore()
|
ctx.restore()
|
||||||
ctx.strokeStyle = 'rgba(70,76,84,0.9)'
|
|
||||||
ctx.lineWidth = 2
|
|
||||||
ctx.stroke()
|
|
||||||
}
|
}
|
||||||
// 中梃: sp 在其作用区域 bbox 内的投影线
|
// 中梃: sp 在其作用区域 bbox 内的投影线
|
||||||
const regionBBs = regions.map(bboxOf)
|
const regionBBs = regions.map(bboxOf)
|
||||||
|
|||||||
@@ -142,8 +142,12 @@ export function renderAI(
|
|||||||
ctx.closePath(); ctx.fill()
|
ctx.closePath(); ctx.fill()
|
||||||
ctx.globalAlpha = 1
|
ctx.globalAlpha = 1
|
||||||
ctx.restore()
|
ctx.restore()
|
||||||
|
// 型材线:重建玻璃多边形路径再描边(restore 后当前路径是反光带,不可直接 stroke)
|
||||||
ctx.strokeStyle = pal.frame
|
ctx.strokeStyle = pal.frame
|
||||||
ctx.lineWidth = 2.4
|
ctx.lineWidth = 2.4
|
||||||
|
ctx.beginPath()
|
||||||
|
rpts.forEach((p, i) => (i ? ctx.lineTo(tx(p.x), ty(p.y)) : ctx.moveTo(tx(p.x), ty(p.y))))
|
||||||
|
ctx.closePath()
|
||||||
ctx.stroke()
|
ctx.stroke()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user