浏览代码

feat: 新增区域选择行组件

cuiyalong 4 年之前
父节点
当前提交
e92a9766ff

+ 0 - 2
public/index.html

@@ -18,8 +18,6 @@
       <script src="https://web2-jytest.jydev.jianyu360.com/js/jquery-3.2.1.min.js?v=6302"></script>
       <script src="https://web2-jytest.jydev.jianyu360.com/js/jquery.cookie.js"></script>
       <script src="https://web2-jytest.jydev.jianyu360.com/js/bootstrap.min.js"></script>
-      <script src="https://cdn.jsdelivr.net/npm/pdfjs-dist@2.1.266/build/pdf.min.js"></script>
-      <script src="https://cdn.jsdelivr.net/npm/pdfjs-dist@2.1.266/web/pdf_viewer.js"></script>
 
       <link href='https://web2-jytest.jydev.jianyu360.com/css/reset.css?v=6302' rel="stylesheet" type="text/css"/>
       <link href='https://web2-jytest.jydev.jianyu360.com/pccss/reset_pc.css' rel="stylesheet" type="text/css"/>

+ 29 - 551
src/components/selector/AreaSelector.vue

@@ -1,504 +1,50 @@
 <template>
   <selector-card
-    class="area-selector card"
+    class="area-selector"
+    :cardType="selectorType"
     @onConfirm="onConfirm"
-    @onCancel="onCancel"
-  >
-    <div slot="header">选择区域</div>
-    <div class="selector-content" v-loading="loading">
-      <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>
+    @onCancel="onCancel">
+    <div slot="header" v-if="selectorType === 'card'" key="header">选择区域</div>
+    <div slot="header" class="s-header" v-if="selectorType === 'line'" key="header">选择区域:</div>
+    <AreaSelectorContent
+      ref="areaSelectorContent"
+      :selectorType="selectorType"
+      :initCityMap="initCityMap"
+      @onChange="onChange"
+    />
   </selector-card>
 </template>
 
 <script>
-import { Input, Icon } from 'element-ui'
-import 'element-ui/lib/theme-chalk/base.css'
-import CollapseTransition from 'element-ui/lib/transitions/collapse-transition'
 import SelectorCard from '@/components/selector/SelectorCard.vue'
-import chinaMapJSON from '@/assets/js/china_area.js'
-import { provinceListMapExp } from '@/assets/js/selector.js'
-import { debounce, getRandomString } from '@/utils/'
+import AreaSelectorContent from '@/components/selector/AreaSelectorContent.vue'
 export default {
-  name: 'area-selector-card',
+  name: 'area-selector',
   components: {
-    [Input.name]: Input,
-    [Icon.name]: Icon,
-    [CollapseTransition.name]: CollapseTransition,
-    SelectorCard
+    SelectorCard,
+    AreaSelectorContent
   },
   props: {
+    selectorType: {
+      type: String,
+      default: 'card'
+    },
     // 初始化城市数据
     // 刚进入页面需要被选中的城市数据
     initCityMap: {
       type: Object,
       default () {
-        return {
-          // '北京': [],
-          // '安徽': [],
-          // '广东': [
-          //     '揭阳市',
-          //     '茂名市',
-          //     '韶关市'
-          // ],
-          // '河北': [
-          //     '邯郸市',
-          //     '秦皇岛市',
-          //     '保定市'
-          // ],
-          // '福建': [
-          //     '福州市',
-          //     '厦门市',
-          //     '宁德市'
-          // ],
-          // '重庆': []
-        }
+        return {}
       }
     }
   },
-  data () {
-    return {
-      searchContent: '',
-      loading: false,
-      // 省份与字母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: ''
-      }
-    }
-  },
-  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.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)
-  },
+  created () {},
   methods: {
-    changeLoadingState (s) {
-      this.loading = s
-    },
-    // 整理城市数据列表(并初始化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
-      }
-    },
-    // 控制城市盒子展开和收起
-    changeExpandState (e, province) {
-      if (!province.canExpanded) return
-      province.expanded = !province.expanded
-    },
-    // 城市选择按钮点击事件
-    // 根据城市的选择情况判断省份的选择情况
-    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()
-      }
-    },
-    // 省份checkbox点击事件
-    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()
-      }
-    },
-    // 检查是否所有省份按钮被全选中
-    // 全部被全选->返回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
-      }
-    },
-    // 初始化选中城市数据
     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) {
-                // 全省被选中
-                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 = ''
-            }
-          })
-        }
-      }
+      return this.$refs.areaSelectorContent.setCitySelected(data)
     },
-    // 获取当前选中城市数据
     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 (cityTotalCount === selectedCityArr.length && item.selectedState === 'checked') {
-            // 城市被全选
-            counter[item.name] = []
-          } else {
-            if (selectedCityArr.length !== 0) {
-              counter[item.name] = selectedCityArr
-            }
-          }
-        })
-      }
-
-      return counter
-    },
-    // 统计城市分布数量
-    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
-      }
+      return this.$refs.areaSelectorContent.getSelectedCity()
     },
     onCancel () {
       this.$emit('onCancel')
@@ -506,86 +52,18 @@ export default {
     onConfirm () {
       const selectedCity = this.getSelectedCity()
       this.$emit('onConfirm', selectedCity)
+    },
+    onChange (city) {
+      this.$emit('onChange', city)
     }
   }
 }
 </script>
 
 <style lang="scss" scoped>
-  .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;
-    }
-  }
-
-  .j-button-item {
-    &.global {
-      padding: 6px 8px;
-      height: 24px;
-      line-height: 24px;
-      font-weight: 700;
-      color: inherit;
-      border-color: rgba(0,0,0,.05);
-    }
-  }
-
-  [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 {
+    .s-header {
+      line-height: 36px;
     }
   }
 </style>

+ 947 - 0
src/components/selector/AreaSelectorContent.vue

@@ -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>

+ 1 - 1
src/components/selector/IndustrySelector.vue

@@ -286,7 +286,7 @@ export default {
           giveId = level1.id
           return level1.id
         } else {
-          level1.children.find(level2 => {
+          return level1.children.find(level2 => {
             if (level2.name.includes(s)) {
               giveId = level1.id
               return level2

+ 106 - 75
src/components/selector/SelectorCard.vue

@@ -1,12 +1,18 @@
 <template>
-  <div class="selector-card">
+  <div
+    class="selector-card"
+    :class="{
+      's-card': cardType === 'card',
+      's-line': cardType === 'line',
+    }"
+    >
     <div class="selector-card-header">
       <slot name="header"></slot>
     </div>
     <div class="selector-card-content scrollbar">
       <slot name="default"></slot>
     </div>
-    <div class="selector-card-footer">
+    <div class="selector-card-footer" v-if="cardType === 'card'">
       <slot name="footer">
         <el-button type="primary" class="confirm" @click="onConfirm">保存</el-button>
         <el-button class="cancel" @click="onCancel">取消</el-button>
@@ -22,8 +28,11 @@ export default {
   components: {
     [Button.name]: Button
   },
-  data () {
-    return {}
+  props: {
+    cardType: {
+      type: String,
+      default: 'card'
+    }
   },
   methods: {
     onCancel () {
@@ -37,85 +46,58 @@ export default {
 </script>
 
 <style lang="scss" scoped>
-  .selector-card::v-deep {
-    // 输入框公共样式
-    .el-input__inner {
-      padding-left: 42px;
-      background-color: #f7f7f7;
-      border-radius: 22px;
-    }
-    .search-container {
-      margin: 20px auto;
-      width: 360px;
-      .el-icon-search {
-        margin-left: 6px;
-        font-size: 18px;
-      }
-    }
-
-    // 子组件按钮公共样式
-    .j-button-item {
-      display: flex;
-      align-items: center;
-      margin: 6px 5px;
-      padding: 2px 6px;
-      line-height: 20px;
-      border-radius: 4px;
-      font-size: 14px;
-      text-align: center;
-      color: #606266;
-      background-color: #fff;
-      border: 1px solid rgba(0,0,0,.05);
-      cursor: pointer;
-      &.hover:hover {
-        color: #2abed1;
-      }
-      &.active {
-        color: #2abed1;
-        border-color: #2abed1;
-      }
-    }
-
-    // 子组件卡片布局样式
-    .selector-content {
-      display: flex;
-      flex-direction: column;
-      margin: 0 auto;
-      width: 400px;
-      height: 100%;
-      border-radius: 5px;
-      border: 1px solid rgba(0,0,0,.05);
-    }
-
-    // 搜索框下的列表
-    .select-list {
+  .selector-card {
+    display: flex;
+    color: #1d1d1d;
+    background-color: #fff;
+    .selector-card-content {
       position: relative;
+      display: flex;
       flex: 1;
-      overflow-y: scroll;
     }
-
-    // indexBar样式
-    .index-anchor {
-      margin-top: 10px;
-      padding: 0 20px;
-      height: 30px;
-      line-height: 30px;
-      background-color: #f5f5fb;
-      text-align: left;
+    &::v-deep {
+      // 子组件按钮公共样式
+      .j-button-item {
+        display: flex;
+        align-items: center;
+        margin: 6px 5px;
+        padding: 2px 6px;
+        line-height: 20px;
+        border-radius: 4px;
+        font-size: 14px;
+        text-align: center;
+        color: #606266;
+        background-color: #fff;
+        border: 1px solid rgba(0,0,0,.05);
+        cursor: pointer;
+        &.global {
+          padding: 6px 8px;
+          height: 24px;
+          line-height: 24px;
+          font-weight: 700;
+          color: inherit;
+          border-color: rgba(0,0,0,.05);
+        }
+        &.hover:hover {
+          color: #2abed1;
+        }
+        &.active {
+          color: #2abed1;
+          border-color: #2abed1;
+        }
+      }
     }
   }
 
-  .selector-card {
-    display: flex;
+  .selector-card.s-card {
+    width: 460px;
+    height: 582px;
     flex-direction: column;
     align-items: center;
     justify-content: space-between;
-    width: 460px;
-    height: 582px;
-    color: #1d1d1d;
-    background-color: #fff;
     box-shadow: 0 0 28px rgb(0 0 0 / 16%);
     border-radius: 5px;
+
     .selector-card-header,
     .selector-card-content,
     .selector-card-footer {
@@ -132,10 +114,7 @@ export default {
       border-radius: 5px 5px 0 0;
     }
     .selector-card-content {
-      position: relative;
-      display: flex;
       align-items: center;
-      flex: 1;
       overflow: hidden;
     }
     .selector-card-footer {
@@ -161,5 +140,57 @@ export default {
         margin: 0 20px;
       }
     }
+
+    &::v-deep {
+      // 输入框公共样式
+      .el-input__inner {
+        padding-left: 42px;
+        background-color: #f7f7f7;
+        border-radius: 22px;
+      }
+      .search-container {
+        margin: 20px auto;
+        width: 360px;
+        .el-icon-search {
+          margin-left: 6px;
+          font-size: 18px;
+        }
+      }
+
+      // 子组件卡片布局样式
+      .selector-content {
+        display: flex;
+        flex-direction: column;
+        margin: 0 auto;
+        width: 400px;
+        height: 100%;
+        border-radius: 5px;
+        border: 1px solid rgba(0,0,0,.05);
+      }
+
+      // 搜索框下的列表
+      .select-list {
+        position: relative;
+        flex: 1;
+        overflow-y: scroll;
+      }
+
+      // indexBar样式
+      .index-anchor {
+        margin-top: 10px;
+        padding: 0 20px;
+        height: 30px;
+        line-height: 30px;
+        background-color: #f5f5fb;
+        text-align: left;
+      }
+    }
+  }
+
+  .selector-card.s-line {
+    padding: 12px 40px;
+    .selector-card-header {
+      margin-right: 10px;
+    }
   }
 </style>