地址
Showing
1 changed file
with
123 additions
and
7 deletions
| ... | @@ -63,11 +63,16 @@ | ... | @@ -63,11 +63,16 @@ |
| 63 | 63 | ||
| 64 | <view class="form-item"> | 64 | <view class="form-item"> |
| 65 | <text class="form-label">省市区</text> | 65 | <text class="form-label">省市区</text> |
| 66 | <picker class="form-picker" mode="region" :value="region" @change="onRegionChange"> | 66 | <view class="form-picker data-picker-wrap"> |
| 67 | <view class="picker-value"> | 67 | <uni-data-picker |
| 68 | {{ region[0] || '请选择' }} {{ region[1] || '' }} {{ region[2] || '' }} | 68 | v-model="regionValue" |
| 69 | :localdata="regionsList" | ||
| 70 | :clear-icon="false" | ||
| 71 | popup-title="请选择省市区" | ||
| 72 | placeholder="请选择" | ||
| 73 | @change="onRegionChange" | ||
| 74 | /> | ||
| 69 | </view> | 75 | </view> |
| 70 | </picker> | ||
| 71 | </view> | 76 | </view> |
| 72 | 77 | ||
| 73 | <view class="form-item"> | 78 | <view class="form-item"> |
| ... | @@ -94,6 +99,8 @@ const list = ref([]); | ... | @@ -94,6 +99,8 @@ const list = ref([]); |
| 94 | const addressPopup = ref(null); | 99 | const addressPopup = ref(null); |
| 95 | const isEdit = ref(false); | 100 | const isEdit = ref(false); |
| 96 | const editId = ref(null); | 101 | const editId = ref(null); |
| 102 | const regionsList = ref([]); | ||
| 103 | let regionsListPromise = null; | ||
| 97 | 104 | ||
| 98 | const form = ref({ | 105 | const form = ref({ |
| 99 | name: '', | 106 | name: '', |
| ... | @@ -105,9 +112,11 @@ const form = ref({ | ... | @@ -105,9 +112,11 @@ const form = ref({ |
| 105 | }); | 112 | }); |
| 106 | 113 | ||
| 107 | const region = ref([]); | 114 | const region = ref([]); |
| 115 | const regionValue = ref([]); | ||
| 108 | 116 | ||
| 109 | onMounted(() => { | 117 | onMounted(() => { |
| 110 | initData(); | 118 | initData(); |
| 119 | getRegionsList(); | ||
| 111 | }); | 120 | }); |
| 112 | 121 | ||
| 113 | const initData = async () => { | 122 | const initData = async () => { |
| ... | @@ -171,7 +180,8 @@ const handleSetDefault = async (item) => { | ... | @@ -171,7 +180,8 @@ const handleSetDefault = async (item) => { |
| 171 | }); | 180 | }); |
| 172 | }; | 181 | }; |
| 173 | 182 | ||
| 174 | const handleEdit = (item) => { | 183 | const handleEdit = async (item) => { |
| 184 | if (!await ensureRegionsReady()) return; | ||
| 175 | isEdit.value = true; | 185 | isEdit.value = true; |
| 176 | editId.value = item.id; | 186 | editId.value = item.id; |
| 177 | form.value = { | 187 | form.value = { |
| ... | @@ -183,10 +193,12 @@ const handleEdit = (item) => { | ... | @@ -183,10 +193,12 @@ const handleEdit = (item) => { |
| 183 | a: item.a | 193 | a: item.a |
| 184 | }; | 194 | }; |
| 185 | region.value = [item.province, item.city, item.area]; | 195 | region.value = [item.province, item.city, item.area]; |
| 196 | regionValue.value = getRegionValueByNames(region.value); | ||
| 186 | addressPopup.value.open(); | 197 | addressPopup.value.open(); |
| 187 | }; | 198 | }; |
| 188 | 199 | ||
| 189 | const goAddAddress = () => { | 200 | const goAddAddress = async () => { |
| 201 | if (!await ensureRegionsReady()) return; | ||
| 190 | isEdit.value = false; | 202 | isEdit.value = false; |
| 191 | editId.value = null; | 203 | editId.value = null; |
| 192 | form.value = { | 204 | form.value = { |
| ... | @@ -198,11 +210,57 @@ const goAddAddress = () => { | ... | @@ -198,11 +210,57 @@ const goAddAddress = () => { |
| 198 | a: '' | 210 | a: '' |
| 199 | }; | 211 | }; |
| 200 | region.value = []; | 212 | region.value = []; |
| 213 | regionValue.value = []; | ||
| 201 | addressPopup.value.open(); | 214 | addressPopup.value.open(); |
| 202 | }; | 215 | }; |
| 203 | 216 | ||
| 204 | const onRegionChange = (e) => { | 217 | const onRegionChange = (e) => { |
| 205 | region.value = e.detail.value; | 218 | const selected = e?.detail?.value || []; |
| 219 | region.value = selected.map(item => getNodeText(item)).filter(Boolean); | ||
| 220 | regionValue.value = selected.map(item => getNodeValue(item)).filter(Boolean); | ||
| 221 | }; | ||
| 222 | |||
| 223 | const ensureRegionsReady = async () => { | ||
| 224 | await getRegionsList(); | ||
| 225 | if (regionsList.value.length) return true; | ||
| 226 | uni.showToast({ title: '地区数据加载失败,请稍后重试', icon: 'none' }); | ||
| 227 | return false; | ||
| 228 | }; | ||
| 229 | |||
| 230 | const getRegionsList = async () => { | ||
| 231 | if (regionsList.value.length) return; | ||
| 232 | if (regionsListPromise) return regionsListPromise; | ||
| 233 | regionsListPromise = api.regionsList(null, { showLoading: false }) | ||
| 234 | .then(res => { | ||
| 235 | regionsList.value = res.data || []; | ||
| 236 | if (region.value.length) { | ||
| 237 | regionValue.value = getRegionValueByNames(region.value); | ||
| 238 | } | ||
| 239 | }) | ||
| 240 | .catch(e => { | ||
| 241 | console.error('获取地区数据失败', e); | ||
| 242 | regionsList.value = []; | ||
| 243 | }) | ||
| 244 | .finally(() => { | ||
| 245 | regionsListPromise = null; | ||
| 246 | }); | ||
| 247 | return regionsListPromise; | ||
| 248 | }; | ||
| 249 | |||
| 250 | const getNodeText = (node) => node?.text ?? node?.label ?? node?.name ?? node; | ||
| 251 | const getNodeValue = (node) => node?.value ?? node?.id ?? node; | ||
| 252 | |||
| 253 | const getRegionValueByNames = (names = []) => { | ||
| 254 | if (!names.length || !regionsList.value.length) return []; | ||
| 255 | const path = []; | ||
| 256 | let list = regionsList.value; | ||
| 257 | for (const name of names) { | ||
| 258 | const node = list.find(item => getNodeText(item) === name); | ||
| 259 | if (!node) return []; | ||
| 260 | path.push(getNodeValue(node)); | ||
| 261 | list = node.children || []; | ||
| 262 | } | ||
| 263 | return path; | ||
| 206 | }; | 264 | }; |
| 207 | 265 | ||
| 208 | const closePopup = () => { | 266 | const closePopup = () => { |
| ... | @@ -430,6 +488,64 @@ const submitAddress = async () => { | ... | @@ -430,6 +488,64 @@ const submitAddress = async () => { |
| 430 | font-size: 28rpx; | 488 | font-size: 28rpx; |
| 431 | color: #333; | 489 | color: #333; |
| 432 | } | 490 | } |
| 491 | |||
| 492 | &.data-picker-wrap { | ||
| 493 | padding: 0; | ||
| 494 | |||
| 495 | :deep(.uni-data-tree) { | ||
| 496 | width: 100%; | ||
| 497 | } | ||
| 498 | |||
| 499 | :deep(.uni-data-tree-input) { | ||
| 500 | width: 100%; | ||
| 501 | } | ||
| 502 | |||
| 503 | :deep(.input-value) { | ||
| 504 | position: relative; | ||
| 505 | display: flex; | ||
| 506 | width: 100%; | ||
| 507 | height: 80rpx; | ||
| 508 | border: none; | ||
| 509 | background: transparent; | ||
| 510 | padding: 0 20rpx; | ||
| 511 | box-sizing: border-box; | ||
| 512 | } | ||
| 513 | |||
| 514 | :deep(.selected-area) { | ||
| 515 | height: 80rpx; | ||
| 516 | line-height: 80rpx; | ||
| 517 | font-size: 28rpx; | ||
| 518 | color: #333; | ||
| 519 | padding-right: 0; | ||
| 520 | box-sizing: border-box; | ||
| 521 | } | ||
| 522 | |||
| 523 | :deep(.selected-list) { | ||
| 524 | justify-content: flex-start; | ||
| 525 | } | ||
| 526 | |||
| 527 | :deep(.placeholder) { | ||
| 528 | color: #999; | ||
| 529 | } | ||
| 530 | |||
| 531 | :deep(.arrow-area) { | ||
| 532 | display: none; | ||
| 533 | } | ||
| 534 | |||
| 535 | :deep(.input-arrow) { | ||
| 536 | display: none; | ||
| 537 | } | ||
| 538 | |||
| 539 | :deep(.uni-data-tree-dialog .selected-area) { | ||
| 540 | overflow: hidden; | ||
| 541 | } | ||
| 542 | |||
| 543 | :deep(.uni-data-tree-dialog .selected-area ::-webkit-scrollbar) { | ||
| 544 | display: none; | ||
| 545 | width: 0; | ||
| 546 | height: 0; | ||
| 547 | } | ||
| 548 | } | ||
| 433 | } | 549 | } |
| 434 | 550 | ||
| 435 | .form-textarea { | 551 | .form-textarea { | ... | ... |
-
Please register or sign in to post a comment