|
@@ -0,0 +1,1157 @@
|
|
|
+<template>
|
|
|
+ <Layout
|
|
|
+ ref="layoutRef"
|
|
|
+ :type="type"
|
|
|
+ :placeholder="placeholder"
|
|
|
+ :trigger="trigger"
|
|
|
+ :value="computedVal"
|
|
|
+ @visible="onVisibleChange"
|
|
|
+ >
|
|
|
+ <div slot="empty" class="zhima-bid--wrap dropdown-content--wrap">
|
|
|
+ <div class="dropdown-content--hd" v-if="showSearch">
|
|
|
+ <div class="dropdown-content--hd-item dropdown-content--hd-left">
|
|
|
+ <el-input
|
|
|
+ size="small"
|
|
|
+ clearable
|
|
|
+ placeholder="请输入标签名称搜索"
|
|
|
+ suffix-icon="el-icon-search"
|
|
|
+ v-model="searchContent"
|
|
|
+ @keyup.native="onKeyup"
|
|
|
+ @focus="onFocus"
|
|
|
+ @blur="onBlur"
|
|
|
+ @keydown.native="onKeydown"
|
|
|
+ :class="{ 'input-focus': inputFocus }"
|
|
|
+ >
|
|
|
+ </el-input>
|
|
|
+ </div>
|
|
|
+ <div class="dropdown-content--hd-item dropdown-content--hd-right">
|
|
|
+ <slot name="header-right"></slot>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="dropdown-content--bd">
|
|
|
+ <div class="module-container level-1-container">
|
|
|
+ <header class="module-header"></header>
|
|
|
+ <div class="list-empty-container" v-if="searchEmpty">
|
|
|
+ 暂无相关选项
|
|
|
+ </div>
|
|
|
+ <div class="module-main">
|
|
|
+ <ul>
|
|
|
+ <li
|
|
|
+ class="module-item"
|
|
|
+ @mouseover="onLevel1MouseOver(level1, pIndex)"
|
|
|
+ @mouseout="onLevel1MouseOut($event)"
|
|
|
+ :class="{ active: pActive === pIndex }"
|
|
|
+ v-for="(level1, pIndex) in level1List"
|
|
|
+ v-show="!level1.searchHide"
|
|
|
+ :key="level1.name"
|
|
|
+ >
|
|
|
+ <el-checkbox
|
|
|
+ v-model="level1.checked"
|
|
|
+ :indeterminate="level1.indeterminate"
|
|
|
+ @change="onProvinceChange($event, level1, pIndex)"
|
|
|
+ ></el-checkbox>
|
|
|
+ <span
|
|
|
+ class="item-name"
|
|
|
+ @click.self="onOpenLevel2(level1, pIndex)"
|
|
|
+ v-html="level1.label"
|
|
|
+ ></span>
|
|
|
+ <i class="el-icon-arrow-right"></i>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="module-container level-2-container">
|
|
|
+ <header class="module-header"></header>
|
|
|
+ <div class="module-main">
|
|
|
+ <ul>
|
|
|
+ <li
|
|
|
+ class="module-item"
|
|
|
+ @mouseover="onLevel2MouseOver(level2, cIndex)"
|
|
|
+ @mouseout="onLevel2MouseOut($event)"
|
|
|
+ :class="{ active: cActive === cIndex }"
|
|
|
+ v-for="(level2, cIndex) in level2List"
|
|
|
+ v-show="!level2.searchHide"
|
|
|
+ :key="level2.name"
|
|
|
+ >
|
|
|
+ <el-checkbox
|
|
|
+ v-model="level2.checked"
|
|
|
+ :disabled="level2.disabled"
|
|
|
+ :indeterminate="level2.indeterminate"
|
|
|
+ @change="onCitiesChange($event, level2, cIndex)"
|
|
|
+ ></el-checkbox>
|
|
|
+ <span
|
|
|
+ class="item-name"
|
|
|
+ @click.self="onOpenLevel3(level2, cIndex)"
|
|
|
+ v-html="level2.label"
|
|
|
+ ></span>
|
|
|
+ <i class="el-icon-arrow-right"></i>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="module-container level-3-container">
|
|
|
+ <header class="module-header"></header>
|
|
|
+ <div class="module-main">
|
|
|
+ <ul>
|
|
|
+ <li
|
|
|
+ class="module-item"
|
|
|
+ v-for="(level3, index) in level3List"
|
|
|
+ :key="level3 + index"
|
|
|
+ v-show="!level3.searchHide"
|
|
|
+ >
|
|
|
+ <el-checkbox
|
|
|
+ v-model="level3.checked"
|
|
|
+ :disabled="level3.disabled"
|
|
|
+ :indeterminate="level3.indeterminate"
|
|
|
+ @change="onLevel3Change($event, level3)"
|
|
|
+ ></el-checkbox>
|
|
|
+ <span class="item-name" v-html="level3.label"></span>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <template #suffix-icon>
|
|
|
+ <slot name="suffix-icon">
|
|
|
+ <el-tooltip effect="dark" placement="bottom" v-if="showHelpIcon">
|
|
|
+ <div class="iconfont icon-help pointer zhima-bid--icon"></div>
|
|
|
+ <div slot="content" class="zhima-bid-help-tip" v-html="helpIconText"></div>
|
|
|
+ </el-tooltip>
|
|
|
+ </slot>
|
|
|
+ </template>
|
|
|
+ </Layout>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { Tag, Checkbox, Input, Tooltip } from 'element-ui'
|
|
|
+import Layout from '@/components/filter-items/Layout.vue'
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'ZhiMaBidSelector',
|
|
|
+ components: {
|
|
|
+ [Tag.name]: Tag,
|
|
|
+ [Input.name]: Input,
|
|
|
+ [Checkbox.name]: Checkbox,
|
|
|
+ [Tooltip.name]: Tooltip,
|
|
|
+ Layout
|
|
|
+ },
|
|
|
+ props: {
|
|
|
+ showSearch: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ sourceList: {
|
|
|
+ type: Array,
|
|
|
+ default: () => [
|
|
|
+ // {
|
|
|
+ // label: 'xxx',
|
|
|
+ // value: 'xxx',
|
|
|
+ // children: [
|
|
|
+ // {
|
|
|
+ // label: 'xx',
|
|
|
+ // value: 'xx'
|
|
|
+ // }
|
|
|
+ // ]
|
|
|
+ // }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ showHelpIcon: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ helpIconText: {
|
|
|
+ type: String,
|
|
|
+ default: ''
|
|
|
+ },
|
|
|
+ type: {
|
|
|
+ type: String,
|
|
|
+ default: 'dropdown'
|
|
|
+ },
|
|
|
+ trigger: {
|
|
|
+ type: String,
|
|
|
+ default: 'hover'
|
|
|
+ },
|
|
|
+ placeholder: {
|
|
|
+ type: String,
|
|
|
+ default: ''
|
|
|
+ },
|
|
|
+ // 是否展示level1的全部
|
|
|
+ isHaveAll: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },
|
|
|
+ value: {
|
|
|
+ type: Object,
|
|
|
+ default: () => {}
|
|
|
+ },
|
|
|
+ formatSourceData: Function,
|
|
|
+ },
|
|
|
+ model: {
|
|
|
+ prop: 'value',
|
|
|
+ event: 'change'
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ searchContent: '',
|
|
|
+ inputFocus: false,
|
|
|
+ tags: [],
|
|
|
+ pActive: 0,
|
|
|
+ cActive: 0,
|
|
|
+ level1List: [],
|
|
|
+ level2List: [],
|
|
|
+ level3List: [],
|
|
|
+ pTimer: null,
|
|
|
+ cTimer: null
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ computedVal() {
|
|
|
+ let count = this.tags.length
|
|
|
+ const value = this.value
|
|
|
+ if (!value) return ''
|
|
|
+ const emptyObj = Object.keys(value).length === 0
|
|
|
+ if (count <= 0 || emptyObj) {
|
|
|
+ return ''
|
|
|
+ } else {
|
|
|
+ return `${this.placeholder}${count}个`
|
|
|
+ }
|
|
|
+ },
|
|
|
+ showedLevel1List() {
|
|
|
+ return this.level1List.filter((v) => !v.searchHide)
|
|
|
+ },
|
|
|
+ // 是否没有搜索到数据
|
|
|
+ searchEmpty() {
|
|
|
+ if (this.searchContent && this.showedLevel1List.length === 0) {
|
|
|
+ return true
|
|
|
+ } else {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ value(val) {
|
|
|
+ this.setState(val)
|
|
|
+ },
|
|
|
+ searchContent(n) {
|
|
|
+ // 思路:
|
|
|
+ // 1. 对其显示隐藏做标记,level1、level2和level3则用computed过滤
|
|
|
+ //
|
|
|
+ this.calcMatch(n)
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.openLevel1First()
|
|
|
+ })
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.refreshSourceList(this.sourceList)
|
|
|
+ this.calcMatch()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ calcMatch(searchValue = '') {
|
|
|
+ this.level1List.forEach((level1) => {
|
|
|
+ // 一级匹配
|
|
|
+ const { searchShow: level1ItemShow } = this.doMatch(searchValue, level1)
|
|
|
+ this.$set(level1, 'searchHide', !level1ItemShow)
|
|
|
+ // 二级匹配
|
|
|
+ level1.children.forEach((level2) => {
|
|
|
+ // 如果一级匹配到了,其子集都要显示
|
|
|
+ const { searchShow: level2ItemShow } = this.doMatch(
|
|
|
+ searchValue,
|
|
|
+ level2
|
|
|
+ )
|
|
|
+ let needHide = !level2ItemShow
|
|
|
+ if (level1ItemShow) {
|
|
|
+ needHide = false
|
|
|
+ }
|
|
|
+ this.$set(level2, 'searchHide', needHide)
|
|
|
+ if (level2ItemShow) {
|
|
|
+ this.$set(level1, 'searchHide', false)
|
|
|
+ }
|
|
|
+
|
|
|
+ level2.children.forEach((level3) => {
|
|
|
+ const { searchShow: level3ItemShow } = this.doMatch(
|
|
|
+ searchValue,
|
|
|
+ level3
|
|
|
+ )
|
|
|
+ let needHide = !level3ItemShow
|
|
|
+ if (level1ItemShow || level2ItemShow) {
|
|
|
+ needHide = false
|
|
|
+ }
|
|
|
+ this.$set(level3, 'searchHide', needHide)
|
|
|
+ if (level3ItemShow) {
|
|
|
+ this.$set(level1, 'searchHide', false)
|
|
|
+ this.$set(level2, 'searchHide', false)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ doMatch(searchValue, item) {
|
|
|
+ let notAll = true
|
|
|
+ if (searchValue) {
|
|
|
+ notAll = item.name !== '全部'
|
|
|
+ }
|
|
|
+
|
|
|
+ const matched = item.name?.includes(searchValue)
|
|
|
+ if (matched && searchValue) {
|
|
|
+ item.label = item.name.replace(
|
|
|
+ searchValue,
|
|
|
+ `<span class="highlight-text">${searchValue}</span>`
|
|
|
+ )
|
|
|
+ } else {
|
|
|
+ item.label = item.name
|
|
|
+ }
|
|
|
+
|
|
|
+ let searchShow = true
|
|
|
+ if (searchValue) {
|
|
|
+ searchShow = notAll && matched
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ notAll,
|
|
|
+ matched,
|
|
|
+ searchShow
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onFocus() {
|
|
|
+ this.onKeydown()
|
|
|
+ this.inputFocus = true
|
|
|
+ },
|
|
|
+ onBlur() {
|
|
|
+ this.inputFocus = false
|
|
|
+ },
|
|
|
+ refreshSourceList(list) {
|
|
|
+ if (Array.isArray(list)) {
|
|
|
+ this.initAreaMap(list)
|
|
|
+
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.calcMatch()
|
|
|
+ })
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 获取选中的数据列表tag
|
|
|
+ getSelectedTags() {
|
|
|
+ const tagsArr = []
|
|
|
+ this.level1List.forEach((level1) => {
|
|
|
+ if (Array.isArray(level1.children)) {
|
|
|
+ level1.children.forEach((level2) => {
|
|
|
+ if (Array.isArray(level2.children)) {
|
|
|
+ level2.children.forEach((level3) => {
|
|
|
+ if (level3.name !== '全部') {
|
|
|
+ if (level3.checked) {
|
|
|
+ tagsArr.push(level3.name)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.tags = tagsArr
|
|
|
+ return tagsArr
|
|
|
+ },
|
|
|
+ // 整理城市数据列表
|
|
|
+ initAreaMap(list) {
|
|
|
+ const level1List = this.getStandardData(list)
|
|
|
+ // 如果需要包含全国选项
|
|
|
+ if (this.isHaveAll) {
|
|
|
+ level1List.unshift({
|
|
|
+ name: '全部',
|
|
|
+ label: '全部',
|
|
|
+ checked: false,
|
|
|
+ disabled: false,
|
|
|
+ indeterminate: false,
|
|
|
+ children: []
|
|
|
+ })
|
|
|
+ }
|
|
|
+ level1List.forEach((level1) => {
|
|
|
+ level1.children.unshift({
|
|
|
+ name: '全部',
|
|
|
+ label: '全部',
|
|
|
+ checked: false,
|
|
|
+ disabled: false,
|
|
|
+ indeterminate: false,
|
|
|
+ children: []
|
|
|
+ })
|
|
|
+ level1.children.forEach((level2) => {
|
|
|
+ level2.children.unshift({
|
|
|
+ name: '全部',
|
|
|
+ label: '全部',
|
|
|
+ checked: false,
|
|
|
+ disabled: level2.children.length === 0,
|
|
|
+ indeterminate: false
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+ this.level1List = level1List
|
|
|
+
|
|
|
+ // 默认打开第一个城市、区县
|
|
|
+ this.openLevel1First()
|
|
|
+ },
|
|
|
+ openLevel1First(level1List = this.level1List) {
|
|
|
+ // 默认打开第一个城市、区县
|
|
|
+ if (this.searchContent) {
|
|
|
+ // 找到子集第一个hide为false的子集展示
|
|
|
+ const r2 = this.findFirstShowChildren(level1List)
|
|
|
+ this.level2List = r2.list
|
|
|
+ this.pActive = r2.index
|
|
|
+ const r3 = this.findFirstShowChildren(this.level2List)
|
|
|
+ this.level3List = r3.list
|
|
|
+ this.cActive = r3.index
|
|
|
+ } else {
|
|
|
+ this.level2List = level1List[0].children
|
|
|
+ this.level3List = level1List[0].children[0].children
|
|
|
+ }
|
|
|
+ },
|
|
|
+ findFirstShowChildren(levelList) {
|
|
|
+ const findIndex = levelList.findIndex((t) => !t.searchHide)
|
|
|
+ if (findIndex > 0) {
|
|
|
+ return {
|
|
|
+ list: levelList[findIndex]?.children || [],
|
|
|
+ index: findIndex
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return {
|
|
|
+ list: [],
|
|
|
+ index: 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 返回需要的数组格式
|
|
|
+ */
|
|
|
+ getStandardData(initData = []) {
|
|
|
+ // 处理成标准字段
|
|
|
+ if (this.formatSourceData) {
|
|
|
+ return this.formatSourceData(initData)
|
|
|
+ }
|
|
|
+ const standardData = initData.map((p) => {
|
|
|
+ return {
|
|
|
+ name: p.label,
|
|
|
+ label: p.label,
|
|
|
+ checked: false,
|
|
|
+ disabled: false,
|
|
|
+ indeterminate: false,
|
|
|
+ children: p.children.map((c) => {
|
|
|
+ return {
|
|
|
+ name: c.label,
|
|
|
+ label: c.label,
|
|
|
+ checked: false,
|
|
|
+ disabled: false,
|
|
|
+ indeterminate: false,
|
|
|
+ children: c.children.map((a) => {
|
|
|
+ return {
|
|
|
+ name: a.label,
|
|
|
+ label: a.label,
|
|
|
+ checked: false,
|
|
|
+ disabled: false
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return standardData
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 将过滤好的地区数据转换成map格式(根据场景需要转换)
|
|
|
+ * 例:{北京:{北京市:[]}, 河南:{ 郑州市:[新郑市, 登封市、金水区]}}
|
|
|
+ */
|
|
|
+ getCitiesToMap(filterData = this.getStandardData()) {
|
|
|
+ const obj = {}
|
|
|
+ if (filterData.length > 0) {
|
|
|
+ filterData.forEach((province) => {
|
|
|
+ const cityMap = {}
|
|
|
+ province.children.forEach((city) => {
|
|
|
+ cityMap[city.name] = city.children.map((v) => v.name)
|
|
|
+ })
|
|
|
+ obj[province.name] = cityMap
|
|
|
+ })
|
|
|
+ }
|
|
|
+ return obj
|
|
|
+ },
|
|
|
+ // 判断全国、全部全选半选状态
|
|
|
+ getAllCheckBoxSelectedStatus() {
|
|
|
+ if (!this.isHaveAll) return
|
|
|
+ const level1List = this.level1List
|
|
|
+ const allProvinceCount = level1List.filter(
|
|
|
+ (v) => v.name !== '全部'
|
|
|
+ ).length
|
|
|
+ const allSelectedProvinceCount = level1List.filter(
|
|
|
+ (v) => v.name !== '全部' && v.checked
|
|
|
+ ).length
|
|
|
+ const allHalfSelectedProvinceCount = level1List.filter(
|
|
|
+ (v) => v.name !== '全部' && v.indeterminate
|
|
|
+ ).length
|
|
|
+ level1List.forEach((province) => {
|
|
|
+ if (allProvinceCount === allSelectedProvinceCount) {
|
|
|
+ level1List[0].checked = true
|
|
|
+ level1List[0].indeterminate = false
|
|
|
+ } else {
|
|
|
+ level1List[0].indeterminate =
|
|
|
+ allSelectedProvinceCount > 0 || allHalfSelectedProvinceCount > 0
|
|
|
+ const allCityCount = province.children.filter(
|
|
|
+ (v) => v.name !== '全部'
|
|
|
+ ).length
|
|
|
+ const allSelectedCityCount = province.children.filter(
|
|
|
+ (v) => v.name !== '全部' && v.checked
|
|
|
+ ).length
|
|
|
+ const allHalfSelectedCityCount = province.children.filter(
|
|
|
+ (v) => v.name !== '全部' && v.indeterminate
|
|
|
+ ).length
|
|
|
+ province.children.forEach((city) => {
|
|
|
+ if (
|
|
|
+ allCityCount === allSelectedCityCount &&
|
|
|
+ allSelectedCityCount > 0
|
|
|
+ ) {
|
|
|
+ province.children[0].checked = true
|
|
|
+ province.children[0].indeterminate = false
|
|
|
+ } else {
|
|
|
+ province.children[0].indeterminate =
|
|
|
+ allSelectedCityCount > 0 || allHalfSelectedCityCount > 0
|
|
|
+ const allDistrictCount = city.children.filter(
|
|
|
+ (v) => v.name !== '全部'
|
|
|
+ ).length
|
|
|
+ const allSelectedDistrictCount = city.children.filter(
|
|
|
+ (v) => v.name !== '全部' && v.checked
|
|
|
+ ).length
|
|
|
+ const allHalfSelectedDistrictCount = city.children.filter(
|
|
|
+ (v) => v.name !== '全部' && v.indeterminate
|
|
|
+ ).length
|
|
|
+ city.children.forEach((district) => {
|
|
|
+ if (
|
|
|
+ allDistrictCount === allSelectedDistrictCount &&
|
|
|
+ allSelectedDistrictCount > 0
|
|
|
+ ) {
|
|
|
+ city.children[0].checked = true
|
|
|
+ city.children[0].indeterminate = false
|
|
|
+ } else {
|
|
|
+ city.children[0].indeterminate =
|
|
|
+ allSelectedDistrictCount > 0 ||
|
|
|
+ allHalfSelectedDistrictCount > 0
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // 点击省展开城市
|
|
|
+ onOpenLevel2(province, pIndex) {
|
|
|
+ this.cActive = 0
|
|
|
+ this.pActive = pIndex
|
|
|
+ this.level3List = []
|
|
|
+ this.level2List = province.children
|
|
|
+ this.level3List = province.children[0].children
|
|
|
+ },
|
|
|
+ // 点击城市展开区县
|
|
|
+ onOpenLevel3(city, cIndex) {
|
|
|
+ this.cActive = cIndex
|
|
|
+ this.level3List = city.children
|
|
|
+ },
|
|
|
+ onLevel1MouseOut(e) {
|
|
|
+ clearTimeout(this.pTimer)
|
|
|
+ this.pTimer = null
|
|
|
+ },
|
|
|
+ onLevel1MouseOver(level1, pIndex) {
|
|
|
+ if (!this.pTimer) {
|
|
|
+ this.pTimer = setTimeout(() => {
|
|
|
+ this.onOpenLevel2(level1, pIndex)
|
|
|
+ }, 150)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onLevel2MouseOut(e) {
|
|
|
+ clearTimeout(this.cTimer)
|
|
|
+ this.cTimer = null
|
|
|
+ },
|
|
|
+ onLevel2MouseOver(city, cIndex) {
|
|
|
+ if (!this.cTimer) {
|
|
|
+ this.cTimer = setTimeout(() => {
|
|
|
+ this.onOpenLevel3(city, cIndex)
|
|
|
+ }, 150)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 设置全国全选、半选状态
|
|
|
+ setWholeCountryCheckedStatus() {
|
|
|
+ const selectedProvince = this.level1List.filter((province) => {
|
|
|
+ return province.checked && province.name !== '全部'
|
|
|
+ })
|
|
|
+ const allProvince = this.level1List.filter((province) => {
|
|
|
+ return province.name !== '全部'
|
|
|
+ })
|
|
|
+ const selectedIndeterminate = this.level1List.filter((province) => {
|
|
|
+ return province.name !== '全部' && province.indeterminate
|
|
|
+ })
|
|
|
+ if (this.isHaveAll) {
|
|
|
+ // 如果有全国选项 则选中的省份数量(排除全国)等于全部省份数量 则绑定全国选中
|
|
|
+ if (selectedProvince.length === allProvince.length) {
|
|
|
+ this.level1List[0].indeterminate = false
|
|
|
+ this.level1List[0].checked = true
|
|
|
+ } else {
|
|
|
+ // 如果选中全国数量不等于全部省份数量 则全国半选 选中数等于0除外
|
|
|
+ this.level1List[0].checked = false
|
|
|
+ this.level1List[0].indeterminate =
|
|
|
+ selectedIndeterminate.length > 0 || selectedProvince.length > 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.getSelectedTags()
|
|
|
+ },
|
|
|
+ // 设置省全选、半选状态
|
|
|
+ setProvinceCheckedStatus() {
|
|
|
+ // 设置当前省份下城市的全选状态(全选、半选)
|
|
|
+ const currentProvince = this.level1List[this.pActive]
|
|
|
+ const selectedCities = currentProvince.children.filter(
|
|
|
+ (v) => v.checked && v.name !== '全部'
|
|
|
+ )
|
|
|
+ const allCities = currentProvince.children.filter(
|
|
|
+ (v) => v.name !== '全部'
|
|
|
+ )
|
|
|
+ const cityIndeterminate = currentProvince.children.filter(
|
|
|
+ (v) => v.name !== '全部' && v.indeterminate
|
|
|
+ )
|
|
|
+ if (selectedCities.length === allCities.length) {
|
|
|
+ this.level1List[this.pActive].checked = true
|
|
|
+ this.level1List[this.pActive].indeterminate = false
|
|
|
+ } else {
|
|
|
+ this.level1List[this.pActive].checked = false
|
|
|
+ this.level1List[this.pActive].indeterminate =
|
|
|
+ selectedCities.length !== 0 || cityIndeterminate.length > 0
|
|
|
+ }
|
|
|
+ currentProvince.children[0].indeterminate =
|
|
|
+ (selectedCities.length !== allCities.length &&
|
|
|
+ selectedCities.length !== 0) ||
|
|
|
+ cityIndeterminate.length > 0
|
|
|
+ currentProvince.children[0].checked =
|
|
|
+ selectedCities.length === allCities.length
|
|
|
+ this.setWholeCountryCheckedStatus()
|
|
|
+ },
|
|
|
+ setCitiesCheckedStatus() {
|
|
|
+ // 设置当前省份下城市的全选状态(全选、半选)
|
|
|
+ const currentCity = this.level2List[this.cActive]
|
|
|
+ const selectedCountry = currentCity.children.filter(
|
|
|
+ (v) => v.checked && v.name !== '全部'
|
|
|
+ )
|
|
|
+ const allCountry = currentCity.children.filter((v) => v.name !== '全部')
|
|
|
+ if (selectedCountry.length === allCountry.length) {
|
|
|
+ currentCity.checked = true
|
|
|
+ currentCity.indeterminate = false
|
|
|
+ } else {
|
|
|
+ currentCity.checked = false
|
|
|
+ currentCity.indeterminate = selectedCountry.length !== 0
|
|
|
+ }
|
|
|
+ // if (this.isHaveAll) {
|
|
|
+ currentCity.children[0].indeterminate =
|
|
|
+ selectedCountry.length !== allCountry.length &&
|
|
|
+ selectedCountry.length !== 0
|
|
|
+ currentCity.children[0].checked =
|
|
|
+ selectedCountry.length === allCountry.length
|
|
|
+ // }
|
|
|
+ this.setProvinceCheckedStatus()
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 提取省份checkbox选择状态方法
|
|
|
+ * checked: checkbox点击状态
|
|
|
+ * province: 当前点击的城市数据
|
|
|
+ */
|
|
|
+ setProvinceChangeCommon(checked, province) {
|
|
|
+ // 全国选中/取消选中
|
|
|
+ if (province.name === '全部' || province.name === '全部') {
|
|
|
+ this.level1List.forEach((first) => {
|
|
|
+ first.checked = checked
|
|
|
+ first.indeterminate = false
|
|
|
+ first.children.forEach((second) => {
|
|
|
+ second.checked = checked
|
|
|
+ second.indeterminate = false
|
|
|
+ second.children.forEach((third) => {
|
|
|
+ third.checked = checked
|
|
|
+ third.indeterminate = false
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ // 省份选中/取消选中
|
|
|
+ province.indeterminate = false
|
|
|
+ province.children.forEach((second) => {
|
|
|
+ second.checked = checked
|
|
|
+ second.indeterminate = false
|
|
|
+ second.children.forEach((third) => {
|
|
|
+ third.checked = checked
|
|
|
+ third.indeterminate = false
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+ this.setWholeCountryCheckedStatus()
|
|
|
+ },
|
|
|
+ // 省份选中事件
|
|
|
+ onProvinceChange(checked, province, index) {
|
|
|
+ this.onOpenLevel2(province, index)
|
|
|
+ province.checked = checked
|
|
|
+ this.setProvinceChangeCommon(checked, province)
|
|
|
+ this.onSelectChange()
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 提取城市checkbox选择状态方法
|
|
|
+ * checked: checkbox点击状态
|
|
|
+ * city: 当前点击的城市数据
|
|
|
+ */
|
|
|
+ setCitiesChangeCommon(checked, city) {
|
|
|
+ if (city.name === '全部') {
|
|
|
+ // 全部城市选中/取消选中
|
|
|
+ this.level1List.forEach((first, index) => {
|
|
|
+ if (this.pActive === index) {
|
|
|
+ first.checked = checked
|
|
|
+ first.indeterminate = false
|
|
|
+ first.children.forEach((second) => {
|
|
|
+ second.checked = checked
|
|
|
+ second.indeterminate = false
|
|
|
+ second.children.forEach((third) => {
|
|
|
+ third.checked = checked
|
|
|
+ third.indeterminate = false
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ // 当前城市选中/取消选中
|
|
|
+ city.indeterminate = false
|
|
|
+ city.children.forEach((third) => {
|
|
|
+ third.checked = checked
|
|
|
+ third.indeterminate = false
|
|
|
+ })
|
|
|
+ }
|
|
|
+ this.setProvinceCheckedStatus()
|
|
|
+ },
|
|
|
+ // 城市选中事件
|
|
|
+ onCitiesChange(checked, city, cIndex) {
|
|
|
+ this.onOpenLevel3(city, cIndex)
|
|
|
+ // 选择超出可选区域冒泡事件
|
|
|
+ if (checked) {
|
|
|
+ city.checked = true
|
|
|
+ this.setCitiesChangeCommon(checked, city)
|
|
|
+ } else {
|
|
|
+ // 取消选中
|
|
|
+ city.checked = false
|
|
|
+ this.setCitiesChangeCommon(checked, city)
|
|
|
+ }
|
|
|
+ this.onSelectChange()
|
|
|
+ },
|
|
|
+ setCountryChangeCommon(checked, country) {
|
|
|
+ if (country.name === '全部') {
|
|
|
+ this.level3List.forEach((third) => {
|
|
|
+ third.checked = checked
|
|
|
+ third.indeterminate = false
|
|
|
+ })
|
|
|
+ this.setCitiesCheckedStatus()
|
|
|
+ } else {
|
|
|
+ this.setCitiesCheckedStatus()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 区县选中事件
|
|
|
+ onLevel3Change(checked, country) {
|
|
|
+ // 选择超出可选区域冒泡事件
|
|
|
+ if (checked) {
|
|
|
+ country.checked = true
|
|
|
+ this.setCountryChangeCommon(checked, country)
|
|
|
+ } else {
|
|
|
+ country.checked = false
|
|
|
+ this.setCountryChangeCommon(checked, country)
|
|
|
+ }
|
|
|
+ this.onSelectChange()
|
|
|
+ },
|
|
|
+ // 下拉框出现/隐藏时触发
|
|
|
+ onVisibleChange(flag) {
|
|
|
+ if (!flag) {
|
|
|
+ this.$emit('hideSelect', this.getState())
|
|
|
+ } else {
|
|
|
+ this.$emit('showSelect', this.getState())
|
|
|
+ }
|
|
|
+ },
|
|
|
+ getDropdownRef() {
|
|
|
+ const layoutRef = this.$refs.layoutRef
|
|
|
+ if (layoutRef) {
|
|
|
+ const dropdownRef = layoutRef.$refs?.dropdownRef
|
|
|
+ return dropdownRef
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onKeyup() {
|
|
|
+ const dropdownRef = this.getDropdownRef()
|
|
|
+ if (dropdownRef) {
|
|
|
+ dropdownRef.visible = true
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // dropdown的坑点,微软输入法,input输入的时候会失去焦,dropdown会收起,暂且如此处理
|
|
|
+ onKeydown() {
|
|
|
+ const dropdownRef = this.getDropdownRef()
|
|
|
+ if (dropdownRef && dropdownRef.show) {
|
|
|
+ dropdownRef.show()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onNoPowerLimit(payload) {
|
|
|
+ this.$emit('limit', payload)
|
|
|
+ },
|
|
|
+ onSelectChange() {
|
|
|
+ const state = this.getState()
|
|
|
+ this.$emit('change', state)
|
|
|
+ },
|
|
|
+ // 省市县区三级结构拆分省市(省:[市])和区县(地市:[区县])
|
|
|
+ formatProvinceAndCities(regionMap) {
|
|
|
+ let area = {}
|
|
|
+ const district = {}
|
|
|
+ if (Object.keys(regionMap).length === 0) {
|
|
|
+ area = {}
|
|
|
+ } else {
|
|
|
+ for (const key in regionMap) {
|
|
|
+ if (Object.keys(regionMap[key]).length === 0) {
|
|
|
+ area[key] = []
|
|
|
+ } else {
|
|
|
+ const cities = regionMap[key]
|
|
|
+ const cityArr = []
|
|
|
+ for (const city in cities) {
|
|
|
+ cityArr.push(city)
|
|
|
+ area[key] = cityArr
|
|
|
+ if (cities[city].length > 0) {
|
|
|
+ district[city] = cities[city]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return { area, district }
|
|
|
+ },
|
|
|
+ // 省市县区map转字符串 应用场景:平铺选择结果需要
|
|
|
+ formatRegionToString(regionMap, mark = '、') {
|
|
|
+ if (!regionMap || !Object.keys(regionMap).length) return '全部'
|
|
|
+ const tagsArr = []
|
|
|
+ for (const province in regionMap) {
|
|
|
+ if (Object.keys(regionMap[province]).length === 0) {
|
|
|
+ tagsArr.push(province)
|
|
|
+ } else {
|
|
|
+ const cityObj = regionMap[province]
|
|
|
+ for (const cKey in cityObj) {
|
|
|
+ if (cityObj[cKey].length === 0) {
|
|
|
+ tagsArr.push(cKey)
|
|
|
+ } else {
|
|
|
+ tagsArr.push(...cityObj[cKey])
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return tagsArr.join(mark)
|
|
|
+ },
|
|
|
+ // 获取数据,并整理成前端标准格式
|
|
|
+ getState() {
|
|
|
+ let level1List = JSON.parse(JSON.stringify(this.level1List))
|
|
|
+ const allProvinceCount = level1List.filter(
|
|
|
+ (v) => v.name !== '全部'
|
|
|
+ ).length
|
|
|
+ const allSelectedProvinceCount = level1List.filter(
|
|
|
+ (v) => v.name !== '全部' && v.checked
|
|
|
+ ).length
|
|
|
+ const allCountryChecked = level1List.some(
|
|
|
+ (v) => v.name === '全部' && v.checked
|
|
|
+ )
|
|
|
+ const noSelected = level1List.every((v) => !v.checked && !v.indeterminate)
|
|
|
+ let regionMap = null
|
|
|
+ if (noSelected) {
|
|
|
+ // console.log('no region selected')
|
|
|
+ } else {
|
|
|
+ if (
|
|
|
+ allProvinceCount === allSelectedProvinceCount &&
|
|
|
+ allCountryChecked
|
|
|
+ ) {
|
|
|
+ level1List = []
|
|
|
+ } else {
|
|
|
+ level1List.forEach((province) => {
|
|
|
+ const allCityCount = province.children.filter(
|
|
|
+ (v) => v.name !== '全部'
|
|
|
+ ).length
|
|
|
+ const allSelectedCityCount = province.children.filter(
|
|
|
+ (v) => v.name !== '全部' && v.checked
|
|
|
+ ).length
|
|
|
+ if (allCityCount === allSelectedCityCount) {
|
|
|
+ province.children = []
|
|
|
+ } else {
|
|
|
+ province.children.forEach((city) => {
|
|
|
+ const allDistrictCount = city.children.filter(
|
|
|
+ (v) => v.name !== '全部'
|
|
|
+ ).length
|
|
|
+ const allSelectedDistrictCount = city.children.filter(
|
|
|
+ (v) => v.name !== '全部' && v.checked
|
|
|
+ ).length
|
|
|
+ if (allDistrictCount === allSelectedDistrictCount) {
|
|
|
+ city.children = []
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ const formatData = level1List.filter((first) => {
|
|
|
+ return (first.checked || first.indeterminate) && first.name !== '全部'
|
|
|
+ })
|
|
|
+ formatData.forEach((second) => {
|
|
|
+ const secondList = second.children.filter((v) => {
|
|
|
+ return (v.checked || v.indeterminate) && v.name !== '全部'
|
|
|
+ })
|
|
|
+ secondList.forEach((item) => {
|
|
|
+ item.children = item.children.filter((v) => {
|
|
|
+ return v.checked && v.name !== '全部'
|
|
|
+ })
|
|
|
+ })
|
|
|
+ second.children = secondList
|
|
|
+ })
|
|
|
+ regionMap = this.getCitiesToMap(formatData)
|
|
|
+ }
|
|
|
+ return regionMap
|
|
|
+ },
|
|
|
+ setState(data = {}) {
|
|
|
+ this.resetState()
|
|
|
+ if (!data) return
|
|
|
+ if (Object.keys(data).length === 0) {
|
|
|
+ // 选择的全国
|
|
|
+ this.level1List.forEach((province) => {
|
|
|
+ province.checked = true
|
|
|
+ province.indeterminate = false
|
|
|
+ province.children.forEach((city) => {
|
|
|
+ city.checked = true
|
|
|
+ city.indeterminate = false
|
|
|
+ city.children.forEach((country) => {
|
|
|
+ country.checked = true
|
|
|
+ country.indeterminate = false
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ // 选择的省
|
|
|
+ const level1List = this.level1List
|
|
|
+ level1List[0].indeterminate = true
|
|
|
+ level1List.forEach((province) => {
|
|
|
+ for (const key in data) {
|
|
|
+ if (province.name === key) {
|
|
|
+ if (Object.keys(data[key]).length === 0) {
|
|
|
+ // 选择的全省(省下的全部地市)
|
|
|
+ province.checked = true
|
|
|
+ province.children.forEach((city) => {
|
|
|
+ city.checked = true
|
|
|
+ city.children.forEach((district) => {
|
|
|
+ district.checked = true
|
|
|
+ })
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ // 选择省下的部分地市
|
|
|
+ province.indeterminate = true
|
|
|
+ province.children.forEach((city) => {
|
|
|
+ for (const cKey in data[key]) {
|
|
|
+ if (city.name === cKey) {
|
|
|
+ if (Object.keys(data[key][cKey]).length === 0) {
|
|
|
+ // 选择的市下的全部区县
|
|
|
+ city.checked = true
|
|
|
+ city.children.forEach((district) => {
|
|
|
+ district.checked = true
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ // 选择的市下的部分区县
|
|
|
+ city.indeterminate = true
|
|
|
+ city.children.forEach((district) => {
|
|
|
+ if (data[key][cKey].length === 0) {
|
|
|
+ district.checked = true
|
|
|
+ } else {
|
|
|
+ data[key][cKey].forEach((item) => {
|
|
|
+ if (item === district.name) {
|
|
|
+ district.checked = true
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.getAllCheckBoxSelectedStatus()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ this.getSelectedTags()
|
|
|
+ },
|
|
|
+ resetState() {
|
|
|
+ this.level1List.forEach((province) => {
|
|
|
+ province.checked = false
|
|
|
+ province.indeterminate = false
|
|
|
+ province.children.forEach((city) => {
|
|
|
+ city.checked = false
|
|
|
+ city.indeterminate = false
|
|
|
+ city.children.forEach((country) => {
|
|
|
+ country.checked = false
|
|
|
+ country.indeterminate = false
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+ this.tags = []
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss">
|
|
|
+.vip-module {
|
|
|
+ .zhima-bid--icon {
|
|
|
+ color: rgba(201, 143, 55, 1) !important;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|
|
|
+<style lang="scss" scoped>
|
|
|
+::v-deep {
|
|
|
+ .el-dropdown-menu.fixed-dropdown {
|
|
|
+ transform: translate(-20px, 0);
|
|
|
+ }
|
|
|
+ .suffix-icon-container {
|
|
|
+ position: relative;
|
|
|
+ z-index: 99;
|
|
|
+ }
|
|
|
+
|
|
|
+ .input-focus {
|
|
|
+ .el-input__suffix-inner {
|
|
|
+ color: $color_main;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.zhima-bid-help-tip {
|
|
|
+ padding: 2px;
|
|
|
+ line-height: 18px;
|
|
|
+}
|
|
|
+
|
|
|
+.zhima-bid--icon {
|
|
|
+ color: $color_main;
|
|
|
+}
|
|
|
+
|
|
|
+.list-empty-container {
|
|
|
+ padding: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.dropdown-content--wrap {
|
|
|
+ max-width: 580px;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 5px;
|
|
|
+ border: 1px solid $color_main;
|
|
|
+ overflow: hidden;
|
|
|
+ .dropdown-content--hd {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 8px;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 22px;
|
|
|
+ .dropdown-content--hd-left {
|
|
|
+ margin-right: 12px;
|
|
|
+ flex: 1;
|
|
|
+ }
|
|
|
+ ::v-deep {
|
|
|
+ .el-input__icon {
|
|
|
+ font-size: 16px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .select--result {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ padding: 8px 0 0px;
|
|
|
+ max-height: 100px;
|
|
|
+ overflow-y: auto;
|
|
|
+ &::-webkit-scrollbar {
|
|
|
+ width: 4px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .dropdown-content--bd {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ border-top: 1px solid #ececec;
|
|
|
+ height: 360px;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+ .level-1-container {
|
|
|
+ min-width: 140px;
|
|
|
+ border-right: 1px solid #ececec;
|
|
|
+ }
|
|
|
+ .level-2-container {
|
|
|
+ min-width: 180px;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+ .level-3-container {
|
|
|
+ min-width: 220px;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+ .level-2-container {
|
|
|
+ border-right: 1px solid #ececec;
|
|
|
+ }
|
|
|
+ .module-container {
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ }
|
|
|
+ .module-header {
|
|
|
+ // padding: 12px 11px;
|
|
|
+ // color:#999999;
|
|
|
+ // font-size: 14px;
|
|
|
+ // line-height: 22px;
|
|
|
+ }
|
|
|
+ .module-main {
|
|
|
+ flex: 1;
|
|
|
+ overflow-y: scroll;
|
|
|
+ }
|
|
|
+ .module-item {
|
|
|
+ position: relative;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 4px 8px;
|
|
|
+ min-height: 30px;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 22px;
|
|
|
+ color: #1d1d1d;
|
|
|
+ &.active,
|
|
|
+ &:hover {
|
|
|
+ background: #ececec;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ .item-name {
|
|
|
+ flex: 1;
|
|
|
+ margin-left: 4px;
|
|
|
+ white-space: pre-wrap;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ::v-deep {
|
|
|
+ .el-tag {
|
|
|
+ width: auto;
|
|
|
+ max-width: unset !important;
|
|
|
+ margin: 0 0 8px 8px;
|
|
|
+ &.el-tag--info {
|
|
|
+ height: 24px;
|
|
|
+ line-height: 22px;
|
|
|
+ background: #f5f6f7;
|
|
|
+ color: #1d1d1d;
|
|
|
+ border: 1px solid#ececec;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+ .el-tag__close.el-icon-close {
|
|
|
+ background: transparent;
|
|
|
+ color: #aaa;
|
|
|
+ font-size: 15px;
|
|
|
+ right: -4px;
|
|
|
+ }
|
|
|
+ &:hover {
|
|
|
+ color: $color-text--highlight;
|
|
|
+ border-color: $color-text--highlight;
|
|
|
+ background: #fff;
|
|
|
+ cursor: pointer;
|
|
|
+ .el-tag__close {
|
|
|
+ color: $color-text--highlight;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .module-main::-webkit-scrollbar {
|
|
|
+ width: 4px;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|