Files
websopy-taro/src/hooks/useAddress.ts
赵忠林 9df90c1176 feat(address): 新增收货地址与售后申请功能
- 新增地址编辑页面,支持地址智能识别、地图选点、地区选择和默认地址设置
- 实现地址列表页面,支持地址查看、删除、设为默认及选择返回结算页
- 新增售后申请页面,支持退款类型选择、商品选择、原因填写、图片上传和提交审核
- 修复 passport 分包配置,移除不存在分包并补充缺失声明,避免 Taro 编译报错
- 新增地址类型定义,增强前端地址数据结构类型安全
- 优化页面交互体验,完善表单校验及错误提示逻辑
- 统一代码格式与命名规范,保持代码风格一致性
2026-07-16 01:18:42 +08:00

121 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState, useCallback } from 'react'
import {
listShopUserAddress,
getShopUserAddress,
addShopUserAddress,
updateShopUserAddress,
removeShopUserAddress,
setDefaultAddress,
} from '@/api/shop/shopUserAddress'
import type { ShopUserAddress } from '@/api/shop/shopUserAddress/model'
interface UseAddressReturn {
addresses: ShopUserAddress[]
loading: boolean
defaultAddress: ShopUserAddress | null
loadAddresses: () => Promise<void>
getAddress: (id: number) => Promise<ShopUserAddress | null>
addAddress: (data: Partial<ShopUserAddress>) => Promise<boolean>
updateAddress: (data: ShopUserAddress) => Promise<boolean>
deleteAddress: (id: number) => Promise<boolean>
setDefault: (id: number) => Promise<boolean>
}
/**
* 兜底:保证列表中最多只有一个地址是 isDefault=true。
* 兼容历史脏数据(之前没有"取消其他默认"逻辑时遗留下来的多个默认)。
* 保留最早创建id 最小)的为默认;其余的在前端展示时按非默认处理。
*/
function ensureSingleDefault(list: ShopUserAddress[]): ShopUserAddress[] {
const defaults = list.filter(a => a.isDefault)
if (defaults.length <= 1) return list
// 多个默认:保留 createTime 最早的;如果都缺 createTime则保留 id 最小的
const sorted = [...defaults].sort((a, b) => {
const at = a.createTime || ''
const bt = b.createTime || ''
if (at && bt) return at < bt ? -1 : at > bt ? 1 : 0
if (at) return -1
if (bt) return 1
return (a.id || 0) - (b.id || 0)
})
const keepId = sorted[0].id
return list.map(a => {
if (a.isDefault && a.id !== keepId) {
return {...a, isDefault: false}
}
return a
})
}
export function useAddress(): UseAddressReturn {
const [addresses, setAddresses] = useState<ShopUserAddress[]>([])
const [loading, setLoading] = useState(false)
const loadAddresses = useCallback(async () => {
setLoading(true)
try {
const list = await listShopUserAddress()
const raw: ShopUserAddress[] = Array.isArray(list) ? list : (list as any)?.data || []
setAddresses(ensureSingleDefault(raw))
} catch (error) {
console.error('Load addresses error:', error)
setAddresses([])
} finally {
setLoading(false)
}
}, [])
/** 根据 ID 获取单个地址 */
const getAddress = useCallback(async (id: number): Promise<ShopUserAddress | null> => {
try {
return await getShopUserAddress(id)
} catch {
return null
}
}, [])
const addAddress = useCallback(async (data: Partial<ShopUserAddress>): Promise<boolean> => {
try {
await addShopUserAddress(data as any)
await loadAddresses()
return true
} catch {
return false
}
}, [loadAddresses])
const updateAddress = useCallback(async (data: ShopUserAddress): Promise<boolean> => {
try {
await updateShopUserAddress(data)
await loadAddresses()
return true
} catch {
return false
}
}, [loadAddresses])
const deleteAddress = useCallback(async (id: number): Promise<boolean> => {
try {
await removeShopUserAddress(id)
setAddresses(prev => prev.filter(a => a.id !== id))
return true
} catch {
return false
}
}, [])
const setDefault = useCallback(async (id: number): Promise<boolean> => {
try {
await setDefaultAddress(id)
await loadAddresses()
return true
} catch {
return false
}
}, [loadAddresses])
const defaultAddress = addresses.find(a => a.isDefault) || addresses[0] || null
return { addresses, loading, defaultAddress, loadAddresses, getAddress, addAddress, updateAddress, deleteAddress, setDefault }
}