390 lines
9.9 KiB
Plaintext
390 lines
9.9 KiB
Plaintext
<template>
|
|
<view class="address-list-page">
|
|
<scroll-view class="address-scroll" scroll-y="true">
|
|
<view class="address-content">
|
|
<view v-if="addresses.length === 0" class="empty-state">
|
|
<text class="empty-icon">📍</text>
|
|
<text class="empty-title">还没有服务地址</text>
|
|
<text class="empty-text">新增一个常用服务地址,预约时会更快</text>
|
|
</view>
|
|
|
|
<view
|
|
v-for="item in addresses"
|
|
:key="item.addressId"
|
|
:class="['address-card', isSelected(item) ? 'address-card-selected' : '']"
|
|
@click="selectAddress(item)"
|
|
>
|
|
<view class="address-main">
|
|
<view class="address-top-row">
|
|
<text class="address-name">{{ item.contactName }}</text>
|
|
<text class="address-phone">{{ getPhone(item) }}</text>
|
|
<text v-if="item.isDefault" class="default-tag">默认</text>
|
|
<text v-if="isSelected(item)" class="selected-tag">当前选择</text>
|
|
</view>
|
|
<text class="address-location">{{ getLocationTitle(item) }}</text>
|
|
<text class="address-full">{{ getFullAddress(item) }}</text>
|
|
<text v-if="item.remark != ''" class="address-remark">备注:{{ item.remark }}</text>
|
|
</view>
|
|
<view class="address-actions">
|
|
<view class="action-btn" @click.stop="editAddress(item.addressId)">
|
|
<text class="action-text">编辑</text>
|
|
</view>
|
|
<view class="action-btn action-btn-delete" @click.stop="deleteAddress(item.addressId)">
|
|
<text class="action-text action-text-delete">删除</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
|
|
<view class="bottom-bar">
|
|
<button class="add-btn" @click="addAddress">新建服务地址</button>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="uts">
|
|
import { ref } from 'vue'
|
|
import { onShow } from '@dcloudio/uni-app'
|
|
import { HomeServiceSelectedAddressType } from '@/types/home-service.uts'
|
|
|
|
const SELECTED_KEY = 'hss_selected_service_address'
|
|
const LIST_KEY = 'hss_service_address_list'
|
|
|
|
const addresses = ref<Array<HomeServiceSelectedAddressType>>([])
|
|
const selectedAddressId = ref('')
|
|
|
|
function normalizeAddress(raw: HomeServiceSelectedAddressType): HomeServiceSelectedAddressType {
|
|
const phoneText = raw.phone != null && raw.phone != '' ? raw.phone : (raw.contactPhone != null ? raw.contactPhone : '')
|
|
const locationName = raw.locationName != null && raw.locationName != '' ? raw.locationName : (raw.addressName != null ? raw.addressName : '')
|
|
const locationAddress = raw.locationAddress != null && raw.locationAddress != '' ? raw.locationAddress : (raw.addressDetail != null ? raw.addressDetail : '')
|
|
const doorNo = raw.doorNo != null && raw.doorNo != '' ? raw.doorNo : (raw.houseNumber != null ? raw.houseNumber : '')
|
|
const fullAddressText = raw.fullAddress != null && raw.fullAddress != '' ? raw.fullAddress : locationAddress + ' ' + doorNo
|
|
return {
|
|
...raw,
|
|
addressId: raw.addressId != null && raw.addressId != '' ? raw.addressId : 'local-address-' + Date.now(),
|
|
userId: raw.userId != null ? raw.userId : '',
|
|
isDefault: raw.isDefault === true,
|
|
contactName: raw.contactName != null ? raw.contactName : '',
|
|
phone: phoneText,
|
|
contactPhone: phoneText,
|
|
locationName: locationName,
|
|
addressName: locationName,
|
|
locationAddress: locationAddress,
|
|
addressDetail: locationAddress,
|
|
doorNo: doorNo,
|
|
houseNumber: doorNo,
|
|
remark: raw.remark != null ? raw.remark : '',
|
|
coordinateType: raw.coordinateType != null && raw.coordinateType != '' ? raw.coordinateType : 'gcj02',
|
|
latitude: raw.latitude != null ? raw.latitude : 0,
|
|
longitude: raw.longitude != null ? raw.longitude : 0,
|
|
createdAt: raw.createdAt != null ? raw.createdAt : Date.now(),
|
|
updatedAt: raw.updatedAt != null ? raw.updatedAt : Date.now(),
|
|
fullAddress: fullAddressText.trim()
|
|
}
|
|
}
|
|
|
|
function readAddressList(): Array<HomeServiceSelectedAddressType> {
|
|
const stored = uni.getStorageSync(LIST_KEY)
|
|
if (stored == null) {
|
|
return []
|
|
}
|
|
try {
|
|
let parsed: Array<HomeServiceSelectedAddressType> = []
|
|
if (typeof stored === 'string') {
|
|
const storedText = (stored as string).trim()
|
|
if (storedText == '') {
|
|
return []
|
|
}
|
|
const parsedValue = JSON.parse(storedText) as Array<HomeServiceSelectedAddressType> | null
|
|
if (parsedValue == null) {
|
|
return []
|
|
}
|
|
parsed = parsedValue
|
|
} else {
|
|
parsed = stored as Array<HomeServiceSelectedAddressType>
|
|
}
|
|
if (parsed == null || parsed.length == 0) {
|
|
return []
|
|
}
|
|
const normalized: Array<HomeServiceSelectedAddressType> = []
|
|
for (let i = 0; i < parsed.length; i++) {
|
|
if (parsed[i] != null) {
|
|
normalized.push(normalizeAddress(parsed[i]))
|
|
}
|
|
}
|
|
return normalized
|
|
} catch (error) {
|
|
console.error('解析服务地址列表失败', error)
|
|
uni.removeStorageSync(LIST_KEY)
|
|
return []
|
|
}
|
|
}
|
|
|
|
function writeAddressList(list: Array<HomeServiceSelectedAddressType>): void {
|
|
uni.setStorageSync(LIST_KEY, JSON.stringify(list))
|
|
}
|
|
|
|
function loadAddresses(): void {
|
|
const selected = uni.getStorageSync(SELECTED_KEY) as HomeServiceSelectedAddressType | null
|
|
if (selected != null) {
|
|
const normalizedSelected = normalizeAddress(selected)
|
|
selectedAddressId.value = normalizedSelected.addressId
|
|
}
|
|
const list = readAddressList()
|
|
if (list.length == 0 && selected != null) {
|
|
const seeded: Array<HomeServiceSelectedAddressType> = []
|
|
seeded.push(normalizeAddress(selected))
|
|
addresses.value = seeded
|
|
writeAddressList(seeded)
|
|
return
|
|
}
|
|
addresses.value = list
|
|
}
|
|
|
|
function isSelected(item: HomeServiceSelectedAddressType): boolean {
|
|
return selectedAddressId.value != '' && item.addressId == selectedAddressId.value
|
|
}
|
|
|
|
function getPhone(item: HomeServiceSelectedAddressType): string {
|
|
if (item.phone != null && item.phone != '') {
|
|
return item.phone
|
|
}
|
|
return item.contactPhone
|
|
}
|
|
|
|
function getLocationTitle(item: HomeServiceSelectedAddressType): string {
|
|
if (item.locationName != null && item.locationName != '') {
|
|
return item.locationName
|
|
}
|
|
return item.addressName
|
|
}
|
|
|
|
function getFullAddress(item: HomeServiceSelectedAddressType): string {
|
|
if (item.fullAddress != '') {
|
|
return item.fullAddress
|
|
}
|
|
const locationAddress = item.locationAddress != null && item.locationAddress != '' ? item.locationAddress : item.addressDetail
|
|
const doorNo = item.doorNo != null && item.doorNo != '' ? item.doorNo : item.houseNumber
|
|
return (locationAddress + ' ' + doorNo).trim()
|
|
}
|
|
|
|
function selectAddress(item: HomeServiceSelectedAddressType): void {
|
|
const normalized = normalizeAddress(item)
|
|
uni.setStorageSync(SELECTED_KEY, normalized)
|
|
selectedAddressId.value = normalized.addressId
|
|
uni.navigateBack()
|
|
}
|
|
|
|
function addAddress(): void {
|
|
uni.navigateTo({ url: '/pages/address/address-edit' })
|
|
}
|
|
|
|
function editAddress(addressId: string): void {
|
|
uni.navigateTo({ url: '/pages/address/address-edit?id=' + addressId })
|
|
}
|
|
|
|
function deleteAddress(addressId: string): void {
|
|
uni.showModal({
|
|
title: '提示',
|
|
content: '确定要删除该服务地址吗?',
|
|
success: (res) => {
|
|
if (!res.confirm) {
|
|
return
|
|
}
|
|
const nextList: Array<HomeServiceSelectedAddressType> = []
|
|
for (let i = 0; i < addresses.value.length; i++) {
|
|
if (addresses.value[i].addressId != addressId) {
|
|
nextList.push(addresses.value[i])
|
|
}
|
|
}
|
|
addresses.value = nextList
|
|
writeAddressList(nextList)
|
|
if (selectedAddressId.value == addressId) {
|
|
selectedAddressId.value = ''
|
|
uni.removeStorageSync(SELECTED_KEY)
|
|
if (nextList.length > 0) {
|
|
const nextSelected = normalizeAddress(nextList[0])
|
|
selectedAddressId.value = nextSelected.addressId
|
|
uni.setStorageSync(SELECTED_KEY, nextSelected)
|
|
}
|
|
}
|
|
uni.showToast({
|
|
title: '删除成功',
|
|
icon: 'success'
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
onShow(() => {
|
|
loadAddresses()
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.address-list-page {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: #f4f6f8;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.address-scroll {
|
|
flex: 1;
|
|
min-height: 0;
|
|
}
|
|
|
|
.address-content {
|
|
padding: 24rpx 24rpx 180rpx;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 20rpx;
|
|
}
|
|
|
|
.address-card {
|
|
background: #ffffff;
|
|
border-radius: 28rpx;
|
|
padding: 24rpx;
|
|
box-shadow: 0 12rpx 28rpx rgba(15, 23, 42, 0.05);
|
|
border: 2rpx solid transparent;
|
|
}
|
|
|
|
.address-card-selected {
|
|
border-color: rgba(249, 115, 22, 0.38);
|
|
box-shadow: 0 16rpx 30rpx rgba(249, 115, 22, 0.12);
|
|
}
|
|
|
|
.address-main {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10rpx;
|
|
}
|
|
|
|
.address-top-row,
|
|
.address-actions,
|
|
.bottom-bar,
|
|
.empty-state {
|
|
display: flex;
|
|
flex-direction: row;
|
|
}
|
|
|
|
.address-top-row {
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
gap: 12rpx;
|
|
}
|
|
|
|
.address-name,
|
|
.address-location,
|
|
.empty-title {
|
|
color: #1f2937;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.address-name {
|
|
font-size: 28rpx;
|
|
}
|
|
|
|
.address-phone,
|
|
.address-full,
|
|
.address-remark,
|
|
.empty-text,
|
|
.action-text {
|
|
font-size: 24rpx;
|
|
color: #4b5563;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.address-location {
|
|
font-size: 26rpx;
|
|
}
|
|
|
|
.default-tag,
|
|
.selected-tag {
|
|
padding: 4rpx 12rpx;
|
|
border-radius: 999rpx;
|
|
font-size: 20rpx;
|
|
}
|
|
|
|
.default-tag {
|
|
background: #fff1eb;
|
|
color: #ff5000;
|
|
}
|
|
|
|
.selected-tag {
|
|
background: #fff7ed;
|
|
color: #ea580c;
|
|
}
|
|
|
|
.address-actions {
|
|
justify-content: flex-end;
|
|
gap: 16rpx;
|
|
margin-top: 18rpx;
|
|
}
|
|
|
|
.action-btn {
|
|
padding: 12rpx 22rpx;
|
|
border-radius: 999rpx;
|
|
background: #f8fafc;
|
|
}
|
|
|
|
.action-btn-delete {
|
|
background: #fff5f5;
|
|
}
|
|
|
|
.action-text-delete {
|
|
color: #dc2626;
|
|
}
|
|
|
|
.empty-state {
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 120rpx 40rpx;
|
|
background: #ffffff;
|
|
border-radius: 28rpx;
|
|
box-shadow: 0 12rpx 28rpx rgba(15, 23, 42, 0.05);
|
|
text-align: center;
|
|
gap: 16rpx;
|
|
}
|
|
|
|
.empty-icon {
|
|
font-size: 64rpx;
|
|
opacity: 0.6;
|
|
}
|
|
|
|
.empty-title {
|
|
font-size: 30rpx;
|
|
}
|
|
|
|
.empty-text {
|
|
color: #6b7280;
|
|
}
|
|
|
|
.bottom-bar {
|
|
position: fixed;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
padding: 20rpx 24rpx 36rpx;
|
|
background: rgba(244, 246, 248, 0.96);
|
|
box-shadow: 0 -8rpx 24rpx rgba(15, 23, 42, 0.05);
|
|
}
|
|
|
|
.add-btn {
|
|
width: 100%;
|
|
height: 88rpx;
|
|
line-height: 88rpx;
|
|
border-radius: 999rpx;
|
|
background: linear-gradient(135deg, #ff8a65 0%, #ff7043 100%);
|
|
color: #ffffff;
|
|
font-size: 30rpx;
|
|
font-weight: 600;
|
|
border: none;
|
|
}
|
|
</style> |