# 图纸管理平台 **Repository Path**: teampanel/drawing-management-platform ## Basic Information - **Project Name**: 图纸管理平台 - **Description**: 可以在线预览管理cad图纸 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-24 - **Last Updated**: 2026-09-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 图纸管理 · AI 识图 面向机械图纸的 **图纸管理 + AI 识图** 系统:上传图纸 → 统一预览 → AI 读取工程图数据 → 结构化检验项 → 气泡标注 / 脱敏 / 版本管理。 前端 Vue 3 + TypeScript + Element Plus + Tailwind CSS,后端 Node.js + Express,数据落 JSON 文件,开箱即用、无需数据库。 ![图纸详情(DWG):统一预览 + 气泡标注 + 识别结果](docs/screenshots/03-drawing-detail-dwg.png) > 上图即核心流程:DWG 图纸在后端转成 PNG 后,与普通图片走**完全相同**的预览与标注链路——左侧图纸上叠加可拖拽气泡,右侧是 AI 读出的结构化检验项(检测项 / 标准值 / 上下偏差 / 公差 / 粗糙度…)。 --- ## ✨ 功能特性 | 模块 | 说明 | | --- | --- | | **多格式上传** | 支持 `png` / `jpg` / `jpeg` / `pdf` / `dwg` / `dxf`,可批量拖拽上传 | | **统一预览** | 所有类型在后端统一栅格化为 PNG,前端**用同一个预览区**渲染并叠加气泡 / 脱敏。PDF 与 DWG/DXF 也能在浏览器里直接看图,无需装 AutoCAD | | **AI 识图** | 调用多模态视觉模型(DeepSeek)读取工程图,输出结构化检测项:检测项 / 标准值 / 上偏差 / 下偏差 / 公差 / 粗糙度 / GD&T / 单位 + 置信度,并自动生成归一化气泡坐标 | | **气泡标注** | SVG 覆盖层,可拖拽、新增、删除、改色 / 字号 / 高亮 / 备注;点击结果表某行会联动高亮对应气泡 | | **脱敏** | 在图上框选区域打码,并记录脱敏原因,可逐条撤销 / 删除 | | **结果表** | 可编辑表格,支持新增行、保存、一键导出 Excel(全尺寸检验单) | | **图纸参数** | 图纸编号 / 名称、物料编码 / 名称 / 版本、质检人员、单位类型、转换单位、线性与角度公差标准 | | **版本同步** | 对比前后端数据并刷新图纸版本号 | | **一键启动** | `node start.mjs` 同时拉起前端与后端,跨平台(Windows / macOS / Linux) | --- ## 📸 截图 ### 图纸详情 —— PDF:同一套预览流程 PDF 同样在后端渲染成 PNG,因此气泡坐标、脱敏、识别结果全部对齐,不再有"PDF 单独一套预览"的分支。 ![图纸详情(PDF)](docs/screenshots/04-drawing-detail-pdf.png) ### 图纸列表 支持名称 / 文件类型 / 状态筛选,展示类型、大小、版本、识别状态与操作。 ![图纸列表](docs/screenshots/02-drawing-list.png) ### 批量上传 ![批量上传](docs/screenshots/05-upload-dialog.png) ### 登录 ![登录页](docs/screenshots/01-login.png) --- ## 🏗 架构 ``` ┌──────────────────────────┐ │ 浏览器 (Vue 3 + EP) │ │ http://localhost:3006 │ └────────────┬─────────────┘ │ /api /uploads (Vite 代理) ┌────────────▼──────────────────────────────────────┐ │ Node 后端 http://localhost:9999 (Express ESM) │ │ │ │ ├─ 图纸 CRUD / 识别结果 / 气泡 / 脱敏 / 版本 │ │ ├─ vision.js 多模态识图(OpenAI 兼容) │ │ ├─ cadConvert.js DWG/DXF → SVG → PNG │ │ └─ PDF 首页 → PNG(pdfjs-dist + @napi-rs/canvas) │ └────────────┬──────────────────────────────────────┘ │ ┌─────────▼──────────┐ ┌────────────────────────┐ │ server/data/db.json│ │ server/uploads/* │ │ (图纸 / 结果 / 气泡)│ │ (原图 + 预览 PNG) │ └────────────────────┘ └────────────────────────┘ ``` **统一预览的关键**:后端把 `dwg` / `dxf` / `pdf` 都转换成栅格 PNG 写回 `previewPath`,于是前端只需要一个 `` + 两层 SVG 覆盖层(气泡 / 脱敏),四种格式零分支。 --- ## 🚀 快速开始 ### 环境要求 - Node.js **>= 20.19**(推荐 22.x) - pnpm **>= 8.8**(或直接用 npm) ### 1. 安装依赖 ```bash # 前端依赖(项目根目录) pnpm install # 后端依赖 cd server && npm install ``` ### 2. 配置 AI 识图(可选) ```bash cp server/.env.example server/.env # 编辑 server/.env,填入 VISION_BASE_URL / VISION_API_KEY / VISION_MODEL ``` > 未配置 key 时,后端会回退到内置**占位识别器**:全流程照样跑通,但返回的是占位数据。响应里的 `source` 字段会标成 `mock`,可据此区分是否真的调到了模型。 DeepSeek 实测可用配置(注意:官方模型里**只有 `deepseek-flash` 支持图片输入**): ```ini VISION_BASE_URL=https://api.deepseek.com VISION_API_KEY=sk-xxxxxxxx VISION_MODEL=deepseek-flash VISION_MAX_TOKENS=8000 VISION_JSON_MODE=1 VISION_TIMEOUT_MS=120000 ``` ### 3. 启动 ```bash node start.mjs ``` | 服务 | 地址 | | --- | --- | | 前端页面 | http://localhost:3006 | | 后端接口 | http://localhost:9999 | 按 `Ctrl+C` 会连同子进程一起回收。演示账号:`Super / 123456`、`Admin / 123456`、`User / 123456`。 也可以分开启动: ```bash pnpm dev # 仅前端 node server/src/index.js # 仅后端 ``` Windows 还可以直接双击 `start.bat`,macOS / Linux 用 `./start.sh`。 --- ## 📁 目录结构 ``` tuzhi/ ├── src/ # 前端 │ ├── api/drawing.ts # 图纸相关接口封装 │ ├── router/modules/drawing.ts # 图纸模块路由 │ ├── types/api/api.d.ts # Api.Drawing 类型契约 │ └── views/drawing/ │ ├── index.vue # 图纸列表页 │ ├── detail.vue # 图纸详情页(统一预览 + 参数 + 结果) │ └── modules/ │ ├── drawing-upload.vue # 批量上传对话框 │ ├── bubble-layer.vue # 气泡覆盖层(SVG) │ ├── mask-layer.vue # 脱敏覆盖层 │ └── result-table.vue # 识别结果表(编辑 / 导出 Excel) ├── server/ # 后端 │ ├── src/ │ │ ├── index.js # Express 入口 + 全部路由 │ │ ├── vision.js # 多模态识图客户端 │ │ ├── cadConvert.js # DWG / DXF → PNG │ │ ├── store.js # JSON 文件存储 │ │ └── config.js # 环境变量集中配置 │ ├── tools/libredwg/ # GNU LibreDWG 控制台工具(无 GUI) │ ├── data/db.json # 数据 │ ├── uploads/ # 原图与预览图 │ └── .env.example # 配置模板 ├── docs/screenshots/ # README 截图 ├── start.mjs / start.sh / start.bat # 一键启动 └── vite.config.ts ``` --- ## 🔌 接口一览 统一响应契约:`{ code: 200, msg, data }`,字段 camelCase。 | 方法 | 路径 | 说明 | | --- | --- | --- | | POST | `/api/auth/login` | 登录,返回 `token` / `refreshToken` | | GET | `/api/user/info` | 用户信息(路由守卫必需) | | POST | `/api/drawing/list` | 分页查询图纸 | | POST | `/api/drawing/upload` | 上传图纸(multipart,自动生成预览) | | POST | `/api/drawing/update` | 保存图纸参数 | | POST | `/api/drawing/delete` | 批量删除 | | POST | `/api/drawing/recognize` | **AI 识别**(自动选用栅格预览图) | | POST | `/api/drawing/result-list` / `result-save` / `result-delete` | 识别结果增删查 | | POST | `/api/drawing/bubble-list` / `bubble-save` | 气泡 | | POST | `/api/drawing/mask-list` / `mask-save` | 脱敏区域 | | POST | `/api/drawing/version-sync` | 版本同步 | | GET | `/health` | 健康检查(含识图配置,便于排查) | --- ## 🧩 关键实现与踩坑记录 这些是本项目里真正花过时间的地方,留档备查。 **1. DWG 预览:无头转换 + 按"渲染墨迹"自适应视口** 沙箱/服务器上不能依赖任何带 GUI 的 CAD 软件(LibreCAD、ODA File Converter 等会卡死),所以走 GNU LibreDWG 的控制台程序 `dwg2SVG` 输出 SVG,再由 `@resvg/resvg-js` 栅格化为 PNG。 `dwg2SVG` 有三个坑:块定义放在 `` 里被 `` 引用(按 `` 字面坐标算包围盒会把**定义体**算进去)、自带 `viewBox` 常常不准(内容跑到视口外被裁)、所有线条都是 `stroke-width:0.1`(大 viewBox 栅格化后线条直接消失)。 最终方案是**两遍栅格化**:先用「自带 viewBox 外扩 12%」的种子视口渲染一遍,量出墨迹的行/列投影边界;**若墨迹贴到画面边缘说明种子太小,继续外扩重测**(最多 5 次);再按最终边界重渲染并做线宽保底(`stroke-width ≥ viewBox宽/输出宽`)。另用 `trimSparse()` 剔除被大片空白隔开的孤立图框。 **2. PDF 预览:后端渲染首页为 PNG** 早期前端用 `pdfjs-dist` 渲染 PDF,与图片 / CAD 走两套分支,预览经常坏。现在改为后端用 `pdfjs-dist` + `@napi-rs/canvas` 渲染 PDF 首页,并注入 `cmaps` 与 `standard_fonts` 以正确显示中文——前端不必再关心文件类型。 **2.1 只注入字体还不够:`wasmUrl` 少了会"静默丢图"** 这是最容易骗过排查的一类 bug:某张扫描件 PDF 预览出来**几乎全白**,只剩矢量标注(尺寸线、公差框)在,看着像"渲染成功了但图没了"。 根因是这类工程图(扫描件、CAD 导出)用 **JBIG2** 压缩位图,而 JBIG2 / JPEG2000 解码器是 WebAssembly。`pdfjs-dist` 在 Node 端**要求显式传入 `wasmUrl`**,否则解码器初始化失败,位图被静默跳过: ``` Warning: Unable to decode image "img_p0_1": "Jbig2Error: JBig2 failed to initialize" Warning: #instantiateWasm: UnknownErrorException: Ensure that the wasmUrl API parameter is provided ``` 修复就是把它和 `cmaps` / `standard_fonts` 一起注入: ```js const PDFJS_ROOT = path.join(__pdfDir, '..', 'node_modules', 'pdfjs-dist') // ... await pdfjs.getDocument({ data, canvasFactory: new NodeCanvasFactory(), standardFontDataUrl: PDFJS_STANDARD_FONT_URL, cMapUrl: PDFJS_CMAP_URL, cMapPacked: true, wasmUrl: PDFJS_WASM_URL, // ← JBIG2 / JPEG2000 解码必需 iccUrl: PDFJS_ICC_URL }).promise ``` 同一张图修复前后对比:墨迹占比 **0.34% → 8.16%**,预览 PNG **57 KB → 539 KB**。所以**换环境/升级 pdfjs 后,务必用一张扫描件 PDF 回归一次**,别只看矢量图。 > 排查手法:写个一次性脚本直接调 `getDocument` + `page.render`,统计输出 PNG 的**非白像素占比**。占比低到 0.x% 基本就是位图被丢了,而不是"这张图本来就很稀疏"。 **3. DeepSeek 推理模型:光配 key 是不够的** `deepseek-flash` 是**推理模型**,会先吐 `reasoning_content` 且计入 `completion_tokens`。如果不传 `max_tokens`(用默认值),思考过程就会吃光预算,`finish_reason=length`、`content` 变成**空字符串** → JSON 解析失败 → **静默回退占位假数据**(接口还是 200,看着像成功)。 解法:`response_format={type:'json_object'}`(`VISION_JSON_MODE=1`)+ `max_tokens >= 8000`。同一张图实测:不开时 `content` 长度为 0,开启后正常收敛;不支持该参数的网关会自动降级重试一次。另外响应里新增 `source: 'model' | 'mock'`,一眼就能看出是真识别还是回退了假数据。 **4. 同一文件不要并行编辑** 对同一个文件在同一批操作里发多次修改会互相覆盖(本项目的 `index.js` 就踩过,改动被冲掉、白排查一轮)。同一文件的多次修改必须串行。 ---