jobsys-explore
Version:
Enhanced component based on vant
196 lines (171 loc) • 5.25 kB
JSX
import { computed, defineComponent, inject, ref, watch } from "vue"
import { Cascader } from "vant"
import localData from "./addressData.json"
import PickerWrapper, { pickerProps, pickerSlots } from "./PickerWrapper.jsx"
import { defaultFieldProps, defaultOptionsProps, useOptionTrait } from "../utils"
import { cloneDeep, isArray, last } from "lodash-es"
import { useFindTextsFromPath } from "../../hooks"
import { EX_ADDRESS } from "../provider/ExProvider.jsx"
/**
* 地址组件
*
* 数据优先级:`dataSource` > `url` > `本地数据`
*
* @version 1.0.0
*/
export default defineComponent({
name: "ExAddress",
props: {
...defaultOptionsProps,
...defaultFieldProps,
modelValue: { type: [String, Number, Array], default: () => [] },
/**
* 标题
*/
title: { type: String, default: "" },
/**
* 生成哪个级别的数据
* 1: 省, 2: 省市, 3: 省市区
*/
level: { type: Number, default: 3 },
/**
* 显示值的类型
* 空值或all: 所有, last:最后
*/
displayTextType: { type: String, default: "" },
/**
* 是否把选项的值返回到modelValue
*/
textInValue: { type: Boolean, default: false },
},
emits: ["update:modelValue"],
setup(props, { emit, slots, expose }) {
const addressProvider = inject(EX_ADDRESS, () => ({}))
const defaultAddressUrl = addressProvider.addressUrl || ""
const defaultDisplayTextType = addressProvider.displayTextType || ""
const defaultAfterFetched = addressProvider.afterFetched || ""
const optionKeys = addressProvider.optionKeys || {}
const { text: textKey, value: valueKey, children: childrenKey } = optionKeys
const componentValue = ref("")
const setModelValue = () => {
let value = isArray(props.modelValue) ? last(props.modelValue) : props.modelValue
if (props.textInValue && value) {
value = value[valueKey]
}
componentValue.value = value
}
setModelValue()
watch(
() => props.modelValue,
() => setModelValue(),
)
const pickerRef = ref(null)
const options = ref([])
const displayText = computed(() => {
if (props.modelValue.length === 0) {
return ""
}
const displayTextType = props.displayTextType || defaultDisplayTextType
//textInValue状态下的初始值
if (props.textInValue && props.modelValue && props.modelValue.length === 1) {
return last(props.modelValue)[textKey]
}
//反向赋值
const mValue = props.textInValue ? props.modelValue.map((item) => item[valueKey]) : props.modelValue
const optionsTexts = useFindTextsFromPath(options.value, mValue, {
value: valueKey,
children: childrenKey,
label: textKey,
})
return displayTextType === "last" ? last(optionsTexts) : optionsTexts.join("/")
})
//把默认值赋值给props
const cloneProps = cloneDeep(props)
if (!cloneProps.url && defaultAddressUrl) {
cloneProps.url = defaultAddressUrl
}
if (!cloneProps.afterFetched && defaultAfterFetched) {
cloneProps.afterFetched = defaultAfterFetched
}
//先处理好 options
const dealOptions = () => {
useOptionTrait(options, cloneProps, localData)
}
dealOptions()
watch(
() => props.options,
() => {
dealOptions()
},
)
const onFinish = ({ selectedOptions }) => {
pickerRef.value.close()
emit("update:modelValue", props.textInValue ? selectedOptions : selectedOptions.map((item) => item[valueKey]))
}
expose({ displayText })
/********** render **********/
return () => (
<PickerWrapper ref={pickerRef} {...pickerProps(props)}>
{{
...pickerSlots(slots, props),
default: () => (
<Cascader
v-model={componentValue.value}
fieldNames={{ text: textKey, value: valueKey, children: childrenKey }}
closeable={false}
showHeader={false}
options={options.value}
onFinish={onFinish}
{...props.defaultProps}
/>
),
}}
</PickerWrapper>
)
},
})
/**
*
* 根据地址编码获取完整的地址编码
*
* @param code
* @param {number} [level] 地址级别: 1: 省, 2: 省市, 3: 省市区
* @return {string[]|(string|*)[]|*[]}
*/
export function useAddressFullCode(code, level) {
code += ""
if (code && code.length === 6) {
if (!level) {
if (/0000$/.test(code)) {
level = 1
} else if (/00$/.test(code)) {
level = 2
} else {
level = 3
}
}
if (level === 1) {
return [`${code.substr(0, 2)}0000`]
}
if (level === 2) {
return [`${code.substr(0, 2)}0000`, `${code.substr(0, 4)}00`]
}
if (level === 3) {
return [`${code.substr(0, 2)}0000`, `${code.substr(0, 4)}00`, code]
}
}
return []
}
/**
* 根据地址编码获取完整的地址名称
* @param code
* @param {number} [level] 地址级别: 1: 省, 2: 省市, 3: 省市区
* @return {*[]}
*/
export function useAddressNameFormCode(code, level) {
if (!isArray(code)) {
code = useAddressFullCode(code, level)
}
return useFindTextsFromPath(localData, code, { value: "code", label: "name", children: "children" })
}
export const addressData = localData