Newer
Older
IntegratedFront / src / components / PcasCascader / index.vue
lyg on 1 Nov 3 KB first
<script lang="ts" setup name="PcasCascader">
// 行政区划数据来源于 https://github.com/modood/Administrative-divisions-of-China
import pcasRaw from './pcas-code.json'

const props = defineProps({
  modelValue: {
    type: Array,
    default: () => [],
  },
  disabled: {
    type: Boolean,
    default: false,
  },
  type: {
    type: String as () => 'pc' | 'pca' | 'pcas',
    default: 'pca',
  },
  format: {
    type: String as () => 'code' | 'name' | 'both',
    default: 'code',
  },
})

const emit = defineEmits(['update:modelValue'])

interface pcasItem {
  code: string
  name: string
  children?: pcasItem[]
}

const pcasData = computed(() => {
  const data: pcasItem[] = []
  // 省份
  pcasRaw.forEach((p) => {
    const tempP: pcasItem = {
      code: p.code,
      name: p.name,
    }
    const tempChildrenC: pcasItem[] = []
    // 城市
    p.children.forEach((c) => {
      const tempC: pcasItem = {
        code: c.code,
        name: c.name,
      }
      if (['pca', 'pcas'].includes(props.type)) {
        const tempChildrenA: pcasItem[] = []
        // 区县
        c.children.forEach((a) => {
          const tempA: pcasItem = {
            code: a.code,
            name: a.name,
          }
          if (props.type === 'pcas') {
            const tempChildrenS: pcasItem[] = []
            // 街道
            a.children.forEach((s) => {
              const tempS: pcasItem = {
                code: s.code,
                name: s.name,
              }
              tempChildrenS.push(tempS)
            })
            tempA.children = tempChildrenS
          }
          tempChildrenA.push(tempA)
        })
        tempC.children = tempChildrenA
      }
      tempChildrenC.push(tempC)
    })
    tempP.children = tempChildrenC
    data.push(tempP)
  })
  return data
})

const myValue = computed({
  // 将入参数据转成 code 码
  get: () => {
    return anyToCode(props.modelValue)
  },
  // 将 code 码转成出参数据
  set: (value) => {
    emit('update:modelValue', value ? codeToAny(value) : [])
  },
})

function anyToCode(value: any[], dictionarie: any[] = pcasData.value) {
  const input: string[] = []
  if (value.length > 0) {
    const findItem = dictionarie.find((item) => {
      if (props.format === 'code') {
        return item.code === value[0]
      }
      else if (props.format === 'name') {
        return item.name === value[0]
      }
      else {
        return item.name === value[0].name && item.code === value[0].code
      }
    })
    input.push(findItem.code)
    if (findItem.children) {
      input.push(...anyToCode(value.slice(1 - value.length), findItem.children))
    }
  }
  return input
}

function codeToAny(codes: string[], dictionarie: any[] = pcasData.value): any {
  const output = []
  const findItem = dictionarie.find(item => item.code === codes[0])
  if (findItem) {
    switch (props.format) {
      case 'code':
        output.push(findItem.code)
        break
      case 'name':
        output.push(findItem.name)
        break
      case 'both':
        output.push({
          code: findItem.code,
          name: findItem.name,
        })
    }
    const newCodes = codes.slice(1 - codes.length)
    if (newCodes.length > 0 && findItem.children) {
      output.push(...codeToAny(newCodes, findItem.children))
    }
  }
  return output
}
</script>

<template>
  <el-cascader v-model="myValue" :options="pcasData as any[]" :props="{ value: 'code', label: 'name' }" :disabled="disabled" clearable filterable />
</template>