选择省市区:
<select v-model="user.selectAddrs.p">
<option :value="p" v-for="p in addrs">{{p.province}}</option>
</select>
<select v-model="user.selectAddrs.c">
<option :value="c" v-for="c in user.selectAddrs.p.cities">{{c.city}}</option>
</select>
<select v-model="user.selectAddrs.a">
<option v-for="a in user.selectAddrs.c.areas">
{{a}}
</option>
</select>
<br>
(function () {
new Vue({
el:"#app",
data:{
addrs:[
{
province:"陕西",
cities:[
{
city:"西安",
areas:["高新区","长安区"]
},
{
city:"咸阳",
areas:["渭城区","秦都区"]
}
]
},
{
province:"山西",
cities:[
{
city:"太原",
areas:["太原区1","太原区2"]
},
{
city:"运城",
areas:["运城区1","运城区2"]
}
]
},
],
user:{
selectAddrs:{
p:"",
c:"",
a:""
}
}
}
})
})()
实现思路
通过 watch 监视所选省,省份改变后将所有城市数组根据省id进行过滤。
<template>
<div>
<el-drawer
v-model="dialogShow"
size="35%"
:show-close="false"
@opened="opened"
@closed="onClosed"
>
<template #header>
<e-block title="买家退货寄回地址" class="flex-1" sider />
</template>
<e-form
ref="returnFormRef"
:model="returnForm"
:rules="rules"
:show-ellipsis="false"
label-width="110px"
class="returnForm"
>
<e-form-item label="收货人" prop="consignee">
<e-input v-model="returnForm.consignee" style="width: var(--from-width-small)" />
</e-form-item>
<e-form-item label="收货电话" prop="mobile">
<e-input v-model="returnForm.mobile" style="width: var(--from-width-small)" />
</e-form-item>
<e-form-item label="收货地址" prop="returnAddresses">
<e-select v-model="province" placeholder="请选择省">
<e-option
v-for="item in allAreasList"
:key="item.value"
:label="item.name"
:value="item.code"
/>
</e-select>
<e-select v-model="city" placeholder="请选择市">
<e-option
v-for="item in selectCityList"
:key="item.value"
:label="item.name"
:value="item.code"
/>
</e-select>
<e-select v-model="district" placeholder="请选择区">
<e-option
v-for="item in selectDistrictList"
:key="item.value"
:label="item.name"
:value="item.code"
/>
</e-select>
<!-- <el-cascader
v-model="returnForm.returnAddresses"
:options="areaData"
:props="addressProps"
@change="handleChangeAddress"
/> -->
</e-form-item>
<e-form-item label prop="detailedAddress">
<e-input
v-model="returnForm.detailedAddress"
placeholder="请在此输入详细地址"
type="textarea"
style="width: var(--from-width-large)"
/>
</e-form-item>
<e-form-item label="是否默认地址" prop="first">
<e-radio-group v-model="returnForm.first">
<e-radio v-for="item in defaultOptions" :key="item.label" :label="item.label">
{{ item.text }}
</e-radio>
</e-radio-group>
</e-form-item>
</e-form>
<template #footer>
<e-button type="main" @click="dialogConfirm(returnFormRef)">确 认</e-button>
<e-button type="secondary" @click="dialogCancel">取 消</e-button>
</template>
</el-drawer>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, computed, defineProps, defineEmits, watch } from 'vue';
import { ElMessage as Message } from 'element-plus';
import type { ElForm } from 'element-plus';
import { reg_tel_mobile } from '@/assets/regex';
import { defaultOptions } from '@/config/index';
import api from '@/api/request';
import { saveConfig } from '@/api/order';
type FormInstance = InstanceType<typeof ElForm>;
interface AreaItem {
id: number;
name: string;
code: string;
level: number;
districtCount?: number; // 区的数量
parent_code: string;
status: number;
subAddresses?: AreaItem[];
}
const props = defineProps<{
dialogVisible: Boolean;
}>();
const returnFormRef = ref<FormInstance>();
const returnForm = ref<OrderConfig.ReturnAddressesItem[]>([]);
const rules = reactive({
consignee: [
{
required: true,
message: '请输入收货人',
trigger: 'blur'
}
],
mobile: [
{
required: true,
pattern: reg_tel_mobile,
message: '请输入正确的手机号或座机号',
trigger: ['blur', 'change']
}
],
returnAddresses: [
{
message: '请选择地址',
trigger: 'change'
}
],
detailedAddress: [
{
required: true,
message: '请输入详细地址',
trigger: 'blur'
}
],
first: [
{
required: true,
message: '请选择是否默认地址',
trigger: 'blur'
}
]
});
const dialogShow = computed({
get: () => props.dialogVisible,
set: (val) => emit('update: dialogVisible', val)
});
const emit = defineEmits(['on-confirm', 'on-cancel', 'update: dialogVisible', 'on-closed']);
const opened = () => {
getAllProvinceData();
getAreaData();
};
// 地址相关
// const areaData = ref<AreaItem[]>([]);
const addressProps = ref({
value: 'code',
label: 'name',
children: 'subAddresses'
});
// 获取省市区-全量地址树 TODO 层级为4就报 !!!!timeout of 1000ms exceeded
const getAllProvinceData = () =>
api.post<{ address: AreaItem }>('/address/tree', {
root_code: '086', // 根结点编码,默认取086/中国
max_level: 3 // 最大地址层级
});
const getAreaData = async () => {
const { code, data } = await getAllProvinceData();
if (`${code}` === '0' && data) {
console.log(data.address);
// areaData.value = data.address.subAddresses || [];
allAreasList.value = data.address.subAddresses || [];
}
};
// const handleChangeAddress = (arr: string[]) => {
// console.log('arr:', arr);
// const [provinceCode, cityCode, districtCode] = arr;
// returnForm.value.returnAddresses = {
// provinceCode,
// cityCode,
// districtCode
// };
// };
const allAreasList = ref([]);
const selectCityList = ref<AreaItem[]>([]);
const selectDistrictList = ref<AreaItem[]>([]);
const province = ref<string>('');
const city = ref<string>('');
const district = ref<string>('');
// 监听选择省份--确定市
watch(
() => province.value,
(val) => {
if (val) {
const cities = allAreasList.value.find((item) => item.code === province.value)!.subAddresses;
selectCityList.value = cities;
}
city.value = '';
district.value = '';
}
);
// 监听选择城--确定街道
watch(
() => city.value,
(val) => {
if (val) {
const districts = selectCityList.value.find((item) => item.code === city.value)!.subAddresses;
selectDistrictList.value = districts;
}
district.value = '';
}
);
const dialogConfirm = async (formEl) => {
if (!formEl) return;
formEl.validate((valid) => {
if (valid) {
console.log(returnForm.value);
saveConfig().then((res) => {});
}
});
};
// 弹窗确定
const dialogConfirm1 = (formEl: FormInstance | undefined) => {
if (!formEl) return;
console.log(222, formEl);
let param = {};
formEl.validate((valid) => {
if (valid) {
param = {
operatorId: '51',
source: 'admin'
};
const res = api.post('/order-admin/afterSaleRefundCreate', param);
const { code, message } = res;
if (`${code}` === '0') {
Message({
type: 'success',
message: '操作成功'
});
emit('on-confirm');
} else {
Message({
type: 'error',
message: `${message}`
});
}
} else {
console.log('error submit!');
return false;
}
});
};
// 弹窗取消
const dialogCancel = () => {
emit('on-cancel');
};
const onClosed = () => {
emit('on-closed');
};
</script>
<style lang="scss" scoped>
:deep(.el-drawer__header) {
padding: 0;
margin-bottom: 0;
}
:deep(.el-drawer__body) {
padding: 20px;
}
:deep(.e-block) {
margin-bottom: 0;
}
:deep(.el-drawer__footer) {
text-align: unset;
border-top: 1px solid #e9ebf3;
}
.e-select.el-input__wrapper {
width: 160px;
}
</style>