- 新增地址类型定义,增强前端地址数据结构 - 新增地址编辑页面,支持地址智能识别和定位选点功能 - 地址编辑支持省市区选择及默认地址设置 - 新增地址列表页面,支持地址展示、删除、编辑和选择功能 - 实现售后申请页面,支持选择售后类型和退款原因 - 售后申请支持商品选择、退款金额计算和凭证上传 - 新增售后详情页面,支持售后状态展示及申请取消 - 优化页面加载和用户交互体验,增加错误提示和权限处理
179 lines
5.7 KiB
TypeScript
179 lines
5.7 KiB
TypeScript
import { View, Text, Image } from '@tarojs/components';
|
||
import Taro, { useRouter } from '@tarojs/taro';
|
||
import { useState, useEffect } from 'react';
|
||
import { getBenefitPackageDetail, exchangeBenefitPackage } from '@/api/shop/shopMemberBenefit';
|
||
import { getDefaultAddress } from '@/api/shop/shopUserAddress';
|
||
import { getUserBalance } from '@/api/system/user/balance';
|
||
import './index.scss';
|
||
|
||
definePageConfig({
|
||
navigationBarTitleText: '确认兑换',
|
||
});
|
||
|
||
export default function BenefitExchangeConfirmPage() {
|
||
const router = useRouter();
|
||
const pkgId = Number(router.params.id);
|
||
|
||
const [pkg, setPkg] = useState<any>(null);
|
||
const [address, setAddress] = useState<any>(null);
|
||
const [userBalance, setUserBalance] = useState<string>('--');
|
||
const [userPoints, setUserPoints] = useState<string>('--');
|
||
const [submitting, setSubmitting] = useState(false);
|
||
|
||
useEffect(() => {
|
||
loadPackage();
|
||
loadAddress();
|
||
loadUserBalance();
|
||
}, []);
|
||
|
||
const loadPackage = async () => {
|
||
const res = await getBenefitPackageDetail(pkgId);
|
||
if (res.code === 200) setPkg(res.data);
|
||
};
|
||
|
||
const loadAddress = async () => {
|
||
const res = await getDefaultAddress();
|
||
if (res.code === 200 && res.data) setAddress(res.data);
|
||
};
|
||
|
||
const loadUserBalance = async () => {
|
||
try {
|
||
const data = await getUserBalance();
|
||
setUserBalance(data.balance || '0');
|
||
setUserPoints(String(data.points || 0));
|
||
} catch {
|
||
// ignore
|
||
}
|
||
};
|
||
|
||
const handleSelectAddress = () => {
|
||
Taro.navigateTo({ url: '/pages/user/address-list?select=1' });
|
||
};
|
||
|
||
const handleExchange = async () => {
|
||
if (!pkg) return;
|
||
|
||
if (pkg.needShip && !address) {
|
||
Taro.showToast({ title: '请先选择收货地址', icon: 'none' });
|
||
return;
|
||
}
|
||
|
||
Taro.showModal({
|
||
title: '确认兑换',
|
||
content: `确认兑换「${pkg.name}」?`,
|
||
success: async (res) => {
|
||
if (!res.confirm) return;
|
||
setSubmitting(true);
|
||
try {
|
||
const res2 = await exchangeBenefitPackage({
|
||
packageId: pkgId,
|
||
addressId: address?.id,
|
||
});
|
||
if (res2.code === 200) {
|
||
Taro.showToast({ title: '兑换申请成功', icon: 'success' });
|
||
setTimeout(() => {
|
||
Taro.redirectTo({ url: '/pages/user/benefit-exchange-list/index' });
|
||
}, 1500);
|
||
} else {
|
||
Taro.showToast({ title: res2.message || '兑换失败', icon: 'none' });
|
||
}
|
||
} catch (e) {
|
||
Taro.showToast({ title: '网络错误', icon: 'none' });
|
||
} finally {
|
||
setSubmitting(false);
|
||
}
|
||
},
|
||
});
|
||
};
|
||
|
||
if (!pkg) return null;
|
||
|
||
return (
|
||
<View className="confirm-page">
|
||
{/* 收货地址 */}
|
||
{pkg.needShip === 1 && (
|
||
<View className="address-card" onClick={handleSelectAddress}>
|
||
{address ? (
|
||
<>
|
||
<View className="addr-info">
|
||
<Text className="addr-name">{address.name}</Text>
|
||
<Text className="addr-phone">{address.phone}</Text>
|
||
</View>
|
||
<Text className="addr-detail">
|
||
{address.province}{address.city}{address.district}{address.detail}
|
||
</Text>
|
||
</>
|
||
) : (
|
||
<Text className="addr-empty">+ 请选择收货地址</Text>
|
||
)}
|
||
<Text className="addr-arrow">></Text>
|
||
</View>
|
||
)}
|
||
|
||
{/* 权益包信息 */}
|
||
<View className="pkg-info-card">
|
||
{pkg.coverImage && (
|
||
<Image className="pkg-img" src={pkg.coverImage} mode="aspectFill" />
|
||
)}
|
||
<View className="pkg-detail">
|
||
<Text className="pkg-name">{pkg.name}</Text>
|
||
{pkg.description && (
|
||
<Text className="pkg-desc">{pkg.description}</Text>
|
||
)}
|
||
<View className="pkg-cost-row">
|
||
{pkg.pointsCost > 0 && (
|
||
<Text className="cost-item points">{pkg.pointsCost} 积分</Text>
|
||
)}
|
||
{pkg.balanceCost > 0 && (
|
||
<Text className="cost-item balance">¥{pkg.balanceCost}</Text>
|
||
)}
|
||
{!pkg.pointsCost && !pkg.balanceCost && (
|
||
<Text className="cost-item free">免费兑换</Text>
|
||
)}
|
||
</View>
|
||
</View>
|
||
</View>
|
||
|
||
{/* 我的资产 */}
|
||
<View className="assets-card">
|
||
<Text className="assets-title">我的资产</Text>
|
||
<View className="assets-row">
|
||
{pkg.pointsCost > 0 && (
|
||
<View className="asset-item">
|
||
<Text className="asset-value">{userPoints}</Text>
|
||
<Text className="asset-label">当前积分</Text>
|
||
</View>
|
||
)}
|
||
{pkg.balanceCost > 0 && (
|
||
<View className="asset-item">
|
||
<Text className="asset-value">{userBalance}</Text>
|
||
<Text className="asset-label">当前余额</Text>
|
||
</View>
|
||
)}
|
||
</View>
|
||
</View>
|
||
|
||
{/* 须知 */}
|
||
<View className="notice-card">
|
||
<Text className="notice-title">兑换须知</Text>
|
||
<Text className="notice-item">· 兑换后平台将安排配送,请耐心等待</Text>
|
||
<Text className="notice-item">· 仅待处理状态可申请取消</Text>
|
||
<Text className="notice-item">· 如有问题请联系客服</Text>
|
||
{pkg.validDays && (
|
||
<Text className="notice-item">· 权益有效期:{pkg.validDays}天</Text>
|
||
)}
|
||
</View>
|
||
|
||
{/* 底部按钮 */}
|
||
<View className="bottom-bar">
|
||
<View
|
||
className={`confirm-btn ${submitting ? 'disabled' : ''}`}
|
||
onClick={!submitting ? handleExchange : undefined}
|
||
>
|
||
{submitting ? '提交中...' : '确认兑换'}
|
||
</View>
|
||
</View>
|
||
</View>
|
||
);
|
||
}
|