fix: 首页弹窗收货信息优化
All checks were successful
构建并部署前端到生产环境 / build-and-deploy (push) Successful in 2m23s
All checks were successful
构建并部署前端到生产环境 / build-and-deploy (push) Successful in 2m23s
This commit is contained in:
@@ -18,22 +18,55 @@
|
||||
|
||||
<template v-else-if='isAddressStep'>
|
||||
<view class='popup-header'>
|
||||
<view class='popup-heading'>换卡收货信息</view>
|
||||
<view class='popup-heading'>换货收货信息</view>
|
||||
<view class='popup-close' role='button' aria-label='关闭' @tap='dismiss'>×</view>
|
||||
</view>
|
||||
<view class='form-item'>
|
||||
<view class='form-label'>收件人姓名</view>
|
||||
<up-input v-model='addressForm.recipient_name' placeholder='请输入收件人姓名' border='surround' maxlength='50'/>
|
||||
</view>
|
||||
<view class='form-item'>
|
||||
<view class='form-label'>收件人电话</view>
|
||||
<up-input v-model='addressForm.recipient_phone' type='number' placeholder='请输入收件人电话' border='surround' maxlength='20'/>
|
||||
</view>
|
||||
<view class='form-item'>
|
||||
<view class='form-label'>收货地址</view>
|
||||
<up-textarea v-model='addressForm.recipient_address' placeholder='请输入完整收货地址'/>
|
||||
</view>
|
||||
<view class='popup-actions'>
|
||||
<scroll-view scroll-y class='popup-address-form'>
|
||||
<view class='form-item'>
|
||||
<view class='form-label'>粘贴收货信息</view>
|
||||
<up-textarea
|
||||
v-model='addressForm.raw_shipping_text'
|
||||
placeholder='可粘贴包含收件人、电话、地址的一整段文字'
|
||||
autoHeight
|
||||
:maxlength='-1'
|
||||
border='surround'
|
||||
/>
|
||||
<view class='form-helper'>识别结果可继续手动修改</view>
|
||||
<view class='paste-action-row'>
|
||||
<button class='btn-apple btn-secondary paste-action-btn' @tap='clearPastedText'>清除</button>
|
||||
<button class='btn-apple btn-secondary paste-action-btn' @tap='fillFromPastedText'>识别并填充</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class='form-item'>
|
||||
<view class='form-label'>收件人姓名</view>
|
||||
<up-input v-model='addressForm.recipient_name' placeholder='请输入收件人姓名' border='surround' maxlength='50'/>
|
||||
</view>
|
||||
<view class='form-item'>
|
||||
<view class='form-label'>收件人电话</view>
|
||||
<up-input v-model='addressForm.recipient_phone' type='number' placeholder='请输入11位手机号' border='surround' maxlength='11'/>
|
||||
</view>
|
||||
<view class='form-item'>
|
||||
<view class='form-label'>所在地区</view>
|
||||
<view class='region-trigger' @tap='openAreaPicker'>
|
||||
<text class='region-trigger-text' :class='{ placeholder: !regionDisplayText }'>
|
||||
{{ regionDisplayText || '请选择省 / 市 / 区' }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class='form-item'>
|
||||
<view class='form-label'>详细地址</view>
|
||||
<up-textarea
|
||||
v-model='addressForm.recipient_address_detail'
|
||||
placeholder='请输入详细收货地址'
|
||||
autoHeight
|
||||
:maxlength='-1'
|
||||
border='surround'
|
||||
/>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class='popup-address-actions'>
|
||||
<up-button plain @tap='dismiss'>取消</up-button>
|
||||
<up-button type='primary' :loading='submitting' :disabled='submitting' @tap='submitAddress'>提交</up-button>
|
||||
</view>
|
||||
</template>
|
||||
@@ -60,12 +93,32 @@
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
<up-picker
|
||||
:show='showAreaPicker'
|
||||
:columns='areaPickerColumns'
|
||||
keyName='label'
|
||||
title='选择所在地区'
|
||||
:defaultIndex='areaPickerDefaultIndex'
|
||||
closeOnClickOverlay
|
||||
@confirm='confirmAreaPicker'
|
||||
@change='handleAreaPickerChange'
|
||||
@cancel='showAreaPicker = false'
|
||||
@close='showAreaPicker = false'
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, onMounted } from 'vue';
|
||||
import { popupApi, notificationApi } from '@/api/index.js';
|
||||
import { handledPopupNotificationIds } from '@/utils/popup.js';
|
||||
import {
|
||||
buildRegionColumns,
|
||||
composeRecipientAddress,
|
||||
getRegionDisplayText,
|
||||
parseShippingText
|
||||
} from '@/utils/shippingAddress.js';
|
||||
|
||||
const PHONE_REG = /^1[3-9]\d{9}$/;
|
||||
|
||||
const props = defineProps({
|
||||
page: {
|
||||
@@ -85,16 +138,22 @@
|
||||
const candidate = ref(null);
|
||||
const exchange = ref(null);
|
||||
const submitting = ref(false);
|
||||
const showAreaPicker = ref(false);
|
||||
const areaPickerColumns = ref([]);
|
||||
const areaPickerDefaultIndex = ref([0, 0, 0]);
|
||||
const addressForm = reactive({
|
||||
raw_shipping_text: '',
|
||||
recipient_name: '',
|
||||
recipient_phone: '',
|
||||
recipient_address: ''
|
||||
recipient_region_codes: [],
|
||||
recipient_address_detail: ''
|
||||
});
|
||||
|
||||
const isCandidateStep = computed(() => step.value === 'candidate');
|
||||
const isAddressStep = computed(() => step.value === 'address');
|
||||
const isDoneStep = computed(() => step.value === 'done');
|
||||
const isRiskExchange = computed(() => candidate.value?.popup_type === 'risk_exchange');
|
||||
const regionDisplayText = computed(() => getRegionDisplayText(addressForm.recipient_region_codes));
|
||||
|
||||
const actionLabelMap = {
|
||||
package_purchase: '立即购买',
|
||||
@@ -113,9 +172,82 @@
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
addressForm.raw_shipping_text = '';
|
||||
addressForm.recipient_name = '';
|
||||
addressForm.recipient_phone = '';
|
||||
addressForm.recipient_address = '';
|
||||
addressForm.recipient_region_codes = [];
|
||||
addressForm.recipient_address_detail = '';
|
||||
};
|
||||
|
||||
const syncAreaPickerState = (regionCodes = []) => {
|
||||
const { columns, defaultIndex } = buildRegionColumns(regionCodes);
|
||||
areaPickerColumns.value = columns;
|
||||
areaPickerDefaultIndex.value = defaultIndex.map((index) => (index < 0 ? 0 : index));
|
||||
};
|
||||
|
||||
const openAreaPicker = () => {
|
||||
syncAreaPickerState(addressForm.recipient_region_codes);
|
||||
showAreaPicker.value = true;
|
||||
};
|
||||
|
||||
const handleAreaPickerChange = (event) => {
|
||||
const selectedValues = event.value || [];
|
||||
const selectedProvinceCode = selectedValues[0]?.value || '';
|
||||
const selectedCityCode = event.columnIndex === 0 ? '' : selectedValues[1]?.value || '';
|
||||
const selectedDistrictCode = event.columnIndex === 2 ? selectedValues[2]?.value || '' : '';
|
||||
const { columns, defaultIndex } = buildRegionColumns([
|
||||
selectedProvinceCode,
|
||||
selectedCityCode,
|
||||
selectedDistrictCode
|
||||
]);
|
||||
areaPickerColumns.value = columns;
|
||||
areaPickerDefaultIndex.value = defaultIndex.map((index) => (index < 0 ? 0 : index));
|
||||
};
|
||||
|
||||
const confirmAreaPicker = ({ value }) => {
|
||||
const selectedCodes = (value || []).map((item) => item?.value).filter(Boolean);
|
||||
if (selectedCodes.length === 3) {
|
||||
addressForm.recipient_region_codes = selectedCodes;
|
||||
syncAreaPickerState(selectedCodes);
|
||||
}
|
||||
showAreaPicker.value = false;
|
||||
};
|
||||
|
||||
const fillFromPastedText = () => {
|
||||
if (!addressForm.raw_shipping_text.trim()) {
|
||||
uni.showToast({ title: '请先粘贴收货信息', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
const parsed = parseShippingText(addressForm.raw_shipping_text);
|
||||
let updatedCount = 0;
|
||||
if (parsed.recipient_name) {
|
||||
addressForm.recipient_name = parsed.recipient_name;
|
||||
updatedCount += 1;
|
||||
}
|
||||
if (parsed.recipient_phone) {
|
||||
addressForm.recipient_phone = parsed.recipient_phone;
|
||||
updatedCount += 1;
|
||||
}
|
||||
if (parsed.regionCodes.length === 3) {
|
||||
addressForm.recipient_region_codes = parsed.regionCodes;
|
||||
syncAreaPickerState(parsed.regionCodes);
|
||||
updatedCount += 1;
|
||||
}
|
||||
if (parsed.detailAddress) {
|
||||
addressForm.recipient_address_detail = parsed.detailAddress;
|
||||
updatedCount += 1;
|
||||
}
|
||||
|
||||
if (!updatedCount) {
|
||||
uni.showToast({ title: '未识别到有效收货信息', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
uni.showToast({ title: '已识别并填充', icon: 'success' });
|
||||
};
|
||||
|
||||
const clearPastedText = () => {
|
||||
addressForm.raw_shipping_text = '';
|
||||
};
|
||||
|
||||
const markPopupRead = async () => {
|
||||
@@ -130,6 +262,7 @@
|
||||
|
||||
const dismiss = () => {
|
||||
visible.value = false;
|
||||
showAreaPicker.value = false;
|
||||
markPopupRead();
|
||||
emit('close', 'dismissed');
|
||||
};
|
||||
@@ -147,11 +280,30 @@
|
||||
const submitAddress = async () => {
|
||||
if (submitting.value) return;
|
||||
|
||||
const { recipient_name, recipient_phone, recipient_address } = addressForm;
|
||||
if (!recipient_name || !recipient_phone || !recipient_address) {
|
||||
uni.showToast({ title: '请填写完整收货信息', icon: 'none' });
|
||||
const recipientName = addressForm.recipient_name.trim();
|
||||
const recipientPhone = addressForm.recipient_phone.trim();
|
||||
const detailAddress = addressForm.recipient_address_detail.trim();
|
||||
if (!recipientName) {
|
||||
uni.showToast({ title: '请输入收件人姓名', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (!recipientPhone) {
|
||||
uni.showToast({ title: '请输入收件人电话', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (!PHONE_REG.test(recipientPhone)) {
|
||||
uni.showToast({ title: '请输入正确的手机号', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (addressForm.recipient_region_codes.length !== 3) {
|
||||
uni.showToast({ title: '请选择省市区', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (!detailAddress) {
|
||||
uni.showToast({ title: '请输入详细收货地址', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
const recipientAddress = composeRecipientAddress(addressForm.recipient_region_codes, detailAddress);
|
||||
|
||||
const assetId = Number(candidate.value?.asset_id);
|
||||
if (!Number.isInteger(assetId) || assetId <= 0) {
|
||||
@@ -162,9 +314,9 @@
|
||||
submitting.value = true;
|
||||
try {
|
||||
exchange.value = await popupApi.submitRiskExchangeAddress(assetId, {
|
||||
recipient_name,
|
||||
recipient_phone,
|
||||
recipient_address
|
||||
recipient_name: recipientName,
|
||||
recipient_phone: recipientPhone,
|
||||
recipient_address: recipientAddress
|
||||
});
|
||||
await markPopupRead();
|
||||
step.value = 'done';
|
||||
@@ -177,6 +329,7 @@
|
||||
|
||||
const finish = () => {
|
||||
visible.value = false;
|
||||
showAreaPicker.value = false;
|
||||
emit('close', 'done');
|
||||
};
|
||||
|
||||
@@ -222,6 +375,9 @@
|
||||
.popup-candidate-card {
|
||||
width: 100%;
|
||||
max-width: 640rpx;
|
||||
max-height: calc(100vh - 80rpx);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
border-radius: 24rpx;
|
||||
background: #fff;
|
||||
@@ -269,15 +425,68 @@
|
||||
}
|
||||
|
||||
.form-item {
|
||||
padding: 0 32rpx 20rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
margin-bottom: 12rpx;
|
||||
margin-bottom: 10rpx;
|
||||
color: var(--text-primary);
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.form-helper {
|
||||
margin-top: 8rpx;
|
||||
font-size: 22rpx;
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.popup-address-form {
|
||||
box-sizing: border-box;
|
||||
max-height: 60vh;
|
||||
padding: 0 32rpx;
|
||||
}
|
||||
|
||||
.paste-action-row,
|
||||
.popup-address-actions {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.paste-action-row {
|
||||
margin-top: 16rpx;
|
||||
|
||||
.paste-action-btn {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.region-trigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 84rpx;
|
||||
padding: 0 24rpx;
|
||||
border: 2rpx solid var(--border-light);
|
||||
border-radius: 12rpx;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.region-trigger-text {
|
||||
font-size: 28rpx;
|
||||
color: var(--text-primary);
|
||||
|
||||
&.placeholder {
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
}
|
||||
|
||||
.popup-address-actions {
|
||||
padding: 16rpx 32rpx 32rpx;
|
||||
|
||||
:deep(.u-button) {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.result-item {
|
||||
padding: 8rpx 32rpx;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
<image v-else-if="method.value === 'wechat'" class="method-icon" src="/static/微信支付.png" mode="aspectFit"></image>
|
||||
<text class="method-name">{{ method.label }}</text>
|
||||
</view>
|
||||
<view class="method-radio" :class="{ checked: paymentMethod === method.value }"></view>
|
||||
<text v-if="operationMode === 'order-payment'" class="method-locked-label">订单支付方式</text>
|
||||
<view v-else class="method-radio" :class="{ checked: paymentMethod === method.value }"></view>
|
||||
</view>
|
||||
<view v-if="paymentMethodOptions.length === 0" class="method-empty">暂无可用支付方式</view>
|
||||
</view>
|
||||
@@ -146,10 +147,11 @@
|
||||
show.value = true;
|
||||
};
|
||||
|
||||
const openOrderPayment = async (orderId, names = []) => {
|
||||
const openOrderPayment = (orderId, names = [], method = '') => {
|
||||
if (!orderId) return;
|
||||
if (!props.identifier) {
|
||||
uni.showToast({ title: '未找到当前资产', icon: 'none' });
|
||||
const selectedMethod = normalizePaymentMethods([String(method || '').trim().toLowerCase()])[0];
|
||||
if (!selectedMethod) {
|
||||
uni.showToast({ title: '订单支付方式无效,请刷新订单后重试', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -158,22 +160,13 @@
|
||||
renewalPrice.value = null;
|
||||
packageIds.value = [];
|
||||
packageNames.value = Array.isArray(names) ? names.filter(Boolean) : [];
|
||||
try {
|
||||
await loadAssetInfo();
|
||||
} catch (error) {
|
||||
console.error('加载订单支付方式失败', error);
|
||||
uni.showToast({ title: error.msg || error.message || '加载支付方式失败', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!paymentMethodOptions.value.length) {
|
||||
uni.showToast({ title: '暂无可用支付方式', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
allowedPaymentMethods.value = [selectedMethod];
|
||||
paymentMethod.value = selectedMethod;
|
||||
show.value = true;
|
||||
};
|
||||
|
||||
const selectPaymentMethod = (method) => {
|
||||
if (operationMode.value === 'order-payment') return;
|
||||
if (paymentMethodOptions.value.some((item) => item.value === method)) {
|
||||
paymentMethod.value = method;
|
||||
}
|
||||
@@ -481,6 +474,7 @@
|
||||
|
||||
.method-badge-alipay { background: #1677ff; }
|
||||
.method-name { color: var(--text-primary); font-size: 28rpx; }
|
||||
.method-locked-label { color: var(--text-tertiary); font-size: 24rpx; white-space: nowrap; }
|
||||
|
||||
.method-radio {
|
||||
width: 36rpx;
|
||||
|
||||
@@ -222,11 +222,12 @@
|
||||
const showOrderPaymentMethods = (order) => {
|
||||
if (!order?.order_id) return;
|
||||
const packageNames = Array.isArray(order.package_names) ? order.package_names : [];
|
||||
if (String(order.payment_method || '').toLowerCase() === 'wallet') {
|
||||
const paymentMethod = String(order.payment_method || '').trim().toLowerCase();
|
||||
if (paymentMethod === 'wallet') {
|
||||
renewalPopupRef.value?.payOrderDirectly(order.order_id, 'wallet');
|
||||
return;
|
||||
}
|
||||
renewalPopupRef.value?.openOrderPayment(order.order_id, packageNames);
|
||||
renewalPopupRef.value?.openOrderPayment(order.order_id, packageNames, paymentMethod);
|
||||
};
|
||||
|
||||
onShow(() => {
|
||||
|
||||
Reference in New Issue
Block a user