mirror of
https://github.com/Megghy/vtsuru.live.git
synced 2025-12-06 18:36:55 +08:00
feat: 更新地址信息接口,优化地址选择逻辑和表单验证
This commit is contained in:
@@ -698,9 +698,9 @@ export interface PointGoodsModel {
|
|||||||
export interface AddressInfo {
|
export interface AddressInfo {
|
||||||
id?: string
|
id?: string
|
||||||
province: string
|
province: string
|
||||||
city: string
|
city?: string
|
||||||
district: string
|
district?: string
|
||||||
street: string
|
street?: string
|
||||||
address: string
|
address: string
|
||||||
phone: number
|
phone: number
|
||||||
name: string
|
name: string
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import { computed, ref } from 'vue'
|
|||||||
//@ts-expect-error 导入有点问题
|
//@ts-expect-error 导入有点问题
|
||||||
import UserAgreement from '@/document/UserAgreement.md'
|
import UserAgreement from '@/document/UserAgreement.md'
|
||||||
|
|
||||||
|
// 地区数据类型定义
|
||||||
type AreaData = {
|
type AreaData = {
|
||||||
[province: string]: {
|
[province: string]: {
|
||||||
[city: string]: {
|
[city: string]: {
|
||||||
@@ -43,9 +44,13 @@ type AreaData = {
|
|||||||
const useAuth = useAuthStore()
|
const useAuth = useAuthStore()
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
const isLoading = ref(false)
|
const isLoading = ref(false)
|
||||||
|
|
||||||
const userAgree = ref(false)
|
const userAgree = ref(false)
|
||||||
|
const showAddressModal = ref(false)
|
||||||
|
const showAgreementModal = ref(false)
|
||||||
|
const formRef = ref()
|
||||||
|
const currentAddress = ref<AddressInfo>()
|
||||||
|
|
||||||
|
// 本地存储区域数据
|
||||||
const areas = useStorage<{
|
const areas = useStorage<{
|
||||||
createAt: number
|
createAt: number
|
||||||
data: AreaData
|
data: AreaData
|
||||||
@@ -53,21 +58,34 @@ const areas = useStorage<{
|
|||||||
createAt: 0,
|
createAt: 0,
|
||||||
data: {},
|
data: {},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 计算属性:获取省份选项
|
||||||
const provinceOptions = computed(() => {
|
const provinceOptions = computed(() => {
|
||||||
return Object.keys(areas.value?.data ?? {}).map((p) => ({ label: p, value: p }))
|
return Object.keys(areas.value?.data ?? {}).map((p) => ({ label: p, value: p }))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 计算属性:当前用户授权信息
|
||||||
|
const biliAuth = computed(() => useAuth.biliAuth)
|
||||||
|
|
||||||
|
// 获取城市选项
|
||||||
const cityOptions = (province: string) => {
|
const cityOptions = (province: string) => {
|
||||||
if (!areas.value?.data[province]) return []
|
if (!areas.value?.data[province]) return []
|
||||||
return Object.keys(areas.value?.data[province] ?? {}).map((c) => ({ label: c, value: c }))
|
return Object.keys(areas.value?.data[province] ?? {}).map((c) => ({ label: c, value: c }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取区/县选项
|
||||||
const districtOptions = (province: string, city: string) => {
|
const districtOptions = (province: string, city: string) => {
|
||||||
if (!areas.value?.data[province]?.[city]) return []
|
if (!areas.value?.data[province]?.[city]) return []
|
||||||
return Object.keys(areas.value?.data[province][city] ?? {}).map((d) => ({ label: d, value: d }))
|
return Object.keys(areas.value?.data[province][city] ?? {}).map((d) => ({ label: d, value: d }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取街道选项
|
||||||
const streetOptions = (province: string, city: string, district: string) => {
|
const streetOptions = (province: string, city: string, district: string) => {
|
||||||
if (!areas.value?.data[province]?.[city]?.[district]) return []
|
if (!areas.value?.data[province]?.[city]?.[district]) return []
|
||||||
return areas.value?.data[province][city][district]?.map((s) => ({ label: s, value: s })) ?? []
|
return areas.value?.data[province][city][district]?.map((s) => ({ label: s, value: s })) ?? []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 表单验证规则
|
||||||
const rules: FormRules = {
|
const rules: FormRules = {
|
||||||
phone: {
|
phone: {
|
||||||
required: true,
|
required: true,
|
||||||
@@ -99,29 +117,30 @@ const rules: FormRules = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
const formRef = ref()
|
|
||||||
|
|
||||||
const biliAuth = computed(() => useAuth.biliAuth)
|
// 处理API错误的工具函数
|
||||||
|
const handleApiError = (action: string, err: any) => {
|
||||||
const currentAddress = ref<AddressInfo>()
|
message.error(`${action}失败: ${err}`)
|
||||||
|
console.error(err)
|
||||||
const showAddressModal = ref(false)
|
}
|
||||||
const showAgreementModal = ref(false)
|
|
||||||
|
|
||||||
|
// 地址管理相关函数
|
||||||
|
// 更新地址信息
|
||||||
async function updateAddress() {
|
async function updateAddress() {
|
||||||
formRef.value
|
|
||||||
?.validate()
|
|
||||||
.then(async () => {
|
|
||||||
isLoading.value = true
|
|
||||||
try {
|
try {
|
||||||
|
await formRef.value?.validate()
|
||||||
|
isLoading.value = true
|
||||||
|
|
||||||
const data = await useAuth.QueryBiliAuthPostAPI<AddressInfo>(
|
const data = await useAuth.QueryBiliAuthPostAPI<AddressInfo>(
|
||||||
POINT_API_URL + 'user/update-address',
|
POINT_API_URL + 'user/update-address',
|
||||||
currentAddress.value,
|
currentAddress.value,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (data.code == 200) {
|
if (data.code == 200) {
|
||||||
message.success('已保存')
|
message.success('已保存')
|
||||||
showAddressModal.value = false
|
showAddressModal.value = false
|
||||||
currentAddress.value = {} as AddressInfo
|
|
||||||
|
// 更新本地地址列表
|
||||||
if (biliAuth.value.address) {
|
if (biliAuth.value.address) {
|
||||||
const index = biliAuth.value.address?.findIndex((a) => a.id == data.data.id) ?? -1
|
const index = biliAuth.value.address?.findIndex((a) => a.id == data.data.id) ?? -1
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
@@ -130,22 +149,23 @@ async function updateAddress() {
|
|||||||
biliAuth.value.address.push(data.data)
|
biliAuth.value.address.push(data.data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentAddress.value = {} as AddressInfo
|
||||||
} else {
|
} else {
|
||||||
message.error('更新地址失败: ' + data.message)
|
handleApiError('更新地址', data.message)
|
||||||
console.error(data)
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
message.error('更新地址失败: ' + err)
|
if (err instanceof Error) {
|
||||||
console.error(err)
|
handleApiError('更新地址', err)
|
||||||
}
|
} else {
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
message.error('信息未填写完成')
|
message.error('信息未填写完成')
|
||||||
})
|
}
|
||||||
.finally(() => {
|
} finally {
|
||||||
isLoading.value = false
|
isLoading.value = false
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除地址
|
||||||
async function deleteAddress(id: string) {
|
async function deleteAddress(id: string) {
|
||||||
isLoading.value = true
|
isLoading.value = true
|
||||||
try {
|
try {
|
||||||
@@ -156,66 +176,69 @@ async function deleteAddress(id: string) {
|
|||||||
biliAuth.value.address = biliAuth.value.address?.filter((a) => a.id != id)
|
biliAuth.value.address = biliAuth.value.address?.filter((a) => a.id != id)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
message.error('删除地址失败: ' + data.message)
|
handleApiError('删除地址', data.message)
|
||||||
console.error(data)
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
message.error('删除地址失败: ' + err)
|
handleApiError('删除地址', err)
|
||||||
console.error(err)
|
|
||||||
} finally {
|
} finally {
|
||||||
isLoading.value = false
|
isLoading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取区域数据
|
||||||
async function getArea() {
|
async function getArea() {
|
||||||
|
// 缓存一周内的数据,避免频繁请求
|
||||||
if (areas.value && Date.now() - areas.value?.createAt < 1000 * 60 * 60 * 24 * 7) {
|
if (areas.value && Date.now() - areas.value?.createAt < 1000 * 60 * 60 * 24 * 7) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
isLoading.value = true
|
isLoading.value = true
|
||||||
const data = await fetch(THINGS_URL + 'area_data.json')
|
const data = await fetch('https://oss.suki.club/vtsuru/area_data.json')
|
||||||
if (data.ok) {
|
if (data.ok) {
|
||||||
const area = {
|
const area = {
|
||||||
createAt: Date.now(),
|
createAt: Date.now(),
|
||||||
data: await data.json(),
|
data: await data.json(),
|
||||||
}
|
}
|
||||||
console.log(area)
|
|
||||||
areas.value = area
|
areas.value = area
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
handleApiError('获取区域数据', err)
|
||||||
message.error('获取区域数据失败')
|
} finally {
|
||||||
}
|
|
||||||
isLoading.value = false
|
isLoading.value = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 打开地址编辑模态框
|
||||||
async function onOpenAddressModal() {
|
async function onOpenAddressModal() {
|
||||||
showAddressModal.value = true
|
showAddressModal.value = true
|
||||||
currentAddress.value = {} as AddressInfo
|
currentAddress.value = {} as AddressInfo
|
||||||
await getArea()
|
await getArea()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理地区选择变化,级联清除下级选项
|
||||||
function onAreaSelectChange(level: number) {
|
function onAreaSelectChange(level: number) {
|
||||||
if (!currentAddress.value) return
|
if (!currentAddress.value) return
|
||||||
const newValue = {} as AddressInfo
|
|
||||||
|
// 根据变化的级别清除下级数据
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case 0: {
|
case 0: // 省份变化,清除市区街道
|
||||||
// @ts-expect-error 不管这个,直接赋值
|
|
||||||
currentAddress.value.city = undefined
|
currentAddress.value.city = undefined
|
||||||
// @ts-expect-error 不管这个,直接赋值
|
|
||||||
currentAddress.value.district = undefined
|
currentAddress.value.district = undefined
|
||||||
// @ts-expect-error 不管这个,直接赋值
|
|
||||||
currentAddress.value.street = undefined
|
currentAddress.value.street = undefined
|
||||||
}
|
break
|
||||||
case 1: {
|
case 1: // 城市变化,清除区县街道
|
||||||
// @ts-expect-error 不管这个,直接赋值
|
|
||||||
currentAddress.value.district = undefined
|
currentAddress.value.district = undefined
|
||||||
// @ts-expect-error 不管这个,直接赋值
|
|
||||||
currentAddress.value.street = undefined
|
currentAddress.value.street = undefined
|
||||||
}
|
break
|
||||||
case 2: {
|
case 2: // 区县变化,清除街道
|
||||||
// @ts-expect-error 不管这个,直接赋值
|
|
||||||
currentAddress.value.street = undefined
|
currentAddress.value.street = undefined
|
||||||
}
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 账号管理相关函数
|
||||||
|
// 切换当前使用的授权账号
|
||||||
function switchAuth(token: string) {
|
function switchAuth(token: string) {
|
||||||
if (token == useAuth.biliToken) {
|
if (token == useAuth.biliToken) {
|
||||||
message.info('当前正在使用该账号')
|
message.info('当前正在使用该账号')
|
||||||
@@ -225,6 +248,7 @@ function switchAuth(token: string) {
|
|||||||
message.success('已切换账号')
|
message.success('已切换账号')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 登出当前账号
|
||||||
function logout() {
|
function logout() {
|
||||||
useAuth.logout()
|
useAuth.logout()
|
||||||
}
|
}
|
||||||
@@ -392,7 +416,7 @@ function logout() {
|
|||||||
<NSelect
|
<NSelect
|
||||||
:key="currentAddress.city"
|
:key="currentAddress.city"
|
||||||
v-model:value="currentAddress.district"
|
v-model:value="currentAddress.district"
|
||||||
:options="districtOptions(currentAddress.province, currentAddress.city)"
|
:options="currentAddress.city ? districtOptions(currentAddress.province, currentAddress.city) : []"
|
||||||
:disabled="!currentAddress?.city"
|
:disabled="!currentAddress?.city"
|
||||||
placeholder="请选择区"
|
placeholder="请选择区"
|
||||||
style="width: 100px"
|
style="width: 100px"
|
||||||
@@ -402,7 +426,7 @@ function logout() {
|
|||||||
<NSelect
|
<NSelect
|
||||||
:key="currentAddress.district"
|
:key="currentAddress.district"
|
||||||
v-model:value="currentAddress.street"
|
v-model:value="currentAddress.street"
|
||||||
:options="streetOptions(currentAddress.province, currentAddress.city, currentAddress.district)"
|
:options="currentAddress.city && currentAddress.district ? streetOptions(currentAddress.province, currentAddress.city, currentAddress.district) : []"
|
||||||
:disabled="!currentAddress?.district"
|
:disabled="!currentAddress?.district"
|
||||||
placeholder="请选择街道"
|
placeholder="请选择街道"
|
||||||
style="width: 150px"
|
style="width: 150px"
|
||||||
|
|||||||
Reference in New Issue
Block a user