feat(address): 新增收货地址与售后申请功能
- 新增地址编辑页面,支持地址智能识别、地图选点、地区选择和默认地址设置 - 实现地址列表页面,支持地址查看、删除、设为默认及选择返回结算页 - 新增售后申请页面,支持退款类型选择、商品选择、原因填写、图片上传和提交审核 - 修复 passport 分包配置,移除不存在分包并补充缺失声明,避免 Taro 编译报错 - 新增地址类型定义,增强前端地址数据结构类型安全 - 优化页面交互体验,完善表单校验及错误提示逻辑 - 统一代码格式与命名规范,保持代码风格一致性
This commit is contained in:
120
src/hooks/useAddress.ts
Normal file
120
src/hooks/useAddress.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
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 }
|
||||
}
|
||||
Reference in New Issue
Block a user