feat: 订单模块 v0.1 实现与样板二维平面图全量采集

- 后端分层架构: api(Controller)/services(业务)/repositories(数据)/models(ORM)
- 订单模块: 创建(契约对齐目标站{contract_id,drawing_data,pic_url})、搜索、
  详情、更新、删除、状态机(意向单→正式单→生产中→完工/取消,非法迁移拒绝)、
  7节点生产进度、审计日志
- 认证模块: JWT签发(HS256/24h)、PBKDF2密码、注册登录
- 样板库API: 分类树/模板搜索/模板详情, drawing_data 与采集样本同构
- 254张样板二维平面图全部采集并静态挂载 /static/windoor-images/
- 种子脚本: 管理员+分类树+254套样板入库
- 统一响应envelope与付费墙(code=10086)/权限(code=210)语义
- 端到端冒烟测试7/7通过, 更新API.md §12自研接口规范
This commit is contained in:
HHY
2026-09-20 08:16:03 -07:00
parent 7554f2e3c7
commit d3e6de585c
288 changed files with 1835 additions and 9 deletions
+7
View File
@@ -8,3 +8,10 @@ wheels/
# Virtual environments # Virtual environments
.venv .venv
# Database
*.db
*.sqlite3
# Logs
*.log
+2
View File
@@ -1,6 +1,8 @@
# CHANGELOG # CHANGELOG
- [2026-09-20 08:14] FEAT: 订单模块 v0.1 实现与二维平面图全量采集——FastAPI 分层架构(api/services/repositories/models)、订单状态机(意向单→正式单→生产中→完工/取消)、7节点生产进度、审计日志、JWT认证、样板库API;创建契约对齐目标站{contract_id,drawing_data,pic_url};254张样板平面图全部下载成功并静态挂载;端到端冒烟测试7/7通过 (Files: src/huamenchuang/**, pyproject.toml, README.md, doc/API.md, data/windoor-images/*, data/fetch-images.py)
- [2026-09-20 07:18] FEAT: 整站全量采集——GET 扫描 279 个接口全部留档(业务成功76)、POST 安全探测 24 个(付费墙/参数契约确认)、订单写入接口契约经源码静态分析补全(orders CRUD + 创建订单请求体);doc/API.md 新增 §11 采集结果与付费墙语义 (Files: data/full-site/*, doc/API.md, doc/克隆实施方案.md) - [2026-09-20 07:18] FEAT: 整站全量采集——GET 扫描 279 个接口全部留档(业务成功76)、POST 安全探测 24 个(付费墙/参数契约确认)、订单写入接口契约经源码静态分析补全(orders CRUD + 创建订单请求体);doc/API.md 新增 §11 采集结果与付费墙语义 (Files: data/full-site/*, doc/API.md, doc/克隆实施方案.md)
- [2026-09-20 06:41] FEAT: 完成目标站逆向采集——样板库 254 套模板 drawing_data 全量采集(254/254)、16 个核心接口响应样本、约 300 条接口清单;输出《克隆实施方案》《API 接口文档》(Files: doc/克隆实施方案.md, doc/API.md, data/api-endpoint-inventory.txt, data/api-samples/*, data/windoor-drawings/*) - [2026-09-20 06:41] FEAT: 完成目标站逆向采集——样板库 254 套模板 drawing_data 全量采集(254/254)、16 个核心接口响应样本、约 300 条接口清单;输出《克隆实施方案》《API 接口文档》(Files: doc/克隆实施方案.md, doc/API.md, data/api-endpoint-inventory.txt, data/api-samples/*, data/windoor-drawings/*)
- [2026-09-20 06:41] DOCS: 初始化 README 项目导航 (Files: README.md) - [2026-09-20 06:41] DOCS: 初始化 README 项目导航 (Files: README.md)
+19 -6
View File
@@ -2,10 +2,16 @@
门窗行业云平台(功能对标 windoorcraft.com,全部自研实现)。 门窗行业云平台(功能对标 windoorcraft.com,全部自研实现)。
## 当前进度
- ✅ 目标站逆向与数据采集(样板库 254 套全量 + 二维平面图 254 张 + 接口全量留档)
- ✅ 后端 v0.1:认证 / 订单模块(状态机+生产进度+审计日志)/ 样板库 API
- ⏳ 前端 Vue3 与画布编辑器(规划中,见方案 §3.3)
## 文档导航 ## 文档导航
- [克隆实施方案](doc/克隆实施方案.md) — 产品画像、架构设计、拖拽画布编辑器复刻方案、里程碑 - [克隆实施方案](doc/克隆实施方案.md) — 产品画像、架构设计、拖拽画布编辑器复刻方案、里程碑
- [API 接口文档](doc/API.md) — 接口规范与目标站对照表 - [API 接口文档](doc/API.md) — 目标站对照表 + 自研接口规范(§12)
- [变更日志](CHANGELOG) - [变更日志](CHANGELOG)
## 目录 ## 目录
@@ -15,14 +21,21 @@ doc/ 设计文档
data/ data/
├── api-endpoint-inventory.txt 目标站接口名清单(≈300 条) ├── api-endpoint-inventory.txt 目标站接口名清单(≈300 条)
├── api-samples/ 核心接口真实响应样本 + 样板库全量清单 ├── api-samples/ 核心接口真实响应样本 + 样板库全量清单
└── windoor-drawings/ 254 套官方样板库完整绘制数据 (drawing_data) ├── windoor-drawings/ 254 套官方样板完整绘制数据 (drawing_data)
src/huamenchuang/ 后端(FastAPI,规划中) ├── windoor-images/ 254 张样板二维平面图
└── full-site/ 整站接口全量扫描留档
src/huamenchuang/ 后端(FastAPI,分层: api/services/repositories/models)
frontend/ 前端(Vue3 + TS,规划中) frontend/ 前端(Vue3 + TS,规划中)
``` ```
## 开发 ## 快速开始
```bash ```bash
uv sync # 安装后端依赖(规划) uv sync # 安装依赖
uv run uvicorn huamenchuang.main:app --reload uv run python -m huamenchuang.scripts.seed # 管理员 + 254 套样板入库
uv run uvicorn huamenchuang.main:app --reload # 启动 → http://localhost:8000/docs
``` ```
管理员账号(开发):`13800000000 / 123456`。
环境变量(均可选):`HMC_DATABASE_URL`(默认 SQLite,可切 MySQL)、`HMC_JWT_SECRET`(生产必设)、`HMC_ENABLED_MODULES`(套餐模块开关)。
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env python3
"""下载 254 套样板的二维平面图(pic_url,公开 OSS)。限速 0.2s。"""
import json, os, time, urllib.request, urllib.error
templates = json.load(open(r"D:\Code\huamenchuang\data\api-samples\windoor-templates-clean.json", encoding="utf-8"))
OUT = r"D:\Code\huamenchuang\data\windoor-images"
os.makedirs(OUT, exist_ok=True)
ok, skip, fail = 0, 0, []
for i, t in enumerate(templates):
ext = ".png"
url = t["pic_url"]
if url.lower().endswith((".jpg", ".jpeg")):
ext = ".jpg"
out = os.path.join(OUT, f"{t['id']}{ext}")
if os.path.exists(out) and os.path.getsize(out) > 100:
skip += 1
continue
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
try:
with urllib.request.urlopen(req, timeout=20) as r:
data = r.read()
open(out, "wb").write(data)
ok += 1
except Exception as e:
fail.append((t["id"], str(e)[:60]))
if (i + 1) % 50 == 0:
print(f"进度 {i+1}/{len(templates)} 成功{ok} 跳过{skip}", flush=True)
time.sleep(0.2)
print(f"完成: 新下载 {ok}, 已存在 {skip}, 失败 {len(fail)}")
if fail:
print(fail[:10])
Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

Some files were not shown because too many files have changed in this diff Show More