# Checkout 地址管理改造设计 ## 背景 小程序商城购买流程中,checkout 页面当前使用了 `consignees`(收货人)系统来管理地址信息,但存在以下问题: 1. **收货人系统无省市区字段**:`consignees` 表只有 name/phone/idCard/ethnicity/bloodType/address(纯文本),没有 province/city/district/street 结构化地址 2. **身份证等字段混入地址管理**:idCard/ethnicity/bloodType 属于商品维度的购买信息,不应与地址绑定 3. **地址编辑后不保存**:收货人编辑页面没有省市区选择器,输入的地址信息无法正确存储 ## 现状分析 ### 两个并存的系统 | 系统 | 表 | 有省市区 | 有默认地址 | 当前 checkout 使用 | |------|-----|---------|-----------|------------------| | 地址系统 | `user_address` | ✅ province/city/district/street | ✅ isDefault | ❌ | | 收货人系统 | `consignees` | ❌(只有 text address) | ✅ isDefault | ✅ | ### 已有可用资源 - **前端**:`address-edit.vue` 已有完整的省市区三级联动选择器 + 地址表单 - **前端**:`address.vue` 已有地址列表 + 选择模式 + 编辑/删除/设为默认 - **后端**:`UserAddressController` 提供完整 CRUD + setDefault - **后端**:`ProductPurchaseFieldService` 已实现按商品配置购买信息字段 ## 设计 ### 核心变更 **checkout 页面从 `consignees` 系统切换到 `user_address` 系统**,身份证等购买信息字段保持独立。 ### 数据流 ``` 商品详情 → checkout │ ├─ 地址区域 → 调用 /api/user/address/list │ ├─ 有地址 → 跳转 address/address.vue?selectMode=1 │ │ ├─ 选择地址 → 回传 → checkout │ │ ├─ 编辑 → address-edit?addressId=X │ │ └─ 新增 → address-edit │ └─ 无地址 → 直接跳转 address-edit(新增) │ ├─ 购买信息区域 → 保持 getProductRequiredFields 逻辑 │ 身份证/民族/血型等按商品配置显示 │ └─ 提交订单 → 传 addressId(代替 consigneeId) ``` ### 文件改动清单 #### 1. `checkout.vue`(核心改动) | 改动项 | 说明 | |--------|------| | `loadDefaultConsignee()` → `loadDefaultAddress()` | 调用 `/api/user/address/list` 加载地址列表,选中默认地址 | | 地址卡片显示 | 改为显示 receiverName、phone、province+city+district+street、isDefault 标签 | | 移除购买信息字段 | 地址卡片中不再显示 idCard、ethnicity、bloodType | | `openConsigneePicker()` → `openAddressPicker()` | 跳转到 `address/address.vue?selectMode=1` | | `goAddConsignee()` → `goAddAddress()` | 跳转到 `address-edit/address-edit` | | 提交订单 | `consigneeId` → 改为 `addressId`,取选中地址的 id | | `onShow` 生命周期 | 监听返回时重新加载地址列表,自动选中刚保存的地址 | | 移除 `consigneeList` API 引用 | 改为调用 `uni.request` 直接访问 `/api/user/address/list` | #### 2. `address/address.vue`(完善选择模式) | 改动项 | 说明 | |--------|------| | 选择模式回传 | 确保 `onSelect` 回传完整数据:`{ id, receiverName, phone, province, city, district, street, isDefault }` | | 回传机制 | 当前用 `prevPage.selectedAddress = item` 方式,确认 checkout 能正确读取 | #### 3. `address-edit/address-edit.vue` 无需改动。已有省市区联动选择器、详细地址、默认地址开关、保存逻辑。 #### 4. 后端 无需改动。`UserAddressController` 已有完整 CRUD + setDefault。 ### 购买信息字段的独立机制 身份证号、民族、血型、手签名等字段: - 由 `ProductPurchaseFieldService` 管理,按商品维度配置 - 管理端通过 `product_purchase_fields` 表配置每个商品需要哪些字段 - 接口 `/api/product/purchase_fields/required` 返回该商品需要的字段列表 - 预填来源:默认收货人 → 用户信息 - 不在地址卡片中显示,仅在"购买信息"区域按需显示 ### 交互流程 ``` checkout 页面加载(onLoad/onShow) ├─ 调用 /api/user/address/list → 获取地址列表 ├─ 有地址 → 选中默认地址(isDefault=1)或第一个地址 └─ 无地址 → 显示"请选择地址"空状态 点击地址区域 ├─ 有地址列表 → navigateTo address/address.vue?selectMode=1 │ ├─ 点击地址卡片 → 回传选中地址数据 → navigateBack │ ├─ 点击编辑 → navigateTo address-edit?addressId=X │ └─ 点击新增 → navigateTo address-edit │ └─ 无地址 → navigateTo address-edit(新增) └─ 保存成功 → navigateBack checkout onShow 行为 ├─ 每次页面显示时重新调用 /api/user/address/list 加载地址列表 ├─ 如果当前未选中地址,自动选中默认地址(isDefault=1)或第一个 └─ 如果已选中地址但列表有变化,保持选中状态不变 提交订单 ├─ 验证:地址必选、购买信息字段必填校验 ├─ 传参:{ addressId, items, remark, purchaseInfo, pointsUsed } └─ 成功 → 跳转支付 ``` ## 未改动部分 - `ProductPurchaseFieldService` 和 `ProductPurchaseField` 实体 - `ConsigneeController` / `ConsigneeService` / `Consignee` 实体(保留,但不再用于地址选择) - 后端 `UserAddressController` / `UserAddressService` - 数据库表结构 - `address-picker.vue` 组件(备用,有四级地址选择)