hgLevel4Address.vue 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. <template>
  2. <view class="address-page">
  3. <view class="picker-content">
  4. <!-- 市 -->
  5. <scroll-view scroll-y class="column city">
  6. <view v-for="(city, i) in filteredCities" :key="i" class="item"
  7. :class="{ cityActive: selectedCity && selectedCity.code === city.code }" @click="selectCity(city)">
  8. {{ city.name }}
  9. </view>
  10. </scroll-view>
  11. <!-- 区 -->
  12. <scroll-view scroll-y class="column district">
  13. <view v-for="(area, i) in filteredAreas" :key="i" class="item"
  14. :class="{ districtActive: selectedArea && selectedArea.code === area.code }" @click="selectArea(area)">
  15. {{ area.name }}
  16. </view>
  17. </scroll-view>
  18. <!-- 街道 -->
  19. <scroll-view scroll-y class="column street">
  20. <view v-for="(street, i) in filteredStreets" :key="i" class="item"
  21. :class="{ streetActive: selectedStreet && selectedStreet.code === street.code }"
  22. @click="selectStreet(street)">
  23. {{ street.name }}
  24. </view>
  25. </scroll-view>
  26. </view>
  27. <!-- 底部按钮 -->
  28. <view class="picker-footer">
  29. <!-- <button class="btn-clear" @click="clear">清除</button> -->
  30. <button class="btn-confirm" @click="handleConfirm">确定</button>
  31. </view>
  32. </view>
  33. </template>
  34. <script>
  35. import addressData from './level4_address.js'
  36. export default {
  37. name: "AddressPicker",
  38. props: {
  39. city: {
  40. type: [String, Number],
  41. default: ''
  42. },
  43. county: {
  44. type: [String, Number],
  45. default: ''
  46. },
  47. street: {
  48. type: [String, Number],
  49. default: ''
  50. }
  51. },
  52. data() {
  53. return {
  54. addressData,
  55. selectedProvince: null,
  56. selectedCity: null,
  57. selectedArea: {
  58. code: 'all',
  59. name: '全部'
  60. },
  61. selectedStreet: {
  62. code: 'all',
  63. name: '全部'
  64. }
  65. }
  66. },
  67. computed: {
  68. filteredProvinces() {
  69. return this.addressData || []
  70. },
  71. filteredCities() {
  72. return this.selectedProvince && this.selectedProvince.children ?
  73. this.selectedProvince.children :
  74. []
  75. },
  76. filteredAreas() {
  77. if (!this.selectedCity) return []
  78. // 市为“全部”或者无子级,区返回一个“全部”
  79. const areas = this.selectedCity.children || []
  80. return [{
  81. code: 'all',
  82. name: '全部'
  83. }, ...areas]
  84. },
  85. filteredStreets() {
  86. if (!this.selectedArea) return []
  87. // 区为“全部”或者无子级,街道返回一个“全部”
  88. const streets = this.selectedArea.children || []
  89. return [{
  90. code: 'all',
  91. name: '全部'
  92. }, ...streets]
  93. }
  94. },
  95. mounted() {
  96. this.initByCity()
  97. },
  98. methods: {
  99. /** 根据 city code 或名称自动定位 */
  100. initByCity() {
  101. if (!this.addressData.length) return
  102. for (const province of this.addressData) {
  103. for (const city of province.children || []) {
  104. if (this.city!=''&&(city.code == this.city || city.name.indexOf(this.city) !== -1)) {
  105. this.selectedProvince = province
  106. this.selectedCity = city
  107. for (const area of city.children || []) {
  108. if (this.county!=''&&(area.code == this.county || area.name.indexOf(this.county) !== -1)) {
  109. this.selectedArea=area
  110. }
  111. for (const street of area.children || []) {
  112. if (this.street!=''&&(street.code == this.street || street.name.indexOf(this.street) !== -1)) {
  113. this.selectedStreet=street
  114. }
  115. }
  116. }
  117. return
  118. }
  119. }
  120. }
  121. // 没找到就选第一个省市
  122. this.selectedProvince = this.addressData[0]
  123. this.selectedCity = this.addressData[0]?.children?.[0] || null
  124. this.selectedArea = {
  125. code: 'all',
  126. name: '全部'
  127. }
  128. this.selectedStreet = {
  129. code: 'all',
  130. name: '全部'
  131. }
  132. },
  133. /** 市选择 */
  134. selectCity(city) {
  135. this.selectedCity = city
  136. this.selectedArea = {
  137. code: 'all',
  138. name: '全部'
  139. }
  140. this.selectedStreet = {
  141. code: 'all',
  142. name: '全部'
  143. }
  144. },
  145. /** 区选择 */
  146. selectArea(area) {
  147. this.selectedArea = area
  148. this.selectedStreet = {
  149. code: 'all',
  150. name: '全部'
  151. }
  152. },
  153. /** 街道选择 */
  154. selectStreet(street) {
  155. return this.$queue.showToast('街道选择暂未开放')
  156. this.selectedStreet = street
  157. },
  158. // /** 清除选择 */
  159. // clear() {
  160. // this.selectedCity = this.selectedProvince?.children?.[0] || null
  161. // this.selectedArea = {
  162. // code: 'all',
  163. // name: '全部'
  164. // }
  165. // this.selectedStreet = {
  166. // code: 'all',
  167. // name: '全部'
  168. // }
  169. // },
  170. /** 确认选择 */
  171. handleConfirm() {
  172. const result = []
  173. if (this.selectedProvince)
  174. result.push({
  175. code: this.selectedProvince.code,
  176. name: this.selectedProvince.name
  177. })
  178. if (this.selectedCity)
  179. result.push({
  180. code: this.selectedCity.code,
  181. name: this.selectedCity.name
  182. })
  183. if (this.selectedArea)
  184. result.push({
  185. code: this.selectedArea.code,
  186. name: this.selectedArea.name
  187. })
  188. if (this.selectedStreet)
  189. result.push({
  190. code: this.selectedStreet.code,
  191. name: this.selectedStreet.name
  192. })
  193. this.$emit('confirm', result)
  194. }
  195. }
  196. }
  197. </script>
  198. <style scoped>
  199. .address-page {
  200. display: flex;
  201. flex-direction: column;
  202. background: #FBFBFB;
  203. margin: 0 16rpx;
  204. flex: 1;
  205. box-sizing: border-box;
  206. }
  207. .picker-content {
  208. display: flex;
  209. overflow: auto;
  210. gap: 16rpx;
  211. }
  212. .column {
  213. padding: 40rpx 0;
  214. box-sizing: border-box;
  215. border-radius: 12rpx;
  216. }
  217. .city{
  218. width: 200rpx;
  219. background: rgba(245, 245, 245, 1);
  220. box-sizing: border-box;
  221. }
  222. .district{
  223. flex: 1;
  224. background: rgba(255, 255, 255, 1);
  225. }
  226. .street{
  227. flex: 1;
  228. background: linear-gradient(to right, rgba(251, 251, 251, 1), rgba(255, 255, 255, 1));
  229. .item{
  230. color: #ccc;
  231. }
  232. }
  233. .item {
  234. padding: 15rpx 50rpx;
  235. font-family: DM Sans;
  236. font-size: 32rpx;
  237. font-weight: 400;
  238. margin-bottom: 16rpx;
  239. }
  240. .item.cityActive {
  241. color: rgba(1, 107, 246, 1);
  242. }
  243. .item.districtActive{
  244. background: rgba(153, 196, 250, 0.4);
  245. color: rgba(1, 107, 246, 1);
  246. }
  247. .item.streetActive{
  248. background: rgba(1, 107, 246, 1);
  249. color: rgba(255, 255, 255, 1);
  250. border-radius: 0px 12rpx 12rpx 0px;
  251. }
  252. .picker-footer {
  253. display: flex;
  254. padding: 30rpx 0;
  255. height: 140rpx;
  256. box-sizing: border-box;
  257. margin: 0 4rpx;
  258. }
  259. .btn-clear,
  260. .btn-confirm {
  261. flex: 1;
  262. height: 80rpx;
  263. line-height: 80rpx;
  264. border-radius: 999px;
  265. font-family: DM Sans;
  266. font-size: 32rpx;
  267. font-weight: 400;
  268. color: rgba(255, 255, 255, 1);
  269. }
  270. .btn-clear {
  271. background: #f5f5f5;
  272. color: #333;
  273. margin-right: 20rpx;
  274. }
  275. .btn-confirm {
  276. box-shadow: 0px 2px 4px 0px rgba(9, 196, 116, 0.3);
  277. background: linear-gradient(90.00deg, rgba(13, 39, 247, 1),rgba(19, 193, 234, 1) 100%);
  278. }
  279. uni-button:after{
  280. border: none;
  281. }
  282. </style>