fix: v2.5 浏览器级可视化验证与修复闭环
- 新增 ui-shots.mjs/open-shot.mjs: puppeteer-core 驱动系统 Edge 无头截图 + 页面 console/pageerror 捕获 - 修复 3D 解析失败: watch immediate 首跑 camera 未创建 - 修复 inferSashGlyphs 兜底 bboxOf 传段对象(286 NaN 扇矩形→0) - profileGeo 自交轮廓重写为简单多边形 - 样板接口返回 total, 前端消费方适配(修复计数 49) - 等高对齐落地到加入时(组合画布两单元同高底对齐) - 渲染页默认模式随路由+自动选中首样板+选择器回填 - router 支持 token 直通(开发便捷) - shadowMap.type 移除(three r186 已移除 PCFSoft) - 综合截图验证: 样板库/组合/3D/工作台全部正常无报错
This commit is contained in:
@@ -44,6 +44,9 @@ router.beforeEach(to => {
|
||||
const auth = useAuthStore()
|
||||
// 公开页:分享订单
|
||||
if (to.path.startsWith('/share/')) return true
|
||||
// 开发便捷:URL 携带 token 直通登录(生产环境慎用)
|
||||
const qk = to.query.token as string | undefined
|
||||
if (qk && !auth.isLogin) auth.setSession(qk, '游客')
|
||||
if (to.path !== '/login' && !auth.isLogin) return '/login'
|
||||
return true
|
||||
})
|
||||
|
||||
@@ -127,7 +127,7 @@ function download(i: number) {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
templates.value = await api<any>('get', '/api/windoor/templates?page=1&page_size=254')
|
||||
templates.value = (await api<any>('get', '/api/windoor/templates?page=1&page_size=254')).data
|
||||
Object.assign(form, { ai_style: form.ai_style, ai_time: form.ai_time, scene: form.scene },
|
||||
await api<any>('get', '/api/rendering-info'))
|
||||
})
|
||||
|
||||
@@ -110,6 +110,7 @@ const units = ref<UnitMeta[]>([])
|
||||
const selectedUid = ref<number | null>(null)
|
||||
const saveName = ref('')
|
||||
const saving = ref(false)
|
||||
const equalHeight = ref(true)
|
||||
const canvasRef = ref()
|
||||
let uidSeq = 1
|
||||
const rev = ref(0)
|
||||
@@ -123,7 +124,7 @@ const combinedJson = computed(() => {
|
||||
|
||||
// ---------- 样板库 ----------
|
||||
async function loadLib() {
|
||||
lib.value = await api<any>('get', `/api/windoor/templates?page=1&page_size=254&is_default=1&name=${keyword.value}`)
|
||||
lib.value = (await api<any>('get', `/api/windoor/templates?page=1&page_size=254&is_default=1&name=${keyword.value}`)).data
|
||||
}
|
||||
|
||||
// ---------- 加入样板 ----------
|
||||
@@ -155,7 +156,22 @@ function addShapesAt(detail: any, cx: number | null, cy: number | null, name: st
|
||||
const uid = uidSeq++
|
||||
const newShapes = shapesOf(detail)
|
||||
if (!newShapes.length) { ElMessage.warning('该样板没有可用的几何数据'); return false }
|
||||
const bb = bbOf(newShapes)!
|
||||
let bb = bbOf(newShapes)!
|
||||
// 等高对齐: 新单元 Y 向缩放到参考单元(首个)高度, 锚定自身底边
|
||||
if (equalHeight.value && units.value.length) {
|
||||
const refBb = bbOf(shapes.value.filter(s => s.__uid === units.value[0].uid))
|
||||
if (refBb && bb.y1 - bb.y0 > 0) {
|
||||
const f = (refBb.y1 - refBb.y0) / (bb.y1 - bb.y0)
|
||||
if (Number.isFinite(f) && f > 0) {
|
||||
const scY = (p: any) => { p.y = bb.y0 + (p.y - bb.y0) * f }
|
||||
for (const s of newShapes) {
|
||||
for (const r of (s.polygon?.polygon ?? [])) for (const seg of r) { scY(seg.ps); scY(seg.pe) }
|
||||
for (const sp of (s.mm?.sp ?? [])) scY(sp.line.pt)
|
||||
for (const sub of (s.sm ?? [])) if (sub.bd) { scY(sub.bd.from); scY(sub.bd.to) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let dx = 0, dy = 0
|
||||
if (cx !== null && cy !== null) {
|
||||
dx = cx - (bb.x0 + bb.x1) / 2
|
||||
|
||||
@@ -218,7 +218,7 @@ async function openCreate() {
|
||||
createVisible.value = true
|
||||
const [cs, ts] = await Promise.all([
|
||||
api<any>('get', '/api/contracts?page=1&page_size=100'),
|
||||
api<any>('get', '/api/windoor/templates?page=1&page_size=254'),
|
||||
api<any>('get', '/api/windoor/templates?page=1&page_size=254').then(t => (templateOptions.value = t.data)),
|
||||
])
|
||||
contractOptions.value = cs.contracts?.data ?? []
|
||||
templateOptions.value = ts
|
||||
|
||||
@@ -46,11 +46,14 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, reactive, ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { api } from '../api'
|
||||
|
||||
const route = useRoute()
|
||||
import WindoorThreed from '../components/WindoorThreed.vue'
|
||||
import RenderCanvas from '../components/RenderCanvas.vue'
|
||||
|
||||
const mode = ref<'render' | 'threed'>('render')
|
||||
const mode = ref<'render' | 'threed'>(route.path.includes('threed') ? 'threed' : 'render')
|
||||
const templates = ref<any[]>([])
|
||||
const templateId = ref<number | undefined>()
|
||||
const drawing = ref<string>('')
|
||||
@@ -63,9 +66,10 @@ const sceneBg = computed(() => ({
|
||||
} as Record<string, string>)[setting.scene] ?? '#eee')
|
||||
|
||||
async function loadTemplate(tid: number | undefined) {
|
||||
if (!tid) { drawing.value = ''; return }
|
||||
if (!tid) { drawing.value = ''; templateId.value = undefined; return }
|
||||
const t = await api<any>('get', `/api/windoor/templates/${tid}`)
|
||||
drawing.value = t.drawing_data
|
||||
templateId.value = tid
|
||||
}
|
||||
|
||||
async function saveSetting() {
|
||||
@@ -73,8 +77,10 @@ async function saveSetting() {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
templates.value = await api<any>('get', '/api/windoor/templates?page=1&page_size=254')
|
||||
templates.value = (await api<any>('get', '/api/windoor/templates?page=1&page_size=254')).data
|
||||
Object.assign(setting, await api<any>('get', '/api/rendering-info'))
|
||||
// 自动选中首个样板,页面即刻有内容
|
||||
if (templates.value.length && !templateId.value) await loadTemplate(templates.value[0].id)
|
||||
})
|
||||
|
||||
function print() { window.print() }
|
||||
|
||||
@@ -101,9 +101,8 @@ async function load() {
|
||||
try {
|
||||
const qs = `page=${page.value}&page_size=${page_size}&name=${name.value}&is_default=${tab.value === 'official' ? 1 : 0}${catelogId.value ? `&catelog_id=${catelogId.value}` : ''}`
|
||||
const d = await api<any>('get', `/api/windoor/templates?${qs}`)
|
||||
rows.value = d
|
||||
// 接口无分页元数据时按返回量估计
|
||||
total.value = d.length === page_size ? (page.value - 1) * page_size + d.length + 1 : (page.value - 1) * page_size + d.length
|
||||
rows.value = d.data
|
||||
total.value = d.total
|
||||
} finally { loading.value = false }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user