pcaaUtils.js 4.55 KB
/*
 * 省市区联动组件通用工具类。
 * 列表翻译、组件反推、表单设计器组件反推等功能都可以用该工具类实现。
 *
 * 1. leafName字段的意义:
 *      AntdvUI和ElementUI的叶级节点名字是不一样的,
 *      AntdvUI的名字是 isLeaf,ElementUI是 leaf,
 *      默认是AntdvUI的名字,在表单设计器那边需要手动 setLeafName
 */

import { pcaa } from 'area-data'

export { pcaa }

/** 根节点Code = 86 */
export const ROOT_CODE = '86'

/** 叶级节点的名字 */
let leafName = 'isLeaf'

/**
 * set leafName
 * @param $leafName
 */
export function setLeafName($leafName = 'isLeaf') {
  leafName = $leafName
}

/**
 *  将地区数据转换成下拉框等组件可识别的Options数组
 * @param data 地区data
 * @param labelName label标签名字
 * @return
 */
export function transToOptions(data, labelName = 'label') {
  if (data) {
    return Object.keys(data).map(key => ({ value: key, [labelName]: data[key] }))
  } else {
    return []
  }
}

/**
 * 获取子级Data对象
 *
 * @param code 父级地区Code
 */
export function getChildrenDataByCode(code) {
  return pcaa[code]
}

/**
 * 获取子级Options对象
 *
 * @param code 父级地区Code
 * @return {Array} 返回的值一定是一个数组,如果数组length===0,则代表没有子级
 */
export function getChildrenOptionsByCode(code) {
  let options = []
  let data = getChildrenDataByCode(code)
  if (data) {
    for (let key in data) {
      if (data.hasOwnProperty(key)) {
        options.push({ value: key, label: data[key], })
      }
    }
    return options
  } else {
    return []
  }
}

/**
 * 获取兄弟Data对象
 *
 * @param code 地区Code
 */
export function getSiblingsDataByCode(code) {
  if (typeof code === 'string' && code.length === 6) {
    // 父级节点Code
    let parentCode = `${code.substring(0, 4)}00`
    return getChildrenDataByCode(parentCode)
  } else {
    console.warn('[getSiblingsByCode]: code不合法')
    return null
  }
}

/**
 * 获取对应的 Label
 *
 * @param code 地区Code
 */
export function getLabelByCode(code) {
  if (code) {
    // 获取当前code所有的兄弟节点
    let siblingsData = getSiblingsDataByCode(code)
    // 然后取出自己的值
    return siblingsData[code]
  } else {
    return code
  }
}

/**
 * 获取所有的 Label,包括自身和所有父级
 *
 * @param code 地区Code
 * @param joinText 合并文本
 */
export function getAllLabelByCode(code, joinText = ' / ') {
  if (code) {
    let { labels } = getAllParentByCode(code)
    return labels.join(joinText)
  } else {
    return code
  }
}

/**
 * 通过子级 code 反推所有父级的 code
 *
 * @param code 子级地区Code
 * @returns {Object} options: 所有父级的选项;codes: 所有父级的code;labels: 所有父级的显示名
 */
export function getAllParentByCode(code) {
  code = (typeof code === 'string' ? code : '').trim()
  if (code.length === 0) {
    return { options: [], codes: [], labels: [] }
  }
  // 获取第一级数据
  let rootOptions = getChildrenOptionsByCode(ROOT_CODE)
  hasChildren(rootOptions)
  // 父级code数组,code长度
  let parentCodes = [code], length = code.length
  // 父级label数组
  let parentLabels = [getLabelByCode(code)]
  // 级别,位数,是否继续循环
  let level = 1, num = 2, flag = true

  let options = rootOptions
  do {
    let endIndex = num * level++
    // 末尾补零个数
    let zeroPadding = [...new Array(length - endIndex)].map(i => '0').join('')
    // 裁剪并补零(获取上级的方式就是将当前code的后两位变成 00)
    let parentCode = code.substring(0, endIndex) + zeroPadding
    // 是否找到在选项中的位置
    let findIt = false
    for (let option of options) {
      if (option.value === parentCode) {
        if (option[leafName]) {
          flag = false
        } else {
          let children = getChildrenOptionsByCode(option.value)
          hasChildren(children)
          option.children = children
          options = children
          parentCodes.splice(parentCodes.length - 1, 0, option.value)
          parentLabels.splice(parentLabels.length - 1, 0, option.label)
        }
        findIt = true
        break
      }
    }

    if (findIt) {
      findIt = false
    } else {
      flag = false
    }
  } while (flag)
  return { options: rootOptions, codes: parentCodes, labels: parentLabels }
}

/**
 * 判断所有的项是否有子节点
 *
 * @param options
 */
export function hasChildren(options) {
  options.forEach(option => {
    option[leafName] = getChildrenOptionsByCode(option.value).length === 0
  })
}