- 下载源站 49 个真实型材截面 DXF 用于学习(临时, 已按约定删除) - 自研 DXF 解析器: 提取截面外轮廓/闭合腔体/实体统计 - 学习结论: 外框深46-62宽74-130(3-6腔), 玻璃扇深80-90宽65-72(4-10腔), 中梃深79-84宽~100(3-7腔), 纱扇薄壁19-38, 转角立柱146x150(5腔)等 - 3D 型材升级: 多腔体截面挤出(外框3腔/扇2腔, 玻璃槽深20%, 壁厚比例修正) - 学习结论沉淀至方案文档§3.3, DXF 素材已全部删除
17 KiB
门窗 Saunders 云平台(windoorcraft.com 同功能系统)克隆实施方案
版本:v0.1 | 日期:2026-09-20 | 编制:HHY 目标站:https://www.windoorcraft.com/home (代号 zzc,出品方 thinkerx.com) 本文档基于对目标站的只读接口采集(用户自有账户)与前端结构分析编写,所有代码实现均为自研原创。
1. 目标产品画像
windoorcraft.com 是一套面向门窗行业的 SaaS 工具集,核心价值链:
画窗(拖拽布置分格) → 自动算料报价 → 客户确认(合同/订单) → 生产(优化下料/打印) → 财务(收付款) → 库存
已探明的子系统:
| 子系统 | 说明 | 证据(路由/接口) |
|---|---|---|
| 2D 画窗编辑器 | 拖拽布置外框、中梃、扇、玻璃、横竖撑,参数化尺寸 | /draw、drawing_data、shapeManager |
| 报价引擎 | 自动报价 + 手动报价,型材/玻璃/五金附件计价 | /manual-quote、automatic_quote、base_price、offer-price |
| 订单/合同 | 意向单→合同→订单流转,电子签名确认 | /orders、contracts、convert-contract/、up-contract-confirmed/ |
| 客户管理 CRM | 客户档案、业务员、客户分级 | /customers_list、salesmen、ywy-* |
| 生产管理 | 订单进度、车间派工、条码打印 | get_order_process、printer、order_format |
| 优化下料 | 一维型材优化切割(BIN 问题) | optimize1d、cut_solution、contract_bars |
| 库存/仓库 | 型材/玻璃/配件库存、出入库 | warehouse_list、product_move_in/、materials_config |
| 3D/渲染 | BabylonJS 3D 展示、DXF 出图、AI 炫图 | /threed、renderV2、sketch-to-window-info |
| 样板库 | 254 套官方窗型模板(6 大分类) | search_default_windoor、default_windoor_info/{id} |
| 商城/会员 | 软件订阅购买、试用、邀请返利 | /purchase、company-module-info、invited_user_list |
| 多端生态 | 微信小程序/公众号/APP、Apple/Google 登录 | wechat-login-with-phone、wx/getwxurllink、apple_login |
| 多语言 | 中/英/韩/俄/越 5 语言包 | lang-en-us 等独立 chunk |
| 子账户/权限 | 主子账户、业务员/经销商角色 | son_user_update、up_son_user_permission、dls-* |
2. 已采集数据资产(本次交付)
全部存于 data/ 目录:
| 文件 | 内容 | 规模 |
|---|---|---|
api-endpoint-inventory.txt |
从前端提取的全部接口名清单 | ≈300 条 |
api-samples/*.json |
16 个核心接口的真实响应样本 | — |
api-samples/windoor-templates-clean.json |
样板库全量清单(含分类名映射) | 254 条 |
windoor-drawings/{id}.json |
每套模板的完整绘制数据 drawing_data |
254 个文件 / 5.4MB |
full-site/get/ + get-manifest.json |
整站 GET 扫描:279 个接口逐一探测留档(200→90,业务成功 76) | 全量 |
full-site/post/ + post-manifest.json |
POST 安全探测:24 个只读/计算语义接口(付费墙/参数契约确认) | 全量 |
full-site/sweep_get.py / sweep_post.py |
可复用的限速采集脚本(白名单制,危险接口永不触碰) | — |
订单模块受目标站付费墙保护(
code=10086),列表/详情数据无法以试用水印账户获取;但订单写入接口的完整请求契约已通过源码静态分析拿到:创建订单POST orders/{contract_id, drawing_data, pic_url}、详情GET orders/{id}、排序PUT orders/{id}、删除DELETE orders/{id}。自研实现不依赖对方付费墙数据。
2.1 样板库统计
| 分类 | 数量 |
|---|---|
| 平开 | 99 |
| 转角窗 | 54 |
| 推拉 | 35 |
| 复古门 | 31 |
| 肯德基门 | 27 |
| 中式门窗 | 8 |
| 合计 | 254 |
说明:
search_default_windoor接口无分页(前端仅传name关键字参数),一次返回全量;经验证page参数被忽略、三页内容完全一致,故 254 条即官方样板库全量,本次已 100% 采集成功(254/254)。
2.2 drawing_data 数据模型(拖拽编辑器核心,已破解)
default_windoor_info/{id} 返回的 drawing_data 是编辑器画布的完整序列化状态,直接喂给 canvas.shapeManager.openFile()。结构:
drawing_data
├── s 全局设置 { cs: 外框默认料宽60, cjs: 100 }
├── cp 预设参数
├── sm[] 形状集合(多形状 = 转角窗/连体窗)
│ └── 每个形状:
│ ├── cm 颜色映射 { g: 玻璃填充色, bn: 边框色, hd: 高光, ben: }
│ ├── dm 尺寸标注 { dims: [{at, ds, eidx, midx, name, type: line|mullion}] }
│ ├── fm 外框模型 { ew: [左,上,右,下]料宽, vs: 顶点, ejw, pew, ast }
│ ├── mm 中梃模型 { sp: [分割线 {line:{pt,norm}, alignType, equalSplit,
│ │ kw(竖撑), ws(窗撑), reinforced, polyId}] }
│ ├── sashes[] 扇:开向 openToward、开启状态 opened、带转框 withTurningFrame
│ ├── bars / bds 格条(防盗格/装饰格)
│ ├── gg / gcs 玻璃配置
│ ├── ut / tcs 推拉窗轨道(emptyTrackAppended)
│ ├── rt / ep 圆弧半径(复古门弧顶)
│ └── polygon 多边形轮廓(非矩形窗)
├── epi / sbf / wlc 编辑器状态(点吸附/选中框/墙线)
├── wall 附墙信息
└── scale 缩放比例
关键结论:编辑器 = "多边形外框 + 中梃分割线树 + 区域→扇/玻璃分配" 的三层模型。分割线(sp)带单位向量 norm 与对齐策略,渲染时递归切割多边形得到玻璃区域。这就是拖拽布置搭建的实现基础。
3. 目标技术架构(自研实现)
3.1 技术选型
结合本仓库已有的 Python 骨架(pyproject.toml,Python ≥3.14):
| 层 | 选型 | 说明 |
|---|---|---|
| 后端 | FastAPI + SQLAlchemy 2.0 + MySQL 8 | 异步、类型安全(符合类型安全原则)、自带 OpenAPI 文档 |
| 前端 | Vue 3 + TypeScript + Element Plus + Pinia | 与原站 Vue 系心智一致;画布层自研 |
| 画布引擎 | 原生 Canvas 2D + 自研 shapeManager(复刻数据模型 §2.2) | 备选 Konva.js 减少底层工作量 |
| 3D | Three.js + DXF 导出库 | 原站用 BabylonJS,功能等效替换 |
| 缓存/队列 | Redis + Celery(优化下料、渲染走异步任务) | optimize1d 计算密集 |
| 文件存储 | 阿里云 OSS / MinIO(自托管备选) | 原站用阿里云 OSS + 华为云 OBS |
| 认证 | JWT (HS256, 24h) + 手机验证码 + 微信 OAuth | 对齐原站鉴权方式 |
3.2 模块划分(严格分层)
src/huamenchuang/
├── main.py # FastAPI 入口、前端静态挂载
├── core/ # 配置、安全(JWT)、依赖注入、统一响应封装
│ ├── config.py security.py response.py # {code,message,data} envelope
├── models/ # SQLAlchemy ORM(见 §4 领域模型)
├── schemas/ # Pydantic 请求/响应模型
├── repositories/ # 数据访问层
├── services/ # 业务逻辑层
│ ├── auth_service.py customer_service.py contract_service.py
│ ├── order_service.py product_service.py warehouse_service.py
│ ├── quote_service.py optimize_service.py template_service.py
├── api/ # Controller 路由层(按模块拆分 router)
└── utils/ # 一维优化算法、公式引擎、单位换算
frontend/
├── src/
│ ├── api/ # axios 封装 + 接口定义
│ ├── stores/ # Pinia
│ ├── views/ # 与原站 42 条路由对应的页面
│ └── components/canvas/ # shapeManager / Frame / Mullion / Sash / Glass / Dimension
└── dist -> 后端静态挂载 # 构建产物挂载(符合前后端规范)
3.3 源站 3D 建模技术探索结论(2026-09-21)
源站 3D 采用 BabylonJS + DXF 型材截面挤出:按产品系存放截面 CAD 文件(外框 frame / 玻璃扇 glassleaf / 中梃 mullion / 纱扇 screenleaf / 固定压线 / 折叠扇 / 转角立柱 / 导轨 / 装饰条 / 水槽等),运行时解析截面沿框架路径挤出成体(ExtrudeShape),sashOpen 参数驱动扇开合,配 _lod2 低模与轨道相机。
对 49 个真实截面 DXF 的解析归纳(事实尺寸,单位 mm):
| 型材 | 深度 | 面宽 | 腔体数 |
|---|---|---|---|
| 外框 frame | 46-62 | 74-130 | 3-6 |
| 玻璃扇 glassleaf | 80-90 | 65-72 | 4-10 |
| 固定玻璃压线 glass | 22-27 | 89-130 | 1-3 |
| 中梃 mullion | 79-84 | ~100 | 3-7 |
| 纱扇 screenleaf | 38-90 | 19-38 | 1-3 |
| 折叠扇 foldleaf | 65 | 67 | 3 |
| 转角立柱 corner | 146×150 | — | 5 |
| 装饰格条 decbar | 15×15 | — | 实心 |
设计结论:真实铝型材为多腔体挤出(隔热腔+加强腔+排水腔,壁厚≈深度 1/30);已按此将自研 3D 型材升级为多腔体截面挤出(外框 3 腔/扇 2 腔/玻璃槽深≈20% 深度),并保留纱扇、压线、转角立柱等型材族的扩展位。
3.4 拖拽布置编辑器(核心难点)复刻方案 —— v2 已实现
原站设计思路(逆向自 drawing_data 序列化结构,经 254 套样本验证):
- 三层模型:
Frame 形状 = 基底多边形(polygon.polygon) + 分割树(mm.sp[]) + 扇子形状(sm[]) - 分割树(关键发现):
polygon.polygon不是最终窗格,而是基底多边形;mm.sp[]按序记录每次分割——line{pt,norm}定位分割线、polyId{idx,pos}指向作用区域与插入位。编辑器打开文件时重放分割树得到最终窗格。同一中梃可能被记录为多条共线分段(随区域生长拆分) - 扇模型:子形状
Sash/DoubleSash,sashes[]描述子扇(od开向角、wtf转框、openToward内开/外开),经polyId挂到窗格;bd边界在序列化中常退化,运行时重算 - 序列化即状态:drawing_data 直接喂给
shapeManager.openFile()恢复整个画布
自研实现(frontend/src/components/WindoorCanvas.vue,约 700 行,Canvas2D):
| 能力 | 实现 |
|---|---|
| 真实网格渲染 | replayShape() 分割树重放(两次交叉点法切多边形,退化/非凸跳过),254 套样板全部还原真实分格(平开 4-7 格、推拉亮子结构、转角窗多体) |
| 中梃绘制 | 每条 sp 按其作用区域 bbox 裁剪为分段双线;共线分段自然重叠无害 |
| 扇样式推断 | 有效bd → polyId 映射区域(双扇对半) → 帧bbox按扇数竖向均分 三级解析;开向三角/内开空心/门标注 |
| 尺寸参数化 | W/H 输入框 + 拖拽外框右缘/下缘/右下角手柄;全部几何(含 sp 点位)按比例缩放,料宽不变 |
| 加中梃 | +竖梃/+横梃 → 点击玻璃区域 → 追加 sp(polyId.idx=被点窗格)→ 重放 |
| 改中梃 | 点击选中(蓝色高亮)→ 拖动(line.pt 更新→重放,30mm 边距钳制)→ Del/按钮删除(移除 sp→重放) |
| 撤销/自动报价 | JSON 快照栈;变化后 600ms 防抖调 offer-price 实时显示总价 |
| 服务端算料 | Python 侧同语义 replay_shape:玻璃面积=重放窗格面积和,中梃长度=作用区域投影(精确到实际跨度) |
数据兼容性:编辑仅增删改 sp 与几何点,不改变 drawing_data 的字段结构——保存后仍是标准 shapeManager 格式。
4. 领域模型(依据真实响应样本归纳)
| 实体 | 关键字段(来自采集样本) |
|---|---|
| users | id, nickname, phone_number, wechat_id, union_id, apple_id, company_id, money, bounty, try_expiration_time, son_account_type, language, is_lose |
| companies | id, name, 参数集(find/update_company_param_value) |
| customers | id, name, phone, address, note, sort, type, salesmen, discount, balance, level, join_date |
| contracts | id, contract_no(如 FG20260818009), customer_id, area, count, money, status(意向单…), cut_status, sign_status, sign_picture_url, contract_type, confirmed, discount, agency_money, oids[] |
| orders | (POST 接口,结构待浏览器抓包补全) order_no, contract_id, products[], process |
| windoor_templates | id, name, pic_url, catelog_id, note, times, low/high_width/height, drawing_data |
| default_windoor_catelogs | 树:推拉门{平开,推拉,复古门,肯德基门,中式门窗,转角窗} |
| product_catelogs | 树,is_reference, lang |
| warehouses(材料) | bom_code, name, material(profile/glass/...), cost, price, color, pricing_method, length, count, warning, unit, meter_weight, thick, agency_price |
| receipt_accounts | type, name, number, bank, pic_url, is_default, balance |
| announcements | name, desc, pic_url, content(富文本) |
| company_modules | name, type, icon, description, price, try_days, label, info |
| operation_logs / invited_users | 分页日志/邀请返利 |
接口响应统一 envelope:{code: 1=成功, message, data, other_data, other_data2};分页为 Laravel 风格 current_page/data[]/total/per_page。自研系统沿用此规范以保持前端迁移成本最低。
5. 接口清单(详见 doc/API.md)
按模块归组(GET 已验证 ✅ / POST 待抓包 ⏳):
- 认证:
loginwechat-loginwechat-login-with-phonecode-loginregister-and-loginverification-code-newcaptchaforget-password - 用户:
current-user✅users✅current-user/passwordcurrent-user/phoneson_user_update/up_son_user_permission - 客户:
customers_list✅customerscustomer_record(s)customers_excel_in - 合同/订单:
contracts✅convert-contract/orders/(POST)⏳order-by-pidget_order_processup_order_no/contract_receipt* - 样板库:
search_default_windoor✅default_windoor_catelog✅default_windoor_info/{id}✅default_windoor/windoor/(用户自存窗型)windoor_template_sort - 产品:
product-catelog✅all-product✅product/search-productdls-price-configteam-discount - 仓库:
warehouse_list✅warehouse_inforeceipt_accounts✅product_move_in//out/materials_config - 下料:
optimize1dcut_solution(_new)contract_bars(_with_stock)up-cut-status - 渲染/3D:
rendering-infothree-d-data(POST)⏳drawing_data_by_oid/sketch-to-window-info - 财务:
contract_receipt_list✅样contract_receipt_statistics(_tb)withdraw-moneypay-order-list - 平台:
announcements✅company-module-info✅get-showdoc-menu✅feedbackip_to_region
⏳ 项:写入类接口(POST/PUT)为避免对生产系统产生副作用未做探测,需要在自研时按功能自行定义,或后续用浏览器 DevTools Network 面板在实际操作时抓包补全。
6. 里程碑计划
| 里程碑 | 内容 | 验收 |
|---|---|---|
| M1 基础框架 | FastAPI 骨架/统一响应/JWT 认证/Vue3 骨架/部署脚本 | 登录+用户中心跑通 |
| M2 业务 CRUD | 客户/合同/订单/产品/仓库 + Excel 导入导出 + 权限 | 全部 ✅ 接口对等实现 |
| M3 样板库+画图编辑器 | 拖拽布置、中梃分割、扇/玻璃指定、尺寸标注 | 加载全部 254 个采集样本渲染一致 |
| M4 报价+算料 | 价格脚本引擎、自动报价、手动报价 | 与原站同窗型报价误差为 0 |
| M5 生产+下料+打印 | 订单进度、optimize1d、打印模板 | 优化利用率 ≥ 原站 |
| M6 生态 | 微信登录/支付、商城、邀请返利、多语言 | 对齐原站 |
7. 风险与合规
- 只仿功能,不搬代码/素材:功能逻辑与数据模型不受版权保护,但对方源码、图标、宣传图文受保护。本项目全部自研,采集数据仅作开发参照;官方样板库图片存于对方 OSS(
webcc-pro.oss-cn-hangzhou...),上线前需替换为自绘素材或取得授权。 - 采集凭据时效:本次使用的 Bearer token 有效期至 2026-09-21 06:05;账户试用期至 2026-09-23。后续采集需重新登录获取 token。
- 生产 API 礼貌访问:所有采集均为只读且 0.3s 限速;不触碰写入接口、不触发异常路径(其报错响应会暴露框架堆栈,属对方运维问题,勿利用)。
- 待补全项:订单/报价写入接口的请求体结构(需浏览器抓包);价格脚本语言文法(需实际配置产品后观察)。
8. 下一步(按优先级)
- M1 搭建 FastAPI + Vue3 骨架,落统一响应与 JWT
- 导入采集数据:
windoor_templates、default_windoor_catelogs建表入库(数据已就绪) - 画布 shapeManager 原型:先实现"读取 254 个样本→静态渲染",再补交互
- 用户在真实环境抓包补全 ⏳ 接口后,更新
doc/API.md