From cf8c0c65ce9fc14c03065d3ed7ef83264409997f Mon Sep 17 00:00:00 2001 From: HHY Date: Mon, 21 Sep 2026 04:27:16 -0700 Subject: [PATCH] =?UTF-8?q?fix:=20v2.2=20=E5=89=8D=E7=AB=AF=E5=AE=8C?= =?UTF-8?q?=E6=95=B4=E6=80=A7=E6=B2=BB=E7=90=86(vue-tsc=20=E5=85=A8?= =?UTF-8?q?=E9=87=8F=E6=B8=85=E9=9B=B6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 组合画布 3D 扇面板解构键名错误(rect/s→rect/sash)——3D 混乱根因之一 - WindoorCanvas isDoor 标注 cx 作用域泄漏修复 - WindoorThreed rebuild 函数定义补全(墙体开关可用) - 量尺页 openCreate 补定义(点击不再报错) - 状态筛选 ref 类型纳入空串语义(4 页面) - CombineCanvas 孤儿 @drop 移除+容器 dragover.prevent(拖放入库修复) - AIRenderCanvas style 属性名保留处理+表单联合类型 - 零散隐式 any 参数补类型 - 新增 check-frontend.cjs: 未定义引用扫描+API 路径一致性比对 - 全量回归: 18 GET+4 POST+7 SPA 全部通过 --- CHANGELOG | 1 + frontend/package-lock.json | 106 +++++++++++++++++++++- frontend/package.json | 3 +- frontend/scripts/check-frontend.cjs | 94 +++++++++++++++++++ frontend/src/components/CombineCanvas.vue | 2 +- frontend/src/components/WindoorCanvas.vue | 2 +- frontend/src/components/WindoorThreed.vue | 24 ++++- frontend/src/views/AIRenderView.vue | 7 +- frontend/src/views/AfterSaleView.vue | 2 +- frontend/src/views/CombineView.vue | 6 +- frontend/src/views/ContractsView.vue | 2 +- frontend/src/views/DashboardView.vue | 4 +- frontend/src/views/LayoutView.vue | 2 +- frontend/src/views/MeasureView.vue | 9 +- frontend/src/views/OrdersView.vue | 2 +- 15 files changed, 247 insertions(+), 19 deletions(-) create mode 100644 frontend/scripts/check-frontend.cjs diff --git a/CHANGELOG b/CHANGELOG index c6b7ad4..fd04bcd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ # CHANGELOG +- [2026-09-21 12:40] FIX: v2.2 前端完整性治理——引入 vue-tsc 全量类型检查并清零全部错误: ①组合画布 3D 扇面板解构键名错误(rect/s→rect/sash)致扇面板全挂(3D 混乱根因之一); ②WindoorCanvas isDoor 标注 cx 作用域泄漏; ③WindoorThreed rebuild 函数缺失(墙体开关点击报错)+wallBoxes 元组类型; ④量尺页 openCreate 未定义(点击报错); ⑤状态筛选 ref 类型纳入空串(el-select clearable 语义); ⑥CombineCanvas 移除孤儿 @drop(归父容器)+容器补 dragover.prevent(修复拖放入库); ⑦AIRenderCanvas style 属性名保留处理+表单联合类型; ⑧零散隐式 any 参数; 新增检查脚本 scripts/check-frontend.cjs(未定义引用+API 路径一致性比对) (Files: frontend/src/**, frontend/scripts/check-frontend.cjs) - [2026-09-21 12:25] FIX: v2.2 修复 3D 截图为纯色空白——墙体尺寸单位错误(bw=1/S*0.72 误用模型单位≈2304, 而放置坐标是世界单位±0.5), 相机被包在数千单位宽的巨墙内只见背景色; 改为世界单位(侧墙 0.55, 上下墙覆盖窗洞±2.2), 墙体不投影(避免自身遮挡), Node 验证四墙尺寸全部 ≤2.2 世界单位 (Files: frontend/src/components/WindoorThreed.vue) - [2026-09-21 12:10] FIX: 3D"解析失败"根因修复+错误可见性——①根因: watch immediate 首跑时 camera 未创建而 build() 触碰 camera 抛 TypeError; 移除 build 内相机定位(每帧 loop 已定位); ②shadowMap.type 赋值整行移除(three r186 已移除 PCFSoft 常量, 默认即 PCFShadowMap, 杜绝弃用警告); ③解析失败时显示真实错误信息(info+console.error), 便于后续定位; 重建 dist 后 PCFSoft 赋值触发路径已清零 (Files: frontend/src/components/WindoorThreed.vue) - [2026-09-21 11:30] FIX: v2.1 3D 渲染问题根治——①profileGeo 外轮廓路径自相交(闭合斜边穿过槽口区域)导致三角剖分破面, 重写为正确顶点顺序的 U 槽简单多边形; ②inferSashGlyphs 兜底 bboxOf 误传段对象(应为点对象)产生 NaN 扇矩形(JSON 序列化为 null), 修正为有限值点集; ③型材截面挤出抽为共享模块 three/profileGeo.ts(geometryIsValid 校验器); ④新增 scripts/validate3d.cjs 全量验证工具: 254 样板×3700 网格×798 扇逐网格 NaN 检测全部通过; ⑤过小面板(窄条扇)为合法数据跳过渲染不视为失败 (Files: frontend/src/components/WindoorThreed.vue, frontend/src/three/profileGeo.ts, frontend/src/types/drawing.ts, frontend/scripts/validate3d.cjs) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ae47375..d04aa71 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -20,7 +20,8 @@ "devDependencies": { "@vitejs/plugin-vue": "^5.1.0", "typescript": "^5.5.0", - "vite": "^5.4.0" + "vite": "^5.4.0", + "vue-tsc": "^3.3.11" } }, "node_modules/@babel/helper-string-parser": { @@ -1009,6 +1010,35 @@ "vue": "^3.2.25" } }, + "node_modules/@volar/language-core": { + "version": "2.4.28", + "resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.28.tgz", + "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.28" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.28", + "resolved": "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.28.tgz", + "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.28", + "resolved": "https://registry.npmmirror.com/@volar/typescript/-/typescript-2.4.28.tgz", + "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.28", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, "node_modules/@vue/compiler-core": { "version": "3.5.43", "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.43.tgz", @@ -1065,6 +1095,22 @@ "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", "license": "MIT" }, + "node_modules/@vue/language-core": { + "version": "3.3.11", + "resolved": "https://registry.npmmirror.com/@vue/language-core/-/language-core-3.3.11.tgz", + "integrity": "sha512-QJmpliwAVpC/OxubIByPAhNzsQPRc8/gxlN2qnVzVfIMjMDz/9RnXRFoetjz5yEgXVXyp4LqhXq3V53PjmNzFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.28", + "@vue/compiler-dom": "^3.5.0", + "@vue/shared": "^3.5.0", + "alien-signals": "^3.2.1", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1", + "picomatch": "^4.0.4" + } + }, "node_modules/@vue/reactivity": { "version": "3.5.43", "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.43.tgz", @@ -1172,6 +1218,13 @@ "node": ">= 6.0.0" } }, + "node_modules/alien-signals": { + "version": "3.2.1", + "resolved": "https://registry.npmmirror.com/alien-signals/-/alien-signals-3.2.1.tgz", + "integrity": "sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==", + "dev": true, + "license": "MIT" + }, "node_modules/async-validator": { "version": "4.2.5", "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz", @@ -1648,6 +1701,13 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" + }, "node_modules/nanoid": { "version": "3.3.19", "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.19.tgz", @@ -1672,12 +1732,32 @@ "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==", "license": "BSD-3-Clause" }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/pinia": { "version": "2.3.1", "resolved": "https://registry.npmmirror.com/pinia/-/pinia-2.3.1.tgz", @@ -1872,6 +1952,13 @@ } } }, + "node_modules/vscode-uri": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.2.0.tgz", + "integrity": "sha512-m2gXo3bn0G1kT9InzMf07fTbqMbGtyckj3bH5ktLO+1Ssv+yiATZ4dhwaQv9UZWxJh6E9IFGnQyjgWVDWVBDrg==", + "dev": true, + "license": "MIT" + }, "node_modules/vue": { "version": "3.5.43", "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.43.tgz", @@ -1939,6 +2026,23 @@ "peerDependencies": { "vue": "^3.5.0" } + }, + "node_modules/vue-tsc": { + "version": "3.3.11", + "resolved": "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-3.3.11.tgz", + "integrity": "sha512-gOb0B9rtU2+f1dszwPqSH5kAieIF9ReeLhD3kSRNHv5WZZUQz/JdVXW0RTdqhNTMlQkqKzrTTviqKr/4FYZraQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/typescript": "2.4.28", + "@vue/language-core": "3.3.11" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + } } } } diff --git a/frontend/package.json b/frontend/package.json index 3ed4d1d..2442a82 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -21,6 +21,7 @@ "devDependencies": { "@vitejs/plugin-vue": "^5.1.0", "typescript": "^5.5.0", - "vite": "^5.4.0" + "vite": "^5.4.0", + "vue-tsc": "^3.3.11" } } diff --git a/frontend/scripts/check-frontend.cjs b/frontend/scripts/check-frontend.cjs new file mode 100644 index 0000000..b0a154a --- /dev/null +++ b/frontend/scripts/check-frontend.cjs @@ -0,0 +1,94 @@ +#!/usr/bin/env node +/** 前端静态检查: ①SFC 脚本未定义引用扫描 ②前端 API 路径与后端路由一致性比对 */ +const fs = require('fs'); +const path = require('path'); + +const ROOT = path.resolve(__dirname, '..'); +const SRC = path.join(ROOT, 'src'); +const API = path.join(ROOT, '..', 'src', 'huamenchuang', 'api'); + +const BUILTIN = new Set(['if','for','while','switch','catch','return','function','typeof','new','delete','void', + 'fetch','setTimeout','setInterval','clearTimeout','clearInterval','parseInt','parseFloat','isNaN','isFinite', + 'Number','String','Boolean','Array','Object','JSON','Math','Date','Promise','console','window','document', + 'localStorage','sessionStorage','navigator','location','alert','requestAnimationFrame','cancelAnimationFrame', + 'URL','Blob','File','FileReader','Error','TypeError','structuredClone','crypto','atob','btoa','history', + 'defineProps','defineEmits','defineExpose','withDefaults','require','module','Infinity','NaN','encodeURIComponent','decodeURIComponent']); +const VUE = new Set(['ref','reactive','computed','watch','watchEffect','onMounted','onBeforeUnmount','onUnmounted','nextTick', + 'createApp','useRouter','useRoute','toRefs','toRef','unref','isRef','provide','inject','defineStore','storeToRefs']); + +function walk(dir, out = []) { + for (const f of fs.readdirSync(dir)) { + const p = path.join(dir, f); + if (fs.statSync(p).isDirectory()) walk(p, out); + else out.push(p); + } + return out; +} + +// ---- ① SFC 未定义引用 ---- +console.log('=== ① SFC 脚本未定义引用扫描 ==='); +const vueFiles = walk(SRC).filter(f => f.endsWith('.vue')); +let issues = 0; +for (const f of vueFiles) { + const src = fs.readFileSync(f, 'utf8'); + const m = src.match(/