hgLevel4Address.vue 6.9 KB

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