UNPKG

magiccube-vue3

Version:

vue3-js版组件库

285 lines (248 loc) 9.64 kB
import Dropdown from '../../utils/dropdown' import { ref, reactive, computed, getCurrentInstance, nextTick, onMounted, provide } from 'vue' import getFormValidMethod from '../../utils/form-valid' import Cascader from './cascader' import CLOSE_ICON from '../../img/icon_remove.svg' import { toast } from '../message' import getJobCategoryOption from './category-data' function codeToData(code, list){ let obj = {} for(let i=0;i<list.length;i++){ const item = list[i] if(item.code === code) { obj = item break } if(item.sub.length && code.indexOf(item.code) === 0){ const res = codeToData(code, item.sub) if(res) { obj = res break } } } return obj } const JobCategoryPicker = { name: 'McJobCategoryPicker', props: { modelValue: { type: [Array, String, Number], default: () => [] }, placeholder: { type: String, default: '请选择职能' }, // 选择数量,如果设置为999,则是无限 max: { type: [String, Number], default: 1 }, disabled: Boolean, downMenuHeight: { type: Number, default: 430 }, enabledSelectSecondLevel: { type: Boolean, default: true }, unchecked: Boolean, optionVersion: Number, }, emits: ['change', 'update:modelValue'], setup(props, { emit }) { const dropdownEl = ref(null) const innerEl = ref(null) const pickerEl = ref(null) const displayInputSearch = ref(false) const keywordEl = ref(false) const state = reactive({ keyword: '', list: [], slide: false, }) const JOB_CATEGORY_DATA = ref([]) const loadingOption = ref(false) const updateCategoryOption = async () => { loadingOption.value = true const data = await getJobCategoryOption(props.optionVersion) loadingOption.value = false JOB_CATEGORY_DATA.value = data } onMounted(updateCategoryOption) const instance = getCurrentInstance() const { fieldName, validator, errorMessage } = getFormValidMethod(instance) const fieldError = computed(() => fieldName && errorMessage?.value && !props.unchecked ? errorMessage.value[fieldName] : '') const model = computed({ get() { if (Array.isArray(props.modelValue)) { return props.modelValue.map(n => { if(typeof n === 'string'){ return codeToData(n, JOB_CATEGORY_DATA.value) } else { return n } }) } else if (props.modelValue) { return [codeToData(props.modelValue, JOB_CATEGORY_DATA.value)] } else { return [] } }, set(value) { emit('update:modelValue', value) validator && validator('change', value) } }) const handleVisible = () => { if (props.disabled) return false dropdownEl.value.visible() } const handleChange = (array) => { model.value = array emit('change', array) if(props.max === array.length) setSlideUp() } const handleRemove = (e) => { e && e.stopPropagation() const list = model.value model.value = list.slice(1, list.length) emit('change', { key: props.keyName, data: model.value }) } const setSlideDown = (event) => { const options = { event, pickerHeight: pickerEl.value.offsetHeight, pickerWidth: pickerEl.value.offsetWidth, dropdownWidth: 668, dropdownHeight: innerEl.value.offsetHeight || props.downMenuHeight } innerEl.value.init() dropdownEl.value.visible(options) displayInputSearch.value = true state.slide = true // 让模糊搜索框自动聚焦 nextTick(() => { keywordEl.value && keywordEl.value.focus() }) } const setSlideUp = () => { state.keyword = '' dropdownEl.value.invisible() displayInputSearch.value = false state.slide = false } const handleShowDropdown = (e) => { if(!JOB_CATEGORY_DATA.value?.length) { updateCategoryOption() toast('暂无职能选项数据,请稍后再试') return false } if (props.disabled || e.target.nodeName.toLowerCase() === 'input') return false if (state.slide) { /** * 隐藏下拉 */ setSlideUp(e) return false } /** * 打开下拉 */ setSlideDown(e) } const handleKeywordChange = () => { // innerEl.value.init() } // 向子级组件传递方法 provide('getDataByCode', (code) => code? codeToData(code, JOB_CATEGORY_DATA.value) : null) const emptyNode = () => ( <span class='mc-job-func-picker__result--placeholder'>{props.placeholder}</span> ) const displayName = computed(() => model.value?.length ? model.value[0].simpleName : '') const multiReviewNode = () => { const len = model.value.length return ( <> <div class='mc-job-func-picker__result--wrap'> <span class='mc-job-func-picker__result--name'>{displayName.value}</span> <span class='mc-job-func-picker__result--close'> <img onClick={handleRemove} src={CLOSE_ICON} /> </span> </div> { len > 1 ? ( <div class='mc-job-func-picker__result--amount'>+{len}</div> ) : '' } </> ) } const keywordPlaceholder = computed(() => { if(props.max > 1){ return '请输入关键词' } else { return displayName.value || '请输入关键词' } }) const singleReviewNode = () => <span class='mc-job-func-picker__result--single' v-ellipsis={displayName.value}>{displayName.value}</span> const getReview = () => { if(props.max === 1){ if(Array.isArray(model.value)){ return displayInputSearch.value ? inputKeywordNode() : (model.value.length === 1? singleReviewNode() : emptyNode()) } else { return displayInputSearch.value ? inputKeywordNode() : (model.value !== ''? singleReviewNode() : emptyNode()) } } else { return displayInputSearch.value ? inputKeywordNode() : (model.value?.length? multiReviewNode() : emptyNode()) } } // 关键词搜索输入框dom const inputKeywordNode = () => ( <div class='mc-job-func-picker__result--keyword'> <input ref={keywordEl} class='mc-job-func-picker__result--keyword__input' autocomplete='off' placeholder={keywordPlaceholder.value} v-model={state.keyword} onInput={handleKeywordChange} /> </div> ) return () => ( <div ref={pickerEl} class={{ 'mc-job-func-picker': true, disabled: props.disabled }} v-loading={loadingOption.value}> <div class={{ 'mc-job-func-picker__result': true, error: Boolean(fieldError.value) }} onClick={handleShowDropdown}> { getReview() } {/* 输入查找 在下拉菜单打开时显示 */ displayInputSearch.value ? inputKeywordNode() : '' } <span class={[ 'mc-job-func-picker__result--arrow', { 'mc-rotate': displayInputSearch.value } ]}> <img src={require('../../img/icon_picker_arrow.svg')} /> </span> </div> <Dropdown ref={dropdownEl} picker={pickerEl.value} onClose={setSlideUp}> { <Cascader ref={innerEl} selected={model.value} options={JOB_CATEGORY_DATA.value} max={props.max} dropdownHeight={props.downMenuHeight} keyword={state.keyword} enabledSelectSecondLevel={props.enabledSelectSecondLevel} onChange={handleChange} /> } </Dropdown> </div> ) } } JobCategoryPicker.install = Vue => { Vue.component(JobCategoryPicker.name, JobCategoryPicker) } const McJobCategoryPicker = JobCategoryPicker export { McJobCategoryPicker, McJobCategoryPicker as default }