Files
frontend-app/pages/mine_package/mine_address/mine_address.vue
T
2026-08-06 18:50:25 +08:00

451 lines
11 KiB
Vue
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="mine_address_page">
<!-- 顶部导航栏 (白色底) -->
<view class="header_box">
<Header :leftTitle="headerTitle" leftPath="1" />
</view>
<!-- 页面内容容器 -->
<view class="content_container">
<!-- ===== 样式2 (moduleType == 2): 展示原地址卡片 + 选择新的收货地址卡片 ===== -->
<template v-if="moduleType == 2 || moduleType == '2'">
<!-- 原地址卡片 -->
<view v-if="currentOriginalAddress" class="card_wrapper">
<view class="card_header">
<text class="card_title">原地址</text>
</view>
<view class="address_item original_item">
<view class="address_info">
<text class="name">{{ currentOriginalAddress.name }}</text>
<text class="phone">{{ currentOriginalAddress.phone }}</text>
</view>
<view class="address_detail">
{{ formatAddress(currentOriginalAddress) }}
</view>
</view>
</view>
<!-- 选择新的收货地址卡片 -->
<view class="card_wrapper">
<view class="card_header">
<text class="card_title">选择新的收货地址</text>
</view>
<view v-if="addressList && addressList.length > 0" class="address_list">
<view
v-for="(item, index) in addressList"
:key="item.id || index"
class="address_item"
:class="{ 'border_bottom': index !== addressList.length - 1 }"
@click="selectAddress(item)"
>
<view class="address_info">
<text class="name">{{ item.name }}</text>
<text class="phone">{{ item.phone }}</text>
</view>
<view class="address_detail">
{{ formatAddress(item) }}
</view>
<view class="address_operate">
<view class="default_check" @click.stop="isDefaultChange(item)">
<view class="check_icon" :class="{ checked: isItemDefault(item) }">
<text v-if="isItemDefault(item)" class="check_mark">✓</text>
</view>
<text class="check_label">已默认</text>
</view>
<view class="operate_btns">
<view class="btn_item" @click.stop="deleteAddressFun(item)">删除</view>
<view class="btn_item" @click.stop="updateAddress(item)">修改</view>
</view>
</view>
</view>
</view>
<!-- 暂无地址 -->
<view v-else class="empty_wrapper">
<image src="/pages/other_package/static/not_search.png" class="empty_img" mode="aspectFit" />
<text class="empty_text">暂无地址,快去添加吧~</text>
</view>
</view>
</template>
<!-- ===== 样式1 (moduleType == 1 / 默认): 单卡片列表 ===== -->
<template v-else>
<view v-if="addressList && addressList.length > 0" class="card_wrapper">
<view
v-for="(item, index) in addressList"
:key="item.id || index"
class="address_item"
:class="{ 'border_bottom': index !== addressList.length - 1 }"
>
<view class="address_info">
<text class="name">{{ item.name }}</text>
<text class="phone">{{ item.phone }}</text>
</view>
<view class="address_detail">
{{ formatAddress(item) }}
</view>
<view class="address_operate">
<view class="default_check" @click.stop="isDefaultChange(item)">
<view class="check_icon" :class="{ checked: isItemDefault(item) }">
<text v-if="isItemDefault(item)" class="check_mark">✓</text>
</view>
<text class="check_label">已默认</text>
</view>
<view class="operate_btns">
<view class="btn_item" @click.stop="deleteAddressFun(item)">删除</view>
<view class="btn_item" @click.stop="updateAddress(item)">修改</view>
</view>
</view>
</view>
</view>
<!-- 暂无地址 -->
<view v-else class="empty_wrapper">
<image src="/pages/other_package/static/not_search.png" class="empty_img" mode="aspectFit" />
<text class="empty_text">暂无地址,快去添加吧~</text>
</view>
</template>
</view>
<!-- 底部固定新增按钮 -->
<view class="bottom_btn_bar">
<view class="add_btn" @click="jumpAddAddress">
新增地址
</view>
</view>
</view>
</template>
<script>
import { getAddress, setAddressDefault, deleteAddress } from '@/api/address.js';
import Header from '@/components/header.vue';
export default {
components: { Header },
data() {
return {
moduleType: '1', // 1: 图一模式 (默认), 2: 图二模式
originalId: '',
passedOriginalAddress: null,
addressList: []
};
},
computed: {
headerTitle() {
if (this.$t && typeof this.$t === 'function') {
try {
const title = this.$t('address.title');
if (title && title !== 'address.title') return title;
} catch (e) {}
}
return '地址管理';
},
currentOriginalAddress() {
if (this.passedOriginalAddress) {
return this.passedOriginalAddress;
}
if (this.originalId && this.addressList && this.addressList.length > 0) {
const found = this.addressList.find(item => String(item.id) === String(this.originalId));
if (found) return found;
}
if (this.addressList && this.addressList.length > 0) {
const defaultItem = this.addressList.find(item => this.isItemDefault(item));
return defaultItem || this.addressList[0];
}
return null;
}
},
onLoad(options) {
if (options) {
const typeVal = options.moduleType || options.type || options.mode || options.style || options.pageType || '1';
this.moduleType = String(typeVal);
if (options.originalId || options.addressId || options.id) {
this.originalId = options.originalId || options.addressId || options.id;
}
if (options.originalAddress) {
try {
this.passedOriginalAddress = JSON.parse(decodeURIComponent(options.originalAddress));
} catch (e) {
console.error('Parse originalAddress error:', e);
}
}
}
},
onShow() {
this.getAddressList();
},
methods: {
// 格式化完整地址显示
formatAddress(item) {
if (!item) return '';
const parts = [
item.countryName,
item.provinceName,
item.cityName,
item.areaName,
item.townshipName,
item.address
].filter(Boolean);
return parts.join(' ') || item.address || '';
},
// 判断是否为默认地址
isItemDefault(item) {
if (!item) return false;
return item.isDefault === true || item.isDefault === 1 || item.isDefault === '1';
},
// 添加地址
jumpAddAddress() {
uni.navigateTo({
url: '/pages/mine_package/mine_address_add/mine_address_add'
});
},
// 查询地址列表
async getAddressList() {
const res = await getAddress();
if (res && res.bizcode === 100) {
this.addressList = res.data || [];
}
},
// 设为默认地址
async isDefaultChange(item) {
const params = {
id: item.id
};
const res = await setAddressDefault(params);
if (res && res.bizcode === 100) {
this.getAddressList();
}
},
// 删除地址确认
deleteAddressFun(item) {
const that = this;
uni.showModal({
title: '提示',
content: '是否要删除该地址?',
success: function (res) {
if (res.confirm) {
that.deleteAddress(item);
}
}
});
},
// 执行删除
async deleteAddress(item) {
const params = {
id: item.id
};
const respon = await deleteAddress(params);
if (respon && respon.bizcode === 100) {
this.getAddressList();
}
},
// 修改地址
updateAddress(item) {
uni.navigateTo({
url: '/pages/mine_package/mine_address_add/mine_address_add?id=' + item.id
});
},
// 选择地址(针对模式2)
selectAddress(item) {
uni.$emit('selectAddress', item);
if (this.moduleType == 2 || this.moduleType == '2') {
uni.navigateBack({
fail: () => {}
});
}
}
}
};
</script>
<style lang="scss" scoped>
.mine_address_page {
min-height: 100vh;
background-color: $app-bj;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.header_box {
background-color: #FFFFFF;
position: sticky;
top: 0;
z-index: 99;
::v-deep .header_ {
background-color: #FFFFFF;
}
}
.content_container {
padding: 24rpx;
padding-bottom: calc(140rpx + env(safe-area-inset-bottom));
flex: 1;
}
.card_wrapper {
background: #FFFFFF;
border-radius: 24rpx;
padding: 0 30rpx;
margin-bottom: 24rpx;
overflow: hidden;
}
.card_header {
padding: 24rpx 0 20rpx;
border-bottom: 1rpx solid #F0F0F0;
.card_title {
font-size: 28rpx;
color: #888888;
font-weight: 400;
}
}
.address_item {
padding: 30rpx 0;
&.border_bottom {
border-bottom: 1rpx solid #F0F0F0;
}
&.original_item {
padding: 24rpx 0 30rpx;
}
}
.address_info {
display: flex;
align-items: center;
.name {
font-size: 28rpx;
color: #333333;
font-weight: 400;
}
.phone {
font-size: 28rpx;
color: #333333;
margin-left: 20rpx;
font-weight: 400;
}
}
.address_detail {
font-size: 32rpx;
font-weight: 600;
color: #1A1A1A;
margin-top: 12rpx;
line-height: 1.4;
word-break: break-all;
}
.address_operate {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 24rpx;
}
.default_check {
display: flex;
align-items: center;
.check_icon {
width: 36rpx;
height: 36rpx;
border-radius: 50%;
border: 2rpx solid #CCCCCC;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12rpx;
box-sizing: border-box;
transition: all 0.2s ease;
&.checked {
background: linear-gradient(135deg, #9747FF 0%, #7934F6 100%);
border-color: #7934F6;
}
.check_mark {
color: #FFFFFF;
font-size: 22rpx;
font-weight: bold;
line-height: 1;
}
}
.check_label {
font-size: 26rpx;
color: #333333;
}
}
.operate_btns {
display: flex;
align-items: center;
.btn_item {
padding: 10rpx 28rpx;
background: #F3F3F5;
border-radius: 30rpx;
font-size: 24rpx;
color: #333333;
margin-left: 16rpx;
line-height: 1.2;
display: flex;
align-items: center;
justify-content: center;
}
}
.empty_wrapper {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
.empty_img {
width: 200rpx;
height: 200rpx;
}
.empty_text {
margin-top: 20rpx;
font-size: 28rpx;
color: #999999;
}
}
.bottom_btn_bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #F5F5F5;
padding: 20rpx 30rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
z-index: 100;
box-sizing: border-box;
.add_btn {
height: 88rpx;
background: linear-gradient(90deg, #8A38F5 0%, #A855F7 100%);
border-radius: 16rpx;
color: #FFFFFF;
font-size: 32rpx;
font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 12rpx rgba(121, 52, 246, 0.25);
}
}
</style>