|
@@ -0,0 +1,947 @@
|
|
|
+<template>
|
|
|
+ <div class="selector-content" v-if="selectorType === 'card'" key="s-content">
|
|
|
+ <div class="search-container">
|
|
|
+ <el-input v-model.trim="searchContent" placeholder="搜索" prefix-icon="el-icon-search"></el-input>
|
|
|
+ </div>
|
|
|
+ <div class="select-list scrollbar" ref="selectList">
|
|
|
+ <div v-for="(item, key) in provinceListMap" :key="key" class="select-group-container">
|
|
|
+ <div class="index-anchor" :id="key" :data-index="key" v-if="key !== '#'">{{ key }}</div>
|
|
|
+ <el-collapse-transition v-for="(province, ii) in item" :key="ii*2">
|
|
|
+ <div class="select-group tab-content global" v-if="province.name == '全国'">
|
|
|
+ <button
|
|
|
+ class="j-button-item global"
|
|
|
+ :class="{
|
|
|
+ active: province.selectedState,
|
|
|
+ [province.id]: true
|
|
|
+ }"
|
|
|
+ @click="changeCityState(province, '#')"
|
|
|
+ >{{ province.name }}</button>
|
|
|
+ </div>
|
|
|
+ <div class="select-group" v-else>
|
|
|
+ <div class="tab" :class="province.id">
|
|
|
+ <div class="tab-name-container" @click="clickCheckbox(province)">
|
|
|
+ <div class="j-checkbox" :class="province.selectedState"></div>
|
|
|
+ <span class="tab-name">{{ province.name }}</span>
|
|
|
+ </div>
|
|
|
+ <span style="flex: 1; height: 100%;" @click="changeExpandState($event, province)"></span>
|
|
|
+ <span
|
|
|
+ v-if="province.canExpanded"
|
|
|
+ @click="changeExpandState($event, province)">
|
|
|
+ <i
|
|
|
+ class="el-icon-arrow-down"
|
|
|
+ :class="{
|
|
|
+ rotate180: province.expanded
|
|
|
+ }"></i>
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <el-collapse-transition>
|
|
|
+ <div v-show="province.expanded" class="tab-content">
|
|
|
+ <div class="content-list">
|
|
|
+ <button v-for="(city, iii) in province.children" :key="iii*3"
|
|
|
+ class="j-button-item"
|
|
|
+ :class="{
|
|
|
+ active: city.selected,
|
|
|
+ [city.id]: true
|
|
|
+ }"
|
|
|
+ :disabled="!city.canSelected"
|
|
|
+ @click="changeCityState(province, city)"
|
|
|
+ >{{ city.city }}</button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-collapse-transition>
|
|
|
+ </div>
|
|
|
+ </el-collapse-transition>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="selector-content" v-else-if="selectorType === 'line'" key="s-content">
|
|
|
+ <div class="selected-list">
|
|
|
+ <el-tag
|
|
|
+ type="plain"
|
|
|
+ closable
|
|
|
+ v-for="tag in selectedTagList"
|
|
|
+ :key="tag"
|
|
|
+ @close="tagClose(tag)"
|
|
|
+ >{{ tag }}</el-tag>
|
|
|
+ </div>
|
|
|
+ <div class="select-list" ref="selectList">
|
|
|
+ <div class="index-item" :data-index="key" :ref="'index-item-' + key" v-for="(item, key) in provinceListMap" :key="key">
|
|
|
+ <span class="index-bar" v-if="key !== '#'">{{ key }}</span>
|
|
|
+ <div
|
|
|
+ class="province-item"
|
|
|
+ v-for="(province, ii) in item"
|
|
|
+ :class="{
|
|
|
+ expand: province.expanded && province.canExpanded
|
|
|
+ }"
|
|
|
+ :key="ii*2"
|
|
|
+ @click="changeExpandStateForLine($event, province)"
|
|
|
+ >{{ province.name }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="city-list" ref="cityList" v-show="expandedCitiesShow">
|
|
|
+ <div class="city-list-content">
|
|
|
+ <div
|
|
|
+ class="city-item"
|
|
|
+ :class="{
|
|
|
+ active: expandedProvince.selectedState === 'checked'
|
|
|
+ }"
|
|
|
+ @click="clickProvinceInCityListForLine(expandedProvince)"
|
|
|
+ >{{ expandedProvince.name }}</div>
|
|
|
+ <div
|
|
|
+ class="city-item"
|
|
|
+ :class="{
|
|
|
+ active: city.selected
|
|
|
+ }"
|
|
|
+ v-for="(city, iii) in expandedProvince.children"
|
|
|
+ :key="iii"
|
|
|
+ @click="changeCityStateForLine(expandedProvince, city)"
|
|
|
+ >{{ city.city }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="city-list-footer">
|
|
|
+ <button class="confirm" @click="confirmCitySelected">确定</button>
|
|
|
+ <button class="cancel" @click="cancelCitySelected">取消</button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { Input, Icon, Tag } from 'element-ui'
|
|
|
+import 'element-ui/lib/theme-chalk/base.css'
|
|
|
+import CollapseTransition from 'element-ui/lib/transitions/collapse-transition'
|
|
|
+import chinaMapJSON from '@/assets/js/china_area.js'
|
|
|
+import { provinceListMapExp } from '@/assets/js/selector.js'
|
|
|
+import { debounce, getRandomString } from '@/utils/'
|
|
|
+export default {
|
|
|
+ name: 'area-selector-content',
|
|
|
+ components: {
|
|
|
+ [Input.name]: Input,
|
|
|
+ [Icon.name]: Icon,
|
|
|
+ [Tag.name]: Tag,
|
|
|
+ [CollapseTransition.name]: CollapseTransition
|
|
|
+ },
|
|
|
+ props: {
|
|
|
+ selectorType: {
|
|
|
+ type: String,
|
|
|
+ default: 'card' // card/line
|
|
|
+ },
|
|
|
+ // 初始化城市数据
|
|
|
+ // 刚进入页面需要被选中的城市数据
|
|
|
+ initCityMap: {
|
|
|
+ type: Object,
|
|
|
+ default () {
|
|
|
+ return {
|
|
|
+ // '北京': [],
|
|
|
+ // '安徽': [],
|
|
|
+ // '广东': [
|
|
|
+ // '揭阳市',
|
|
|
+ // '茂名市',
|
|
|
+ // '韶关市'
|
|
|
+ // ],
|
|
|
+ // '河北': [
|
|
|
+ // '邯郸市',
|
|
|
+ // '秦皇岛市',
|
|
|
+ // '保定市'
|
|
|
+ // ],
|
|
|
+ // '福建': [
|
|
|
+ // '福州市',
|
|
|
+ // '厦门市',
|
|
|
+ // '宁德市'
|
|
|
+ // ],
|
|
|
+ // '重庆': []
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data () {
|
|
|
+ return {
|
|
|
+ searchContent: '',
|
|
|
+ // 省份与字母IndexBar对照表
|
|
|
+ provinceListMapExp,
|
|
|
+ provinceListMap: {
|
|
|
+ // A: [
|
|
|
+ // {
|
|
|
+ // name: '安徽',
|
|
|
+ // expanded: false,
|
|
|
+ // canExpanded: true,
|
|
|
+ // selectedState: '',
|
|
|
+ // children: []
|
|
|
+ // }
|
|
|
+ // ]
|
|
|
+ },
|
|
|
+ // indexBar数据
|
|
|
+ indexList: [],
|
|
|
+ provinceExp: {
|
|
|
+ name: '',
|
|
|
+ // 展开状态
|
|
|
+ expanded: false,
|
|
|
+ // 是否可以展开
|
|
|
+ canExpanded: false,
|
|
|
+ // 选中状态: half(半选)、checked(全选)、''(未选中)、checkeddisabled(全选不能点击)、nonedisabled(未选不能点击)
|
|
|
+ selectedState: '',
|
|
|
+ children: [],
|
|
|
+ id: ''
|
|
|
+ },
|
|
|
+ // line状态下,当前被展开省的省份列表
|
|
|
+ expandedProvince: {
|
|
|
+ children: []
|
|
|
+ },
|
|
|
+ selectedCity: {},
|
|
|
+ selectedTagList: ['全国']
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ expandedCitiesShow () {
|
|
|
+ if (!this.expandedProvince) return false
|
|
|
+ return this.expandedProvince.children.length
|
|
|
+ }
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ initCityMap (newVal, oldVal) {
|
|
|
+ this.setCitySelected(newVal)
|
|
|
+ },
|
|
|
+ searchContent: debounce(function (newVal, oldVal) {
|
|
|
+ const search = newVal
|
|
|
+ const { findP } = this.getProvinceWithString(search)
|
|
|
+ const id = findP[0] && findP[0].id
|
|
|
+ if (id) {
|
|
|
+ if (findP[0].canExpanded) {
|
|
|
+ findP[0].expanded = true
|
|
|
+ }
|
|
|
+ this.$nextTick(() => {
|
|
|
+ const wrapper = document.querySelector('.area-selector.s-card')
|
|
|
+ this.$refs.selectList.scrollTop = wrapper.querySelector(`.${id}`).offsetTop
|
|
|
+ // document.querySelector(`.${id}`).scrollIntoView() // 兼容性有问题
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }, 300)
|
|
|
+ },
|
|
|
+ created () {
|
|
|
+ this.initIndexBarAndAreaMap()
|
|
|
+ this.provinceListMap['#'][0].selectedState = 'checked'
|
|
|
+ this.setCitySelected(this.initCityMap)
|
|
|
+ window.data = this
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ // 整理城市数据列表(并初始化indexBar数据)
|
|
|
+ initIndexBarAndAreaMap () {
|
|
|
+ // 整理数据得到indexListMap(),同时获得indexList
|
|
|
+ const provinceListMap = {}
|
|
|
+ const indexList = []
|
|
|
+ for (const key in this.provinceListMapExp) {
|
|
|
+ const areaArr = []
|
|
|
+ indexList.push(key)
|
|
|
+ this.provinceListMapExp[key].forEach(pName => {
|
|
|
+ const provinceExp = JSON.parse(JSON.stringify(this.provinceExp))
|
|
|
+
|
|
|
+ provinceExp.name = pName
|
|
|
+ provinceExp.id = `ap-${getRandomString(8).toLowerCase()}`
|
|
|
+
|
|
|
+ if (pName !== '全国') {
|
|
|
+ const cities = this.getCitiesFromJSONMap(pName)
|
|
|
+ // console.log(pName, cities)
|
|
|
+ // 筛选掉直辖市和特别行政区(台湾省也不不需要展开)
|
|
|
+ if (cities.ProRemark === '省份' || cities.ProRemark === '自治区') {
|
|
|
+ if (cities.ProID === 32) {
|
|
|
+ provinceExp.children = []
|
|
|
+ provinceExp.canExpanded = false
|
|
|
+ } else {
|
|
|
+ cities.city.forEach(c => {
|
|
|
+ // 将市区重组成一个新的对象
|
|
|
+ return provinceExp.children.push({
|
|
|
+ city: c.name,
|
|
|
+ selected: false,
|
|
|
+ canSelected: true,
|
|
|
+ id: `ac-${getRandomString(8).toLowerCase()}`
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ provinceExp.children = []
|
|
|
+ provinceExp.canExpanded = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ provinceExp.canExpanded = provinceExp.children.length !== 0
|
|
|
+ areaArr.push(provinceExp)
|
|
|
+ })
|
|
|
+
|
|
|
+ provinceListMap[key] = areaArr
|
|
|
+ }
|
|
|
+
|
|
|
+ this.provinceListMap = provinceListMap
|
|
|
+ this.indexList = indexList
|
|
|
+
|
|
|
+ // 给provinceListMap赋值
|
|
|
+ for (const k in provinceListMap) {
|
|
|
+ this.$set(this.provinceListMap, k, provinceListMap[k])
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 循环chinaMapJSON,找到对应省下面对应的市
|
|
|
+ getCitiesFromJSONMap (provinceName) {
|
|
|
+ return chinaMapJSON.find(item => item.name.indexOf(provinceName) !== -1)
|
|
|
+ },
|
|
|
+ // 输入字符串,找到其所在省份
|
|
|
+ getProvinceWithString (s = '') {
|
|
|
+ // 找是否有省份相同的
|
|
|
+ const findP = [] // 匹配到的省份数组
|
|
|
+ const findC = [] // 匹配到的市数组
|
|
|
+ if (s) {
|
|
|
+ for (const key in this.provinceListMap) {
|
|
|
+ const item = this.provinceListMap[key]
|
|
|
+ for (let i = 0; i < item.length; i++) {
|
|
|
+ if (item[i].name.includes(s)) {
|
|
|
+ findP.push(item[i])
|
|
|
+ }
|
|
|
+ if (Array.isArray(item[i].children) && item[i].children.length !== 0) {
|
|
|
+ item[i].children.forEach(city => {
|
|
|
+ if (city.city.includes(s)) {
|
|
|
+ findP.push(item[i])
|
|
|
+ findC.push(city)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ findP,
|
|
|
+ findC
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 控制城市盒子展开和收起(card)
|
|
|
+ changeExpandState (e, province) {
|
|
|
+ if (!province.canExpanded) return
|
|
|
+ province.expanded = !province.expanded
|
|
|
+ },
|
|
|
+ // 控制城市盒子展开和收起(line)
|
|
|
+ changeExpandStateForLine (e, province) {
|
|
|
+ if (province.name === this.expandedProvince.name) return
|
|
|
+ // 循环,将其他全部置为false
|
|
|
+ for (const key in this.provinceListMap) {
|
|
|
+ this.provinceListMap[key].forEach(item => {
|
|
|
+ item.expanded = false
|
|
|
+ })
|
|
|
+ }
|
|
|
+ this.expandedProvince = {
|
|
|
+ children: []
|
|
|
+ }
|
|
|
+ province.expanded = true
|
|
|
+ console.log(province, province.name)
|
|
|
+ // 省份数据与原数据分离(点击确定覆盖原数据,点击取消则不保存数据)
|
|
|
+ this.expandedProvince = JSON.parse(JSON.stringify(province))
|
|
|
+ // 如果直接点击直辖市
|
|
|
+ if (province.children.length === 0) {
|
|
|
+ if (province.name === '全国') {
|
|
|
+ this.setCitySelected()
|
|
|
+ } else {
|
|
|
+ this.provinceListMap['#'][0].selectedState = ''
|
|
|
+ this.expandedProvince.selectedState = 'checked'
|
|
|
+ }
|
|
|
+ this.confirmCitySelected()
|
|
|
+ } else {
|
|
|
+ this.moveTheCityContainer(e)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ moveTheCityContainer (e) {
|
|
|
+ // 距离最近一个定位元素的高度6,44,80. 一个公差为36的等差数列
|
|
|
+ const offsetTop = e.target.offsetTop
|
|
|
+ const lineFirstDom = this.getLineFirstDom()
|
|
|
+ const selectList = this.$refs.selectList
|
|
|
+ const cityList = this.$refs.cityList
|
|
|
+ // 如果页面上cityList插入中间(除了插入到末尾),则都会产生误差,所以需要根据情况减去其高度
|
|
|
+ let correct = cityList.getBoundingClientRect().height
|
|
|
+ // 最后一行则不减去correct
|
|
|
+ if (cityList.getBoundingClientRect().top > 36 * lineFirstDom.length + 6) {
|
|
|
+ correct = 0
|
|
|
+ }
|
|
|
+ const line = Math.floor((offsetTop - correct) / 36) + 1
|
|
|
+ if (line >= lineFirstDom.length) {
|
|
|
+ selectList.appendChild(cityList) // 往列表末尾插入元素
|
|
|
+ } else if (line <= 1) {
|
|
|
+ selectList.insertBefore(cityList, lineFirstDom[1])
|
|
|
+ } else {
|
|
|
+ selectList.insertBefore(cityList, lineFirstDom[line])
|
|
|
+ }
|
|
|
+ // 如果点击的是第一行,则要求插入下一行的前面
|
|
|
+ // absolute定位下可以使用
|
|
|
+ // this.$nextTick(() => {
|
|
|
+ // const selectList = this.$refs.selectList
|
|
|
+ // const cityList = this.$refs.cityList
|
|
|
+ // if (cityList) {
|
|
|
+ // cityList.style.top = `${e.target.getBoundingClientRect().top - selectList.getBoundingClientRect().top + 26}px`
|
|
|
+ // }
|
|
|
+ // })
|
|
|
+ },
|
|
|
+ getLineFirstDom () {
|
|
|
+ if (this.selectorType !== 'line') return
|
|
|
+ const indexTopList = []
|
|
|
+ const lineFirstDom = [
|
|
|
+ ...this.$refs[`index-item-${this.indexList[0]}`]
|
|
|
+ ]
|
|
|
+ this.indexList.forEach(item => {
|
|
|
+ const ref = this.$refs[`index-item-${item}`]
|
|
|
+ if (ref && ref[0]) {
|
|
|
+ indexTopList.push(ref[0].getBoundingClientRect().top)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ for (let i = 0; i < indexTopList.length; i++) {
|
|
|
+ if (indexTopList[i + 1] > indexTopList[i]) {
|
|
|
+ lineFirstDom.push(
|
|
|
+ ...this.$refs[`index-item-${this.indexList[i + 1]}`]
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return lineFirstDom
|
|
|
+ },
|
|
|
+ // 城市选择按钮点击事件(card)
|
|
|
+ // 根据城市的选择情况判断省份的选择情况
|
|
|
+ changeCityState (province, city) {
|
|
|
+ if (city === '#') {
|
|
|
+ return this.setCitySelected()
|
|
|
+ }
|
|
|
+ // 全国置为空
|
|
|
+ this.provinceListMap['#'][0].selectedState = ''
|
|
|
+ city.selected = !city.selected
|
|
|
+
|
|
|
+ // 判断省份的选择状态
|
|
|
+ let count = 0
|
|
|
+ const cityLength = province.children.length
|
|
|
+ if (cityLength) {
|
|
|
+ province.children.forEach(v => {
|
|
|
+ // 前提是可点击的
|
|
|
+ if (v.canSelected && v.selected) {
|
|
|
+ count++
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ // 直辖市或自治区
|
|
|
+ province.canExpanded = false
|
|
|
+ province.expanded = false
|
|
|
+ }
|
|
|
+
|
|
|
+ // 选中状态: half(半选)、checked(全选)、''(未选中)、checkeddisabled(全选不能点击)、nonedisabled(未选不能点击)
|
|
|
+ if (count === 0) {
|
|
|
+ province.selectedState = ''
|
|
|
+ } else if (count < cityLength) {
|
|
|
+ province.selectedState = 'half'
|
|
|
+ } else if (count === cityLength) {
|
|
|
+ province.selectedState = 'checked'
|
|
|
+ } else {
|
|
|
+ province.selectedState = ''
|
|
|
+ }
|
|
|
+
|
|
|
+ const pState = this.checkAllProvinceState()
|
|
|
+ // 如果所有省份被全选,则取消所有选中,让全国选中
|
|
|
+ if (pState.allSelected || pState.noSelected) {
|
|
|
+ this.setCitySelected()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 城市选择按钮点击事件(card)
|
|
|
+ // 根据城市的选择情况判断省份的选择情况
|
|
|
+ changeCityStateForLine (province, city) {
|
|
|
+ this.provinceListMap['#'][0].selectedState = ''
|
|
|
+ province.selectedState = ''
|
|
|
+ city.selected = !city.selected
|
|
|
+ // 判断省份的选择状态
|
|
|
+ let count = 0
|
|
|
+ const cityLength = province.children.length
|
|
|
+ if (cityLength) {
|
|
|
+ province.children.forEach(v => {
|
|
|
+ // 前提是可点击的
|
|
|
+ if (v.canSelected && v.selected) {
|
|
|
+ count++
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ if (count === cityLength) {
|
|
|
+ // line状态下 ,城市全部选中,则只选中省份即可
|
|
|
+ province.selectedState = 'checked'
|
|
|
+ province.children.forEach(item => (item.selected = false))
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 省份checkbox点击事件(card)
|
|
|
+ clickCheckbox (province) {
|
|
|
+ const state = province.selectedState
|
|
|
+ if (state === 'checkeddisabled' || state === 'nonedisabled') return
|
|
|
+
|
|
|
+ // 全国置为空
|
|
|
+ this.provinceListMap['#'][0].selectedState = ''
|
|
|
+ if (state === '' || state === 'half') {
|
|
|
+ province.children.forEach(v => (v.selected = true))
|
|
|
+ province.selectedState = 'checked'
|
|
|
+ } else {
|
|
|
+ province.children.forEach(v => (v.selected = false))
|
|
|
+ province.selectedState = ''
|
|
|
+ }
|
|
|
+
|
|
|
+ const pState = this.checkAllProvinceState()
|
|
|
+ // 如果所有省份被全选,则取消所有选中,让全国选中
|
|
|
+ if (pState.allSelected || pState.noSelected) {
|
|
|
+ this.setCitySelected()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 省份点击事件(城市列表中的省份按钮)(line)
|
|
|
+ clickProvinceInCityListForLine (province) {
|
|
|
+ const state = province.selectedState
|
|
|
+ province.children.forEach(v => (v.selected = false))
|
|
|
+ if (state === 'checked') {
|
|
|
+ province.selectedState = ''
|
|
|
+ } else {
|
|
|
+ province.selectedState = 'checked'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 检查是否所有省份按钮被全选中
|
|
|
+ // 全部被全选->返回true
|
|
|
+ checkAllProvinceState () {
|
|
|
+ const stateArr = []
|
|
|
+ for (const key in this.provinceListMap) {
|
|
|
+ this.provinceListMap[key].forEach(item => {
|
|
|
+ if (item.name !== '全国') {
|
|
|
+ if (item.selectedState === '') {
|
|
|
+ stateArr.push('checked')
|
|
|
+ } else if (item.selectedState === 'checked') {
|
|
|
+ stateArr.push('unchecked')
|
|
|
+ } else {
|
|
|
+ stateArr.push('other')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ // 统计不同状态的个数
|
|
|
+ const counter = {
|
|
|
+ checked: 0,
|
|
|
+ unchecked: 0,
|
|
|
+ other: 0
|
|
|
+ }
|
|
|
+ for (let i = 0; i < stateArr.length; i++) {
|
|
|
+ const k = stateArr[i]
|
|
|
+ if (counter[k]) {
|
|
|
+ counter[k] += 1
|
|
|
+ } else {
|
|
|
+ counter[k] = 1
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // console.log(counter)
|
|
|
+ return {
|
|
|
+ state: stateArr,
|
|
|
+ allSelected: counter.checked === stateArr.length,
|
|
|
+ noSelected: counter.unchecked === stateArr.length
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 初始化选中城市数据(card/line共用)
|
|
|
+ setCitySelected (data) {
|
|
|
+ // 设置全国
|
|
|
+ if (!data || Object.keys(data).length === 0) {
|
|
|
+ // 其他全部设置不选中,全国设置选中
|
|
|
+ for (const key in this.provinceListMap) {
|
|
|
+ this.provinceListMap[key].forEach(item => {
|
|
|
+ item.selectedState = ''
|
|
|
+ item.children.forEach(iitem => {
|
|
|
+ iitem.selected = false
|
|
|
+ })
|
|
|
+ if (item.name === '全国') {
|
|
|
+ item.selectedState = 'checked'
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 先将所有城市选择取消
|
|
|
+ this.setCitySelected()
|
|
|
+ // 设置某几个省份被选中
|
|
|
+ for (const key in this.provinceListMap) {
|
|
|
+ this.provinceListMap[key].forEach(item => {
|
|
|
+ const selectCityArr = data[item.name]
|
|
|
+ if (Array.isArray(selectCityArr)) {
|
|
|
+ if (selectCityArr.length === 0) {
|
|
|
+ // 全省被选中
|
|
|
+ if (this.selectorType === 'line') {
|
|
|
+ // line状态下,全省被选中,则其下城市不需要被选中
|
|
|
+ } else {
|
|
|
+ item.children.forEach(iitem => {
|
|
|
+ iitem.selected = true
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ item.selectedState = 'checked'
|
|
|
+ } else {
|
|
|
+ // 省份中的某些市被选中
|
|
|
+ item.children.forEach(iitem => {
|
|
|
+ if (selectCityArr.indexOf(iitem.city) !== -1) {
|
|
|
+ iitem.selected = true
|
|
|
+ }
|
|
|
+ })
|
|
|
+ item.selectedState = 'half'
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (item.name === '全国') {
|
|
|
+ item.selectedState = ''
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 获取当前选中城市数据
|
|
|
+ getSelectedCity () {
|
|
|
+ const counter = {}
|
|
|
+ // 判断是否全国被选中
|
|
|
+ if (this.provinceListMap['#'][0].selectedState === 'checked') {
|
|
|
+ return counter
|
|
|
+ }
|
|
|
+
|
|
|
+ // 全国没有被选中,排除循环全国
|
|
|
+ for (const key in this.provinceListMap) {
|
|
|
+ if (key === '#') continue
|
|
|
+ this.provinceListMap[key].forEach(item => {
|
|
|
+ // 当前省份下被选中的城市数量
|
|
|
+ const selectedCityArr = []
|
|
|
+ const cityTotalCount = item.children.length
|
|
|
+ item.children.forEach(iitem => {
|
|
|
+ if (iitem.selected && iitem.canSelected) {
|
|
|
+ selectedCityArr.push(iitem.city)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ if (this.selectorType === 'line') {
|
|
|
+ // 先看是否有城市被选,再看是否省份被选
|
|
|
+ if (selectedCityArr.length) {
|
|
|
+ counter[item.name] = selectedCityArr
|
|
|
+ } else {
|
|
|
+ if (item.selectedState === 'checked') {
|
|
|
+ counter[item.name] = []
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 计算出当前省份下的城市是否被全选了
|
|
|
+ if (cityTotalCount === selectedCityArr.length && item.selectedState === 'checked') {
|
|
|
+ // 城市被全选
|
|
|
+ counter[item.name] = []
|
|
|
+ } else {
|
|
|
+ if (selectedCityArr.length !== 0) {
|
|
|
+ counter[item.name] = selectedCityArr
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ return counter
|
|
|
+ },
|
|
|
+ confirmCitySelected () {
|
|
|
+ // 统计时候有城市被选中了
|
|
|
+ let count = 0
|
|
|
+ const cityLength = this.expandedProvince.children.length
|
|
|
+ if (cityLength) {
|
|
|
+ this.expandedProvince.children.forEach(v => {
|
|
|
+ // 前提是可点击的
|
|
|
+ if (v.canSelected && v.selected) {
|
|
|
+ count++
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.expandedProvince.selectedState !== 'checked' && cityLength !== 0 && count === 0) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // 替换赋值
|
|
|
+ for (const key in this.provinceListMap) {
|
|
|
+ if (key === '#') continue
|
|
|
+ const res = this.provinceListMap[key].find(item => {
|
|
|
+ if (item.name === this.expandedProvince.name) {
|
|
|
+ Object.assign(item, this.expandedProvince)
|
|
|
+ }
|
|
|
+ return item.name === this.expandedProvince.name
|
|
|
+ })
|
|
|
+ if (res) {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.selectedCity = this.getSelectedCity()
|
|
|
+ this.getSelectedTagList(this.selectedCity)
|
|
|
+ this.cancelCitySelected()
|
|
|
+ this.$emit('onChange', this.selectedCity)
|
|
|
+ },
|
|
|
+ cancelCitySelected () {
|
|
|
+ for (const key in this.provinceListMap) {
|
|
|
+ this.provinceListMap[key].forEach(item => {
|
|
|
+ item.expanded = false
|
|
|
+ })
|
|
|
+ }
|
|
|
+ this.expandedProvince = {
|
|
|
+ children: []
|
|
|
+ }
|
|
|
+ },
|
|
|
+ getSelectedTagList (v) {
|
|
|
+ if (Object.keys(v).length === 0) {
|
|
|
+ const arr = ['全国']
|
|
|
+ this.selectedTagList = arr
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const privinceArr = []
|
|
|
+ let cityArr = []
|
|
|
+ for (const key in v) {
|
|
|
+ const item = v[key]
|
|
|
+ if (Array.isArray(item)) {
|
|
|
+ if (item.length === 0) {
|
|
|
+ privinceArr.push(key)
|
|
|
+ } else {
|
|
|
+ cityArr = cityArr.concat(item)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.selectedTagList = privinceArr.concat(cityArr)
|
|
|
+ },
|
|
|
+ tagClose (name) {
|
|
|
+ if (name === '全国') {
|
|
|
+ this.selectedTagList = []
|
|
|
+ return
|
|
|
+ }
|
|
|
+ for (const key in this.selectedCity) {
|
|
|
+ const index = this.selectedCity[key].indexOf(name)
|
|
|
+ if (name === key) {
|
|
|
+ delete this.selectedCity[key]
|
|
|
+ break
|
|
|
+ } else if (index !== -1) {
|
|
|
+ this.selectedCity[key].splice(index, 1)
|
|
|
+ if (this.selectedCity[key].length === 0) {
|
|
|
+ delete this.selectedCity[key]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.setCitySelected(this.selectedCity)
|
|
|
+ this.confirmCitySelected()
|
|
|
+ },
|
|
|
+ // 统计城市分布数量
|
|
|
+ getCityCount () {
|
|
|
+ const selectedCount = {
|
|
|
+ // 全国被选中时,country为1
|
|
|
+ country: 1,
|
|
|
+ province: 0,
|
|
|
+ city: {
|
|
|
+ // 一共选了多少个城市
|
|
|
+ totalCount: 0,
|
|
|
+ // 分布在几个省份
|
|
|
+ pCount: 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const selected = this.getSelectedCity()
|
|
|
+ if (Object.keys(selected).length === 0) {
|
|
|
+ // 全国
|
|
|
+ } else {
|
|
|
+ selectedCount.country = 0
|
|
|
+ for (const p in selected) {
|
|
|
+ if (selected[p].length === 0) {
|
|
|
+ selectedCount.province++
|
|
|
+ } else {
|
|
|
+ selectedCount.city.pCount++
|
|
|
+ selected[p].forEach(() => {
|
|
|
+ selectedCount.city.totalCount++
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const tipText = {
|
|
|
+ p: selectedCount.province === 0 ? '' : selectedCount.province + '个省',
|
|
|
+ c: selectedCount.city.totalCount === 0 ? '' : selectedCount.city.totalCount + '个市',
|
|
|
+ s: selectedCount.city.pCount === 1 ? '' : '(分布在' + selectedCount.city.pCount + '个省内)',
|
|
|
+ text: ''
|
|
|
+ }
|
|
|
+
|
|
|
+ if (selectedCount.province === 1) {
|
|
|
+ tipText.text = '全国'
|
|
|
+ } else {
|
|
|
+ let dot = ''
|
|
|
+ if (selectedCount.city.totalCount !== 0 && selectedCount.province !== 0) {
|
|
|
+ dot = '、'
|
|
|
+ }
|
|
|
+ if (selectedCount.city.totalCount === 0 || selectedCount.city.totalCount === 1) {
|
|
|
+ tipText.s = ''
|
|
|
+ }
|
|
|
+ tipText.text = tipText.p + dot + tipText.c + tipText.s
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ data: selectedCount,
|
|
|
+ zh: tipText
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+ .s-card {
|
|
|
+ .j-checkbox {
|
|
|
+ width: 18px;
|
|
|
+ height: 18px;
|
|
|
+ border-radius: 50%;
|
|
|
+ border: 1px solid #e0e0e0;
|
|
|
+ cursor: pointer;
|
|
|
+ &.checked {
|
|
|
+ border: 0;
|
|
|
+ background: url('~@/assets/images/icon/checked.png') no-repeat;
|
|
|
+ background-size: 20px;
|
|
|
+ &[disabled] {
|
|
|
+ background: url('~@/assets/images/icon/checked_disabled.png') no-repeat;
|
|
|
+ background-size: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &.half {
|
|
|
+ border: 0;
|
|
|
+ background: url('~@/assets/images/icon/checked-half.png') no-repeat;
|
|
|
+ background-size: 20px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ [class^=el-icon-] {
|
|
|
+ transition: transform 0.2s ease;
|
|
|
+ }
|
|
|
+ .rotate180 {
|
|
|
+ transform: rotate(180deg);
|
|
|
+ }
|
|
|
+
|
|
|
+ .j-button-item {
|
|
|
+ border-color: transparent;
|
|
|
+ }
|
|
|
+
|
|
|
+ .select-group {
|
|
|
+ font-size: 14px;
|
|
|
+ &.global {
|
|
|
+ padding: 0 18px;
|
|
|
+ }
|
|
|
+ .tab {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 0 18px;
|
|
|
+ height: 40px;
|
|
|
+ border-bottom: 1px solid rgba(0,0,0,.05);
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ .tab-name-container {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ .tab-name {
|
|
|
+ margin-left: 10px;
|
|
|
+ font-weight: bold;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .tab-content {
|
|
|
+ padding: 0 18px;
|
|
|
+ // border-bottom: 1px solid rgba(0,0,0,.05);
|
|
|
+ .content-list {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ padding: 2px 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .s-line {
|
|
|
+ .el-tag--plain {
|
|
|
+ color: $color-text--highlight;
|
|
|
+ border-color: $color-text--highlight;
|
|
|
+ .el-tag__close {
|
|
|
+ color: $color-text--highlight;
|
|
|
+ &:hover {
|
|
|
+ color: #fff;
|
|
|
+ background-color: $color-text--highlight;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .s-header {
|
|
|
+ line-height: 30px;
|
|
|
+ }
|
|
|
+ .el-tag {
|
|
|
+ margin: 4px 6px;
|
|
|
+ height: 30px;
|
|
|
+ }
|
|
|
+ .selector-content {
|
|
|
+ .selected-list {}
|
|
|
+ .select-list {
|
|
|
+ position: relative;
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ .index-item {
|
|
|
+ margin: 6px 0;
|
|
|
+ .index-bar {
|
|
|
+ margin-left: 10px;
|
|
|
+ margin-right: 5px;
|
|
|
+ color: #999;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .province-item {
|
|
|
+ display: inline-block;
|
|
|
+ padding: 4px 8px;
|
|
|
+ border-radius: 4px;
|
|
|
+ cursor: pointer;
|
|
|
+ &:hover {
|
|
|
+ color: $color-text--highlight;
|
|
|
+ }
|
|
|
+ &.active {
|
|
|
+ color: #fff;
|
|
|
+ background-color: $color-text--highlight;
|
|
|
+ }
|
|
|
+ &.expand {
|
|
|
+ background-color: #f5f5fb;
|
|
|
+ border: 1px solid #e0e0e0;
|
|
|
+ border-bottom-color: transparent;
|
|
|
+ border-bottom-left-radius: 0;
|
|
|
+ border-bottom-right-radius: 0;
|
|
|
+ position: relative;
|
|
|
+ z-index: 2;
|
|
|
+ // transform: translateZ(0px);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .city-list {
|
|
|
+ margin-top: -7px;
|
|
|
+ padding: 12px 20px;
|
|
|
+ width: 100%;
|
|
|
+ background-color: #f5f5fb;
|
|
|
+ border-radius: 4px;
|
|
|
+ border: 1px solid #E0E0E0;
|
|
|
+ &.absolute {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ }
|
|
|
+ .city-item {
|
|
|
+ display: inline-block;
|
|
|
+ margin: 0 4px 4px;
|
|
|
+ padding: 4px 8px;
|
|
|
+ border-radius: 4px;
|
|
|
+ cursor: pointer;
|
|
|
+ &.active {
|
|
|
+ color: #fff;
|
|
|
+ background-color: $color-text--highlight;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .city-list-footer {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ margin-top: 12px;
|
|
|
+ button {
|
|
|
+ padding: 4px 16px;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 18px;
|
|
|
+ color: #1D1D1D;
|
|
|
+ background-color: #fff;
|
|
|
+ cursor: pointer;
|
|
|
+ border-radius: 4px;
|
|
|
+ border: 1px solid #E0E0E0;
|
|
|
+ &.confirm {
|
|
|
+ margin-right: 15px;
|
|
|
+ color: #fff;
|
|
|
+ background-color: #2CB7CA;
|
|
|
+ border-color: #2CB7CA;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+</style>
|