UNPKG

magiccube-vue3

Version:

vue3-js版组件库

250 lines (236 loc) 10.4 kB
import { ref, computed, toRaw, nextTick } from 'vue' import ICON_REMOVE from '../../img/icon_close.svg' const Cascade = { props: { selected: [Array, Number, String], keyword: String, options: { type: Array, default: () => [] }, max: { type: Number, default: 1 }, dropdownHeight: Number, enabledSelectSecondLevel: Boolean }, emits: ['change'], setup(props, { emit, expose }){ const JOB_FUNC_DICT = computed(() => { if(props.keyword && props.keyword.trim()){ const arr = props.options.filter(n => n.defaultName.indexOf(props.keyword) > -1) const firstCodeList = [], secondCodeList = [], thirfCodeList = [] arr.forEach((n, i) => { const c = n.propertyCode.toString() firstCodeList.push(c.substring(0, 2)) if(c.substring(0, 4)) secondCodeList.push(c.substring(0, 4)) if(c.substring(0, 6)) thirfCodeList.push(c.substring(0, 6)) }) activeFirst.value = firstCodeList[0] || '' activeSecond.value = secondCodeList[0] || '' return props.options.filter(n => firstCodeList.includes(n.propertyCode) || secondCodeList.includes(n.propertyCode) || thirfCodeList.includes(n.propertyCode)) } else { return props.options } }) const activeFirst = ref('') const activeSecond = ref('') const model = ref([]) const init = () => { if(props.selected?.length){ const _def = props.selected[0] activeFirst.value = _def.propertyCode.substring(0, 2) activeSecond.value = _def.propertyCode.substring(0, 4) } else { activeFirst.value = firstColumn.value[0].propertyCode activeSecond.value = secondColumn.value[0].propertyCode } model.value = props.selected } const firstColumn = computed(() => getData('first')) const secondColumn = computed(() => getData('second')) const thirdColumn = computed(() => getData('third')) const getData = (level) => { switch(level){ case 'first': { return JOB_FUNC_DICT.value.filter(n => n.propertyName === 'first') } case 'second': { return JOB_FUNC_DICT.value.filter(n => n.propertyName === 'second' && n.propertyCode.indexOf(activeFirst.value) === 0) } case 'third': { return JOB_FUNC_DICT.value.filter(n => n.propertyName === 'third' && n.propertyCode.indexOf(activeFirst.value) === 0 && n.propertyCode.indexOf(activeSecond.value) === 0) } } } const handleClear = () => model.value = [] const handleClick = (level, data, event = {}) => { event.stopPropagation() switch(level){ case 'first': { activeFirst.value = data.propertyCode const _c = getData('second') || [] activeSecond.value = _c[0]?.propertyCode || data.propertyCode break } case 'second': { activeSecond.value = data.propertyCode if(!thirdColumn.value.length) { setSelectedData(data) } break } case 'third': { setSelectedData(data) break } } } const setSelectedData = (data) => { let _selected = model.value const _d = typeof data === 'string'? props.options.find(n => n.propertyCode === data) : data const existIdx = model.value.findIndex(n => n.propertyCode === _d.propertyCode) if(existIdx > -1){ _selected.splice(existIdx, 1) } else if(props.max === 1){ _selected = [_d] } else if(props.max === _selected.length){ return false } else { _selected.push(_d) } model.value = _selected emit('change', toRaw(model.value)) } const getBadge = code => { let count = 0 model.value.forEach(n => { if(n.propertyCode.indexOf(code) === 0) count++ }) return count } expose({ init }) return () => ( <div class={[ 'mc-cascader' ]}> <div class={['mc-cascader__tip']}> <span>最多选择 {props.max} 项</span> </div> {/* 一级 */} <ul class={[ 'mc-cascader__column', 'mc-cascader__column--first', ]} style={{ height: props.dropdownHeight + 'px' }}> { firstColumn.value.map((p, idx) => ( <li class={[ 'mc-cascader__column--item', 'view-full', { active: activeFirst.value === p.propertyCode } ]} key={idx} v-ellipsis={p.simpleName} onClick={(e) => handleClick('first', p, e)}> <span>{p.simpleName}</span> { getBadge(p.propertyCode)? <span class="mc-cascader__badge">{getBadge(p.propertyCode)}</span> : '' } </li> )) } </ul> {/* 二级 */} <ul class={[ 'mc-cascader__column', 'mc-cascader__column--second', ]} style={{ height: props.dropdownHeight + 'px' }}> { secondColumn.value.map((c, idx) => ( <li class={[ 'mc-cascader__column--item', 'view-full', { active: activeSecond.value === c.propertyCode } ]} key={idx} onClick={(e) => handleClick('second', c, e)}> <span>{c.simpleName}</span> { getBadge(c.propertyCode)? <span class="mc-cascader__badge">{getBadge(c.propertyCode)}</span> : '' } </li> )) } </ul> {/* 三级 */} <ul class={[ 'mc-cascader__column', 'mc-cascader__column--third', ]} style={{ height: props.dropdownHeight + 'px' }}> { // 如果没有第三级 就不显示全部按钮 props.enabledSelectSecondLevel && !props.keyword && thirdColumn.value?.length? ( <li class={[ 'mc-cascader__column--tag', ]}> <span onClick={e => handleClick('third', activeSecond.value, e)}>全部</span> </li> ) : '' } { thirdColumn.value.map((d, idx) => ( <li class={[ 'mc-cascader__column--tag', { active: model.value.some(n => n.propertyCode === d.propertyCode) } ]} key={idx}> <span onClick={(e) => handleClick('third', d, e)}>{d.simpleName}</span> </li> )) } </ul> { model.value.length? ( <div class={[ 'mc-cascader__selected' ]}> <div class="mc-cascader__selected--title"> <span>已选</span> <span style="flex:1;margin-left:16px;">{model.value.length || 0}个</span> <i onClick={handleClear}> <img src={require('../../img/icon_trash.svg')} /> </i> </div> <ul class="mc-cascader__selected--list"> { model.value.map(n => ( <li class="mc-cascader__selected--list__item"> <div class="mc-cascader__selected--list__item--tag"> <div class="mc-cascader__selected--list__item--tag__inner"> <span class="mc-cascader__selected--list__item--tag--name">{n.defaultName}</span> <i class="mc-cascader__selected--list__item--tag--close" onClick={(e) => handleClick('third', n, e)}> <img src={ICON_REMOVE} /> </i> </div> </div> </li> )) } </ul> </div> ) : '' } </div> ) } } export default Cascade