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.

367 lines
9.5 KiB

4 months ago
<!-- @format -->
<template>
<div>
<a-input
placeholder="请选择"
readonly="readonly"
style="cursor: pointer"
v-model:value="choiceCityName"
@click.stop="showCard">
<template #suffix> <ns-icon name="drow" size="12" @click.stop="showCard" /></template>
</a-input>
<div v-show="visible" class="selectCard">
<header class="card_header">
<div :style="{ background: regionLevel === 1 ? '#fff' : '' }" @click.stop="check(1)"
></div
>
<div :style="{ background: regionLevel === 2 ? '#fff' : '' }" @click.stop="check(2)"
></div
>
<div :style="{ background: regionLevel === 3 ? '#fff' : '' }" @click.stop="check(3)"
></div
>
</header>
<ul>
<li
:class="choiceCity[regionLevel - 1] === item.name ? 'isChoice' : ''"
@click.stop="choiceItem(item)"
v-for="item in data[regionLevel]"
:key="item.code"
>{{ item.name }}</li
>
</ul>
</div>
</div>
</template>
<script lang="ts">
import { cloneDeep, isArray, isEqual, isObject } from 'lodash-es';
import { defineComponent, ref, watch, computed, onMounted } from 'vue';
import { http } from '/nerv-lib/util/http';
export default defineComponent({
name: 'NsInputCityV2',
props: {
value: {
type: Array,
default: () => {
return [];
},
},
defaultValue: {
type: Array,
default: () => {
return [];
},
},
api: {
type: String,
default: '',
},
fieldMap: {
type: Object || Array,
default: () => {
return [];
},
},
formModel: {
type: Object || Array,
},
isSeparate: {
type: Boolean,
default: false,
},
},
emits: ['change'],
setup(props, { emit }) {
// console.log(props);
const visible = ref(false);
const hasload = ref(false);
let choiceCity = ref<any[]>([]);
let choiceCityName = ref('');
let province = ref([]); //省
let city = ref([]); //市
let area = ref([]); //区
const data = ref([]);
data.value[1] = province.value;
const regionLevel = ref(1);
const showCard = () => {
visible.value = true;
};
const closeCard = () => {
visible.value = false;
};
const check = (e) => {
regionLevel.value = e;
initData(regionLevel.value);
};
const choiceItem = (e: any) => {
let currObject = [
{ name: 0, code: 3, enmpitIndex: [1, 2, 4, 5] },
{ name: 1, code: 4, enmpitIndex: [2, 5] },
{ name: 2, code: 5, enmpitIndex: [] },
];
let enmpitIndex = [[1, 2, 4, 5], [2, 5], []][regionLevel.value - 1];
let cureleve: { name: number; code: number; enmpitIndex: any[] } =
currObject[regionLevel.value - 1];
const update = () => {
let copecity = cloneDeep(choiceCity.value);
Object.keys(cureleve).forEach((el: string) => {
let index = cureleve[el];
let value = e[el];
copecity[index] = value;
});
enmpitIndex.forEach((el) => {
copecity[el] = null;
});
choiceCity.value = [...copecity];
};
switch (regionLevel.value) {
case 1:
update();
regionLevel.value = 2;
initData(2, e.code);
break;
case 2:
update();
regionLevel.value = 3;
initData(3, e.code);
break;
case 3:
update();
closeCard();
break;
}
};
const initData = (regionLevel: Number, code?: Number) => {
let parentcode = '';
switch (regionLevel) {
case 1:
province.value = [];
data.value[2] = [];
data.value[3] = [];
break;
case 2:
parentcode = choiceCity.value[3];
city.value = [];
data.value[3] = [];
break;
case 3:
parentcode = choiceCity.value[4];
area.value = [];
break;
}
async function getDate() {
try {
let body: Recordable = {};
body['regionLevel'] = regionLevel;
if (parentcode || regionLevel == 1) {
body.parentCode = parentcode;
const res = await http.get(props.api || '/api/pension/pension/objs/BaseArea', body);
if (res.success) {
switch (regionLevel) {
case 1:
province.value = res.data;
break;
case 2:
city.value = res.data;
break;
case 3:
area.value = res.data;
break;
}
data.value[regionLevel] = res.data;
}
}
} catch (err) {
console.log(err);
}
}
getDate();
};
const updateValue = (newv) => {
let leve = 0;
let code = '';
let cityMap = newv;
newv.forEach((el, i) => {
if (el) {
leve = i;
}
});
if (!props.isSeparate) {
regionLevel.value = leve > 0 ? leve : 1;
} else {
regionLevel.value = leve > 2 ? leve - 2 : 1;
}
regionLevel.value == 1 ? '' : (code = cityMap[leve - 1]);
if (!props.isSeparate) {
newv.forEach((el, i) => {
if (i === 0) {
let cityNameList = el.split('/');
cityNameList.forEach((item, index) => {
cityMap[index] = item;
});
} else {
cityMap[i + 3] = el;
}
});
} else {
cityMap = newv;
}
choiceCity.value = cityMap;
initData(regionLevel.value, code);
};
onMounted(() => {
initData(regionLevel.value);
if (isArray(props.value) && props.value.length) {
updateValue(props.value);
}
if (props.defaultValue.length) {
updateValue(props.defaultValue);
}
});
watch(
() => choiceCity.value,
(newv, oldv) => {
if (newv) {
let list = [];
newv.forEach((el, i) => {
if (el && i < 3) {
list.push(el);
}
});
choiceCityName.value = list.join('/');
if (!props.isSeparate) {
emit('change', [choiceCityName, ...newv.slice(1)]);
} else {
emit('change', newv);
}
}
},
);
watch(
() => props.value,
(newv, oldv) => {
if (!isEqual(newv, oldv) && !isEqual(newv, choiceCity.value)) {
updateValue(newv);
}
if (props.value?.length > 5 && props.value[4]) {
regionLevel.value = 3;
initData(regionLevel.value);
}
},
);
watch(
() => props.formModel,
(newv, oldv) => {
if (newv && !props.value.length && props.fieldMap.length && !hasload.value) {
let cityMap = [];
let leve = 0;
let code = '';
props.fieldMap.forEach((el, i) => {
cityMap[i] = newv[el];
if (newv[el]) {
leve = i;
}
});
if (!props.isSeparate) {
regionLevel.value = leve > 0 ? leve : 1;
} else {
regionLevel.value = leve > 2 ? leve - 2 : 1;
}
regionLevel.value == 1 ? '' : (code = cityMap[leve - 1]);
// choiceCity.value = cityMap;
updateValue(cityMap, code);
hasload.value = true;
}
},
);
watch(
() => visible.value,
(val) => {
val
? document.body.addEventListener('click', closeCard)
: document.body.removeEventListener('click', closeCard);
},
);
return {
choiceCity,
showCard,
closeCard,
regionLevel,
check,
choiceItem,
visible,
province,
city,
area,
data,
choiceCityName,
};
},
});
</script>
<style lang="less" scoped>
.selectCard {
position: absolute;
z-index: 4;
width: 300px;
height: 180px;
transform: translateY(5px);
box-shadow: 0 2px 8px rgb(0 0 0 / 15%);
animation: move-down 0.5s;
background: #fff;
border: 1px solid #ccc;
.card_header {
width: 100%;
height: 26px;
background: rgb(238, 238, 238);
display: flex;
justify-content: space-between;
border-bottom: 1px solid #ccc;
div {
text-align: center;
width: 34%;
cursor: pointer;
}
}
ul {
width: 100%;
height: 150px;
overflow: auto;
list-style: none;
padding: 10px;
li {
line-height: 30px;
cursor: pointer;
padding-left: 10px;
&:hover {
background-color: rgba(3, 141, 218, 0.1);
}
}
}
}
.isChoice {
color: rgb(3, 141, 218);
}
@keyframes move-down {
0% {
transform: scale(0);
height: 0px;
opacity: 0;
}
100% {
transform: scale(1);
height: 180px;
opacity: 1;
}
}
</style>