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.
 
 
 
 
 

380 lines
11 KiB

<template>
<view class="add-address-page">
<view class="form-card">
<view class="form-row">
<text class="form-label">收货人</text>
<input class="form-input" type="text" maxlength="20" v-model="addressForm.receiverName"
@input="onReceiverNameInput" placeholder="姓名" placeholder-class="form-placeholder" />
</view>
<view class="form-row">
<text class="form-label">电话</text>
<input class="form-input" type="number" maxlength="11" v-model="addressForm.receiverPhone"
@input="onReceiverPhoneInput" placeholder="手机号" placeholder-class="form-placeholder" />
</view>
<view class="form-row" @tap="openAreaPopup">
<text class="form-label">楼座区域</text>
<text class="form-value" :class="{'form-placeholder-text': !areaTitleInput}">
{{areaTitleInput || (areaListLoading ? '加载中...' : '选择收货地址')}}
</text>
<uni-icons type="right" size="18" color="#999"></uni-icons>
</view>
<view class="form-row">
<text class="form-label">楼层</text>
<input class="form-input" type="number" v-model="addressForm.floor" @input="onFloorInput"
placeholder="所在楼层,仅限整数" placeholder-class="form-placeholder" />
</view>
<view class="form-row">
<text class="form-label">门牌号</text>
<input class="form-input" type="text" maxlength="30" v-model="addressForm.roomNum"
@input="onRoomNumInput" placeholder="例:5号楼203室" placeholder-class="form-placeholder" />
</view>
<view class="form-row form-row--switch">
<text class="form-label">设为默认地址</text>
<switch :checked="addressForm.isDefault === 1" @change="e => addressForm.isDefault = e.detail.value ? 1 : 0"
color="#a6ffea" />
</view>
</view>
<view class="submit-btn" :class="{'submit-btn--disabled': addressSubmitting}" @tap="submitAddress">
{{addressSubmitting ? '提交中...' : '确定'}}
</view>
<uni-popup ref="areaPopup" type="bottom" background-color="#fff">
<view class="area-popup" @tap.stop>
<view class="area-popup-title">
<text>选择楼座区域</text>
<uni-icons type="closeempty" size="24" color="#333" @tap="closeAreaPopup"></uni-icons>
</view>
<view class="area-search-box">
<input class="area-search-input" type="text" v-model="areaSearchInput" placeholder="请输入楼座名称搜索"
placeholder-class="form-placeholder" confirm-type="search" :cursor-spacing="160" />
</view>
<scroll-view scroll-y class="area-result-list">
<view v-if="filteredAreaList.length === 0" class="area-result-empty">
未找到匹配的楼座
</view>
<view v-for="item in filteredAreaList" :key="item.id" class="area-result-item" @tap="selectArea(item)">
{{item.title}}
</view>
</scroll-view>
</view>
</uni-popup>
</view>
</template>
<script>
export default {
data() {
return {
areaList: [],
areaTitleList: [],
areaListLoading: false,
areaTitleInput: '',
areaSearchInput: '',
addressSubmitting: false,
addressForm: {
id: '',
regionId: '',
areaId: '',
areaName: '',
floor: '',
roomNum: '',
receiverName: '',
receiverPhone: '',
isDefault: 0
}
}
},
computed: {
filteredAreaList() {
const keyword = (this.areaSearchInput || '').toString();
if (!keyword) return this.areaList;
return this.areaList.filter(item => (item.title || '').toString().indexOf(keyword) > -1);
}
},
onLoad(options) {
const id = options && options.id ? options.id : '';
uni.setNavigationBarTitle({
title: id ? '编辑地址' : '新增收货地址'
});
this.addressForm.regionId = this.getCurrentRegionId();
if (id) {
this.addressForm.id = id;
this.initEditAddress(id);
}
this.getAreaList().then(() => {
this.syncAreaTitle();
});
},
methods: {
getCurrentRegionId() {
try {
const area = uni.getStorageSync('area');
if (!area) return '';
if (typeof area === 'object') return area.id ? String(area.id) : '';
const areaInfo = JSON.parse(area);
return areaInfo.id ? String(areaInfo.id) : '';
} catch (e) {
return '';
}
},
initEditAddress(id) {
const cached = uni.getStorageSync('editingAddress');
if (cached && String(cached.id) === String(id)) {
this.applyAddress(cached);
return;
}
this.tui.request("/app/userAddress/get", "GET", {
id: id
}, false, true).then((res) => {
if (res.code == 200 && res.result) {
this.applyAddress(res.result);
}
}).catch(() => {});
},
applyAddress(item) {
this.addressForm = {
id: item.id || '',
regionId: item.regionId || this.getCurrentRegionId(),
areaId: item.areaId || '',
areaName: item.areaName || '',
floor: item.floor || '',
roomNum: item.roomNum || '',
receiverName: item.receiverName || '',
receiverPhone: item.receiverPhone || '',
isDefault: item.isDefault || 0
};
this.areaTitleInput = item.areaName || '';
this.syncAreaTitle();
},
getAreaList() {
if (this.areaListLoading) return Promise.resolve(this.areaList);
const regionId = this.getCurrentRegionId();
if (!regionId) return Promise.resolve([]);
this.areaListLoading = true;
return this.tui.request("/app/shopArea/getByParentId/" + regionId, "GET", {}, false, true).then((res) => {
if (res.code == 200 && res.result) {
this.areaList = res.result;
this.areaTitleList = res.result.map(item => item.title);
}
return this.areaList;
}).catch(() => []).finally(() => {
this.areaListLoading = false;
});
},
syncAreaTitle() {
if (!this.addressForm.areaId || !this.areaList.length) return;
const match = this.areaList.find(item => String(item.id) === String(this.addressForm.areaId));
if (match) this.areaTitleInput = match.title;
},
openAreaPopup() {
this.areaSearchInput = '';
this.getAreaList();
this.$refs.areaPopup.open();
},
closeAreaPopup() {
this.$refs.areaPopup.close();
},
selectArea(item) {
if (!item) return;
this.addressForm.areaId = item.id;
this.addressForm.areaName = item.title;
this.areaTitleInput = item.title;
this.closeAreaPopup();
},
onFloorInput(e) {
const value = (e.detail.value || '').toString();
const hasMinus = value.charAt(0) === '-';
let nextValue = value.replace(/[^\d-]/g, '').replace(/-/g, '');
if (hasMinus) nextValue = '-' + nextValue;
this.addressForm.floor = nextValue;
return nextValue;
},
onRoomNumInput(e) {
const nextValue = (e.detail.value || '').toString().slice(0, 30);
this.addressForm.roomNum = nextValue;
return nextValue;
},
onReceiverNameInput(e) {
const nextValue = (e.detail.value || '').toString().slice(0, 20);
this.addressForm.receiverName = nextValue;
return nextValue;
},
onReceiverPhoneInput(e) {
const nextValue = (e.detail.value || '').toString().replace(/\D/g, '').slice(0, 11);
this.addressForm.receiverPhone = nextValue;
return nextValue;
},
submitAddress() {
if (this.addressSubmitting) return;
if (!this.addressForm.areaId) return this.tui.toast('请选择楼座区域');
this.addressForm.floor = (this.addressForm.floor || '').toString();
this.addressForm.roomNum = (this.addressForm.roomNum || '').toString().trim();
this.addressForm.receiverName = (this.addressForm.receiverName || '').toString().trim();
this.addressForm.receiverPhone = (this.addressForm.receiverPhone || '').toString().replace(/\D/g, '');
if (!this.addressForm.floor) return this.tui.toast('请填写所在楼层,楼层必须为整数数字');
if (!/^-?\d+$/.test(this.addressForm.floor)) return this.tui.toast('楼层必须为整数');
if (!this.addressForm.roomNum) return this.tui.toast('请填写详细地址门牌号最多30字');
if (this.addressForm.roomNum.length > 30) return this.tui.toast('详细地址最多30字');
if (!this.addressForm.receiverName) return this.tui.toast('请填写收件人最多20字');
if (this.addressForm.receiverName.length > 20) return this.tui.toast('收货人名字最多20字');
if (!this.addressForm.receiverPhone) return this.tui.toast('请输入有效的11位手机号码');
if (!/^1[3-9]\d{9}$/.test(this.addressForm.receiverPhone)) return this.tui.toast('请输入有效的11位手机号码');
this.addressForm.userId = uni.getStorageSync('id');
this.addressForm.regionId = this.getCurrentRegionId();
if (!this.addressForm.regionId) return this.tui.toast('请先选择区域');
const url = this.addressForm.id ? "/app/userAddress/edit" : "/app/userAddress/save";
this.addressSubmitting = true;
this.tui.request(url, "POST", this.addressForm, false, true).then((res) => {
if (res.code == 200) {
const pendingAddress = res.result && typeof res.result === 'object' ?
Object.assign({}, this.addressForm, res.result) :
Object.assign({}, this.addressForm);
uni.setStorageSync('pendingSelectedAddress', pendingAddress);
uni.setStorageSync('addressListNeedsRefresh', '1');
uni.removeStorageSync('editingAddress');
this.tui.toast("保存成功", 1000);
setTimeout(() => {
uni.navigateBack();
}, 500);
} else {
this.tui.toast(res.message, 1000);
}
}).catch(() => {}).finally(() => {
this.addressSubmitting = false;
});
}
}
}
</script>
<style lang="scss" scoped>
.add-address-page {
min-height: 100vh;
box-sizing: border-box;
background: #f5f5f5;
padding-bottom: 40rpx;
}
.form-card {
background: #fff;
}
.form-row {
min-height: 98rpx;
box-sizing: border-box;
padding: 0 30rpx;
display: flex;
align-items: center;
border-bottom: 1rpx solid #eee;
background: #fff;
}
.form-row--switch {
justify-content: space-between;
margin-top: 30rpx;
border-bottom: 0;
}
.form-row--switch .form-label {
width: auto;
flex: 1;
white-space: nowrap;
}
.form-label {
width: 150rpx;
flex-shrink: 0;
font-size: 30rpx;
color: #333;
}
.form-input {
flex: 1;
min-width: 0;
height: 98rpx;
line-height: 98rpx;
font-size: 30rpx;
color: #333;
}
.form-placeholder,
.form-placeholder-text {
color: #c7c7c7;
}
.form-value {
flex: 1;
min-width: 0;
font-size: 30rpx;
color: #333;
}
.submit-btn {
height: 88rpx;
line-height: 88rpx;
margin: 40rpx 30rpx 0;
border-radius: 8rpx;
background: linear-gradient(90deg, #e3ff96, #a6ffea);
font-size: 34rpx;
font-weight: 700;
text-align: center;
color: #111;
}
.submit-btn--disabled {
opacity: 0.65;
}
.area-popup {
height: 760rpx;
box-sizing: border-box;
padding: 30rpx;
border-radius: 28rpx 28rpx 0 0;
background: #fff;
}
.area-popup-title {
height: 60rpx;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 34rpx;
font-weight: 700;
color: #333;
}
.area-search-box {
margin-top: 24rpx;
padding: 18rpx 22rpx;
background: #f7f8f8;
border-radius: 16rpx;
}
.area-search-input {
width: 100%;
height: 46rpx;
line-height: 46rpx;
font-size: 28rpx;
color: #333;
}
.area-result-list {
height: 560rpx;
margin-top: 20rpx;
}
.area-result-empty,
.area-result-item {
min-height: 88rpx;
line-height: 88rpx;
padding: 0 20rpx;
box-sizing: border-box;
font-size: 30rpx;
color: #333;
border-bottom: 1rpx solid #f2f2f2;
}
.area-result-empty {
color: #999;
text-align: center;
}
</style>