<!-- @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>