Files
menchuang/doc/克隆实施方案.md
T
HHY 78563267c4 feat: v0.6 分割树架构——横梃竖梃完整编辑
- 逆向确认原站设计思路: 基底多边形+mm.sp分割树(polyId指向作用区域),
  运行时重放得到最终窗格(254套样本验证重放语义)
- 前端 replayShape: 分割树重放还原真实网格(平开1矩形→4-7格)
- 中梃编辑: 点击选中高亮/拖动移动/删除(直接操作sp源真值后重放)
- 加梃升级: polyId.idx 精确指向被点窗格
- Python报价算料同语义重放: 中梃长度精确到实际作用跨度
- 方案文档§3.3: 原站设计思路+编辑器完成设计
2026-09-20 11:40:21 -07:00

221 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 门窗 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 拖拽布置编辑器(核心难点)复刻方案 —— v2 已实现
**原站设计思路**(逆向自 drawing_data 序列化结构,经 254 套样本验证):
1. **三层模型**:`Frame 形状 = 基底多边形(polygon.polygon) + 分割树(mm.sp[]) + 扇子形状(sm[])`
2. **分割树**(关键发现):`polygon.polygon` 不是最终窗格,而是基底多边形;`mm.sp[]` 按序记录每次分割——`line{pt,norm}` 定位分割线、`polyId{idx,pos}` 指向作用区域与插入位。编辑器打开文件时**重放分割树**得到最终窗格。同一中梃可能被记录为多条共线分段(随区域生长拆分)
3. **扇模型**:子形状 `Sash/DoubleSash`,`sashes[]` 描述子扇(`od` 开向角、`wtf` 转框、`openToward` 内开/外开),经 `polyId` 挂到窗格;`bd` 边界在序列化中常退化,运行时重算
4. **序列化即状态**: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 待抓包 ⏳):
- 认证:`login` `wechat-login` `wechat-login-with-phone` `code-login` `register-and-login` `verification-code-new` `captcha` `forget-password`
- 用户:`current-user`✅ `users`✅ `current-user/password` `current-user/phone` `son_user_update/` `up_son_user_permission`
- 客户:`customers_list`✅ `customers` `customer_record(s)` `customers_excel_in`
- 合同/订单:`contracts`✅ `convert-contract/` `orders/`(POST)⏳ `order-by-pid` `get_order_process` `up_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-product` `dls-price-config` `team-discount`
- 仓库:`warehouse_list`✅ `warehouse_info` `receipt_accounts`✅ `product_move_in//out/` `materials_config`
- 下料:`optimize1d` `cut_solution(_new)` `contract_bars(_with_stock)` `up-cut-status`
- 渲染/3D:`rendering-info` `three-d-data`(POST)⏳ `drawing_data_by_oid/` `sketch-to-window-info`
- 财务:`contract_receipt_list`✅样 `contract_receipt_statistics(_tb)` `withdraw-money` `pay-order-list`
- 平台:`announcements`✅ `company-module-info`✅ `get-showdoc-menu`✅ `feedback` `ip_to_region`
> ⏳ 项:写入类接口(POST/PUT)为避免对生产系统产生副作用未做探测,需要在自研时按功能自行定义,或后续用浏览器 DevTools Network 面板在实际操作时抓包补全。
## 6. 里程碑计划
| 里程碑 | 内容 | 验收 |
|---|---|---|
| M1 基础框架 | FastAPI 骨架/统一响应/JWT 认证/Vue3 骨架/部署脚本 | 登录+用户中心跑通 |
| M2 业务 CRUD | 客户/合同/订单/产品/仓库 + Excel 导入导出 + 权限 | 全部 ✅ 接口对等实现 |
| M3 样板库+画图编辑器 | 拖拽布置、中梃分割、扇/玻璃指定、尺寸标注 | **加载全部 254 个采集样本渲染一致** |
| M4 报价+算料 | 价格脚本引擎、自动报价、手动报价 | 与原站同窗型报价误差为 0 |
| M5 生产+下料+打印 | 订单进度、optimize1d、打印模板 | 优化利用率 ≥ 原站 |
| M6 生态 | 微信登录/支付、商城、邀请返利、多语言 | 对齐原站 |
## 7. 风险与合规
1. **只仿功能,不搬代码/素材**:功能逻辑与数据模型不受版权保护,但对方源码、图标、宣传图文受保护。本项目全部自研,采集数据仅作开发参照;官方样板库图片存于对方 OSS(`webcc-pro.oss-cn-hangzhou...`),上线前需替换为自绘素材或取得授权。
2. **采集凭据时效**:本次使用的 Bearer token 有效期至 2026-09-21 06:05;账户试用期至 2026-09-23。后续采集需重新登录获取 token。
3. **生产 API 礼貌访问**:所有采集均为只读且 0.3s 限速;不触碰写入接口、不触发异常路径(其报错响应会暴露框架堆栈,属对方运维问题,勿利用)。
4. **待补全项**:订单/报价写入接口的请求体结构(需浏览器抓包);价格脚本语言文法(需实际配置产品后观察)。
## 8. 下一步(按优先级)
1. M1 搭建 FastAPI + Vue3 骨架,落统一响应与 JWT
2. 导入采集数据:`windoor_templates`、`default_windoor_catelogs` 建表入库(数据已就绪)
3. 画布 shapeManager 原型:先实现"读取 254 个样本→静态渲染",再补交互
4. 用户在真实环境抓包补全 ⏳ 接口后,更新 `doc/API.md`