For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: 将 checkout 页面从 consignees 系统切换到 user_address 系统,身份证等购买信息字段保持独立。
Architecture: checkout.vue 调用 /api/user/address/list 替代 /api/consignee/list,地址选择跳转到 address/address.vue,新增/编辑走 address-edit/address-edit.vue。后端无改动。
Tech Stack: uni-app Vue 2, WeChat mini-program, Spring Boot 2.7.18
?.(用 && 替代)@PostMapping,前端 method: 'POST'uni.request + Authorization: Bearer {token}Files:
cfc-frontend/utils/api.jsInterfaces:
Produces: addressList(), addressDetail(id), addressSave(data), addressDelete(id), addressSetDefault(id)
[ ] Step 1: 在 api.js 末尾添加地址 API 函数
找到 consigneeDelete 函数附近,在 getProductRequiredFields 之前添加以下函数:
// ===== 地址管理 =====
export const addressList = () => request('/api/user/address/list', 'POST', {})
export const addressDetail = (id) => request('/api/user/address/get', 'POST', { id })
export const addressSave = (data) => {
var url = data.id ? '/api/user/address/update' : '/api/user/address/create'
return request(url, 'POST', data)
}
export const addressDelete = (id) => request('/api/user/address/delete', 'POST', { id })
export const addressSetDefault = (id) => request('/api/user/address/setDefault', 'POST', { id })
[ ] Step 2: 验证文件修改
grep -n 'addressList\|addressDetail\|addressSave\|addressDelete\|addressSetDefault' cfc-frontend/utils/api.js
Files:
cfc-frontend/pages/shop/checkout/checkout.vueInterfaces:
addressList() from api.jsProduces: 提交订单时传 addressId 代替 consigneeId
[ ] Step 1: 修改 import,替换 consigneeList 为 addressList
// 替换这一行:
import { getCouponList, consigneeList, getProductRequiredFields, getMyMembership } from '../../../utils/api.js'
// 改为:
import { getCouponList, addressList, getProductRequiredFields, getMyMembership } from '../../../utils/api.js'
[ ] Step 2: 修改 data(),替换 consignee 相关字段为 address 字段
// 在 data() 中,替换:
selectedConsignee: null,
consigneeList: [],
// 改为:
selectedAddress: null,
addressList: [],
// 同时移除:
showConsigneePicker: false,
[ ] Step 3: 修改模板 — 地址卡片区域
找到地址卡片区域(约第 8-25 行),替换为:
<!-- Address Section -->
<view class="section address-section" @click="openAddressPicker">
<view v-if="selectedAddress" class="address-content">
<view class="address-top">
<text class="receiver-name">{{ selectedAddress.receiverName }}</text>
<text class="receiver-phone">{{ formatPhone(selectedAddress.phone) }}</text>
<text v-if="selectedAddress.isDefault === 1" class="default-badge">默认</text>
</view>
<text class="address-detail">
{{ selectedAddress.province }}{{ selectedAddress.city }}{{ selectedAddress.district }}{{ selectedAddress.street }}
</text>
<text class="address-arrow">›</text>
</view>
<view v-else class="address-empty" @click.stop="goAddAddress">
<text class="address-empty-icon">📍</text>
<text class="address-empty-text">请选择收货地址</text>
<text class="address-arrow">›</text>
</view>
</view>
[ ] Step 4: 替换 loadDefaultConsignee 方法为 loadDefaultAddress
loadDefaultAddress() {
this.loading = true
var that = this
addressList().then(function(res) {
that.loading = false
if (res.code === 200) {
var list = res.data || []
that.addressList = list
for (var i = 0; i < list.length; i++) {
if (list[i].isDefault === 1) {
that.selectedAddress = list[i]
break
}
}
if (!that.selectedAddress && list.length > 0) {
that.selectedAddress = list[0]
}
}
}).catch(function(e) {
that.loading = false
console.error(e)
})
}
[ ] Step 5: 替换 openConsigneePicker 方法为 openAddressPicker
openAddressPicker() {
uni.navigateTo({ url: '/pages/shop/address/address?selectMode=1' })
}
[ ] Step 6: 替换 goAddConsignee 方法为 goAddAddress
goAddAddress() {
uni.navigateTo({ url: '/pages/shop/address-edit/address-edit' })
}
[ ] Step 7: 替换 autoFillPurchaseForm 中的 selectedConsignee 引用
autoFillPurchaseForm() {
if (!this.selectedAddress || this.requiredFields.length === 0) return
// ... 其余逻辑不变,只是 selectedConsignee → selectedAddress
}
[ ] Step 8: 修改 onLoad 中的调用
// 替换:
this.loadDefaultConsignee()
// 改为:
this.loadDefaultAddress()
[ ] Step 9: 添加 onShow 生命周期 — 返回时重新加载地址列表
onShow() {
if (this.addressList.length > 0) {
// 从 address-edit 或 address 页面返回后重新加载
this.loadDefaultAddress()
}
}
[ ] Step 10: 修改 onSubmit — 验证和提交参数
// 验证部分:
if (!this.selectedAddress) {
uni.showToast({ title: '请选择收货地址', icon: 'none' })
return
}
// 提交参数部分:
data: {
items: orderItems,
remark: this.remark,
addressId: that.selectedAddress.id,
purchaseInfo: that.purchaseForm,
pointsUsed: that.pointsUsed
}
[ ] Step 11: 移除不再使用的 consigneeList 相关代码
检查并移除:
showConsigneePicker 相关状态consigneeList 引用consignee 相关的 picker 弹窗Files:
cfc-frontend/pages/shop/address/address.vueInterfaces:
Produces: 通过 prevPage.selectedAddress 回传地址数据
[ ] Step 1: 确认 onSelect 方法回传完整数据
当前 onSelect 方法已存在(约第 105-113 行),数据来源于 addressList 加载的 UserAddress 对象,已有 id, receiverName, phone, province, city, district, street, isDefault 字段。确认 onSelect 直接回传 item 对象即可:
onSelect(item) {
if (this.selectMode) {
var pages = getCurrentPages()
var prevPage = pages[pages.length - 2]
if (prevPage) {
prevPage.selectedAddress = item
}
uni.navigateBack()
}
}
无需修改。
Files:
无
[ ] Step 1: 运行构建验证
cd cfc-frontend && npm run build:mp-weixin
预期:构建成功,无报错。
[ ] Step 2: 检查 checkout.vue 中所有 selectedConsignee 和 consigneeList 引用是否已清理
grep -n 'selectedConsignee\|consigneeList\|consignee' cfc-frontend/pages/shop/checkout/checkout.vue | head -20
预期:仅保留 consignee 相关的行不超过 2 行(如注释或无关引用)。