You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

457 lines
9.6 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view class="container">
<!-- 顶部导航栏 -->
<view class="nav-bar">
<view class="back-btn" @click="goBack">
<uv-icon name="arrow-left" color="#333" size="20"></uv-icon>
</view>
<view class="title">新增地址</view>
<view class="right-placeholder"></view>
</view>
<!-- 表单内容 -->
<view class="form-content">
<!-- 联系人信息 -->
<view class="form-section">
<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" placeholder="请输入手机号码" maxlength="11" />
</view>
</view>
<!-- 地址信息 -->
<view class="form-section">
<view class="form-item location-item" @click="chooseLocation">
<text class="label">地址位置</text>
<view class="location-value">
<text v-if="formData.address">{{ formData.address }}</text>
<text v-else class="placeholder">点击选择位置</text>
<uv-icon name="arrow-right" color="#CCCCCC" size="16"></uv-icon>
</view>
</view>
<view class="form-item">
<text class="label">门牌号</text>
<input class="input" v-model="formData.addressDetail" placeholder="详细地址1号楼1单元101室" />
</view>
</view>
<!-- 地址标签 -->
<view class="form-section">
<view class="label-title">地址标签</view>
<view class="tag-list">
<view
class="tag-item"
:class="{ active: formData.tag === tag }"
v-for="(tag, index) in tags"
:key="index"
@click="selectTag(tag)"
>
{{ tag }}
</view>
<view
class="tag-item custom-tag"
:class="{ active: isCustomTag }"
@click="showCustomTagInput"
>
<text v-if="!isCustomTag">自定义</text>
<input
v-else
class="custom-tag-input"
v-model="formData.customTag"
placeholder="自定义标签"
focus
@blur="onCustomTagBlur"
@confirm="onCustomTagConfirm"
/>
</view>
</view>
</view>
<!-- 默认地址设置 -->
<view class="form-section">
<view class="form-item switch-item">
<text class="label">设为默认地址</text>
<switch
:checked="formData.isDefault"
color="#4080FF"
@change="onDefaultChange"
/>
</view>
</view>
</view>
<!-- 底部保存按钮 -->
<view class="footer">
<view class="save-btn" @click="saveAddress"></view>
</view>
</view>
</template>
<script setup>
import { ref, computed } from 'vue';
import { useUserStore } from "@/store";
// 表单数据
const formData = ref({
name: '',
phone: '',
address: '',
addressDetail: '',
latitude: '',
longitude: '',
tag: '家',
customTag: '',
isDefault: false
});
// 预设标签
const tags = ref(['家', '公司', '学校']);
// 是否使用自定义标签
const isCustomTag = computed(() => {
return !tags.value.includes(formData.value.tag);
});
// 选择标签
const selectTag = (tag) => {
formData.value.tag = tag;
};
// 显示自定义标签输入框
const showCustomTagInput = () => {
if (!isCustomTag.value) {
formData.value.customTag = '';
formData.value.tag = '';
}
};
// 自定义标签输入框失焦
const onCustomTagBlur = () => {
if (formData.value.customTag) {
formData.value.tag = formData.value.customTag;
} else {
formData.value.tag = '家'; // 默认回到第一个标签
}
};
// 自定义标签输入确认
const onCustomTagConfirm = () => {
if (formData.value.customTag) {
formData.value.tag = formData.value.customTag;
}
};
// 默认地址切换
const onDefaultChange = (e) => {
formData.value.isDefault = e.detail.value;
};
// 选择位置
const chooseLocation = () => {
uni.chooseLocation({
success: (res) => {
console.log('选择位置成功:', res);
formData.value.address = res.name || res.address;
formData.value.latitude = res.latitude;
formData.value.longitude = res.longitude;
},
fail: (err) => {
console.error('选择位置失败:', err);
// 检查是否是因为权限问题
if (err.errMsg.includes('auth deny')) {
uni.showModal({
title: '提示',
content: '需要您授权使用位置信息',
confirmText: '去设置',
success: (res) => {
if (res.confirm) {
uni.openSetting({
success: (settingRes) => {
console.log('设置结果:', settingRes);
}
});
}
}
});
} else {
uni.showToast({
title: '选择位置失败',
icon: 'none'
});
}
}
});
};
// 保存地址
const saveAddress = () => {
// 表单验证
if (!formData.value.name) {
return uni.showToast({
title: '请输入联系人姓名',
icon: 'none'
});
}
if (!formData.value.phone) {
return uni.showToast({
title: '请输入手机号码',
icon: 'none'
});
}
// 简单的手机号验证
if (!/^1\d{10}$/.test(formData.value.phone)) {
return uni.showToast({
title: '请输入正确的手机号码',
icon: 'none'
});
}
if (!formData.value.address) {
return uni.showToast({
title: '请选择地址位置',
icon: 'none'
});
}
if (!formData.value.addressDetail) {
return uni.showToast({
title: '请输入详细地址',
icon: 'none'
});
}
// 构建地址对象
const addressObj = {
id: Date.now().toString(), // 使用时间戳作为临时ID
name: formData.value.name,
phone: formData.value.phone,
address: formData.value.address,
addressDetail: formData.value.addressDetail,
latitude: formData.value.latitude,
longitude: formData.value.longitude,
tag: formData.value.tag,
isDefault: formData.value.isDefault
};
// 获取已保存的地址列表
let addressList = [];
try {
const savedAddresses = uni.getStorageSync('userAddressList');
if (savedAddresses) {
addressList = JSON.parse(savedAddresses);
}
} catch (e) {
console.error('获取地址列表失败', e);
}
// 如果设置为默认地址,需要将其他地址设为非默认
if (addressObj.isDefault) {
addressList.forEach(item => {
item.isDefault = false;
});
}
// 添加新地址
addressList.push(addressObj);
// 保存地址列表
try {
uni.setStorageSync('userAddressList', JSON.stringify(addressList));
// 如果是默认地址,更新当前使用的地址
if (addressObj.isDefault) {
useUserStore().setAdressInfo({
latitude: addressObj.latitude,
longitude: addressObj.longitude,
adress: addressObj.address,
addressDetail: addressObj.addressDetail
});
}
uni.showToast({
title: '保存成功',
icon: 'success'
});
// 延迟返回上一页
setTimeout(() => {
uni.navigateBack({
delta: 1
});
}, 1500);
} catch (e) {
console.error('保存地址失败', e);
uni.showToast({
title: '保存失败,请重试',
icon: 'none'
});
}
};
// 返回上一页
const goBack = () => {
uni.navigateBack({
delta: 1
});
};
</script>
<style lang="scss" scoped>
.container {
font-size: 14px;
min-height: 100vh;
background-color: #f8f8f8;
display: flex;
flex-direction: column;
}
.nav-bar {
display: flex;
justify-content: space-between;
align-items: center;
height: 90rpx;
background-color: #FFFFFF;
padding: 0 30rpx;
position: relative;
.back-btn {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
}
.title {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
font-size: 32rpx;
font-weight: bold;
}
.right-placeholder {
width: 60rpx;
}
}
.form-content {
flex: 1;
padding-bottom: 120rpx;
}
.form-section {
background-color: #FFFFFF;
margin-top: 20rpx;
padding: 0 30rpx;
.label-title {
padding: 30rpx 0 20rpx;
font-size: 28rpx;
color: #333333;
}
.form-item {
display: flex;
align-items: center;
min-height: 100rpx;
border-bottom: 1px solid #F5F5F5;
&:last-child {
border-bottom: none;
}
.label {
width: 160rpx;
font-size: 28rpx;
color: #333333;
}
.input {
flex: 1;
height: 100rpx;
font-size: 28rpx;
}
&.location-item {
.location-value {
flex: 1;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 28rpx;
.placeholder {
color: #999999;
}
}
}
&.switch-item {
justify-content: space-between;
}
}
.tag-list {
display: flex;
flex-wrap: wrap;
padding: 20rpx 0 30rpx;
.tag-item {
padding: 10rpx 30rpx;
background-color: #F5F5F5;
border-radius: 30rpx;
margin-right: 20rpx;
margin-bottom: 20rpx;
font-size: 26rpx;
color: #666666;
&.active {
background-color: #E6F2FF;
color: #4080FF;
border: 1px solid #4080FF;
}
&.custom-tag {
display: flex;
align-items: center;
justify-content: center;
min-width: 120rpx;
.custom-tag-input {
width: 120rpx;
text-align: center;
height: 40rpx;
}
}
}
}
}
.footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #FFFFFF;
padding: 20rpx 30rpx;
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
.save-btn {
height: 80rpx;
background-color: #4080FF;
color: #FFFFFF;
border-radius: 40rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 30rpx;
}
}
</style>