ui库和web端产品库合并版本(还需修复细节)
This commit is contained in:
368
ui/packages/common/AiArea.vue
Normal file
368
ui/packages/common/AiArea.vue
Normal file
@@ -0,0 +1,368 @@
|
||||
<template>
|
||||
<section class="ai-area">
|
||||
<div v-if="inputClicker" @click="chooseArea" class="input-clicker">
|
||||
<el-row type="flex" justify="space-between">
|
||||
<div class="prepend">
|
||||
<i style="font-size: 16px" class="iconfont iconLocation"/>
|
||||
切换地区
|
||||
</div>
|
||||
<div class="content nowarp-text fill" v-text="fullName"/>
|
||||
<i class="iconfont iconChange pad-r10"/>
|
||||
</el-row>
|
||||
</div>
|
||||
<el-button v-else-if="!customClicker" class="area-btn" type="primary" size="mini" @click="chooseArea">
|
||||
{{ btnShowArea ? selectedName : "切换地区" }}
|
||||
</el-button>
|
||||
<a class="custom-clicker" v-else @click="chooseArea">
|
||||
<slot :areaname="selectedName" :fullname="fullName" :id="selected" :areatype="selectedAreaType"/>
|
||||
</a>
|
||||
<ai-dialog :visible.sync="dialog" title="选择地区" width="60%" @onConfirm="confirmArea" @open="selected=(value||'')">
|
||||
<ai-highlight content="您当前选择 @v" :value="selectedName" color="#333" bold/>
|
||||
<div class="area_edge">
|
||||
<div class="area-box" v-for="ops in showOps">
|
||||
<h2 v-text="ops.header"/>
|
||||
<div class="area-item" :class="{selected: selectedMap.includes(area.id)}" v-for="area in ops.list"
|
||||
@click="getChildrenAreas(area)">
|
||||
<ai-badge>
|
||||
<span>{{ area.name }}</span>
|
||||
<div slot="badge" v-if="showBadge&&area.tipName" :class="getLabelClassByLabelType(area.labelType)">
|
||||
{{ area.tipName }}
|
||||
</div>
|
||||
</ai-badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ai-dialog>
|
||||
</section>
|
||||
</template>
|
||||
<script>
|
||||
import AiHighlight from "../layout/AiHighlight";
|
||||
import instance from "../../meta/js/request";
|
||||
import Area from "../../meta/js/area";
|
||||
|
||||
export default {
|
||||
name: 'AiArea',
|
||||
components: {AiHighlight},
|
||||
inject: {
|
||||
elFormItem: {default: ""},
|
||||
elForm: {default: ''},
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change'
|
||||
},
|
||||
props: {
|
||||
instance: {default: () => instance},
|
||||
action: String,
|
||||
areaLevel: {type: [Number, String], default: 5},
|
||||
btnShowArea: {type: Boolean, default: false},
|
||||
customClicker: {type: Boolean, default: false},
|
||||
disabled: {type: Boolean, default: false},
|
||||
hideLevel: {type: [Number, String], default: 0},
|
||||
inputClicker: {type: Boolean, default: true},
|
||||
provinceAction: String,
|
||||
separator: {type: String, default: ""},
|
||||
showBadge: {type: Boolean, default: true},
|
||||
value: String,
|
||||
valueLevel: {type: [Number, String], default: -1}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selected: null,
|
||||
areaOps: [],
|
||||
fullName: '',
|
||||
dialog: false,
|
||||
ProvinceCityCounty: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentArea: v => v.selected || v.value,
|
||||
selectedArea: v => new Area(v.currentArea, v.hashMap),
|
||||
startLevel: v => Number(v.hideLevel) || 0,//地区最高可选行政地区等级
|
||||
endLevel: v => Number(v.areaLevel) || 0,//地区最低可选行政地区等级
|
||||
selectedName: v => v.selectedArea.name || "无",
|
||||
validateState: v => ['', 'success'].includes(v.elFormItem?.validateState),
|
||||
selectedMap: v => v.selectedArea.areaMap,
|
||||
hashMap() {
|
||||
//地区数据缓存器,用于快速获取数据
|
||||
const hash = {}
|
||||
this.areaOps.flat().map(e => hash[e.id] = e)
|
||||
return hash
|
||||
},
|
||||
showOps() {
|
||||
const levelLabels = {
|
||||
0: "省/直辖市",
|
||||
1: "市",
|
||||
2: "县/区",
|
||||
3: "乡/镇/街道",
|
||||
4: "村/社区"
|
||||
}
|
||||
let ops = this.areaOps.map((list, i) => ({
|
||||
header: levelLabels[i], list
|
||||
})).slice(Math.max(0, this.startLevel), this.endLevel)
|
||||
if (this.startLevel > 0 && ops.length > 0) {
|
||||
ops[0].list = ops[0].list.filter(e => e.id == this.selectedMap[this.startLevel])
|
||||
}
|
||||
return ops
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
immediate: true,
|
||||
handler(v) {
|
||||
this.dispatch('ElFormItem', 'el.form.change', [v]);
|
||||
this.initAreaName()
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
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));
|
||||
}
|
||||
},
|
||||
chooseArea() {
|
||||
if (this.disabled) return
|
||||
this.selected = this.$copy(this.value)
|
||||
this.initOptions().then(() => this.dialog = true)
|
||||
},
|
||||
confirmArea() {
|
||||
if (this.valueLevel > -1) {
|
||||
this.$emit("change", this.selectedMap[this.valueLevel])
|
||||
} else {
|
||||
this.$emit("change", this.selected)
|
||||
}
|
||||
this.$emit("area", this.selected, this.selectedArea);
|
||||
this.dialog = false
|
||||
},
|
||||
getChildrenAreas(area) {
|
||||
this.selected = area.id;
|
||||
const level = Area.getLevelByAreaId(area.id);
|
||||
if (level < 4) {
|
||||
this.getAreasByParentId(area.id).then(list => {
|
||||
this.areaOps.splice(level + 1, 5, list)
|
||||
})
|
||||
}
|
||||
},
|
||||
getAreasByParentId(id) {
|
||||
const level = Area.getLevelByAreaId(id)
|
||||
return new Promise(resolve => {
|
||||
if (level < 2) {
|
||||
this.getProvinceCityCounty().then(() => {
|
||||
resolve(this.ProvinceCityCounty.filter(e => e.parentId == id))
|
||||
})
|
||||
} else {
|
||||
this.instance.post(this.action || "/admin/area/queryAreaByParentId", null, {
|
||||
withoutToken: true,
|
||||
params: {id}
|
||||
}).then(res => {
|
||||
if (res?.data) {
|
||||
resolve(res.data)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
getLabelClassByLabelType(type) {
|
||||
let cls = "badge-label"
|
||||
switch (type) {
|
||||
case '1':
|
||||
cls += ' label-town'
|
||||
break;
|
||||
case '3':
|
||||
cls += ' label-village'
|
||||
break;
|
||||
default:
|
||||
cls += ' label-poor'
|
||||
break
|
||||
}
|
||||
return cls
|
||||
},
|
||||
getProvinceCityCounty() {
|
||||
return new Promise(resolve => {
|
||||
if (localStorage.getItem("ProvinceCityCounty")) {
|
||||
resolve(JSON.parse(localStorage.getItem("ProvinceCityCounty")))
|
||||
} else {
|
||||
this.instance.post(this.provinceAction || "/admin/area/queryProvinceListContainCity", null, {
|
||||
withoutToken: true
|
||||
}).then(res => {
|
||||
if (res && res.data) {
|
||||
localStorage.setItem("ProvinceCityCounty", JSON.stringify(res.data))
|
||||
resolve(res.data)
|
||||
}
|
||||
})
|
||||
}
|
||||
}).then(list => this.ProvinceCityCounty = list)
|
||||
},
|
||||
initOptions() {
|
||||
this.areaOps = []
|
||||
let map = {};
|
||||
return Promise.all([null, ...this.selectedMap].map((id, i) => this.getAreasByParentId(id).then(list => map[i] = list))).then(() => {
|
||||
this.areaOps = Object.values(map)
|
||||
})
|
||||
},
|
||||
initAreaName() {
|
||||
if (this.value) {
|
||||
Area.createByAction(this.currentArea, this.instance).then(names => {
|
||||
this.selectedArea.getName(names)
|
||||
this.fullName = this.selectedArea.nameMap.join(this.separator)
|
||||
this.$emit("update:name", this.selectedName)
|
||||
this.$emit("fullname", this.fullName)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ai-area {
|
||||
.area-btn {
|
||||
box-shadow: 0 2px 8px 0 rgba(76, 132, 255, 0.6);
|
||||
}
|
||||
|
||||
.input-clicker {
|
||||
width: 320px;
|
||||
cursor: pointer;
|
||||
border: 1px solid #D0D4DC;
|
||||
line-height: 32px;
|
||||
border-radius: 2px;
|
||||
font-size: 14px;
|
||||
|
||||
.prepend {
|
||||
background: rgba(245, 245, 245, 1);
|
||||
width: auto;
|
||||
border-right: 1px solid #D0D4DC;
|
||||
padding: 0 8px;
|
||||
white-space: nowrap;
|
||||
|
||||
}
|
||||
|
||||
.content {
|
||||
text-align: left;
|
||||
padding-left: 14px;
|
||||
padding-right: 8px;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.suffix {
|
||||
width: auto;
|
||||
padding: 0 12px
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: $primaryColor;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-clicker {
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.area_edge {
|
||||
max-height: 350px;
|
||||
overflow-y: auto;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.area-box {
|
||||
box-shadow: 0px -1px 0px 0px rgba(238, 238, 238, 1);
|
||||
padding: 16px 0 8px 0;
|
||||
|
||||
& > section {
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
& > h2 {
|
||||
color: rgba(51, 51, 51, 1);
|
||||
line-height: 22px;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.area-item {
|
||||
display: inline-block;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #D0D4DC;
|
||||
margin: 8px 8px 8px 0;
|
||||
padding: 3px 10px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
line-height: normal;
|
||||
font-size: 14px;
|
||||
|
||||
&:hover {
|
||||
color: rgba($primaryColor, .8);
|
||||
border-color: rgba($primaryColor, .8);
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ddd;
|
||||
line-height: normal;
|
||||
margin: 5px;
|
||||
padding: 3px;
|
||||
cursor: pointer;
|
||||
|
||||
span {
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: rgba($primaryColor, .8);
|
||||
border-color: rgba($primaryColor, .8);
|
||||
}
|
||||
}
|
||||
|
||||
.selected {
|
||||
color: rgba($primaryColor, .8);
|
||||
border-color: rgba($primaryColor, .8);
|
||||
}
|
||||
}
|
||||
|
||||
.badge-label {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
border-radius: 15px;
|
||||
color: #fff;
|
||||
width: 12px;
|
||||
letter-spacing: 10px;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
padding: 3px 5px;
|
||||
white-space: nowrap;
|
||||
transition: width 1s, letter-spacing 0.05s;
|
||||
|
||||
&.label-town {
|
||||
background: rgba($primaryColor, .8);
|
||||
}
|
||||
|
||||
&.label-village {
|
||||
background: rgba($primaryColor, .8);
|
||||
}
|
||||
|
||||
&.label-poor {
|
||||
background: #ffb14c;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
width: initial;
|
||||
letter-spacing: unset;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user