Add linked Chinese postal code input and lookup data
This commit is contained in:
1 parent
3f685ca068
commit
1e43d910c0
8 files changed
+141
-4
No files matched your search
Vendored
+1
@@ -12,6 +12,7 @@ export {}
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
AppUpdateManagementPanel: typeof import('./components/AppUpdateManagementPanel.vue')['default']
|
||||
ChinesePostalCodeInput: typeof import('./components/ChinesePostalCodeInput.vue')['default']
|
||||
ElAlert: typeof import('element-plus/es')['ElAlert']
|
||||
ElBadge: typeof import('element-plus/es')['ElBadge']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { nativePlaceCandidatesForPostcode, postcodeForNativePlace } from '../data/nativePlaceLookup'
|
||||
|
||||
const postcode = defineModel<string>({ default: '' })
|
||||
const nativePlace = defineModel<string>('nativePlace', { default: '' })
|
||||
const props = defineProps<{ linked?: boolean }>()
|
||||
|
||||
const candidates = ref<string[]>([])
|
||||
const suggestedPostcode = computed(() => props.linked === false ? undefined : postcodeForNativePlace(nativePlace.value))
|
||||
const lockedPrefix = computed(() => suggestedPostcode.value?.slice(0, 4) ?? '')
|
||||
const suffix = computed({
|
||||
get: () => lockedPrefix.value && postcode.value.startsWith(lockedPrefix.value) ? postcode.value.slice(4, 6) : '',
|
||||
set: (value: string) => { postcode.value = `${lockedPrefix.value}${value.replace(/\D/g, '').slice(0, 2)}` },
|
||||
})
|
||||
|
||||
function normalize(value: string) {
|
||||
return value.replace(/\D/g, '').slice(0, 6)
|
||||
}
|
||||
|
||||
function updatePostcode(value: string) {
|
||||
postcode.value = normalize(value)
|
||||
}
|
||||
|
||||
function selectCandidate(value: string) {
|
||||
nativePlace.value = value
|
||||
candidates.value = []
|
||||
}
|
||||
|
||||
watch(suggestedPostcode, (suggested) => {
|
||||
if (!suggested || props.linked === false) return
|
||||
if (!postcode.value.startsWith(suggested.slice(0, 4))) postcode.value = suggested
|
||||
}, { immediate: true })
|
||||
|
||||
watch(postcode, (value) => {
|
||||
if (props.linked === false || nativePlace.value || lockedPrefix.value) return
|
||||
const matches = nativePlaceCandidatesForPostcode(value)
|
||||
candidates.value = matches
|
||||
if (matches.length === 1) selectCandidate(matches[0])
|
||||
})
|
||||
|
||||
watch(() => props.linked, (linked) => {
|
||||
if (linked === false) candidates.value = []
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="postcode-control">
|
||||
<template v-if="linked !== false && lockedPrefix">
|
||||
<el-input :model-value="lockedPrefix" disabled class="postcode-prefix" aria-label="邮政编码前四位" />
|
||||
<el-input v-model="suffix" inputmode="numeric" maxlength="2" placeholder="后两位" aria-label="邮政编码后两位" />
|
||||
</template>
|
||||
<el-input v-else-if="linked !== false" :model-value="postcode" inputmode="numeric" maxlength="6" placeholder="6位邮政编码" @update:model-value="updatePostcode" />
|
||||
<el-input v-else v-model="postcode" maxlength="20" placeholder="邮政编码" />
|
||||
<el-select v-if="linked !== false && candidates.length > 1" placeholder="请选择匹配的区县" @update:model-value="selectCandidate">
|
||||
<el-option v-for="candidate in candidates" :key="candidate" :label="candidate" :value="candidate" />
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.postcode-control { display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; width: 100%; }
|
||||
.postcode-prefix { width: 100%; }
|
||||
.postcode-control:has(.postcode-prefix) { grid-template-columns: 1fr 1fr; }
|
||||
@media (max-width: 480px) { .postcode-control:has(.postcode-prefix) { grid-template-columns: 1fr; } }
|
||||
</style>
|
||||
@@ -53,7 +53,6 @@ function pathFor(place: Place) {
|
||||
}
|
||||
|
||||
function selectedName() {
|
||||
if (selectedIds.value.length !== 4) return ''
|
||||
return selectedIds.value
|
||||
.map((id) => placesById.get(id)?.name)
|
||||
.filter((name): name is string => Boolean(name))
|
||||
@@ -63,7 +62,7 @@ function selectedName() {
|
||||
function syncFromModel(value: string) {
|
||||
const normalized = value.trim()
|
||||
const matched = places.find((place) =>
|
||||
place.deep === 3 && pathFor(place).map((item) => item.name).join(' / ') === normalized,
|
||||
pathFor(place).map((item) => item.name).join(' / ') === normalized,
|
||||
)
|
||||
selectedIds.value = matched ? pathFor(matched).map((place) => place.id) : []
|
||||
}
|
||||
|
||||
Loaded 3 of 8 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user