Files
menchuang/doc/API.md
T

448 lines
33 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.
# API 接口文档
> 本文档记录自研系统的接口规范,并对照目标站已验证接口。目标站基址:`https://zzc-serv.thinkerx.com/api/`(仅作参照)。
> 自研系统基址:`/api/`(FastAPI 挂载)。
> 认证方式:`Authorization: Bearer <JWT>`(HS256,24h);`X-Requested-With: XMLHttpRequest`;`Accept: application/json`。
## 0. 统一响应规范
```json
{ "code": 1, "message": "获取成功", "data": {}, "other_data": "", "other_data2": "" }
```
- `code=1` 成功,其他为失败;`message` 为用户可读文案。
- **`code=10086` 业务付费墙**:模块未购买/已到期,`message` 为"购买后解锁此功能,点击此处去购买";前端跳转商城。自研系统对应"套餐权限校验中间件"。
- 列表分页:`data: { current_page, data: [], total, per_page, last_page, next_page_url, ... }`。
- 业务错误:HTTP 200 + code≠1;认证失败:HTTP 401;参数缺失:HTTP 200 + code=0(message 提示)或 422。
## 1. 认证模块
| 接口名称 | 方式 | URL 路径 | 请求参数 | 响应示例 |
|---|---|---|---|---|
| 手机验证码登录 | POST | `/api/wechat-login-with-phone` | `{phone_number, code, ...}` | `{token, user}`(原站登录入口,JWT iss 即此) |
| 账号密码登录 | POST | `/api/login` | `{phone_number, password}` | `{token, ...}` |
| 验证码登录 | POST | `/api/code-login` | `{phone_number, code}` | `{token, ...}` |
| 发送验证码 | POST | `/api/verification-code-new` | `{phone_number, scene}` | `{code:1}` |
| 图形验证码 | GET | `/api/captcha` | — | 图形/`{code:1,data}` |
| 注册并登录 | POST | `/api/register-and-login` | `{phone_number, password, code}` | `{token, ...}` |
| 忘记密码 | POST | `/api/forget-password` | `{phone_number, code, password}` | `{code:1}` |
| 微信登录 | POST | `/api/wechat-login` | 微信 OAuth code | `{token, ...}` |
## 2. 用户模块
| 接口名称 | 方式 | URL 路径 | 请求参数 | 响应示例(已验证 ✅ 节选) |
|---|---|---|---|---|
| 当前用户信息 | GET | `/api/current-user` | — | ✅ `{"id":3562856,"nickname":"...","phone_number":"...","company_id":1,"money":"0.00","try_expiration_time":"2026-09-23 00:00:00","son_account_type":1,"language":"zh-CN",...}` |
| 子账户列表 | GET | `/api/users?page=1` | `page` | ✅ Laravel 分页,`data.data[]` |
| 邀请用户列表 | GET | `/api/invited_user_list?page=1` | `page` | ✅ 分页 |
| 修改密码 | POST | `/api/current-user/password` | `{old,new}` | ⏳ |
| 绑定微信 | POST | `/api/bind-wechat` | `code` | ⏳ |
| 解绑微信 | POST | `/api/unbind-wechat` | — | ⏳ |
## 3. 样板库模块(已全量采集 ✅)
| 接口名称 | 方式 | URL 路径 | 请求参数 | 响应示例 |
|---|---|---|---|---|
| 窗型分类树 | GET | `/api/default_windoor_catelog` | — | ✅ 树:`[{id:1,name:"推拉门",children:[{id:3,name:"平开"},...]}]` |
| 搜索官方模板 | GET | `/api/search_default_windoor` | `name`(可选,按名称过滤) | ✅ 无分页全量返回:`data.data: [{id,name,pic_url,catelog_id,note,times}]`,共 254 条 |
| 模板绘制详情 | GET | `/api/default_windoor_info/{id}` | 路径 `id` | ✅ `{id,drawing_data(编辑器画布JSON),pic_url,script_bar,script_glass,low/high_width,low/high_height,...}` |
| 用户自存窗型列表 | GET | `/api/windoor/` | `page` | ⏳(需服务端排序参数,待抓包) |
| 用户窗型详情 | GET | `/api/windoor/{id}` | 路径 `id` | ⏳(同 drawing_data 结构) |
| 模板排序 | POST | `/api/windoor_template_sort` | `{ids:[...]}` | ⏳ |
| **保存自定义样板** | POST | `/api/windoor/templates` | `{name, drawing_data, catelog_id?, note?}` | ✅ v0.4 新增:编辑器"另存为我的样板"(is_default=0,企业隔离) |
`drawing_data` 结构参见《克隆实施方案.md》§2.2。
## 4. 客户模块
| 接口名称 | 方式 | URL 路径 | 请求参数 | 响应示例 |
|---|---|---|---|---|
| 客户列表 | GET | `/api/customers_list` | — | ✅ `[{id,name,phone,address,note,sort,type,salesmen,discount,balance,level,join_date}]` |
| 客户列表(分页) | GET | `/api/customers` | `page,keywords` | ⏳ |
| 新增/编辑客户 | POST | `/api/customers` | `{name,phone,address,...}` | ⏳ |
| 客户跟进记录 | GET | `/api/customer_records/` | `customer_id` | ⏳ |
| 客户导入 | POST | `/api/customers_excel_in` | Excel 文件 | ⏳ |
## 5. 合同/订单模块
| 接口名称 | 方式 | URL 路径 | 请求参数 | 响应示例 |
|---|---|---|---|---|
| 合同列表 | GET | `/api/contracts` | — | ✅ `{"contracts":{current_page,data:[{id,contract_no:"FG20260818009",customer,area,count,money,status:"意向单",cut_status,sign_status,contract_type,confirmed,discount,oids[],agency_money}]}}` |
| 意向单转合同 | POST | `/api/convert-contract/` | `{contract_id,...}` | ⏳ |
| **订单列表/搜索** | POST | `/api/orders/` | `{page:1, ...筛选条件}` | ✅ 已验证(付费墙):`{"code":"10086","message":"购买后解锁此功能,点击此处去购买","data":""}`;已购账号返回 Laravel 分页订单列表 |
| **创建订单(合同+图纸)** | POST | `/api/orders/` | ✅ 源码确认:`{contract_id, drawing_data(shapeManager序列化), pic_url(缩略图)}` | ⏳ |
| 订单详情 | GET | `/api/orders/{id}` | 路径 `id` | ✅ 路由确认(源码),返回 `data.order` |
| 订单排序 | PUT | `/api/orders/{id}` | `{sort:n}` | ✅ 路由确认(源码) |
| 删除订单 | DELETE | `/api/orders/{id}` | 路径 `id`(支持批量 Promise.allSettled) | ✅ 路由确认(源码) |
| 订单详情(按pid) | POST | `/api/order-by-pid` | `{pid}` | ✅ 已验证(付费墙 code=10086) |
| 订单进度 | POST | `/api/get_order_process` | `{order_id}` | ✅ 已验证 code=1 |
| 订单进度列表 | GET | `/api/get_order_process(_list)` | — | ✅ GET code=1 |
| 订单日志 | GET | `/api/order_up_logs` | `订单id`(缺失时提示"订单id 必须") | ✅ 参数契约确认 |
| 阳光房订单 | POST | `/api/sunny_house_order/` | `{page:1,...}` | ✅ 已验证(付费墙 code=10086) |
| 售后单 | POST | `/api/after_sales_orders/` | `{问题描述...}` | ✅ 已验证(校验"请填写问题描述") |
| 重复订单校验 | POST | `/api/is-repeat-order` | 查询条件 | ✅ 已验证 code=1 |
| 订单状态(管家婆) | POST | `/api/cj-orders-status` | 需参数(当前500) | ⏳ |
| 合同确认 | POST | `/api/up-contract-confirmed/` | `{contract_id}` | ⏳ |
| 电子签名上传 | POST | `/api/update-contract-sign-status` | `{contract_id, sign_picture}` | ⏳ |
| 收款记录 | GET | `/api/contract_receipt_list/` | `contract_id` | ✅ GET code=1 |
| 收款统计 | GET | `/api/contract_receipt_statistics` | — | ✅ GET code=1 |
| 收款统计(按年) | GET | `/api/contract_receipt_statistics_tb` | `年份`(缺失提示"请选择年份") | ✅ 参数契约确认 |
**订单写入流完整契约(自研对齐)**:`画图(shapeManager.serialize) → POST windoor_default 保存模板 或 POST orders/{contract_id, drawing_data, pic_url} 创建订单 → GET orders/{id} 详情回显 → PUT orders/{id} 排序 → DELETE orders/{id} 删除`
## 6. 产品/价格模块
| 接口名称 | 方式 | URL 路径 | 请求参数 | 响应示例 |
|---|---|---|---|---|
| 产品分类树 | GET | `/api/product-catelog` | — | ✅ 树(is_reference、lang、children) |
| 全部产品 | GET | `/api/all-product` | — | ✅ `data:[]`(当前账户为空) |
| 产品详情 | GET | `/api/product/{id}` | 路径 `id` | ⏳ |
| 产品搜索 | GET | `/api/search-product` | `keywords` | ⏳ |
| 团队折扣 | GET | `/api/team-discount` | — | ⏳ |
| 报价单 | GET | `/api/quotations?page=1` | `page` | ✅ 分页(当前账户为空) |
## 7. 仓库/库存模块
| 接口名称 | 方式 | URL 路径 | 请求参数 | 响应示例 |
|---|---|---|---|---|
| 材料库存列表 | GET | `/api/warehouse_list` | 分页参数 | ✅ `[{id,bom_code,name,material:"profile",cost,price,color,pricing_method,length,count,warning,unit,meter_weight,thick,agency_price}]` |
| 库存分类 | GET | `/api/warehouse_catelogs` | — | ⏳ |
| 收款账户 | GET | `/api/receipt_accounts` | — | ✅ `[{id,type,name,number,bank,pic_url,is_default,balance}]` |
| 材料入库 | POST | `/api/product_move_in/` | `{...}` | ⏳ |
| 材料出库 | POST | `/api/product_move_out/` | `{...}` | ⏳ |
| 配件配置 | GET | `/api/materials_config` | — | ⏳ |
## 8. 优化下料/生产模块
| 接口名称 | 方式 | URL 路径 | 请求参数 | 响应示例 |
|---|---|---|---|---|
| 一维优化 | POST | `/api/optimize1d` | `{bars:[], stock:[]}` | ⏳ |
| 切割方案 | GET | `/api/cut_solution(_new)/{contract_id}` | 路径 | ⏳ |
| 合同型材清单 | GET | `/api/contract_bars(_with_stock)` | `contract_id` | ⏳ |
| 更新切割状态 | POST | `/api/up-cut-status` | `{...}` | ⏳ |
| 订单打印模板 | GET | `/api/order_format/` | — | ⏳ |
## 9. 渲染/3D 模块
| 接口名称 | 方式 | URL 路径 | 请求参数 | 响应示例 |
|---|---|---|---|---|
| 渲染信息 | GET | `/api/rendering-info` | — | ⏳ |
| 3D 数据 | POST | `/api/three-d-data` | `{drawing_data}` | ⏳ |
| 按订单取绘图 | GET | `/api/drawing_data_by_oid/{oid}` | 路径 `oid` | ⏳ |
| 照片生成窗型(AI) | POST | `/api/sketch-to-window-info` | 图片 | ⏳ |
## 10. 平台模块
| 接口名称 | 方式 | URL 路径 | 请求参数 | 响应示例 |
|---|---|---|---|---|
| 公告列表 | GET | `/api/announcements` | — | ✅ `[{id,name,desc,pic_url,content(富文本)}]` |
| 商城模块配置 | GET | `/api/company-module-info` | — | ✅ 25 个模块(名称/图标/描述/价格/试用天数) |
| 帮助文档菜单 | GET | `/api/get-showdoc-menu` | — | ✅ showdoc 目录结构 |
| 操作日志 | GET | `/api/operation_logs?page=1` | `page` | ✅ 分页 |
| 业务员列表 | GET | `/api/salesmen` | — | ✅(当前账户为空) |
| 反馈 | POST | `/api/feedback` | `{content}` | ⏳ |
> 标注说明:✅ = 已用只读请求实测并留存样本于 `data/api-samples/`;⏳ = 写入/低频接口未对生产系统探测,自研时按功能语义实现,或抓包后补全。
## 11. 整站全量采集结果(2026-09-20)
原始留档:`data/full-site/`(`get/` 279 个接口响应、`post/` 24 个 POST 响应、`get-manifest.json`、`post-manifest.json`、采集脚本 `sweep_get.py`/`sweep_post.py`)。
### 11.1 GET 扫描(279 个接口)
| 结果 | 数量 | 说明 |
|---|---|---|
| HTTP 200 | 90 | 其中 code=1 业务成功 **76 个** |
| HTTP 405 | 110 | POST/PUT/DELETE-only 接口(已列入 ⏳ 并按语义实现) |
| HTTP 404 | 65 | 需路径参数(如 `{id}` 后缀类) |
| HTTP 500 | 14 | 缺必填参数触发(服务端未做输入校验,自研须避免) |
参数契约(由失败提示反推):`order_up_logs`←订单id;`script/`←系列id;`pay-page`←类型;`contract_receipt_statistics_tb`←年份;`ywy-ykt-user`←手机号;`three-d-data`(POST)←order_id。
### 11.2 POST 安全探测(24 个,白名单制)
- 付费墙确认(code=10086):`orders/`、`sunny_house_order/`、`order-by-pid`、`offer-price(/)`、`product_by_warehouse`、`order_format_by_warehouse`、`ai_product`
- 成功(code=1):`get_order_process`、`is-repeat-order`、`xf_contract_workshop`
- 参数提示:`three-d-data`←必须 order_id;`after_sales_orders/`←问题描述
- 未探测(危险类,永不盲发):支付(wechat_pay*、withdraw)、短信(send-bind-code、verification-code-new)、账号绑定(bind-*、login)、删除/更新类(del_*、void_*、up_*、*_sort)、文件上传(upload*)
### 11.3 源码静态提取的写入契约
| 流程 | 方法+路径 | 请求体 |
|---|---|---|
| 创建订单 | POST `orders/` | `{contract_id, drawing_data, pic_url}` |
| 保存官方模板 | POST `windoor_default` | `{drawing_data: shapeManager.serialize(true), ...}` |
| 修改系列脚本 | PUT `script/{id}` | `{drawing_data: shapeManager.serialize(...)}` |
| 模板排序 | POST `windoor_template_sort` | `{[模板id]: 序号, ...}` |
| 删除订单 | DELETE `orders/{id}` | 路径参数,前端支持批量 |
| 订单排序 | PUT `orders/{id}` | `{sort}` |
### 11.4 权限/付费墙语义(自研须实现)
- 试账户可用模块:样板库、客户、合同、仓库、收款账户、公告、报表统计、帮助文档
- 付费墙模块(code=10086):订单全流程、报价(offer-price)、产品库、订单打印模板、AI 产品
- 到期语义:`pay-page-list` 返回 code=0 "您的账号已经到期,请联系销售人员!";`try_render` 返回 "体验版无法体验实景渲染"
- 角色权限:`contract-stat` 返回 code=210 "该账号没有该权限"
## 12. 自研系统接口规范(已实现 v0.1)
> 自研基址 `http://localhost:8000/api/`,envelope 与分页结构完全对齐 §0。认证:`Authorization: Bearer <JWT>`(HS256/24h)。
> 分层:`api/`(Controller) → `services/`(业务) → `repositories/`(数据) → `models/`(ORM)。
### 12.1 认证模块 `/api/auth`
| 接口名称 | 方式 | URL 路径 | 请求参数 | 响应示例 |
|---|---|---|---|---|
| 登录 | POST | `/api/auth/login` | `{"phone_number":"13800000000","password":"123456"}` | `{"code":1,"data":{"token":"...","expires_hours":24,"user":{...}}}` |
| 注册 | POST | `/api/auth/register` | `{"phone_number","password"}` | `{"code":1,"data":{"token","user_id"}}` |
| 当前用户 | GET | `/api/auth/current-user` | Bearer token | `{"code":1,"data":{"id,nickname,phone_number,company_id,language,try_expiration_time}}` |
### 12.2 订单模块 `/api/orders`(本节核心,自研设计)
**订单状态机**:`0意向单 → 1正式单 → 2生产中 → 3已完工`;任意未完工状态可 `4已取消`(终态)。非法迁移返回 code=0。
**单号规则**:`DO + YYYYMMDD + 4位流水`(同企业同日递增),例如 `DO202609200001`。
**创建订单后自动初始化生产进度节点**:下料/组装/玻璃/打胶/五金/质检/完工(7 节点,与目标站 get_order_process 语义对齐)。
| 接口名称 | 方式 | URL 路径 | 请求参数 | 响应示例 |
|---|---|---|---|---|
| **创建订单** | POST | `/api/orders` | `{"contract_id":1,"drawing_data":"{画布JSON}","pic_url":"/static/windoor-images/1.png","customer_id":1,"money":0,"count":0,"area":0,"note":"","status":0}` | `{"code":1,"message":"创建成功","data":{"id":1,"order_no":"DO202609200001","status":"意向单",...}}` |
| 订单搜索 | POST | `/api/orders/search` | `{"page":1,"page_size":15,"keyword":"","status":null,"contract_id":null,"start_date":"","end_date":"","order_by":"created_desc"}` | `{"code":1,"data":{"current_page":1,"data":[...],"total":0,"per_page":15}}` |
| 订单列表 | GET | `/api/orders?page=1&page_size=15` | query | 同上分页结构 |
| **订单详情** | GET | `/api/orders/{id}` | 路径 | `data` 含 `drawing_data`(画布 openFile 直接渲染)与 `processes[7]` |
| 更新订单 | PUT | `/api/orders/{id}` | 基础字段任意子集;`{"action":"change_status","target_status":1}` 执行状态迁移 | `{"code":1,"data":{...}}`;非法迁移 `{"code":0,"message":"不允许的状态迁移: 意向单→已完工"}` |
| 删除订单 | DELETE | `/api/orders/{id}` | 路径 | `{"code":1,"message":"删除成功"}` |
| **更新生产进度** | POST | `/api/orders/{id}/process` | `{"name":"下料","status":2}` (status: 0未开始/1进行中/2完成,自动记 finish_time) | `{"code":1,"data":{"id,"name","status","finish_time"}}` |
| 订单操作日志 | GET | `/api/orders/{id}/logs` | 路径 | `{"code":1,"data":[{"action":"create","detail":"创建订单 DO202609200001","created_at":...}]}` |
### 12.3 样板库模块 `/api/windoor`
| 接口名称 | 方式 | URL 路径 | 请求参数 | 响应示例 |
|---|---|---|---|---|
| 分类树 | GET | `/api/windoor/catelogs` | Bearer | 树结构同目标站 `default_windoor_catelog` |
| 模板搜索 | GET | `/api/windoor/templates?name=&catelog_id=&page=1&page_size=50` | query | 列表含 `pic_url`(本地平面图 `/static/windoor-images/{id}.png`),不含大字段 |
| 模板详情 | GET | `/api/windoor/templates/{id}` | 路径 | `data.drawing_data` — 与采集的 254 套样本同构,画布可直接渲染 |
### 12.4 系统模块
| 接口名称 | 方式 | URL 路径 | 说明 |
|---|---|---|---|
| 健康检查 | GET | `/api/health` | `{"code":1,"data":{"status":"up"}}` |
| 接口文档 | GET | `/docs` | FastAPI 自动生成 OpenAPI |
| 平面图静态 | GET | `/static/windoor-images/{id}.png` | 254 张采集平面图(开发参照,上线前须替换为自绘素材) |
### 12.5 客户模块 `/api/customers`(v0.2 新增)
| 接口名称 | 方式 | URL 路径 | 请求参数 | 说明 |
|---|---|---|---|---|
| 新增客户 | POST | `/api/customers` | `{name(必填), phone, address, note, salesmen}` | |
| 客户列表 | GET | `/api/customers?page=1&page_size=15&keyword=` | query | 模糊匹配姓名/电话/地址 |
| 编辑客户 | PUT | `/api/customers/{id}` | 同新增 | |
| 删除客户 | DELETE | `/api/customers/{id}` | 路径 | |
### 12.6 合同模块 `/api/contracts`(v0.2 新增)
| 接口名称 | 方式 | URL 路径 | 请求参数 | 说明 |
|---|---|---|---|---|
| 创建合同 | POST | `/api/contracts` | `{customer_id, customer_name, phone, address, area, count, money, note}` | 合同号 `FG+YYYYMMDD+3位流水`,默认意向单 |
| 合同列表 | GET | `/api/contracts?page=1&keyword=&status=` | query | 响应 `data.contracts` 分页(对齐目标站结构) |
| 编辑合同 | PUT | `/api/contracts/{id}` | 同创建 | |
| **意向单转正式** | POST | `/api/contracts/convert` | `{contract_id}` | 仅意向单可转,重复转换 code=0 |
| 删除合同 | DELETE | `/api/contracts/{id}` | 路径 | |
**合同→订单联动**:创建订单传 `contract_id` 时,后端自动快照合同的客户名/电话/地址到订单(客户资料后续变更不影响订单)。
### 12.7 优化下料 `/api/optimize1d`(v0.2 新增,纯计算无状态)
| 接口名称 | 方式 | URL 路径 | 请求参数 | 说明 |
|---|---|---|---|---|
| 一维优化 | POST | `/api/optimize1d` | `{demands:[{length,qty,label}], stocks:[{length,qty,label}], kerf:5}` | FFD 首递减装箱;返回 `plans[]`(每根原料的切割组合+余料)、`unplaced[]`、`stats.utilization`;需求>库存时 code=0 |
### 12.8 报价算料 `/api/offer-price`(v0.3 新增)
| 接口名称 | 方式 | URL 路径 | 请求参数 | 说明 |
|---|---|---|---|---|
| 算料报价 | POST | `/api/offer-price` | `{drawing_data \| template_id \| order_id(三选一), prices?}` | 从 drawing_data 几何提取:外框/中梃/扇框型材清单(工程近似)+ 玻璃面积(鞋带公式)+ 五金,套价格本计价。默认价: 型材40-50元/米、玻璃120元/㎡、五金180元/扇;`prices` 可覆盖 |
### 12.9 仓库库存 `/api/warehouse`(v0.3 新增)
| 接口名称 | 方式 | URL 路径 | 请求参数 | 说明 |
|---|---|---|---|---|
| 库存列表 | GET | `/api/warehouse/list?page=1&keyword=&material=` | query | material: profile/glass/hardware/addon |
| 新增材料 | POST | `/api/warehouse` | `{name(必填), material, spec, color, unit, price, count, warning, length}` | |
| 编辑材料 | PUT | `/api/warehouse/{id}` | 同新增 | |
| **出入库** | POST | `/api/warehouse/move` | `{item_id, direction: 1\|-1, count, note}` | 出库拒绝负库存,写流水 |
| 出入库流水 | GET | `/api/warehouse/moves?page=1` | query | 全部流水倒序 |
### 12.10 前端(v0.3,Vue3 + Element Plus,构建产物挂载于后端)
| 路由 | 页面 | 功能 |
|---|---|---|
| `/login` | 登录 | JWT 登录 |
| `/dashboard` | 工作台 | 订单/意向单/客户/合同统计 + 快捷入口 |
| `/orders` | 订单中心 | 搜索/新建(选合同+样板自动带图纸)/详情抽屉(**画布渲染 drawing_data**)+状态机操作+生产进度更新+算料报价+打印 |
| `/contracts` | 合同管理 | 列表/新建(选客户带出信息)/意向单转正式/一键下订单 |
| `/customers` | 客户管理 | CRUD + 搜索 |
| `/templates` | 样板库 | 254 套样板网格(平面图) + 分类筛选 + 画布预览 + 算料报价 + 用此样板下单 |
| `/warehouse` | 仓库库存 | 材料 CRUD + 出入库(流水) + 库存预警高亮 |
| `/optimize` | 优化下料 | 需求/原料编辑 + FFD 计算结果(利用率/切割组合表) |
**画布渲染器**(`components/WindoorCanvas.vue`,自研 Canvas2D):解析 drawing_data → Frame 玻璃区域多边形填充/描边 → 外框加粗 → 尺寸标注;支持滚轮缩放、拖拽平移、双击复位。
**扇样式推断引擎**(v0.5):子形状按 `有效bd → polyId映射区域(双扇对半分) → 帧bbox按扇数竖向均分` 三级解析,还原每套样板的真实分格与开向(od 角度三角标记、inward/outward 空心/实心、门标注)——修复此前"所有样板显示为默认矩形"的问题。
**画布编辑器**:+竖梃/+横梃 → 点击玻璃区域完成分割(两次交叉点法实时重算区域,mm.sp 同步追加分割线记录),支持撤销;**尺寸参数化编辑**(v0.5):W/H 输入框或拖拽外框右缘/下缘/右下角手柄 → 全部几何按比例自动缩放(型材料宽不变,最小 300mm),拖拽中静默、松手提交/回滚;订单详情可"保存图纸"(PUT orders/{id}),样板库可"另存为我的样板"(POST windoor/templates)。
**自动报价**(v0.5):画布变化(改尺寸/加分格)后 600ms 防抖自动调用 offer-price,页面实时显示当前尺寸总价。
**报价弹窗**(`components/QuoteDialog.vue`):明细表 + 总价,可从样板库/订单详情唤起,支持浏览器打印。
### 12.11 业务扩展模块(v0.7,`/api`)
| 接口名称 | 方式 | URL 路径 | 请求参数 | 说明 |
|---|---|---|---|---|
| 产品列表 | GET | `/api/products?page=&keyword=&material=` | query | 产品价格本(型材/玻璃/五金/配件) |
| 新增/编辑/删除产品 | POST/PUT/DELETE | `/api/products[/{id}]` | `{name, material, spec, unit, price, cost}` | |
| 保存报价单 | POST | `/api/quotation` | `{customer_id, items[], total, drawing_data, ...}` | 单号 `BJ+YYYYMMDD+3位流水` |
| 报价单列表/详情/更新/删除 | GET/PUT/DELETE | `/api/quotations[/{id}]` | 分页+keyword+status | status: 0草稿 1已发送 2已成交 3作废 |
| 提交售后单 | POST | `/api/after_sales` | `{title, description(必填), order_no?}` | 对齐原站"问题描述必填"校验 |
| 售后列表/状态流转 | GET/PUT | `/api/after_sales[/{id}]` | status: 0待处理 1处理中 2已完成 | |
| 创建量尺单 | POST | `/api/measures` | `{customer_name, phone, address, measure_date, surveyor, data[{name,width,height,qty}]}` | 对齐原站量尺管理 |
| 量尺列表/更新 | GET/PUT | `/api/measures[/{id}]` | status: 0待量尺 1已量尺 2已出图 | |
| 阳光房订单 | GET | `/api/sunny_house_orders` | 分页 | 订单按 `order_type=1` 过滤(Order 新增 order_type 字段) |
| 修改资料/密码 | PUT | `/api/auth/profile` `/api/auth/password` | — | 对齐原站个人中心 |
| 邀请信息 | GET | `/api/auth/invitation` | — | 邀请码 `HMC+6位用户ID` |
### 12.12 前端页面总览(v0.7,15 个页面,响应式布局)
| 路由 | 页面 | 说明 |
|---|---|---|
| `/login` | 登录/注册 | 双 Tab(注册对齐原站 register) |
| `/dashboard` | 工作台 | 统计 + 快捷入口 |
| `/orders` | 订单管理 | 搜索/创建/图纸编辑/状态机/进度/报价/打印 |
| `/sunny` | 阳光房 | 阳光房订单(order_type=1) |
| `/quotations` | 报价单 | 手动报价(选样板自动算料+手动调整)/转订单 |
| `/contracts` | 合同管理 | 意向单→正式单/一键下单 |
| `/customers` | 客户管理 | CRUD |
| `/measure` | 量尺管理 | 量尺单 + 洞口尺寸清单 |
| `/aftersale` | 售后管理 | 提交/流转 |
| `/templates` | 样板库 | 254 套样板/画布预览/编辑/报价/下单 |
| `/products` | 产品管理 | 价格本 CRUD |
| `/warehouse` | 仓库库存 | 出入库/预警 |
| `/optimize` | 优化下料 | FFD 计算 |
| `/market` | 商城 | 模块开通(购买流程占位,支付需外部资质) |
| `/guide` + `/personal` | 使用指南/个人中心 | 帮助文档/资料/密码/邀请返利 |
**响应式适配**:侧边栏 <900px 自动折叠为图标栏;<700px 主区边距收窄;表格列横向滚动。
### 12.14 平台扩展模块(v1.0,`/api`)
| 接口名称 | 方式 | URL 路径 | 请求参数 | 说明 |
|---|---|---|---|---|
| 渲染设置 + AI 风格 | GET/POST | `/api/rendering-info` | `{wall_color, scene, glass_tint, ai_style, ai_time}` | 存公司参数;风格: modern/chinese/european/nordic,时间: day/dusk/night |
| **合同下料方案** | POST | `/api/cut_solution` | `{contract_id, kerf}` | 汇总合同下订单图纸的算料需求 → FFD 优化 → 参数持久化;`GET /api/cut_solution/{id}` 读回 |
| 设备激活 | POST | `/api/device-activate` | `{sn, activate_code, name}` | 首绑自动生成激活码,防重复绑定 |
| 设备列表 | GET | `/api/devices` | — | |
| 生成订单分享 | POST | `/api/share-order/{id}` | — | HMAC 可逆 token |
| **公开订单摘要** | GET | `/api/shared-order/{token}` | 无需登录 | 分享页数据 |
| 帮助文章 | GET | `/api/articles?category=` | query | 种子 8 篇自撰指南 |
| 报表汇总 | GET | `/api/reports/summary?days=14` | days | 按日订单数/金额 + 8 项总量 + 状态分布 |
> v1.0 调整:按需求**移除短信验证码登录与支付收银接口**(verification-code-new / code-login / pay-orders 已下线);登录采用手机号+密码。
新增前端能力(v1.0):
- **AI 炫图**(`/ai_render`):自研程序化场景合成引擎——风格(现代简约/新中式/欧式/北欧)× 时间(日景/黄昏/夜景)× 场景(室内/室外/影棚),阶段化生成动画,四方案画廊,一键下载 PNG
- **效果图渲染**(`/rendering`)与 **3D 展示**(`/threed`,Three.js 挤出重建)
- **打印中心**(`/printer`)、**下料方案**(`/cut_solution`)、**设备管理**(`/devices`)、**订单分享**(`/share/order/:token` 公开页)、**报表统计**(`/chart`)
- **主题精致化**:品牌色设计变量、Element Plus 主题覆盖、卡片圆角阴影、登录页氛围渐变、响应式侧边栏
### 12.13 种子数据
```bash
uv sync # 安装依赖
uv run python -m huamenchuang.scripts.seed # 管理员 + 分类树 + 254 套样板入库
uv run uvicorn huamenchuang.main:app --reload # 启动,http://localhost:8000/docs
```
管理员账号:`13800000000 / 123456`(开发用,生产必须修改)。
默认 SQLite(`HMC_DATABASE_URL` 可切 MySQL),JWT 密钥 `HMC_JWT_SECRET` 生产必须设置。
### 12.15 价格脚本模块 `/api/scripts`(v2.20 新增,P0-报价真实化)
对齐目标站 `script`/`product-script`/`product-test` 语义:按系列为各计价项配置**定价公式**,报价时启用即按脚本计价。
公式引擎:安全表达式(递归下降解析,无 eval)。支持 `+ - * / ( )` 与函数 `min/max/round/abs/ceil/floor/sqrt`。
变量表:`w`/`h`(窗宽高mm)、`area`(㎡)、`perimeter`(m)、`glass_area`(㎡)、`sashes`(扇)、`meters_frame`/`meters_mullion`/`meters_sash`(各类型材米数)、`length`(作用项对应量:型材=米数、玻璃=面积、五金=扇数)。
公式语义:结果 = 该作用项**单价**(元/米、元/㎡、元/扇);`target=total` 时结果直接作为**总价**。
| 接口名称 | 方式 | URL 路径 | 请求参数 | 说明 |
|---|---|---|---|---|
| 脚本列表 | GET | `/api/scripts` | — | 公司全部脚本 |
| 新增脚本 | POST | `/api/scripts` | `{name(系列名), target, formula, note?, enabled?}` | target ∈ frame/mullion/sash/glass/hardware/total;公式后端白名单+语法校验,非法返回 code=0 |
| 编辑脚本 | PUT | `/api/scripts/{id}` | 同新增 | |
| 删除脚本 | DELETE | `/api/scripts/{id}` | 路径 | |
| **脚本试算** | POST | `/api/scripts/preview` | `{formula, target?, w?, h?, glass_area?, sashes?, meters_*?}` | 对齐目标站 product-test;返回 `{result, vars}` |
| 报价启用脚本 | POST | `/api/offer-price` | 增加 `use_scripts: true` 或 `scripts: {target: formula}` | 响应加 `scripted[]`(被脚本覆盖的项)、`script_total`(总价是否被脚本直取);行级 `scripted` 标记 |
种子示例脚本 5 条:断桥铝-55系列(frame/mullion/sash)、双层中空玻璃(glass)、标准五金(hardware)。
### 12.16 订单 BOM 与导出(v2.20 新增,P0-生产闭环)
| 接口名称 | 方式 | URL 路径 | 请求参数 | 说明 |
|---|---|---|---|---|
| **订单 BOM 单** | GET | `/api/orders/{id}/bom` | 路径 | 对齐目标站 calcbomOrder;返回 `{bars:[{kind,note,length,qty}], glass_area_m2, sash_count, width_mm, height_mm}`(从 drawing_data 重放算料,不含价格) |
| **订单导出 Excel** | GET | `/api/orders/{id}/export` | 路径 | 对齐 orders/export;xlsx(订单信息+BOM 下料清单+玻璃/五金汇总),`Content-Disposition: attachment` |
### 12.17 打印模板 `/api/order-formats`(v2.20 新增,P0-打印模板体系)
对齐目标站 `order_format` 语义:模板=区块列表 `blocks[]`,前端按区块渲染 A4。
区块类型:`title`(text=标题文字)、`info`(fields=订单字段列表:order_no/customer_name/phone/address/count/area/money/created_at/note)、`image`(图纸缩略图)、`table`(kind=process 生产进度 / bom 下料清单)、`sign`(签字行)。
| 接口名称 | 方式 | URL 路径 | 请求参数 | 说明 |
|---|---|---|---|---|
| 模板列表 | GET | `/api/order-formats` | — | 按 sort 排序 |
| 新增模板 | POST | `/api/order-formats` | `{name, order_type, blocks[], is_default?}` | 区块类型校验;is_default=1 时清除其他默认 |
| 编辑模板 | PUT | `/api/order-formats/{id}` | 同新增 | |
| 删除模板 | DELETE | `/api/order-formats/{id}` | 路径 | |
种子模板 2 套:标准生产订单(默认)、生产订单+BOM 下料单。
### 12.18 合同下料方案升级(v2.20,P0-按库存优化)
`POST /api/cut_solution` 请求扩展:`{contract_id, kerf, use_stock?, stock_length?}`。
- `use_stock=true`:从仓库实际库存(material=profile 且 length>0 且 count>0)取原料优化;需求超出库存时输出 `shortage[]` 缺料清单(length/label/qty),不拦截计算
- `use_stock=false`:按 `stock_length`(默认 6000mm)虚拟原料,数量按需求自动估算
- 响应/保存均新增:`result`(完整优化方案)、`preparation[]`(切割准备/领料清单:原料×根数×切割件数×余料)、`shortage[]`(按库存模式的缺料清单)
- `GET /api/cut_solution/{contract_id}` 返回完整保存方案(含 result/preparation/shortage)
### 12.19 财务模块 `/api`(v2.20 新增,P0-收款财务闭环)
对齐目标站 `/manage/financial` + `contract_receipt*` 语义。
**收款方式**:1现金 2银行转账 3微信 4支付宝 5其他;**状态**:1正常 0已作废(作废不参与统计/已收)。
| 接口名称 | 方式 | URL 路径 | 请求参数 | 说明 |
|---|---|---|---|---|
| 收款账户列表 | GET | `/api/receipt-accounts` | — | |
| 新增/编辑/删除账户 | POST/PUT/DELETE | `/api/receipt-accounts[/{id}]` | `{type,name,number?,bank?,note?,is_default?}` | is_default=1 唯一默认 |
| **登记收款** | POST | `/api/contracts/{id}/receipts` | `{amount(>0), method, account_id?, receipt_date?, note?}` | 收款单号 `SK+YYYYMMDD+3位流水` |
| 作废收款 | POST | `/api/receipts/{id}/void` | 路径 | 对齐 void_contract_receipt |
| 收款流水分页 | GET | `/api/receipts` | `page,keyword,year,contract_id,status` | 联合同号/客户名 |
| **收款统计** | GET | `/api/receipts/statistics` | `year?`(默认当年) | `{total_received, contract_total, unreceived, monthly[12]}`(对齐 statistics/_tb) |
合同列表(`GET /api/contracts`)响应行新增:`received`(有效收款合计)、`unreceived`(合同额-已收)。
### 12.20 Excel 导入导出(v2.20 新增,P0-数据迁移)
依赖 `openpyxl` + `python-multipart`。导入文件自动探测表头行(兼容带标题行的导出格式);导出为带样式 xlsx。
| 接口名称 | 方式 | URL 路径 | 请求参数 | 说明 |
|---|---|---|---|---|
| 客户导入模板 | GET | `/api/customers/excel-template` | — | 列:姓名*/电话/地址/业务员/备注 |
| **客户批量导入** | POST | `/api/customers/excel-in` | multipart `file` | 对齐 customers_excel_in;缺姓名行跳过并逐行报错 |
| 客户导出 | GET | `/api/customers/excel-out` | — | 全量 |
| 合同导出 | GET | `/api/contracts/excel-out` | — | 对齐 contracts_excel,含已收金额 |
| **库存批量导入** | POST | `/api/warehouse/excel-in` | multipart `file` | 对齐 materials_config_excel:同名材料更新(数量累加),否则新增 |
| 库存导出 | GET | `/api/warehouse/excel-out` | — | 对齐 warehouse_excel_out |
| 统计报表导出 | GET | `/api/reports/excel-statistics` | — | 对齐 excel-statistics:订单汇总+收款统计双 Sheet |