From d7cd33bccabad2b96b5ba913da737c789a82cdbe Mon Sep 17 00:00:00 2001 From: Zuncle <34310384@qq.com> Date: Tue, 31 Mar 2026 21:13:57 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(shipping):=20=E5=8F=8D=E8=BD=AC?= =?UTF-8?q?=E8=BF=90=E8=B4=B9=E8=A7=84=E5=88=99=E4=B8=BA=E4=B8=8D=E6=BB=A1?= =?UTF-8?q?5=E4=BB=B6=E6=94=B6=E8=BF=90=E8=B4=B9=EF=BC=8C=E6=BB=A15?= =?UTF-8?q?=E4=BB=B6=E5=8C=85=E9=82=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将 onShip() 中运费判断从 > 5 件收运费改为 < 5 件收运费 --- pages/cabinet/index.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pages/cabinet/index.vue b/pages/cabinet/index.vue index 4675af7..34661a3 100755 --- a/pages/cabinet/index.vue +++ b/pages/cabinet/index.vue @@ -823,12 +823,12 @@ async function onShip() { const FREIGHT_THRESHOLD = 5 const FREIGHT_FEE = 10 - if (allIds.length > FREIGHT_THRESHOLD) { - // 超过 5 件,需支付 10 元运费 + if (allIds.length < FREIGHT_THRESHOLD) { + // 不满 5 件,需支付 10 元运费 const confirmed = await new Promise((resolve) => { uni.showModal({ title: '需支付运费', - content: `共 ${allIds.length} 件商品,超过 ${FREIGHT_THRESHOLD} 件需支付 ¥${FREIGHT_FEE}.00 运费,确认继续?`, + content: `共 ${allIds.length} 件商品,不满 ${FREIGHT_THRESHOLD} 件需支付 ¥${FREIGHT_FEE}.00 运费,确认继续?`, confirmText: '去支付', cancelText: '取消', success: (res) => resolve(res.confirm) @@ -867,7 +867,7 @@ async function onShip() { return } - // 不超过 5 件,原有确认发货流程 + // 满 5 件,包邮直接发货 uni.showModal({ title: '确认发货', content: `共 ${allIds.length} 件物品,确认申请发货?`, From 63345f4c2449f930b1b11c51a3e6bfdcf5736b2a Mon Sep 17 00:00:00 2001 From: Zuncle <34310384@qq.com> Date: Wed, 1 Apr 2026 00:55:23 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E5=8F=91=E8=B4=A7=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E5=A2=9E=E5=8A=A0=E5=9C=B0=E5=9D=80=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E5=BC=B9=E7=AA=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/appUser.js | 6 +- pages/cabinet/index.vue | 305 ++++++++++++++++++++++++++++++++++------ 2 files changed, 267 insertions(+), 44 deletions(-) diff --git a/api/appUser.js b/api/appUser.js index 43f8d45..ea6db15 100755 --- a/api/appUser.js +++ b/api/appUser.js @@ -148,8 +148,10 @@ export function redeemInventory(user_id, ids) { return authRequest({ url: `/api/app/users/${user_id}/inventory/redeem`, method: 'POST', data: { inventory_ids: ids } }) } -export function requestShipping(user_id, ids) { - return authRequest({ url: `/api/app/users/${user_id}/inventory/request-shipping`, method: 'POST', data: { inventory_ids: ids } }) +export function requestShipping(user_id, ids, address_id) { + const data = { inventory_ids: ids } + if (address_id) data.address_id = address_id + return authRequest({ url: `/api/app/users/${user_id}/inventory/request-shipping`, method: 'POST', data }) } export function createShippingFeeOrder(user_id, ids) { diff --git a/pages/cabinet/index.vue b/pages/cabinet/index.vue index 34661a3..24261f0 100755 --- a/pages/cabinet/index.vue +++ b/pages/cabinet/index.vue @@ -67,7 +67,7 @@ 没有更多了 - + 已选 {{ totalSelectedCount }} 件 @@ -247,6 +247,41 @@ + + + + + + + + + + + 暂无收货地址 + + + + + + {{ addr.name || addr.realname }} + {{ addr.phone || addr.mobile }} + 默认 + + {{ addr.province }} {{ addr.city }} {{ addr.district }} {{ addr.address || addr.detail }} + + + + + + 新增收货地址 + + + @@ -278,6 +313,12 @@ const pageSize = ref(100) const hasMore = ref(true) const productMetaCache = new Map() +// 地址选择弹窗状态 +const showAddressPicker = ref(false) +const addressList = ref([]) +const selectedAddressId = ref(null) +const pendingShipIds = ref([]) + // Synthesis tab state const recipes = ref([]) const synthLoading = ref(false) @@ -317,7 +358,7 @@ async function fetchProductMeta(productId) { return meta } -onShow(() => { +onShow(async () => { // 检查手机号绑定状态(快速检查本地缓存) if (!checkPhoneBoundSync()) return @@ -345,18 +386,36 @@ onShow(() => { return } + const uid = uni.getStorageSync("user_id") + + // 从新增地址页返回:刷新地址列表并重新打开弹窗 + if (pendingShipIds.value.length > 0) { + try { + const addresses = await listAddresses(uid) + const list = addresses.list || addresses.data || addresses || [] + addressList.value = Array.isArray(list) ? list : [] + if (addressList.value.length > 0) { + if (!selectedAddressId.value) { + const defaultAddr = addressList.value.find(a => a.is_default) + selectedAddressId.value = defaultAddr ? defaultAddr.id : addressList.value[0].id + } + showAddressPicker.value = true + } + } catch (e) {} + return + } + // 重置并加载第一页 page.value = 1 hasMore.value = true aggregatedList.value = [] shippedList.value = [] - const uid = uni.getStorageSync("user_id") if (currentTab.value === 1) { loadShipments(uid) } else if (currentTab.value === 2) { loadRecipes(uid) } else { - loadInventory(uid) // 改为只加载第一页,后续由 onReachBottom 触发 + loadInventory(uid) } }) @@ -779,7 +838,6 @@ async function onShip() { const selectedItems = aggregatedList.value.filter(item => item.selected) if (selectedItems.length === 0) return - // 收集所有需要发货的 inventory id let allIds = [] selectedItems.forEach(item => { if (item.original_ids && item.original_ids.length >= item.selectedCount) { @@ -793,38 +851,45 @@ async function onShip() { return } - // 1. 先检查是否有默认地址 + // 获取地址列表并弹窗选择 try { const addresses = await listAddresses(user_id) - const addressList = addresses.list || addresses.data || addresses || [] + const list = addresses.list || addresses.data || addresses || [] + addressList.value = Array.isArray(list) ? list : [] - if (!addressList || addressList.length === 0) { - // 没有默认地址,提示用户跳转到新建地址页面 + if (addressList.value.length === 0) { uni.showModal({ title: '提示', - content: '申请发货需要设置默认地址,是否前往新建地址?', + content: '申请发货需要设置收货地址,是否前往新建地址?', confirmText: '前往', cancelText: '取消', success: (res) => { - if (res.confirm) { - uni.navigateTo({ url: '/pages-user/address/edit' }) - } + if (res.confirm) uni.navigateTo({ url: '/pages-user/address/edit' }) } }) return } + + pendingShipIds.value = allIds + const defaultAddr = addressList.value.find(a => a.is_default) + selectedAddressId.value = defaultAddr ? defaultAddr.id : addressList.value[0].id + showAddressPicker.value = true } catch (e) { console.error('获取地址列表失败:', e) uni.showToast({ title: '获取地址失败', icon: 'none' }) - return } +} + +async function confirmShipWithAddress() { + const user_id = uni.getStorageSync('user_id') + const allIds = pendingShipIds.value + const addressId = selectedAddressId.value + showAddressPicker.value = false - // 2. 有默认地址,判断是否需要支付运费 const FREIGHT_THRESHOLD = 5 const FREIGHT_FEE = 10 if (allIds.length < FREIGHT_THRESHOLD) { - // 不满 5 件,需支付 10 元运费 const confirmed = await new Promise((resolve) => { uni.showModal({ title: '需支付运费', @@ -850,11 +915,11 @@ async function onShip() { } uni.hideLoading() - // 支付成功后发货 uni.showLoading({ title: '提交中...' }) try { - await requestShipping(user_id, allIds) + await requestShipping(user_id, allIds, addressId) uni.showToast({ title: '申请成功', icon: 'success' }) + pendingShipIds.value = [] aggregatedList.value = [] page.value = 1 hasMore.value = true @@ -867,30 +932,26 @@ async function onShip() { return } - // 满 5 件,包邮直接发货 - uni.showModal({ - title: '确认发货', - content: `共 ${allIds.length} 件物品,确认申请发货?`, - confirmText: '确认发货', - success: async (res) => { - if (res.confirm) { - uni.showLoading({ title: '提交中...' }) - try { - await requestShipping(user_id, allIds) - uni.showToast({ title: '申请成功', icon: 'success' }) - // 刷新列表 - aggregatedList.value = [] - page.value = 1 - hasMore.value = true - loadInventory(user_id) - } catch (e) { - uni.showToast({ title: e.message || '申请失败', icon: 'none' }) - } finally { - uni.hideLoading() - } - } - } - }) + // 满5件包邮直接发货 + uni.showLoading({ title: '提交中...' }) + try { + await requestShipping(user_id, allIds, addressId) + uni.showToast({ title: '申请成功', icon: 'success' }) + pendingShipIds.value = [] + aggregatedList.value = [] + page.value = 1 + hasMore.value = true + loadInventory(user_id) + } catch (e) { + uni.showToast({ title: e.message || '申请失败', icon: 'none' }) + } finally { + uni.hideLoading() + } +} + +function toAddAddress() { + showAddressPicker.value = false + uni.navigateTo({ url: '/pages-user/address/edit' }) } // 检查是否可以撤销发货(48小时内) @@ -1927,4 +1988,164 @@ function onCopyShareLink() { 0% { left: -100%; } 20%, 100% { left: 200%; } } + +/* ── 地址选择弹窗 ── */ +.address-picker-mask { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.4); + z-index: 1009; + backdrop-filter: blur(4rpx); +} + +.address-picker-popup { + position: fixed; + left: 0; + right: 0; + bottom: 0; + background: #fff; + border-radius: 40rpx 40rpx 0 0; + z-index: 1010; + padding: 40rpx 40rpx 0; + transform: translateY(100%); + transition: transform 0.3s cubic-bezier(0.25, 0.1, 0.25, 1); + max-height: 70vh; + display: flex; + flex-direction: column; + + &.show { + transform: translateY(0); + } +} + +.address-scroll { + flex: 1; + max-height: 50vh; + margin: 20rpx 0; +} + +.address-option { + display: flex; + align-items: flex-start; + padding: 24rpx; + border-radius: $radius-md; + margin-bottom: 16rpx; + border: 2rpx solid transparent; + background: $bg-page; + transition: all 0.2s; + + &.selected { + border-color: $brand-primary; + background: rgba($brand-primary, 0.05); + } +} + +.addr-radio { + width: 36rpx; + height: 36rpx; + border-radius: 50%; + border: 2rpx solid $text-tertiary; + margin-right: 20rpx; + margin-top: 6rpx; + flex-shrink: 0; + transition: all 0.2s; + + &.checked { + border-color: $brand-primary; + background: $brand-primary; + position: relative; + + &::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 16rpx; + height: 8rpx; + border-left: 3rpx solid #fff; + border-bottom: 3rpx solid #fff; + transform: translate(-50%, -65%) rotate(-45deg); + } + } +} + +.addr-info { + flex: 1; + min-width: 0; +} + +.addr-top { + display: flex; + align-items: center; + gap: 12rpx; + margin-bottom: 8rpx; +} + +.addr-name { + font-size: 28rpx; + font-weight: 700; + color: $text-main; +} + +.addr-phone { + font-size: 26rpx; + color: $text-sub; +} + +.addr-default-tag { + font-size: 18rpx; + color: #fff; + background: $brand-primary; + padding: 2rpx 10rpx; + border-radius: 6rpx; + font-weight: 600; +} + +.addr-detail { + font-size: 24rpx; + color: $text-sub; + line-height: 1.5; +} + +.empty-address { + text-align: center; + padding: 60rpx 0; + color: $text-tertiary; + font-size: 28rpx; +} + +.address-picker-footer { + padding: 20rpx 0 calc(20rpx + env(safe-area-inset-bottom)); + display: flex; + align-items: center; + justify-content: space-between; + border-top: 1rpx solid rgba(0, 0, 0, 0.05); +} + +.add-address-link { + font-size: 26rpx; + color: $brand-primary; + font-weight: 500; +} + +.confirm-ship-btn { + background: $gradient-brand; + color: #fff; + border: none; + border-radius: $radius-round; + height: 80rpx; + padding: 0 60rpx; + font-size: 28rpx; + font-weight: 600; + box-shadow: $shadow-warm; + + &[disabled] { + opacity: 0.5; + } + + &::after { border: none; } +}