addressChoose.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. <template>
  2. <div class="distpicker-address-wrapper">
  3. <template>
  4. <div>{{regProvince}}{{regCity}}{{regDistrict}}{{regStreet}}</div>
  5. <div>{{chooseAddress}}</div>
  6. <div class="return">
  7. <i class="fa fa-angle-left" @click="goBack"></i>
  8. 填写企业注册地址
  9. <span @click="goFinish">完成</span>
  10. </div>
  11. <div class="choose">
  12. <div class="form-group" @click="popupVisible = true">
  13. <label for="addr">选择地区</label>
  14. <input readonly
  15. id="addr"
  16. placeholder="地区信息"
  17. v-model="chooseAddress">
  18. <i class="fa fa-map-marker"></i>
  19. </div>
  20. <div class="form-group">
  21. <label for="addrs">详细信息</label>
  22. <textarea placeholder="街道、大厦、楼层信息"
  23. id="addrs"
  24. v-model="detailAddress"
  25. @blur="out"></textarea>
  26. </div>
  27. </div>
  28. </template>
  29. <mt-popup v-model="popupVisible" position="bottom" class="mint-popup">
  30. <template>
  31. <div class="handle">
  32. <span class="cancel" @click="cancel">取消</span>
  33. <span class="sure" @click="sure">完成</span>
  34. </div>
  35. <div :class="addressHeader">
  36. <ul>
  37. <li :class="{'active': tab === 1}" @click="resetProvince">{{ currentProvince && !staticPlaceholder ? currentProvince : placeholders.province }}</li>
  38. <template v-if="!onlyProvince">
  39. <li v-if="showCityTab" :class="{'active': tab === 2}" @click="resetCity">{{ currentCity && !staticPlaceholder ? currentCity : placeholders.city }}</li>
  40. <li v-if="showAreaTab && !hideArea" :class="{'active': tab === 3}">{{ currentArea && !staticPlaceholder ? currentArea : placeholders.area }}</li>
  41. </template>
  42. </ul>
  43. </div>
  44. <div :class="addressContainer">
  45. <ul v-if="tab === 1">
  46. <li v-for="(item, index) in provinces"
  47. :class="{'active': item === currentProvince}"
  48. @click="chooseProvince(item)"
  49. :key="index">
  50. {{ item }}
  51. </li>
  52. </ul>
  53. <template v-if="!onlyProvince">
  54. <ul v-if="tab === 2">
  55. <li v-for="(item, index) in cities"
  56. :class="{'active': item === currentCity}"
  57. @click="chooseCity(item)"
  58. :key="index">
  59. {{ item }}
  60. </li>
  61. </ul>
  62. <ul v-if="tab === 3 && !hideArea">
  63. <li v-for="(item, index) in areas"
  64. :class="{'active': item === currentArea}"
  65. @click="chooseArea(item)"
  66. :key="index">
  67. {{ item }}
  68. </li>
  69. </ul>
  70. </template>
  71. </div>
  72. </template>
  73. </mt-popup>
  74. </div>
  75. </template>
  76. <script>
  77. import DISTRICTS from './districts'
  78. const DEFAULT_CODE = 100000
  79. export default {
  80. name: 'v-distpicker',
  81. props: {
  82. province: { type: [String, Number], default: '' },
  83. city: { type: [String, Number], default: '' },
  84. area: { type: [String, Number], default: '' },
  85. type: { type: String, default: '' },
  86. hideArea: { type: Boolean, default: false },
  87. onlyProvince: { type: Boolean, default: false },
  88. staticPlaceholder: { type: Boolean, default: false },
  89. placeholders: {
  90. type: Object,
  91. default () {
  92. return {
  93. province: '省',
  94. city: '市',
  95. area: '区'
  96. }
  97. }
  98. },
  99. disabled: { type: Boolean, default: false },
  100. addressHeader: { type: String, default: 'address-header' },
  101. addressContainer: { type: String, default: 'address-container' },
  102. popAddress: {type: String},
  103. regStreet: {type: String},
  104. regProvince: {type: String},
  105. regCity: {type: String},
  106. regDistrict: {type: String}
  107. },
  108. data () {
  109. return {
  110. popupVisible: false,
  111. allAddress: '',
  112. detailAddress: '',
  113. chooseAddress: '',
  114. tab: 1,
  115. showCityTab: false,
  116. showAreaTab: false,
  117. provinces: [],
  118. cities: [],
  119. areas: [],
  120. currentProvince: this.determineType(this.province) || this.placeholders.province,
  121. currentCity: this.determineType(this.city) || this.placeholders.city,
  122. currentArea: this.determineType(this.area) || this.placeholders.area
  123. }
  124. },
  125. created () {
  126. this.chooseAddress = this.popAddress
  127. this.detailAddress = this.regStreet
  128. if (this.chooseAddress && this.detailAddress) {
  129. this.allAddress = this.chooseAddress + this.detailAddress
  130. }
  131. this.currentProvince = this.regProvince
  132. this.currentCity = this.regCity
  133. this.currentArea = this.regDistrict
  134. if (this.area && !this.hideArea && !this.onlyProvince) {
  135. this.tab = 3
  136. this.showCityTab = true
  137. this.showAreaTab = true
  138. this.areas = this.getDistricts(this.getAreaCode(this.determineType(this.city), this.area))
  139. } else if (this.city && this.hideArea && !this.onlyProvince) {
  140. this.tab = 2
  141. this.showCityTab = true
  142. this.cities = this.getDistricts(this.getAreaCode(this.determineType(this.province)))
  143. } else {
  144. this.provinces = this.getDistricts()
  145. }
  146. },
  147. watch: {
  148. currentProvince (vaule) {
  149. this.$emit('province', this.setData(vaule))
  150. if (this.onlyProvince) this.emit('selected')
  151. },
  152. currentCity (value) {
  153. this.$emit('city', this.setData(value, this.currentProvince))
  154. if (value !== this.placeholders.city && this.hideArea) this.emit('selected')
  155. },
  156. currentArea (value) {
  157. this.$emit('area', this.setData(value, this.currentProvince))
  158. if (value !== this.placeholders.area) this.emit('selected')
  159. },
  160. province (value) {
  161. this.currentProvince = this.province || this.placeholders.province
  162. this.cities = this.determineValue(this.currentProvince, this.placeholders.province)
  163. },
  164. city (value) {
  165. this.currentCity = this.city || this.placeholders.city
  166. this.areas = this.determineValue(this.currentCity, this.placeholders.city, this.currentProvince)
  167. },
  168. area (value) {
  169. this.currentArea = this.area || this.placeholders.area
  170. }
  171. },
  172. mounted () {
  173. this.$nextTick(() => {
  174. if (!this.regProvince && !this.regProvince && !this.regDistrict) {
  175. console.log('result', !this.regProvince && !this.regProvince && !this.regDistrict)
  176. } else {
  177. this.chooseProvince(this.regProvince)
  178. this.chooseCity(this.regCity)
  179. this.chooseArea(this.regDistrict)
  180. }
  181. })
  182. },
  183. methods: {
  184. // 取消选择地址
  185. cancel () {
  186. this.popupVisible = false
  187. this.allAddress = ''
  188. },
  189. // 完成选择地址
  190. sure () {
  191. if (this.currentProvince.length <= 1) {
  192. this.$toast({
  193. message: '请选择省、市、区',
  194. iconClass: 'el-icon-warning'
  195. })
  196. this.popupVisible = true
  197. } else if (this.currentCity.length <= 1) {
  198. this.$toast({
  199. message: '请选择省、市、区',
  200. iconClass: 'el-icon-warning'
  201. })
  202. this.popupVisible = true
  203. } else if (this.currentArea.length <= 1) {
  204. this.$toast({
  205. message: '请选择省、市、区',
  206. iconClass: 'el-icon-warning'
  207. })
  208. this.popupVisible = true
  209. } else {
  210. this.chooseAddress = this.currentProvince + this.currentCity + this.currentArea
  211. this.popupVisible = false
  212. }
  213. },
  214. // 监听textarea
  215. out () {
  216. if (!this.detailAddress) {
  217. this.$toast({
  218. message: '请输入详情地址',
  219. iconClass: 'el-icon-warning'
  220. })
  221. } else {
  222. let reg = /^(?=.*([\w\u4e00-\u9fa5]+)).*$/
  223. if (!reg.test(this.detailAddress)) {
  224. this.$toast({
  225. message: '请输入详情地址',
  226. iconClass: 'el-icon-warning'
  227. })
  228. }
  229. }
  230. },
  231. // 返回注册页面
  232. goBack () {
  233. if (this.chooseAddress && this.detailAddress) {
  234. this.allAddress = this.chooseAddress + this.detailAddress
  235. this.$emit('getAddress', this.allAddress)
  236. this.$emit('getProvince', this.currentProvince)
  237. this.$emit('getCity', this.currentCity)
  238. this.$emit('getArea', this.currentArea)
  239. this.$emit('getDetailAddress', this.detailAddress)
  240. this.$emit('getPopAddress', this.chooseAddress)
  241. } else if (this.chooseAddress && !this.detailAddress) {
  242. this.$emit('getAddress', '')
  243. this.$emit('getProvince', this.currentProvince)
  244. this.$emit('getCity', this.currentCity)
  245. this.$emit('getArea', this.currentArea)
  246. this.$emit('getDetailAddress', '')
  247. this.$emit('popAddress', this.chooseAddress)
  248. } else if (!this.chooseAddress && this.detailAddress) {
  249. this.$emit('getAddress', '')
  250. this.$emit('getProvince', '')
  251. this.$emit('getCity', '')
  252. this.$emit('getArea', '')
  253. this.$emit('getDetailAddress', this.detailAddress)
  254. this.$emit('popAddress', '')
  255. } else {
  256. this.$emit('getAddress', '')
  257. this.$emit('getProvince', '')
  258. this.$emit('getCity', '')
  259. this.$emit('getArea', '')
  260. this.$emit('getDetailAddress', '')
  261. this.$emit('popAddress', '')
  262. }
  263. this.$emit('showEvent', false)
  264. },
  265. goFinish () {
  266. if (!this.chooseAddress) {
  267. this.$toast({
  268. message: '请选择省、市、区',
  269. iconClass: 'el-icon-warning'
  270. })
  271. } else if (!this.detailAddress) {
  272. this.$toast({
  273. message: '请输入详情地址',
  274. iconClass: 'el-icon-warning'
  275. })
  276. } else {
  277. if (this.chooseAddress && this.detailAddress) {
  278. this.allAddress = this.chooseAddress + this.detailAddress
  279. }
  280. this.$emit('getAddress', this.allAddress)
  281. this.$emit('getProvince', this.currentProvince)
  282. this.$emit('getCity', this.currentCity)
  283. this.$emit('getArea', this.currentArea)
  284. this.$emit('getDetailAddress', this.detailAddress)
  285. this.$emit('getPopAddress', this.chooseAddress)
  286. this.$emit('showEvent', false)
  287. }
  288. },
  289. setData (value, check = '') {
  290. return {
  291. code: this.getAreaCode(value, check),
  292. value: value
  293. }
  294. },
  295. emit (name) {
  296. let data = {
  297. province: this.setData(this.currentProvince)
  298. }
  299. if (!this.onlyProvince) {
  300. this.$set(data, 'city', this.setData(this.currentCity))
  301. }
  302. if (!this.onlyProvince || this.hideArea) {
  303. this.$set(data, 'area', this.setData(this.currentArea))
  304. }
  305. this.$emit(name, data)
  306. },
  307. getCities () {
  308. this.currentCity = this.placeholders.city
  309. this.currentArea = this.placeholders.area
  310. this.cities = this.determineValue(this.currentProvince, this.placeholders.province)
  311. this.cleanList('areas')
  312. if (this.cities === null) {
  313. this.emit('selected')
  314. this.tab = 1
  315. this.showCityTab = false
  316. }
  317. },
  318. getAreas () {
  319. this.currentArea = this.placeholders.area
  320. this.areas = this.determineValue(this.currentCity, this.placeholders.city, this.currentProvince)
  321. if (this.areas === null) {
  322. this.emit('selected')
  323. this.tab = 2
  324. this.showAreaTab = false
  325. }
  326. },
  327. resetProvince () {
  328. this.tab = 1
  329. this.provinces = this.getDistricts()
  330. this.showCityTab = false
  331. this.showAreaTab = false
  332. },
  333. resetCity () {
  334. this.tab = 2
  335. this.showCityTab = true
  336. this.showAreaTab = false
  337. this.getCities()
  338. },
  339. chooseProvince (name) {
  340. this.currentProvince = name
  341. if (this.onlyProvince) return
  342. this.tab = 2
  343. this.showCityTab = true
  344. this.showAreaTab = false
  345. this.getCities()
  346. },
  347. chooseCity (name) {
  348. this.currentCity = name
  349. if (this.hideArea) return
  350. this.tab = 3
  351. this.showCityTab = true
  352. this.showAreaTab = true
  353. this.getAreas()
  354. },
  355. chooseArea (name) {
  356. this.currentArea = name
  357. },
  358. getAreaCode (name, check = '') {
  359. for (let x in DISTRICTS) {
  360. for (let y in DISTRICTS[x]) {
  361. if (name === DISTRICTS[x][y]) {
  362. if (check.length > 0) {
  363. if (y.slice(0, 2) !== this.getAreaCode(check).slice(0, 2)) {
  364. continue
  365. } else {
  366. return y
  367. }
  368. } else {
  369. return y
  370. }
  371. }
  372. }
  373. }
  374. },
  375. getCodeValue (code) {
  376. console.log(code)
  377. for (let x in DISTRICTS) {
  378. for (let y in DISTRICTS[x]) {
  379. if (code === parseInt(y)) {
  380. return DISTRICTS[x][y]
  381. }
  382. }
  383. }
  384. },
  385. getDistricts (code = DEFAULT_CODE) {
  386. return DISTRICTS[code] || []
  387. },
  388. determineValue (currentValue, placeholderValue, check = '') {
  389. if (currentValue === placeholderValue) {
  390. return []
  391. } else {
  392. return this.getDistricts(this.getAreaCode(currentValue, check))
  393. }
  394. },
  395. determineType (value) {
  396. if (typeof value === 'number') {
  397. return this.getCodeValue(value)
  398. }
  399. return value
  400. },
  401. cleanList (name) {
  402. this[name] = []
  403. }
  404. }
  405. }
  406. </script>
  407. <style lang="scss" scoped>
  408. .mint-toast.is-placemiddle {
  409. z-index: 1000;
  410. }
  411. .distpicker-address-wrapper {
  412. color: #9caebf;
  413. .handle {
  414. padding: .3rem;
  415. span{
  416. font-size: .28rem;
  417. color: #2d8cf0;
  418. }
  419. span.cancel{
  420. float: left;
  421. }
  422. span.sure{
  423. float: right;
  424. }
  425. }
  426. .return {
  427. padding: 0 .2rem;
  428. margin-bottom: .3rem;
  429. width: 100%;
  430. height: .9rem;
  431. line-height: .9rem;
  432. font-size: .28rem;
  433. text-align: center;
  434. color: #787878;
  435. background: #fff;
  436. overflow: hidden;
  437. i{
  438. float: left;
  439. font-size: .5rem;
  440. margin-top: .2rem;
  441. font-weight: bold;
  442. color: #000;
  443. }
  444. span{
  445. float: right;
  446. font-size: .3rem;
  447. color: #999;
  448. }
  449. }
  450. .choose{
  451. background: #fff;
  452. div.form-group {
  453. padding: 0 .2rem;
  454. position: relative;
  455. height: 1.5rem;
  456. overflow: hidden;
  457. &:first-child{
  458. height: 1rem;
  459. line-height: 1rem;
  460. border-bottom: 1px solid #ddd;
  461. }
  462. label{
  463. float: left;
  464. margin-right: .6rem;
  465. font-size: .3rem;
  466. font-weight: normal;
  467. color: #505050;
  468. }
  469. input{
  470. float: left;
  471. height: 1rem;
  472. color: #555;
  473. font-size: .28rem;
  474. border: none;
  475. }
  476. textarea {
  477. float: left;
  478. /*width: 4.6rem;*/
  479. height: 1.5rem;
  480. font-size: .28rem;
  481. color: #555;
  482. border: none;
  483. outline: none;
  484. resize:none
  485. }
  486. i{
  487. position: absolute;
  488. top: .3rem;
  489. right: .4rem;
  490. font-size: .4rem;
  491. color: #a0a0a0;
  492. }
  493. }
  494. }
  495. select {
  496. padding: .5rem .75rem;
  497. height: 40px;
  498. font-size: 1rem;
  499. line-height: 1.25;
  500. color: #464a4c;
  501. background-color: #fff;
  502. background-image: none;
  503. -webkit-background-clip: padding-box;
  504. background-clip: padding-box;
  505. border: 1px solid rgba(0,0,0,.15);
  506. border-radius: .25rem;
  507. -webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
  508. transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
  509. -o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
  510. transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
  511. transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
  512. option {
  513. font-weight: normal;
  514. display: block;
  515. white-space: pre;
  516. min-height: 1.2em;
  517. padding: 0px 2px 1px;
  518. }
  519. }
  520. ul {
  521. margin: 0;
  522. padding: 0;
  523. li {
  524. list-style: none;
  525. }
  526. }
  527. .address-header {
  528. background-color: #fff;
  529. ul {
  530. display: flex;
  531. justify-content: space-around;
  532. align-items: stretch;
  533. li {
  534. display: inline-block;
  535. padding: 10px 10px 7px;
  536. color: #000;
  537. &.active {
  538. border-bottom: #52697f solid 3px;
  539. color: #52697f;
  540. font-weight: bold;
  541. }
  542. }
  543. }
  544. }
  545. .address-container {
  546. background-color: #fff;
  547. ul {
  548. height: 100%;
  549. overflow: auto;
  550. li {
  551. color: #555;
  552. padding: 8px 10px;
  553. border-top: 1px solid #f6f6f6;
  554. &.active {
  555. color: #52697f;
  556. font-weight: bold;
  557. }
  558. }
  559. }
  560. }
  561. }
  562. </style>