274 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			274 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | |
|   <section class="AiAreaSelect">
 | |
|     <el-row type="flex" :gutter="5">
 | |
|       <el-col v-for="(item,i) in areaInfo" :key="i" v-show="isShowSelector(i)" style="width: auto;">
 | |
|         <el-select :size="selectClass" v-if="areaLists[i].length>0||alwaysShow" @focus="$emit('focus')"
 | |
|                    @blur="$emit('blur')" :placeholder="placeVal[i]" clearable
 | |
|                    :disabled="isDisabledSelector(i)" :value="areaInfo[i]" @change="v=>handleSelectorChange(v,i)">
 | |
|           <template v-if="lockFirstOption&&i==(hideNum||0)">
 | |
|             <el-option v-if="!areaInfo[i]||areaInfo[i]===area.id" v-for="(area,j) in areaLists[i]" :key="j"
 | |
|                        :value="area.id" :label="area.name"/>
 | |
|           </template>
 | |
|           <el-option v-else v-for="(area,j) in areaLists[i]" :key="j" :value="area.id" :label="area.name"/>
 | |
|         </el-select>
 | |
|       </el-col>
 | |
|     </el-row>
 | |
|   </section>
 | |
| </template>
 | |
| 
 | |
| <script>
 | |
| export default {
 | |
|   name: "AiAreaSelect",
 | |
|   model: {
 | |
|     prop: 'value',
 | |
|     event: 'change',
 | |
|   },
 | |
|   inject: {
 | |
|     elFormItem: {default: ""},
 | |
|   },
 | |
|   props: {
 | |
|     value: String,
 | |
|     areaLevel: {type: [Number, String], default: 5},
 | |
|     disabledLevel: {type: [Number, String], default: 0},
 | |
|     disabled: {type: Boolean, default: false},
 | |
|     hideLevel: {type: [Number, String], default: 0},
 | |
|     valueLevel: {type: [Number, String], default: -1},
 | |
|     alwaysShow: {type: Boolean, default: false},
 | |
|     selectClass: {type: String, default: 'small'},
 | |
|     lockFirstOption: {type: Boolean, default: false},
 | |
|     instance: Function,
 | |
|     action: String,
 | |
|     provinceAction: String
 | |
|   },
 | |
|   computed: {
 | |
|     hideNum() {
 | |
|       return Number(this.hideLevel)
 | |
|     },
 | |
|     disabledNum() {
 | |
|       return Number(this.disabledLevel)
 | |
|     },
 | |
|     showNum() {
 | |
|       return Number(this.areaLevel)
 | |
|     },
 | |
|     valueIndex() {
 | |
|       return Number(this.valueLevel)
 | |
|     },
 | |
|     current() {
 | |
|       return this.selected || this.value
 | |
|     },
 | |
|     areaInfo() {
 | |
|       let info = {}
 | |
|       const currentLevel = this.getLevelByAreaId(this.current)
 | |
|       for (let i = 0; i < this.showNum; i++) {
 | |
|         //防止地区代码出现,在获取到选项后再赋值
 | |
|         if (i <= currentLevel) info[i] = this.areaLists[i]?.length ? this.getAreaByAreaType(i) : ""
 | |
|         else info[i] = null
 | |
|       }
 | |
|       return info
 | |
|     },
 | |
|     areaObj() {
 | |
|       let info = {}
 | |
|       for (let key in this.areaInfo) {
 | |
|         if (this.areaInfo[key]) {
 | |
|           info[key] = this.areaLists[key].find(e => e.id === this.areaInfo[key])
 | |
|         }
 | |
|       }
 | |
|       return info
 | |
|     },
 | |
|     selectedName() {
 | |
|       const index = this.getLevelByAreaId(this.current)
 | |
|       if (index > -1) {
 | |
|         const area = this.areaLists[index].find(e => e.id === this.current)
 | |
|         return area ? area.name : ""
 | |
|       } else return ""
 | |
|     },
 | |
|     selectedFullName() {
 | |
|       let name = ""
 | |
|       for (let i in this.areaInfo) {
 | |
|         if (this.areaInfo[i]) {
 | |
|           const area = this.areaLists[i].find(e => e.id === this.areaInfo[i])
 | |
|           name += area ? area.name : ""
 | |
|         }
 | |
|       }
 | |
|       return name
 | |
|     },
 | |
|     areaLelve() {
 | |
|       return this.getLevelByAreaId(this.current);
 | |
|     }
 | |
|   },
 | |
|   watch: {
 | |
|     selected() {
 | |
|       if (this.valueIndex > -1) {
 | |
|         this.$emit("change", this.areaInfo[this.valueIndex] || null)
 | |
|       } else {
 | |
|         this.$emit("change", this.current)
 | |
|       }
 | |
|       this.$emit("area", this.areaInfo);
 | |
|       this.$emit('areaLelve', this.areaLelve)
 | |
|     },
 | |
|     areaObj() {
 | |
|       this.$emit("areaObj", this.areaObj)
 | |
|     },
 | |
|     selectedName() {
 | |
|       this.$emit("name", this.selectedName)
 | |
|     },
 | |
|     selectedFullName() {
 | |
|       this.$emit("fullname", this.selectedFullName)
 | |
|     },
 | |
|     valueLevel() {
 | |
|       this.refreshAreaList();
 | |
|     },
 | |
|     value(v) {
 | |
|       //特殊处置结果 后台传值赋值改变需要重新加载数据
 | |
|       this.dispatch('ElFormItem', 'el.form.change', [v]);
 | |
|       if (!this.selected) {
 | |
|         this.refreshAreaList();
 | |
|       }
 | |
|     }
 | |
|   },
 | |
|   data() {
 | |
|     return {
 | |
|       selected: null,
 | |
|       areaLists: {
 | |
|         0: [],
 | |
|         1: [],
 | |
|         2: [],
 | |
|         3: [],
 | |
|         4: [],
 | |
|       },
 | |
|       placeVal: {
 | |
|         0: '请选择省',
 | |
|         1: '请选择市',
 | |
|         2: '请选择区',
 | |
|         3: '请选择镇',
 | |
|         4: '请选择村'
 | |
|       },
 | |
|       ProvinceCityCounty: []
 | |
|     }
 | |
|   },
 | |
|   methods: {
 | |
|     isShowSelector(i) {
 | |
|       let index = Number(i)
 | |
|       return index >= this.hideNum
 | |
|     },
 | |
|     isDisabledSelector(i) {
 | |
|       let index = Number(i)
 | |
|       return this.disabled || (index < this.disabledNum)
 | |
|     },
 | |
|     handleSelectorChange(area, index) {
 | |
|       if (area) {
 | |
|         this.selected = area
 | |
|         if (index < 4 && this.areaInfo[index]) {
 | |
|           this.getAreasByParentId(index).then(() => {
 | |
|             for (let i = index; i < this.showNum; i++) {
 | |
|               if (this.areaLists[i + 2]) this.areaLists[i + 2] = []
 | |
|             }
 | |
|           })
 | |
|         }
 | |
|       } else {//清空操作
 | |
|         let i = Number(index), pre = i - 1, origin = JSON.parse(JSON.stringify(this.areaInfo))
 | |
|         if (pre > 0) {
 | |
|           this.selected = origin[pre]
 | |
|           for (let j = i + 1; j < this.showNum; j++) {
 | |
|             this.areaLists[j] = []
 | |
|           }
 | |
|         } else {
 | |
|           this.selected = origin[0]
 | |
|           for (let j = i + 2; j < this.showNum; j++) {
 | |
|             this.areaLists[j] = []
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     },
 | |
|     getAreasByParentId(index) {
 | |
|       index = Number(index)
 | |
|       return new Promise((resolve) => {
 | |
|         this.areaLists[index + 1] = []
 | |
|         if (index < 2) {
 | |
|           index = Number(index)
 | |
|           let data = this.ProvinceCityCounty.filter(e => e.parentId == this.areaInfo[index])
 | |
|           if (data && (index + 1 < this.showNum)) this.areaLists[index + 1] = data
 | |
|           this.$forceUpdate();
 | |
|           resolve(index)
 | |
|         } else {
 | |
|           this.instance.post(this.action || "/admin/area/queryAreaByParentId", null, {
 | |
|             withoutToken: true,
 | |
|             params: {id: this.areaInfo[index]}
 | |
|           }).then(res => {
 | |
|             if (res?.data) {
 | |
|               index = Number(index)
 | |
|               if (index + 1 < this.showNum) this.areaLists[index + 1] = res.data
 | |
|               this.$forceUpdate()
 | |
|             }
 | |
|             resolve(index)
 | |
|           })
 | |
|         }
 | |
| 
 | |
|       })
 | |
|     },
 | |
|     getProvinceCityCounty() {
 | |
|       return this.instance.post(this.provinceAction || "/admin/area/queryProvinceListContainCity", null, {withoutToken: true})
 | |
|     },
 | |
|     getAreaByAreaType(areaType) {
 | |
|       let lvCount = [2, 4, 6, 9, 12]
 | |
|       return this.current?.split("").map((e, i) => i < lvCount[areaType] ? e : 0).join("")
 | |
|     },
 | |
|     getLevelByAreaId(code) {
 | |
|       if (code) {
 | |
|         if (code.length == 2 || code.endsWith('0000000000')) return 0
 | |
|         else if (code.endsWith('00000000')) return 1
 | |
|         else if (code.endsWith('000000')) return 2
 | |
|         else if (code.endsWith('000')) return 3
 | |
|         else return 4
 | |
|       } else return -1
 | |
|     },
 | |
|     refreshAreaList() {
 | |
|       for (let i = 0; i < this.showNum; i++) {
 | |
|         this.areaLists[i] = []
 | |
|       }
 | |
|       this.getProvinceCityCounty().then(res => {
 | |
|         this.ProvinceCityCounty = res.data
 | |
|         this.areaLists[0] = res.data.filter(d => !d.parentId)
 | |
|         const getAreaList = i => {
 | |
|           if (this.areaInfo?.[i])
 | |
|             this.getAreasByParentId(i).then(next => getAreaList(next + 1))
 | |
|         }
 | |
|         getAreaList(0)
 | |
|       })
 | |
|     },
 | |
|     /**
 | |
|      * 表单验证
 | |
|      * @param componentName
 | |
|      * @param eventName
 | |
|      * @param params
 | |
|      */
 | |
|     dispatch(componentName, eventName, params) {
 | |
|       let parent = this.$parent || this.$root;
 | |
|       let name = parent.$options.componentName;
 | |
| 
 | |
|       while (parent && (!name || name !== componentName)) {
 | |
|         parent = parent.$parent;
 | |
| 
 | |
|         if (parent) {
 | |
|           name = parent.$options.componentName;
 | |
|         }
 | |
|       }
 | |
|       if (parent) {
 | |
|         parent.$emit.apply(parent, [eventName].concat(params));
 | |
|       }
 | |
|     },
 | |
|   },
 | |
|   created() {
 | |
|     this.refreshAreaList()
 | |
|   }
 | |
| }
 | |
| </script>
 | |
| 
 | |
| <style lang="scss" scoped>
 | |
| .AiAreaSelect {
 | |
|   .el-col {
 | |
|     min-width: 90px;
 | |
|   }
 | |
| }
 | |
| </style>
 |