selector.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. <template>
  2. <div>
  3. <el-row :gutter="gutterNum">
  4. <el-col v-if="show(COUNTRY_KEY)" :span="span">
  5. <el-select
  6. ref="country"
  7. v-model="currCountry"
  8. :filterable="filterable"
  9. :placeholder="handledPlaceholder(COUNTRY_KEY)"
  10. :size="size"
  11. :no-data-text="handledNoDataText(COUNTRY_KEY)"
  12. :disabled="
  13. disabled === undefined ? false : handledDisabled(COUNTRY_KEY)
  14. "
  15. transfer
  16. style="width: 100%"
  17. @change="hasChange(COUNTRY_KEY)"
  18. >
  19. <el-option v-for="item in countryList" :key="item" :value="item">{{
  20. item
  21. }}</el-option>
  22. </el-select>
  23. </el-col>
  24. <el-col v-if="show(PROVINCE_KEY)" :span="span">
  25. <el-select
  26. ref="prov"
  27. v-model="currProvince"
  28. :filterable="filterable"
  29. :placeholder="handledPlaceholder(PROVINCE_KEY)"
  30. :size="size"
  31. :no-data-text="handledNoDataText(PROVINCE_KEY)"
  32. :disabled="
  33. disabled === undefined ? false : handledDisabled(PROVINCE_KEY)
  34. "
  35. transfer
  36. style="width: 100%"
  37. @change="hasChange(PROVINCE_KEY)"
  38. >
  39. <el-option v-for="item in provinceList" :key="item" :value="item">{{
  40. item
  41. }}</el-option>
  42. </el-select>
  43. </el-col>
  44. <el-col v-if="show(CITY_KEY)" :span="span">
  45. <el-select
  46. ref="city"
  47. v-model="currCity"
  48. :filterable="filterable"
  49. :placeholder="handledPlaceholder(CITY_KEY)"
  50. :size="size"
  51. :no-data-text="handledNoDataText(CITY_KEY)"
  52. :disabled="disabled === undefined ? false : handledDisabled(CITY_KEY)"
  53. transfer
  54. style="width: 100%"
  55. @change="hasChange(CITY_KEY)"
  56. >
  57. <el-option v-for="item in cityList" :key="item" :value="item">{{
  58. item
  59. }}</el-option>
  60. </el-select>
  61. </el-col>
  62. <el-col v-if="show(DISTRICT_KEY)" :span="span">
  63. <el-select
  64. ref="district"
  65. v-model="currDistrict"
  66. :filterable="filterable"
  67. :placeholder="handledPlaceholder(DISTRICT_KEY)"
  68. :size="size"
  69. :no-data-text="handledNoDataText(DISTRICT_KEY)"
  70. :disabled="
  71. disabled === undefined ? false : handledDisabled(DISTRICT_KEY)
  72. "
  73. transfer
  74. style="width: 100%"
  75. @change="hasChange(DISTRICT_KEY)"
  76. >
  77. <el-option v-for="item in districtList" :key="item" :value="item">{{
  78. item
  79. }}</el-option>
  80. </el-select>
  81. </el-col>
  82. <el-col v-if="show(STREET_KEY)" :span="span">
  83. <el-select
  84. ref="stre"
  85. v-model="currStreet"
  86. :filterable="filterable"
  87. :placeholder="handledPlaceholder(STREET_KEY)"
  88. :size="size"
  89. :no-data-text="handledNoDataText(STREET_KEY)"
  90. :disabled="
  91. disabled === undefined ? false : handledDisabled(STREET_KEY)
  92. "
  93. transfer
  94. style="width: 100%"
  95. @change="hasChange(STREET_KEY)"
  96. >
  97. <el-option v-for="item in streetList" :key="item" :value="item">{{
  98. item
  99. }}</el-option>
  100. </el-select>
  101. </el-col>
  102. </el-row>
  103. <slot />
  104. </div>
  105. </template>
  106. <script>
  107. import { get } from './util/areaData'
  108. import util from './util'
  109. const dataTypeArr = util.dataTypeArr
  110. const levelArr = util.levelArr
  111. const ROOT_VALUE = '0'
  112. export default {
  113. name: 'ibps-address-selector',
  114. props: {
  115. value: {
  116. type: Array
  117. },
  118. gutter: {
  119. type: [String, Number],
  120. default: 10
  121. },
  122. top: {
  123. // country、province、city、district、street
  124. type: String,
  125. default: 'country',
  126. validator: (val) => {
  127. return util.oneOf(val, levelArr)
  128. }
  129. },
  130. topVal: {
  131. type: String,
  132. default: ROOT_VALUE
  133. },
  134. level: {
  135. type: String,
  136. default: 'district',
  137. validator: (val) => {
  138. return util.oneOf(val, levelArr)
  139. }
  140. },
  141. filterable: {
  142. type: Boolean,
  143. default: false
  144. },
  145. data: {
  146. type: Object
  147. },
  148. dataType: {
  149. type: String,
  150. default: 'all',
  151. validator: (val) => {
  152. return util.oneOf(val, dataTypeArr)
  153. }
  154. },
  155. auto: {
  156. type: Boolean,
  157. default: false
  158. },
  159. placeholder: {
  160. type: [Array, String],
  161. default() {
  162. return this.defaultPlaceholder
  163. }
  164. },
  165. size: {
  166. type: String,
  167. default: 'small'
  168. },
  169. notFoundText: {
  170. type: [String, Array],
  171. default() {
  172. return this.defaultnotFoundText
  173. }
  174. },
  175. disabled: {
  176. type: [Boolean, Array, Number, String],
  177. default: false
  178. }
  179. },
  180. data() {
  181. return {
  182. areaData: [],
  183. currCountry: '', // 国家名称
  184. currProvince: '',
  185. currCity: '',
  186. currDistrict: '',
  187. currStreet: '',
  188. countryIndex: 0, // 国家code
  189. provinceIndex: 0,
  190. cityIndex: 0,
  191. districtIndex: 0,
  192. streetIndex: 0,
  193. countryList: {},
  194. provinceList: {},
  195. cityList: {},
  196. districtList: {},
  197. streetList: {},
  198. // ====================
  199. COUNTRY_KEY: 'country',
  200. PROVINCE_KEY: 'province',
  201. CITY_KEY: 'city',
  202. DISTRICT_KEY: 'district',
  203. STREET_KEY: 'street',
  204. isInit: true,
  205. defaultPlaceholder: this.$t('components.address.defaultPlaceholder'),
  206. defaultnotFoundText: this.$t('components.address.defaultnotFoundText'),
  207. cloneValue: []
  208. }
  209. },
  210. computed: {
  211. gutterNum() {
  212. return typeof this.gutter === 'number'
  213. ? this.gutter
  214. : parseInt(this.gutter)
  215. },
  216. showLevel() {
  217. return util.getLevelIndex(this.level)
  218. },
  219. span() {
  220. const curlevel =
  221. util.getLevelIndex(this.level) - util.getLevelIndex(this.top)
  222. if (curlevel > -1) {
  223. // 取整
  224. return parseInt(24 / (curlevel + 1), 10)
  225. } else {
  226. return null
  227. }
  228. }
  229. },
  230. watch: {
  231. // 当前 国家
  232. currCountry(name) {
  233. this.updateNextSelector(
  234. 'countryIndex',
  235. 'countryList',
  236. 'provinceList',
  237. name,
  238. 'currProvince',
  239. 'country'
  240. )
  241. if (this.level === 'country' || !this.auto) {
  242. this.returnRes('country')
  243. }
  244. },
  245. // 当前 省
  246. currProvince(name) {
  247. this.updateNextSelector(
  248. 'provinceIndex',
  249. 'provinceList',
  250. 'cityList',
  251. name,
  252. 'currCity',
  253. 'province'
  254. )
  255. if (
  256. this.level === 'province' ||
  257. !this.areaData[util.getIndex(this.countryList, name)] ||
  258. !this.auto
  259. ) {
  260. this.returnRes('province')
  261. }
  262. },
  263. // 当前 市
  264. currCity(name) {
  265. this.updateNextSelector(
  266. 'cityIndex',
  267. 'cityList',
  268. 'districtList',
  269. name,
  270. 'currDistrict',
  271. 'city'
  272. )
  273. if (
  274. this.level === 'city' ||
  275. !this.areaData[util.getIndex(this.provinceList, name)] ||
  276. !this.auto
  277. ) {
  278. this.returnRes('city')
  279. }
  280. },
  281. // 当前 县
  282. currDistrict(name) {
  283. this.updateNextSelector(
  284. 'districtIndex',
  285. 'districtList',
  286. 'streetList',
  287. name,
  288. 'currStreet',
  289. 'district'
  290. )
  291. if (this.level === 'district' || !this.auto) {
  292. this.returnRes('district')
  293. }
  294. },
  295. // 当前 街道
  296. currStreet(name) {
  297. this.streetIndex = util.getIndex(this.streetList, name)
  298. if (this.level === 'street' || !this.auto) {
  299. this.returnRes('street')
  300. }
  301. },
  302. value(val) {
  303. if (val) {
  304. this.initData()
  305. }
  306. }
  307. },
  308. mounted() {
  309. this.init()
  310. },
  311. beforeDestroy() {
  312. this.cloneValue = null
  313. this.areaData = null
  314. },
  315. methods: {
  316. init() {
  317. get(this.data).then((data) => {
  318. this.areaData = data
  319. this.initData()
  320. this.initDefaultValue()
  321. })
  322. },
  323. initData() {
  324. // 设置顶部值
  325. const topList = this.areaData[this.topVal]
  326. if (this.top === 'country') {
  327. this.countryList = topList
  328. } else if (this.top === 'province') {
  329. this.provinceList = topList
  330. } else if (this.top === 'city') {
  331. this.cityList = topList
  332. } else if (this.top === 'district') {
  333. this.districtList = topList
  334. } else if (this.top === 'street') {
  335. this.streetList = topList
  336. }
  337. // 设置初始值
  338. if (this.value && this.value.length > 0) {
  339. this.cloneValue = this.value
  340. if (this.dataType === 'all') {
  341. if (
  342. this.value[0] &&
  343. this.value[0].code &&
  344. topList[this.value[0].code]
  345. ) {
  346. this.updateTopValue(topList, this.value[0].code)
  347. }
  348. } else if (this.dataType === 'name') {
  349. if (this.value[0] && util.getIndex(topList, this.value[0])) {
  350. this.updateTopNameValue(topList, this.value[0])
  351. }
  352. } else if (this.dataType === 'code') {
  353. if (this.value[0] && topList[this.value[0]]) {
  354. this.updateTopValue(topList, this.value[0])
  355. }
  356. }
  357. }
  358. },
  359. updateTopValue(topList, code) {
  360. if (this.top === 'country') {
  361. this.currCountry = topList[code]
  362. this.countryIndex = code
  363. } else if (this.top === 'province') {
  364. this.currProvince = topList[code]
  365. this.provinceIndex = code
  366. } else if (this.top === 'city') {
  367. this.currCity = topList[code]
  368. this.cityIndex = code
  369. } else if (this.top === 'district') {
  370. this.currDistrict = topList[code]
  371. this.districtIndex = code
  372. } else if (this.top === 'street') {
  373. this.currStreet = topList[code]
  374. this.streetIndex = code
  375. }
  376. },
  377. updateTopNameValue(topList, name) {
  378. if (this.top === 'country') {
  379. this.currCountry = name
  380. } else if (this.top === 'province') {
  381. this.currProvince = name
  382. } else if (this.top === 'city') {
  383. this.currCity = name
  384. } else if (this.top === 'district') {
  385. this.currDistrict = name
  386. } else if (this.top === 'street') {
  387. this.currStreet = name
  388. }
  389. },
  390. show(level) {
  391. const top = util.getLevelIndex(this.top)
  392. const thisLevel = util.getLevelIndex(this.level)
  393. const curLevel = util.getLevelIndex(level)
  394. return thisLevel >= curLevel && top <= curLevel
  395. },
  396. /**
  397. * 更新下级选择器
  398. * index 当前index eg:provinceIndex
  399. * list 当前select 的list的key eg:provinceList
  400. * nextList 下一个的list的key eg:cityList
  401. * name 当前的数据名 eg:广东
  402. * nextName 下一个的数据名 eg:广州
  403. * level 当前等级 eg:1
  404. */
  405. updateNextSelector(index, list, nextList, name, nextName, level) {
  406. const curLevel = util.getLevelIndex(level) - util.getLevelIndex(this.top)
  407. const showLevel = util.getLevelIndex(this.level)
  408. let nextSelected = ''
  409. if (curLevel > showLevel) {
  410. return
  411. }
  412. if (this.isInit && this.value[curLevel]) {
  413. // 初始化当前等级的值
  414. name = this.getCurName(name, this.value, curLevel, list)
  415. }
  416. this[index] = util.getIndex(this[list], name)
  417. if (this.areaData[this[index]]) {
  418. if (this[index] === undefined) {
  419. this.$refs[nextList.substr(0, 4)].setQuery('')
  420. }
  421. this[nextList] = this.areaData[this[index]]
  422. if (this.isInit && this.cloneValue[curLevel + 1]) {
  423. // 初始化下一个值
  424. nextSelected = this.getCurName(
  425. nextSelected,
  426. this.cloneValue,
  427. curLevel + 1,
  428. nextList
  429. )
  430. }
  431. if (this.isInit && this.value.length !== 0) {
  432. this[nextName] = nextSelected || this.setNextSelect(index)
  433. } else if (!this.isInit && this.auto) {
  434. this[nextName] = nextSelected || this.setNextSelect(index)
  435. }
  436. if (this.isInit && curLevel === showLevel) {
  437. this.returnRes(curLevel)
  438. }
  439. } else {
  440. this[nextName] = ''
  441. this[nextList] = []
  442. }
  443. // 没有这样的数据
  444. // if ((this[nextName] === '市辖区' && this.auto) || (this[nextName] === '市辖区' && this.value.length !== 0)) {
  445. // this.updateNextSelector('cityIndex', 'cityList', 'districtList', '市辖区', 'currDistrict', 'city')
  446. // }
  447. },
  448. getCurName(name, value, curLevel, list) {
  449. const valueItem = value[curLevel]
  450. if (this.dataType === 'all') {
  451. if (
  452. valueItem &&
  453. valueItem.name &&
  454. util.getIndex(this[list], valueItem.name)
  455. ) {
  456. return valueItem.name
  457. }
  458. } else {
  459. if (isNaN(parseInt(valueItem))) {
  460. if (util.getIndex(this[list], valueItem)) {
  461. return valueItem
  462. }
  463. } else {
  464. if (Object.keys(this[list]).indexOf(valueItem) > -1) {
  465. if (curLevel === 0) {
  466. return this.areaData[this.topVal][valueItem]
  467. } else {
  468. return this.areaData[value[curLevel - 1]][valueItem]
  469. }
  470. }
  471. }
  472. }
  473. return name
  474. },
  475. setNextSelect(index) {
  476. return this.areaData[this[index]][
  477. Object.keys(this.areaData[this[index]])[0]
  478. ]
  479. },
  480. returnRes(level) {
  481. if (this.auto) {
  482. this.returnResArr(this.showLevel)
  483. } else {
  484. this.returnResArr(util.getLevelIndex(level))
  485. }
  486. },
  487. /**
  488. * 设置结果值
  489. */
  490. returnResArr(level) {
  491. const res = []
  492. let i = 0
  493. const codeArr = [
  494. this.countryIndex,
  495. this.provinceIndex,
  496. this.cityIndex,
  497. this.districtIndex,
  498. this.streetIndex
  499. ]
  500. const nameArr = [
  501. this.currCountry,
  502. this.currProvince,
  503. this.currCity,
  504. this.currDistrict,
  505. this.currStreet
  506. ]
  507. if (this.dataType === 'all') {
  508. while (i <= level) {
  509. if (codeArr[i] && nameArr[i]) {
  510. const item = {
  511. code: codeArr[i],
  512. name: nameArr[i]
  513. }
  514. res.push(item)
  515. }
  516. i++
  517. }
  518. } else if (this.dataType === 'name') {
  519. // 名称
  520. while (i <= level) {
  521. if (nameArr[i]) {
  522. res.push(nameArr[i])
  523. }
  524. i++
  525. }
  526. } else {
  527. while (i <= level) {
  528. if (codeArr[i]) {
  529. res.push(codeArr[i])
  530. }
  531. i++
  532. }
  533. }
  534. this.$emit('input', res)
  535. this.$emit('change', res)
  536. },
  537. /**
  538. * 判断是否有改变
  539. */
  540. hasChange(level) {
  541. this.isInit = false
  542. // 级联下个级别的展示值为空
  543. if (level === 'province') {
  544. this.currCity = ''
  545. } else if (level === 'city') {
  546. this.currDistrict = ''
  547. } else if (level === 'district') {
  548. this.currStreet = ''
  549. }
  550. },
  551. /**
  552. * 处理 占位符
  553. */
  554. handledPlaceholder(level) {
  555. if (this.placeholder !== '' && typeof this.placeholder === 'string') {
  556. return this.placeholder
  557. } else {
  558. const curLevel = util.getLevelIndex(level)
  559. if (this.placeholder && this.placeholder[curLevel]) {
  560. return this.placeholder[curLevel]
  561. } else {
  562. return this.defaultPlaceholder[curLevel]
  563. }
  564. }
  565. },
  566. /**
  567. * 处理 选项为空时显示的文字
  568. */
  569. handledNoDataText(level) {
  570. const index = util.getLevelIndex(level)
  571. if (typeof this.notFoundText === 'string' && this.notFoundText !== '') {
  572. return this.notFoundText
  573. } else {
  574. if (!this.notFoundText) {
  575. return this.defaultnotFoundText[index]
  576. } else {
  577. if (this.notFoundText[index]) {
  578. return this.notFoundText[index]
  579. } else {
  580. return this.defaultnotFoundText[index]
  581. }
  582. }
  583. }
  584. },
  585. /**
  586. * 处理 禁用的
  587. */
  588. handledDisabled(level) {
  589. const curLevel = util.getLevelIndex(level)
  590. if (typeof this.disabled === 'string') {
  591. // 字符串
  592. if (util.oneOf(this.disabled, levelArr)) {
  593. const curDisabled = util.getLevelIndex(this.disabled)
  594. if (curLevel >= curDisabled) {
  595. return true
  596. } else {
  597. return false
  598. }
  599. }
  600. } else if (typeof this.disabled === 'number') {
  601. if (this.disabled <= levelArr.length) {
  602. if (curLevel >= this.disabled) {
  603. return true
  604. } else {
  605. return false
  606. }
  607. }
  608. } else if (Array.isArray(this.disabled)) {
  609. let i = 0
  610. let isDisabled = false
  611. while (this.disabled[i]) {
  612. const curDisabled =
  613. typeof this.disabled === 'number'
  614. ? this.disabled[i]
  615. : util.getLevelIndex(this.disabled[i])
  616. if (curDisabled === curLevel) {
  617. isDisabled = true
  618. break
  619. }
  620. i++
  621. }
  622. return isDisabled
  623. } else {
  624. return this.disabled
  625. }
  626. }
  627. }
  628. }
  629. </script>