magiccube-vue3
Version:
vue3-js版组件库
285 lines (248 loc) • 9.64 kB
JavaScript
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 }