fa-citys.vue 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. <template>
  2. <u-popup
  3. v-model="value"
  4. mode="bottom"
  5. :popup="false"
  6. :mask="true"
  7. :closeable="true"
  8. :safe-area-inset-bottom="true"
  9. close-icon-color="#ffffff"
  10. :z-index="uZIndex"
  11. :maskCloseAble="maskCloseAble"
  12. @close="close"
  13. >
  14. <u-tabs v-if="value" :list="genTabsList" :active-color="theme.bgColor" :is-scroll="true" :current="tabsIndex" @change="tabsChange" ref="tabs"></u-tabs>
  15. <view class="area-box">
  16. <view class="u-flex" :class="{ change: isChange }">
  17. <view class="area-item">
  18. <view class="u-padding-10 u-bg-gray" style="height: 100%;">
  19. <scroll-view :scroll-y="true" style="height: 100%">
  20. <u-cell-group>
  21. <u-cell-item
  22. v-for="(item, index) in provinces"
  23. :title="item.label"
  24. :arrow="false"
  25. :index="index"
  26. :key="index"
  27. @click="provinceChange"
  28. >
  29. <u-icon v-if="isChooseP && province === index" slot="right-icon" size="34" name="checkbox-mark"></u-icon>
  30. </u-cell-item>
  31. </u-cell-group>
  32. </scroll-view>
  33. </view>
  34. </view>
  35. <view class="area-item">
  36. <view class="u-padding-10 u-bg-gray" style="height: 100%;">
  37. <scroll-view :scroll-y="true" style="height: 100%">
  38. <u-cell-group v-if="isChooseP">
  39. <u-cell-item v-for="(item, index) in citys" :title="item.label" :arrow="false" :index="index" :key="index" @click="cityChange">
  40. <u-icon v-if="isChooseC && city === index" slot="right-icon" size="34" name="checkbox-mark"></u-icon>
  41. </u-cell-item>
  42. </u-cell-group>
  43. </scroll-view>
  44. </view>
  45. </view>
  46. <view class="area-item">
  47. <view class="u-padding-10 u-bg-gray" style="height: 100%;">
  48. <scroll-view :scroll-y="true" style="height: 100%">
  49. <u-cell-group v-if="isChooseC">
  50. <u-cell-item v-for="(item, index) in areas" :title="item.label" :arrow="false" :index="index" :key="index" @click="areaChange">
  51. <u-icon v-if="isChooseA && area === index" slot="right-icon" size="34" name="checkbox-mark"></u-icon>
  52. </u-cell-item>
  53. </u-cell-group>
  54. </scroll-view>
  55. </view>
  56. </view>
  57. </view>
  58. </view>
  59. </u-popup>
  60. </template>
  61. <script>
  62. /**
  63. * city-select 省市区级联选择器
  64. * @property {String Number} z-index 弹出时的z-index值(默认1075)
  65. * @property {Boolean} mask-close-able 是否允许通过点击遮罩关闭Picker(默认true)
  66. * @property {String} default-region 默认选中的地区,中文形式
  67. * @property {String} default-code 默认选中的地区,编号形式
  68. */
  69. export default {
  70. name: 'fa-citys',
  71. props: {
  72. // 通过双向绑定控制组件的弹出与收起
  73. value: {
  74. type: Boolean,
  75. default: false
  76. },
  77. // 默认显示地区的编码,areaCode可传类似["13", "1303", "130304"]
  78. areaCode: {
  79. type: Array,
  80. default() {
  81. return [];
  82. }
  83. },
  84. // 是否允许通过点击遮罩关闭Picker
  85. maskCloseAble: {
  86. type: Boolean,
  87. default: true
  88. },
  89. // 弹出的z-index值
  90. zIndex: {
  91. type: [String, Number],
  92. default: 0
  93. }
  94. },
  95. data() {
  96. return {
  97. cityValue: '',
  98. isChooseP: false, //是否已经选择了省
  99. province: 0, //省级下标
  100. provinces: [],
  101. isChooseC: false, //是否已经选择了市
  102. city: 0, //市级下标
  103. citys: [],
  104. isChooseA: false, //是否已经选择了区
  105. area: 0, //区级下标
  106. areas: [],
  107. tabsIndex: 0
  108. };
  109. },
  110. mounted() {
  111. this.init();
  112. },
  113. computed: {
  114. isChange() {
  115. return this.tabsIndex > 1;
  116. },
  117. genTabsList() {
  118. let tabsList = [
  119. {
  120. name: '请选择'
  121. }
  122. ];
  123. if (this.isChooseP) {
  124. tabsList[0]['name'] = this.provinces[this.province]['label'];
  125. tabsList[1] = {
  126. name: '请选择'
  127. };
  128. }
  129. if (this.isChooseC) {
  130. tabsList[1]['name'] = this.citys[this.city]['label'];
  131. tabsList[2] = {
  132. name: '请选择'
  133. };
  134. }
  135. if (this.isChooseA) {
  136. tabsList[2]['name'] = this.areas[this.area]['label'];
  137. }
  138. return tabsList;
  139. },
  140. uZIndex() {
  141. // 如果用户有传递z-index值,优先使用
  142. return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
  143. }
  144. },
  145. methods: {
  146. async getArea(type = '', id = '') {
  147. let where = {};
  148. if (type == 'citys') {
  149. where = {
  150. province: id
  151. };
  152. } else if (type == 'areas') {
  153. where = {
  154. city: id
  155. };
  156. }
  157. let res = await this.$api.area(where);
  158. if (res.code) {
  159. let key = type ? type : 'provinces';
  160. this[key] = res.data;
  161. }
  162. },
  163. async init() {
  164. if (this.areaCode.length == 3) {
  165. await this.setProvince('', this.areaCode[0]);
  166. }else{
  167. await this.getArea();
  168. }
  169. },
  170. async setProvince(label = '', value = '') {
  171. await this.getArea();
  172. this.provinces.map(async (v, k) => {
  173. if (value ? v.value == value : v.label == label) {
  174. await this.provinceChange(k);
  175. await this.setCity('', this.areaCode[1]);
  176. }
  177. });
  178. },
  179. async setCity(label = '', value = '') {
  180. this.citys.map(async (v, k) => {
  181. if (value ? v.value == value : v.label == label) {
  182. await this.cityChange(k);
  183. await this.setArea('', this.areaCode[2]);
  184. }
  185. });
  186. },
  187. async setArea(label = '', value = '') {
  188. this.areas.map((v, k) => {
  189. if (value ? v.value == value : v.label == label) {
  190. this.isChooseA = true;
  191. this.area = k;
  192. this.areaChange(k)
  193. }
  194. });
  195. },
  196. close() {
  197. this.$emit('input', false);
  198. },
  199. tabsChange(index) {
  200. this.tabsIndex = index;
  201. },
  202. async provinceChange(index) {
  203. this.isChooseP = true;
  204. this.isChooseC = false;
  205. this.isChooseA = false;
  206. this.province = index;
  207. await this.getArea('citys', this.provinces[index].value);
  208. this.tabsIndex = 1;
  209. },
  210. async cityChange(index) {
  211. this.isChooseC = true;
  212. this.isChooseA = false;
  213. this.city = index;
  214. await this.getArea('areas', this.citys[index].value);
  215. this.tabsIndex = 2;
  216. },
  217. areaChange(index) {
  218. this.isChooseA = true;
  219. this.area = index;
  220. let result = {};
  221. result.province = this.provinces[this.province];
  222. result.city = this.citys[this.city];
  223. result.area = this.areas[this.area];
  224. this.$emit('city-change', result);
  225. this.close();
  226. }
  227. }
  228. };
  229. </script>
  230. <style lang="scss">
  231. .area-box {
  232. width: 100%;
  233. overflow: hidden;
  234. height: 800rpx;
  235. > view {
  236. width: 150%;
  237. transition: transform 0.3s ease-in-out 0s;
  238. transform: translateX(0);
  239. &.change {
  240. transform: translateX(-33.3333333%);
  241. }
  242. }
  243. .area-item {
  244. width: 33.3333333%;
  245. height: 800rpx;
  246. }
  247. }
  248. </style>