ui库和web端产品库合并版本(还需修复细节)
This commit is contained in:
295
ui/packages/common/AiAreaGet.vue
Normal file
295
ui/packages/common/AiAreaGet.vue
Normal file
@@ -0,0 +1,295 @@
|
||||
<template>
|
||||
<section class="AiAreaGet">
|
||||
<el-cascader v-if="refresh" ref="areaCascader" :value="value" size="small" :props="props" :show-all-levels="showAll"
|
||||
:options="options" @visible-change="editing=true" clearable
|
||||
filterable :before-filter="handleFindArea" @change="handleAfterFilter"
|
||||
v-bind="$attrs" v-on="$listeners" popper-class="popperSelectors"/>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 智能地区选择器
|
||||
* @displayName AiAreaGet
|
||||
*/
|
||||
export default {
|
||||
name: "AiAreaGet",
|
||||
inject: {
|
||||
elFormItem: {default: ""},
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change',
|
||||
},
|
||||
props: {
|
||||
/**
|
||||
* 接口方法类:必填
|
||||
*/
|
||||
instance: {default: () => null},
|
||||
/**
|
||||
* 绑定地区编码
|
||||
* @model
|
||||
*/
|
||||
value: {default: ""},
|
||||
/**
|
||||
* 是否多选
|
||||
*/
|
||||
multiple: Boolean,
|
||||
/**
|
||||
* 获取地区信息接口地址,默认为:/admin/area/queryAreaByParentId
|
||||
*/
|
||||
action: {default: "/admin/area/queryAreaByParentId"},
|
||||
/**
|
||||
* 限制获取地区编码的范围,1:省 2:地级市 3:县/区 4:镇/街道 5:村/社区
|
||||
* @values 1,2,3,4,5
|
||||
*/
|
||||
valueLevel: {default: 5},
|
||||
/**
|
||||
* 指定根级地区范围
|
||||
*/
|
||||
root: {default: ""},
|
||||
/**
|
||||
* 获取地区名称,支持.sync 双向获取绑定
|
||||
*/
|
||||
name: {default: ""},
|
||||
/**
|
||||
* 显示完整地区名称
|
||||
*/
|
||||
showAll: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
rules: [10, 8, 6, 3, 0],
|
||||
cacheOptions: [],
|
||||
editing: false,
|
||||
filterData: [],
|
||||
caches: [],
|
||||
roots: [],
|
||||
refresh: true,
|
||||
rootLoad: ""
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(v) {
|
||||
!this.editing && !this.caches.includes(this.value) && this.getCacheOptions()
|
||||
this.dispatch('ElFormItem', 'el.form.change', [v]);
|
||||
setTimeout(() => this.$emit("update:name", this.$refs.areaCascader?.inputValue))
|
||||
},
|
||||
root() {
|
||||
if (this.value) {
|
||||
this.getCacheOptions()
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
this.refresh = false
|
||||
this.$nextTick(() => this.refresh = true)
|
||||
}, 200)
|
||||
}
|
||||
},
|
||||
options: {
|
||||
handler() {
|
||||
this.$nextTick(() => this.$forceUpdate())
|
||||
}, deep: true, immediate: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fullArea() {
|
||||
const length = 12,
|
||||
getFull = v => this.rules.map(e => {
|
||||
let reg = new RegExp(`(\\d{${length-e}})\\d{${e}}`, 'g')
|
||||
return v?.replace(reg, '$1' + Array(e).fill(0).join(''))
|
||||
}).filter((e, i) => i <= this.getLevel(v))
|
||||
return this.multiple ? [this.value].flat()?.map(e => getFull(e)) : getFull(this.value)
|
||||
},
|
||||
props() {
|
||||
return {
|
||||
label: 'name',
|
||||
value: 'id',
|
||||
lazy: true,
|
||||
multiple: this.multiple,
|
||||
checkStrictly: true,
|
||||
emitPath: false,
|
||||
lazyLoad: (node, resolve) => {
|
||||
if (!(this.caches.includes(node.value) && this.fullArea.includes(node.value)) || node.loading) {
|
||||
if (node?.level == 0) {
|
||||
this.getRoots(resolve, "lazyLoad")
|
||||
} else if (node?.level > 0 && node.children?.length == 0) {
|
||||
let {id, leaf} = node.data
|
||||
leaf ? resolve([]) : this.getAreasByParent(id, resolve)
|
||||
} else resolve([])
|
||||
} else resolve([])
|
||||
}
|
||||
}
|
||||
},
|
||||
options() {
|
||||
return [...this.cacheOptions, ...this.filterData]
|
||||
},
|
||||
filtering() {
|
||||
let v = this.$refs?.areaCascader?.filtering
|
||||
if (!v) this.filterData = []
|
||||
return v
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getLevel(code) {
|
||||
let lv = -1
|
||||
this.rules.some((e, index) => {
|
||||
let reg = new RegExp(`0{${e}}$`, "g")
|
||||
if (reg.test(code)) {
|
||||
lv = index
|
||||
return true
|
||||
}
|
||||
})
|
||||
return lv
|
||||
},
|
||||
getRoots(resolve, from) {
|
||||
let url = '/admin/area/queryProvinceList'
|
||||
if (this.root) {
|
||||
url = "/admin/area/queryAreaByAreaid"
|
||||
if (this.rootLoad == this.root) {
|
||||
let waitRoots = (count = 0) => setTimeout(() => {
|
||||
if (this.roots.length > 0 || count == 5) {
|
||||
resolve(this.roots)
|
||||
} else waitRoots(++count)
|
||||
}, 500)
|
||||
return from == "lazyLoad" ? '' : waitRoots()
|
||||
}
|
||||
}
|
||||
this.rootLoad = JSON.parse(JSON.stringify(this.root))
|
||||
if (this.roots.some(e => e.id == this.root)) {
|
||||
resolve(this.roots)
|
||||
} else this.instance.post(url, null, {
|
||||
params: {id: this.root, from}, withoutToken: true
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
this.roots = [res.data].flat().map(e => ({...e, leaf: e.type == this.valueLevel}))
|
||||
resolve(this.roots)
|
||||
}
|
||||
})
|
||||
},
|
||||
getAreasByParent(id, resolve) {
|
||||
id && this.instance.post(this.action, null, {
|
||||
params: {id}, withoutToken: true,
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
resolve(res.data.map(e => ({...e, leaf: e.type == this.valueLevel})))
|
||||
}
|
||||
})
|
||||
},
|
||||
async getCacheOptions() {
|
||||
let finished = 0
|
||||
const hasChild = ids => ids?.some(e => this.fullArea?.flat()?.includes(e)),
|
||||
appendChildren = (area, resolve) => {
|
||||
let values = [this.value].flat()
|
||||
if (values.includes(area.id)) {
|
||||
finished++
|
||||
if (finished == values.length) {
|
||||
this.$emit("update:name", area.name)
|
||||
resolve()
|
||||
}
|
||||
} else this.getAreasByParent(area.id, data => {
|
||||
this.$set(area, "children", data)
|
||||
data.map(d => {
|
||||
this.caches.push(d.id)
|
||||
hasChild([d.id]) && appendChildren(d, resolve)
|
||||
})
|
||||
})
|
||||
}
|
||||
if (!!this.value?.toString()) {
|
||||
this.cacheOptions = []
|
||||
this.caches = []
|
||||
await this.getRoots(data => {
|
||||
this.caches = data?.map(e => e.id) || []
|
||||
new Promise(resolve => {
|
||||
if (hasChild(data.map(e => e.id))) {
|
||||
data.map(e => hasChild([e.id]) && appendChildren(e, resolve))
|
||||
} else resolve()
|
||||
}).then(() => {
|
||||
this.cacheOptions = data
|
||||
})
|
||||
}, "initWithValue")
|
||||
} else if (!!this.root) {
|
||||
this.caches = []
|
||||
await this.getRoots(data => {
|
||||
this.caches = data?.map(e => e.id) || []
|
||||
new Promise(resolve => {
|
||||
if (hasChild(data.map(e => e.id))) {
|
||||
data.map(e => hasChild([e.id]) && appendChildren(e, resolve))
|
||||
} else resolve()
|
||||
}).then(() => {
|
||||
this.cacheOptions = data
|
||||
})
|
||||
}, "initWithRoot")
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 表单验证
|
||||
* @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));
|
||||
}
|
||||
},
|
||||
handleFindArea(areaName) {
|
||||
return new Promise(resolve => {
|
||||
this.instance.post("/admin/area/queryAreaByAreaName", null, {
|
||||
params: {areaName}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
let range = new RegExp(`^${this.root.replace(/0+$/g, '')||'\d'}`)
|
||||
this.filterData = res.data.filter(e => !this.caches.includes(e.id) && range.test(e.id)).map(e => ({
|
||||
...e,
|
||||
leaf: e.type == this.valueLevel
|
||||
}))
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
handleAfterFilter(v) {
|
||||
this.$emit('select', this.$refs.areaCascader?.getCheckedNodes(true))
|
||||
this.$refs.areaCascader?.toggleDropDownVisible(false)
|
||||
if (!this.multiple) {
|
||||
if (this.filterData?.length > 0) {
|
||||
this.filterData = []
|
||||
}
|
||||
this.editing = this.caches.includes(v);
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
setTimeout(() => {
|
||||
this.cacheOptions.length == 0 && this.getCacheOptions()
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AiAreaGet {
|
||||
width: 100%;
|
||||
|
||||
.el-cascader {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
.popperSelectors {
|
||||
.el-cascader-menu__wrap {
|
||||
height: 300px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user