Files
medical-mall/pages/mall/consumer/address-edit.uvue
2026-01-30 17:29:02 +08:00

436 lines
11 KiB
Plaintext
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.
<template>
<view class="address-edit-page">
<view class="form-group">
<view class="form-item">
<text class="label">收货人</text>
<input class="input" v-model="formData.name" placeholder="请填写收货人姓名" />
</view>
<view class="form-item">
<text class="label">手机号码</text>
<input class="input" v-model="formData.phone" type="number" maxlength="11" placeholder="请填写手机号码" />
</view>
<view class="form-item">
<text class="label">所在地区</text>
<input class="input" v-model="regionString" placeholder="省市区县、乡镇等" />
</view>
<view class="form-item">
<text class="label">详细地址</text>
<input class="input" v-model="formData.detail" placeholder="街道、楼牌号等" />
</view>
</view>
<view class="form-group">
<view class="form-item">
<text class="label">智能填写</text>
<textarea class="smart-textarea" v-model="smartInput" placeholder="粘贴姓名+电话+地址,自动识别填充" @input="parseSmartInput" maxlength="200"></textarea>
<text class="smart-tip">示例:张三 13800138000 北京市朝阳区三里屯SOHO A座</text>
</view>
<view class="form-item">
<text class="label">标签</text>
<view class="tags-container">
<text
v-for="tag in tags"
:key="tag"
class="tag-item"
:class="{ active: formData.label === tag }"
@click="selectTag(tag)"
>{{ tag }}</text>
</view>
</view>
<view class="form-item switch-item">
<text class="label">设为默认收货地址</text>
<switch :checked="formData.isDefault" color="#ff5000" @change="onSwitchChange" />
</view>
</view>
<view class="footer-btn">
<button class="save-btn" @click="saveAddress">保存</button>
<button v-if="isEdit" class="delete-btn" @click="deleteAddress">删除收货地址</button>
</view>
</view>
</template>
<script setup lang="uts">
import { ref, reactive, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { supabaseService } from '@/utils/supabaseService.uts'
type Address = {
id: string
name: string
phone: string
province: string
city: string
district: string
detail: string
isDefault: boolean
label?: string
}
const isEdit = ref(false)
const addressId = ref('')
const regionString = ref('')
const tags = ['家', '公司', '学校']
const smartInput = ref('')
const formData = reactive({
name: '',
phone: '',
detail: '',
isDefault: false,
label: ''
} as {
name: string
phone: string
detail: string
isDefault: boolean
label: string
})
onLoad((options) => {
if (options['id']) {
isEdit.value = true
addressId.value = options['id'] as string
loadAddress(addressId.value)
}
})
const loadAddress = async (id: string) => {
try {
// 从Supabase加载地址详情
const address = await supabaseService.getAddressById(id)
if (address) {
formData.name = address.recipient_name
formData.phone = address.phone
formData.detail = address.detail_address
formData.isDefault = address.is_default
formData.label = address.label || ''
regionString.value = `${address.province} ${address.city} ${address.district}`.trim()
} else {
// 如果Supabase没有找到尝试从本地存储加载
const storedAddresses = uni.getStorageSync('addresses')
if (storedAddresses) {
const addresses = JSON.parse(storedAddresses as string) as Address[]
const localAddress = addresses.find(item => item.id === id)
if (localAddress) {
formData.name = localAddress.name
formData.phone = localAddress.phone
formData.detail = localAddress.detail
formData.isDefault = localAddress.isDefault
formData.label = localAddress.label || ''
regionString.value = `${localAddress.province} ${localAddress.city} ${localAddress.district}`.trim()
}
}
}
} catch (error) {
console.error('加载地址详情失败:', error)
// 失败时从本地存储加载
const storedAddresses = uni.getStorageSync('addresses')
if (storedAddresses) {
try {
const addresses = JSON.parse(storedAddresses as string) as Address[]
const address = addresses.find(item => item.id === id)
if (address) {
formData.name = address.name
formData.phone = address.phone
formData.detail = address.detail
formData.isDefault = address.isDefault
formData.label = address.label || ''
regionString.value = `${address.province} ${address.city} ${address.district}`.trim()
}
} catch (e) {
console.error('解析本地地址数据失败', e)
}
}
}
}
const selectTag = (tag: string) => {
if (formData.label === tag) {
formData.label = ''
} else {
formData.label = tag
}
}
const onSwitchChange = (e: UniSwitchChangeEvent) => {
formData.isDefault = e.detail.value
}
const saveAddress = async () => {
if (!formData.name) {
uni.showToast({ title: '请填写收货人', icon: 'none' })
return
}
if (!formData.phone) {
uni.showToast({ title: '请填写手机号码', icon: 'none' })
return
}
if (!regionString.value) {
uni.showToast({ title: '请填写所在地区', icon: 'none' })
return
}
if (!formData.detail) {
uni.showToast({ title: '请填写详细地址', icon: 'none' })
return
}
// 简单解析地区(这里简化处理,实际应使用选择器)
const regions = regionString.value.split(' ')
const province = regions[0] || ''
const city = regions[1] || ''
const district = regions.slice(2).join(' ') || ''
// 构建地址对象
const addressData = {
recipient_name: formData.name,
phone: formData.phone,
province: province,
city: city,
district: district,
detail_address: formData.detail,
postal_code: '', // 如果需要可以添加邮政编码字段
is_default: formData.isDefault,
label: formData.label || ''
}
let success = false
if (isEdit.value) {
// 更新地址
success = await supabaseService.updateAddress(addressId.value, addressData)
} else {
// 添加新地址
success = await supabaseService.addAddress(addressData)
}
if (success) {
// 同时更新本地存储作为缓存
const storedAddresses = uni.getStorageSync('addresses')
let addresses: Address[] = []
if (storedAddresses) {
try {
addresses = JSON.parse(storedAddresses as string) as Address[]
} catch (e) {
addresses = []
}
}
// 如果设为默认,取消其他默认
if (formData.isDefault) {
addresses.forEach(item => {
item.isDefault = false
})
}
if (isEdit.value) {
const index = addresses.findIndex(item => item.id === addressId.value)
if (index !== -1) {
addresses[index] = {
...addresses[index],
name: formData.name,
phone: formData.phone,
province: province,
city: city,
district: district,
detail: formData.detail,
isDefault: formData.isDefault,
label: formData.label
}
}
} else {
const newAddress: Address = {
id: `addr_${Date.now()}`, // 临时ID实际由Supabase生成
name: formData.name,
phone: formData.phone,
province: province,
city: city,
district: district,
detail: formData.detail,
isDefault: formData.isDefault,
label: formData.label
}
addresses.push(newAddress)
}
uni.setStorageSync('addresses', JSON.stringify(addresses))
uni.showToast({
title: '保存成功',
icon: 'success'
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
} else {
console.error('保存地址失败')
uni.showToast({
title: '保存失败',
icon: 'none'
})
}
}
const parseSmartInput = () => {
const input = smartInput.value.trim()
if (!input) return
// 提取手机号
const phoneRegex = /(1[3-9]\d{9})/
const phoneMatch = input.match(phoneRegex)
if (phoneMatch) {
formData.phone = phoneMatch[0]
}
// 提取姓名取第一个2-4位中文
const nameRegex = /([\u4e00-\u9fa5]{2,4})/
const nameMatch = input.match(nameRegex)
if (nameMatch) {
formData.name = nameMatch[0]
}
// 去掉姓名和电话后剩余作为地址
let addrText = input
if (formData.name) addrText = addrText.replace(formData.name, '')
if (formData.phone) addrText = addrText.replace(formData.phone, '')
addrText = addrText.replace(/[,;\s]+/g, ' ').trim()
// 解析省市区
const pattern1 = /^(.*?省)?(.*?市)?(.*?[区县])?(.*)$/
const m = addrText.match(pattern1)
if (m) {
const [, province, city, district, detail] = m
regionString.value = `${(province||'').trim()} ${(city||'').trim()} ${(district||'').trim()}`.trim()
formData.detail = (detail||'').trim()
} else {
formData.detail = addrText
}
}
const deleteAddress = async () => {
uni.showModal({
title: '提示',
content: '确定要删除该地址吗?',
success: async (res) => {
if (res.confirm) {
// 调用Supabase服务删除地址
const success = await supabaseService.deleteAddress(addressId.value)
if (success) {
// 同时从本地存储中移除
const storedAddresses = uni.getStorageSync('addresses')
if (storedAddresses) {
let addresses = JSON.parse(storedAddresses as string) as Address[]
addresses = addresses.filter(item => item.id !== addressId.value)
uni.setStorageSync('addresses', JSON.stringify(addresses))
}
uni.showToast({
title: '删除成功',
icon: 'success'
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
} else {
console.error('删除地址失败')
uni.showToast({
title: '删除失败',
icon: 'none'
})
}
}
}
})
}
</script>
<style>
.address-edit-page {
min-height: 100vh;
background-color: #f5f5f5;
padding-top: 15px;
}
.form-group {
background-color: white;
margin-bottom: 15px;
padding: 0 15px;
}
.form-item {
display: flex;
align-items: center;
border-bottom: 1px solid #f5f5f5;
padding: 15px 0;
}
.form-item:last-child {
border-bottom: none;
}
.label {
width: 80px;
font-size: 15px;
color: #333;
}
.input {
flex: 1;
font-size: 15px;
color: #333;
}
.switch-item {
justify-content: space-between;
}
.tags-container {
flex: 1;
display: flex;
flex-wrap: wrap;
}
.tag-item {
font-size: 12px;
color: #666;
border: 1px solid #ddd;
padding: 4px 12px;
border-radius: 15px;
margin-right: 10px;
}
.tag-item.active {
background-color: #ff5000;
color: white;
border-color: #ff5000;
}
.footer-btn {
margin-top: 30px;
padding: 0 15px;
}
.save-btn {
background-color: #ff5000;
color: white;
border-radius: 25px;
font-size: 16px;
height: 44px;
line-height: 44px;
border: none;
margin-bottom: 15px;
}
.delete-btn {
background-color: white;
color: #333;
border-radius: 25px;
font-size: 16px;
height: 44px;
line-height: 44px;
border: 1px solid #ddd;
}
</style>