bonus-ui/src/views/address-manage/index.vue

623 lines
14 KiB
Vue

<template>
<div class="app-container">
<!-- 搜索表单 -->
<el-form
ref="searchFormRef"
:model="searchParams"
:inline="true"
label-width="auto"
size="small"
>
</el-form>
<!-- 主内容卡片 -->
<el-card class="content-box">
<!-- 操作按钮区域 -->
<div class="action-bar">
<el-button
size="mini"
type="primary"
@click="handleAddAddress"
>
新建收货地址
</el-button>
</div>
<!-- 地址列表表格 -->
<el-table
:data="addressList"
border
stripe
class="my-table"
show-overflow-tooltip
>
<el-table-column
type="index"
label="序号"
align="center"
width="80"
/>
<el-table-column
label="收货地址"
align="center"
>
<template slot-scope="{ row }">
{{ formatFullAddress(row) }}
</template>
</el-table-column>
<el-table-column
label="操作"
align="center"
width="220"
>
<template slot-scope="{ row }">
<el-button
size="small"
type="text"
@click="handleEditAddress(row)"
>
编辑
</el-button>
<el-button
size="small"
type="text"
class="danger-text"
@click="handleDeleteAddress(row.id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<div class="pagination-wrapper">
<pagination
:total="total"
:page.sync="searchParams.pageNum"
:limit.sync="searchParams.pageSize"
@pagination="getAddressListData"
/>
</div>
</el-card>
<!-- 地址编辑对话框 -->
<el-dialog
:title="dialogTitle"
:visible="dialogVisible"
width="40%"
align-center
append-to-body
@close="handleDialogClose"
>
<el-form
ref="addressFormRef"
:model="addressForm"
:rules="addressFormRules"
label-position="right"
label-width="auto"
>
<el-row :gutter="20">
<!-- 省份选择 -->
<el-col :span="24">
<el-form-item
label="所在省"
prop="provinceCode"
>
<el-select
v-model="addressForm.provinceCode"
placeholder="请选择省"
clearable
style="width: 95%"
@change="handleProvinceChange"
>
<el-option
v-for="item in provinceList"
:key="item.areaId"
:value="item.areaCode * 1"
:label="item.areaName"
/>
</el-select>
</el-form-item>
</el-col>
<!-- 城市选择 -->
<el-col :span="24">
<el-form-item
label="所在市"
prop="cityCode"
>
<el-select
v-model="addressForm.cityCode"
placeholder="请选择市"
clearable
style="width: 95%"
@change="handleCityChange"
>
<el-option
v-for="item in cityList"
:key="item.areaId"
:value="item.areaCode * 1"
:label="item.areaName"
/>
</el-select>
</el-form-item>
</el-col>
<!-- 区县选择 -->
<el-col :span="24">
<el-form-item
label="所在区/县"
prop="areaCode"
>
<el-select
v-model="addressForm.areaCode"
placeholder="请选择区/县"
clearable
style="width: 95%"
>
<el-option
v-for="item in districtList"
:key="item.areaId"
:value="item.areaCode * 1"
:label="item.areaName"
/>
</el-select>
</el-form-item>
</el-col>
<!-- 详细地址 -->
<el-col :span="24">
<el-form-item
label="详细地址"
prop="address"
>
<el-input
v-model="addressForm.address"
placeholder="请输入详细地址"
clearable
:maxlength="99"
style="width: 95%"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 对话框按钮 -->
<div slot="footer" class="dialog-footer">
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleSubmit">提交</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
getAreaApi,
addAddressInfoApi,
getAddressListApi,
editAddressApi,
delAddressApi
} from '@/api/address-manage/index'
import { Message } from 'element-ui'
export default {
name: 'AddressManage',
data() {
return {
// 列表数据
addressList: [],
total: 0,
// 搜索参数
searchParams: {
pageSize: 10,
pageNum: 1
},
// 对话框相关
dialogVisible: false,
dialogTitle: '',
isEditMode: false,
// 表单数据
addressForm: {
id: '',
provinceCode: '',
cityCode: '',
areaCode: '',
address: ''
},
// 地区数据
provinceList: [],
cityList: [],
districtList: [],
// 表单引用
searchFormRef: null,
addressFormRef: null
}
},
computed: {
// 表单验证规则
addressFormRules() {
return {
provinceCode: [
{ required: true, message: '请选择所在省', trigger: 'change' }
],
cityCode: [
{ required: true, message: '请选择所在市', trigger: 'change' }
],
areaCode: [
{ required: true, message: '请选择所在区/县', trigger: 'change' }
],
address: [
{ required: true, message: '请输入详细地址', trigger: 'blur' },
{ max: 99, message: '详细地址不能超过99个字符', trigger: 'blur' }
]
}
}
},
created() {
this.initData()
},
methods: {
/**
* 初始化数据
*/
async initData() {
await Promise.all([
this.getAddressListData(),
this.getProvinceList()
])
},
/**
* 获取地址列表数据
*/
async getAddressListData() {
try {
const res = await getAddressListApi(this.searchParams)
if (res.code === 200) {
this.addressList = res.rows || []
this.total = res.total || 0
}
} catch (error) {
console.error('获取地址列表失败:', error)
}
},
/**
* 获取省份列表
*/
async getProvinceList() {
try {
const res = await getAreaApi(0)
if (res.code === 200) {
this.provinceList = res.data || []
}
} catch (error) {
console.error('获取省份列表失败:', error)
}
},
/**
* 获取城市列表
*/
async getCityList(provinceCode) {
try {
const res = await getAreaApi(provinceCode)
if (res.code === 200) {
this.cityList = res.data || []
this.districtList = [] // 清空区县列表
}
} catch (error) {
console.error('获取城市列表失败:', error)
}
},
/**
* 获取区县列表
*/
async getDistrictList(cityCode) {
try {
const res = await getAreaApi(cityCode)
if (res.code === 200) {
this.districtList = res.data || []
}
} catch (error) {
console.error('获取区县列表失败:', error)
}
},
/**
* 格式化完整地址
*/
formatFullAddress(row) {
const { provinceName = '', cityName = '', areaName = '', address = '' } = row
return `${provinceName}${cityName}${areaName}${address}`
},
/**
* 处理新增地址
*/
handleAddAddress() {
this.dialogTitle = '新增收货地址'
this.isEditMode = false
this.resetAddressForm()
this.dialogVisible = true
},
/**
* 处理编辑地址
*/
async handleEditAddress(row) {
this.dialogTitle = '编辑收货地址'
this.isEditMode = true
// 填充表单数据
this.addressForm = {
id: row.id,
provinceCode: row.provinceCode,
cityCode: row.cityCode,
areaCode: row.areaCode,
address: row.address
}
// 加载地区数据
await this.loadRegionDataForEdit()
this.dialogVisible = true
},
/**
* 编辑时加载地区数据
*/
async loadRegionDataForEdit() {
const { provinceCode, cityCode } = this.addressForm
if (provinceCode) {
await this.getCityList(provinceCode)
}
if (cityCode) {
await this.getDistrictList(cityCode)
}
},
/**
* 处理省份变化
*/
async handleProvinceChange(provinceCode) {
if (!provinceCode) {
this.cityList = []
this.districtList = []
this.addressForm.cityCode = ''
this.addressForm.areaCode = ''
return
}
await this.getCityList(provinceCode)
this.addressForm.cityCode = ''
this.addressForm.areaCode = ''
},
/**
* 处理城市变化
*/
async handleCityChange(cityCode) {
if (!cityCode) {
this.districtList = []
this.addressForm.areaCode = ''
return
}
await this.getDistrictList(cityCode)
this.addressForm.areaCode = ''
},
/**
* 处理删除地址
*/
handleDeleteAddress(id) {
this.$confirm('确定删除该收货地址吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async() => {
try {
const res = await delAddressApi(id)
if (res.code === 200) {
Message.success('删除成功')
this.getAddressListData()
}
} catch (error) {
console.error('删除地址失败:', error)
}
}).catch(() => {
})
},
/**
* 处理表单提交
*/
async handleSubmit() {
try {
await this.$refs.addressFormRef.validate()
const api = this.isEditMode ? editAddressApi : addAddressInfoApi
const res = await api(this.addressForm)
if (res.code === 200) {
Message.success(this.isEditMode ? '编辑成功' : '新增成功')
this.dialogVisible = false
this.getAddressListData()
}
} catch (error) {
// 验证失败或API调用失败
console.error('提交失败:', error)
}
},
/**
* 处理对话框关闭
*/
handleDialogClose() {
this.dialogVisible = false
this.resetAddressForm()
this.resetRegionLists()
if (this.$refs.addressFormRef) {
this.$refs.addressFormRef.clearValidate()
}
},
/**
* 处理取消操作
*/
handleCancel() {
this.dialogVisible = false
},
/**
* 重置地址表单
*/
resetAddressForm() {
this.addressForm = {
id: '',
provinceCode: '',
cityCode: '',
areaCode: '',
address: ''
}
},
/**
* 重置地区列表
*/
resetRegionLists() {
this.cityList = []
this.districtList = []
}
}
}
</script>
<style lang="scss" scoped>
.app-container {
height: 100%;
.content-box {
border-radius: 8px;
//height: calc(100vh - 125px);
display: flex;
flex-direction: column;
::v-deep .el-card__body {
display: flex;
flex-direction: column;
height: 100%;
padding: 20px;
}
.action-bar {
margin-bottom: 16px;
text-align: right;
flex-shrink: 0;
}
.pagination-wrapper {
flex-shrink: 0;
padding-top: 6px;
margin-top: auto;
::v-deep .pagination-container {
padding: 0 20px;
}
}
}
.danger-text {
color: #FF5129;
&:hover {
color: #f78989;
}
}
}
// 表格样式优化
::v-deep .el-table {
flex: 1;
min-height: 0;
&.el-table--striped {
.el-table__body {
tr.el-table__row--striped {
td {
background-color: #F6FBFA !important;
}
}
}
}
.el-table__header {
background: #E9F0EE;
th {
background: #E9F0EE !important;
color: #606266;
font-weight: 600;
height: 50px;
}
}
&.el-table--striped {
.el-table__body {
tr.el-table__row:hover > td.el-table__cell {
background-color: #CCF1E9 !important;
}
}
}
}
// 分页样式
::v-deep .el-pagination {
&.is-background {
.el-pager {
li.is-active {
background-color: #3cb4a6;
}
}
}
}
// 对话框样式
.dialog-footer {
text-align: right;
}
::v-deep.el-button--primary{
background-color: #2CBAB2;
border-color: #2CBAB2;
}
::v-deep .el-button--text{
height: 22px;
font-family: Microsoft YaHei, Microsoft YaHei;
font-weight: 400;
font-size: 14px;
color: #2CBAB2;
line-height: 22px;
text-align: left;
font-style: normal;
text-transform: none;
}
</style>