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 @@
+
+
+
+
@@ -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; }
+}