| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- <template>
- <view class="region-cascader">
- <view class="form-row" @click="openPicker">
- <text class="form-row__label form-row__label--req">所在地区</text>
- <view class="form-row__picker region-cascader__value">
- <text :class="{ 'form-row__placeholder': !displayText }">
- {{ displayText || '请选择省 / 市 / 区' }}
- </text>
- </view>
- <u-icon name="arrow-right" color="#ccc" size="16" />
- </view>
- <up-cascader
- v-if="treeReady"
- :show="pickerShow"
- :data="cascaderTree"
- v-model="pathCodes"
- value-key="code"
- label-key="name"
- children-key="children"
- :closeable="true"
- @update:show="pickerShow = $event"
- @confirm="onConfirm"
- />
- </view>
- </template>
- <script setup>
- import { ref, computed, watch, onMounted } from 'vue'
- import {
- loadRegionCascaderTree,
- findRegionPath,
- parseRegionSelection,
- formatRegionDisplay
- } from '@/utils/region'
- const props = defineProps({
- modelValue: {
- type: Object,
- default: () => ({
- regionCode: '',
- regionName: '',
- code: '',
- name: '',
- pathCodes: []
- })
- }
- })
- const emit = defineEmits(['update:modelValue'])
- const pickerShow = ref(false)
- const treeReady = ref(false)
- const rawTree = ref([])
- const cascaderTree = ref([])
- const pathCodes = ref([])
- const displayText = computed(() => {
- const name = props.modelValue?.regionName || props.modelValue?.name || ''
- return formatRegionDisplay(name)
- })
- watch(
- () => props.modelValue,
- (v) => {
- if (!v || !rawTree.value.length) return
- syncPathFromModel(v)
- },
- { deep: true }
- )
- onMounted(() => {
- loadRegionCascaderTree()
- .then(({ raw, cascader }) => {
- rawTree.value = raw
- cascaderTree.value = cascader
- treeReady.value = true
- syncPathFromModel(props.modelValue)
- })
- .catch(() => {
- uni.showToast({ title: '地区数据加载失败', icon: 'none' })
- })
- })
- function syncPathFromModel(v) {
- if (!v) return
- if (Array.isArray(v.pathCodes) && v.pathCodes.length) {
- pathCodes.value = [...v.pathCodes]
- return
- }
- const code = v.regionCode || v.code
- if (code && rawTree.value.length) {
- const path = findRegionPath(rawTree.value, code)
- pathCodes.value = path || []
- }
- }
- function openPicker() {
- if (!treeReady.value) {
- uni.showToast({ title: '地区数据加载中', icon: 'none' })
- return
- }
- pickerShow.value = true
- }
- function onConfirm(codes) {
- const parsed = parseRegionSelection(rawTree.value, codes)
- if (!parsed.valid) {
- uni.showToast({ title: '请选择完整的省市区', icon: 'none' })
- return
- }
- emit('update:modelValue', {
- regionCode: parsed.code,
- regionName: parsed.name,
- code: parsed.code,
- name: parsed.name,
- pathCodes: codes
- })
- }
- </script>
- <style lang="scss" scoped>
- @import '@/styles/mine.scss';
- .region-cascader .form-row {
- border-bottom: none;
- }
- .region-cascader__value {
- flex: 1;
- min-width: 0;
- }
- </style>
|