You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
6.9 KiB
251 lines
6.9 KiB
<template> |
|
<div class="el-transfer-panel"> |
|
<p class="el-transfer-panel__header"> |
|
<el-checkbox |
|
v-model="allChecked" |
|
@change="handleAllCheckedChange" |
|
:indeterminate="isIndeterminate"> |
|
{{ title }} |
|
<span>{{ checkedSummary }}</span> |
|
</el-checkbox> |
|
</p> |
|
|
|
<div :class="['el-transfer-panel__body', hasFooter ? 'is-with-footer' : '']"> |
|
<el-input |
|
class="el-transfer-panel__filter" |
|
v-model="query" |
|
size="small" |
|
:placeholder="placeholder" |
|
@mouseenter.native="inputHover = true" |
|
@mouseleave.native="inputHover = false" |
|
v-if="filterable"> |
|
<i slot="prefix" |
|
:class="['el-input__icon', 'el-icon-' + inputIcon]" |
|
@click="clearQuery" |
|
></i> |
|
</el-input> |
|
<el-checkbox-group |
|
v-model="checked" |
|
v-show="!hasNoMatch && data.length > 0" |
|
:class="{ 'is-filterable': filterable }" |
|
class="el-transfer-panel__list"> |
|
<el-checkbox |
|
class="el-transfer-panel__item" |
|
:label="item[keyProp]" |
|
:disabled="item[disabledProp]" |
|
:key="item[keyProp]" |
|
v-for="item in filteredData"> |
|
<option-content :option="item"></option-content> |
|
</el-checkbox> |
|
</el-checkbox-group> |
|
<p |
|
class="el-transfer-panel__empty" |
|
v-show="hasNoMatch">{{ t('el.transfer.noMatch') }}</p> |
|
<p |
|
class="el-transfer-panel__empty" |
|
v-show="data.length === 0 && !hasNoMatch">{{ t('el.transfer.noData') }}</p> |
|
</div> |
|
<p class="el-transfer-panel__footer" v-if="hasFooter"> |
|
<slot></slot> |
|
</p> |
|
</div> |
|
</template> |
|
|
|
<script> |
|
import ElCheckboxGroup from 'element-ui/packages/checkbox-group'; |
|
import ElCheckbox from 'element-ui/packages/checkbox'; |
|
import ElInput from 'element-ui/packages/input'; |
|
import Locale from 'element-ui/src/mixins/locale'; |
|
|
|
export default { |
|
mixins: [Locale], |
|
|
|
name: 'ElTransferPanel', |
|
|
|
componentName: 'ElTransferPanel', |
|
|
|
components: { |
|
ElCheckboxGroup, |
|
ElCheckbox, |
|
ElInput, |
|
OptionContent: { |
|
props: { |
|
option: Object |
|
}, |
|
render(h) { |
|
const getParent = vm => { |
|
if (vm.$options.componentName === 'ElTransferPanel') { |
|
return vm; |
|
} else if (vm.$parent) { |
|
return getParent(vm.$parent); |
|
} else { |
|
return vm; |
|
} |
|
}; |
|
const panel = getParent(this); |
|
const transfer = panel.$parent || panel; |
|
return panel.renderContent |
|
? panel.renderContent(h, this.option) |
|
: transfer.$scopedSlots.default |
|
? transfer.$scopedSlots.default({ option: this.option }) |
|
: <span>{ this.option[panel.labelProp] || this.option[panel.keyProp] }</span>; |
|
} |
|
} |
|
}, |
|
|
|
props: { |
|
data: { |
|
type: Array, |
|
default() { |
|
return []; |
|
} |
|
}, |
|
renderContent: Function, |
|
placeholder: String, |
|
title: String, |
|
filterable: Boolean, |
|
format: Object, |
|
filterMethod: Function, |
|
defaultChecked: Array, |
|
props: Object |
|
}, |
|
|
|
data() { |
|
return { |
|
checked: [], |
|
allChecked: false, |
|
query: '', |
|
inputHover: false, |
|
checkChangeByUser: true |
|
}; |
|
}, |
|
|
|
watch: { |
|
checked(val, oldVal) { |
|
this.updateAllChecked(); |
|
if (this.checkChangeByUser) { |
|
const movedKeys = val.concat(oldVal) |
|
.filter(v => val.indexOf(v) === -1 || oldVal.indexOf(v) === -1); |
|
this.$emit('checked-change', val, movedKeys); |
|
} else { |
|
this.$emit('checked-change', val); |
|
this.checkChangeByUser = true; |
|
} |
|
}, |
|
|
|
data() { |
|
const checked = []; |
|
const filteredDataKeys = this.filteredData.map(item => item[this.keyProp]); |
|
this.checked.forEach(item => { |
|
if (filteredDataKeys.indexOf(item) > -1) { |
|
checked.push(item); |
|
} |
|
}); |
|
this.checkChangeByUser = false; |
|
this.checked = checked; |
|
}, |
|
|
|
checkableData() { |
|
this.updateAllChecked(); |
|
}, |
|
|
|
defaultChecked: { |
|
immediate: true, |
|
handler(val, oldVal) { |
|
if (oldVal && val.length === oldVal.length && |
|
val.every(item => oldVal.indexOf(item) > -1)) return; |
|
const checked = []; |
|
const checkableDataKeys = this.checkableData.map(item => item[this.keyProp]); |
|
val.forEach(item => { |
|
if (checkableDataKeys.indexOf(item) > -1) { |
|
checked.push(item); |
|
} |
|
}); |
|
this.checkChangeByUser = false; |
|
this.checked = checked; |
|
} |
|
} |
|
}, |
|
|
|
computed: { |
|
filteredData() { |
|
return this.data.filter(item => { |
|
if (typeof this.filterMethod === 'function') { |
|
return this.filterMethod(this.query, item); |
|
} else { |
|
const label = item[this.labelProp] || item[this.keyProp].toString(); |
|
return label.toLowerCase().indexOf(this.query.toLowerCase()) > -1; |
|
} |
|
}); |
|
}, |
|
|
|
checkableData() { |
|
return this.filteredData.filter(item => !item[this.disabledProp]); |
|
}, |
|
|
|
checkedSummary() { |
|
const checkedLength = this.checked.length; |
|
const dataLength = this.data.length; |
|
const { noChecked, hasChecked } = this.format; |
|
if (noChecked && hasChecked) { |
|
return checkedLength > 0 |
|
? hasChecked.replace(/\${checked}/g, checkedLength).replace(/\${total}/g, dataLength) |
|
: noChecked.replace(/\${total}/g, dataLength); |
|
} else { |
|
return `${ checkedLength }/${ dataLength }`; |
|
} |
|
}, |
|
|
|
isIndeterminate() { |
|
const checkedLength = this.checked.length; |
|
return checkedLength > 0 && checkedLength < this.checkableData.length; |
|
}, |
|
|
|
hasNoMatch() { |
|
return this.query.length > 0 && this.filteredData.length === 0; |
|
}, |
|
|
|
inputIcon() { |
|
return this.query.length > 0 && this.inputHover |
|
? 'circle-close' |
|
: 'search'; |
|
}, |
|
|
|
labelProp() { |
|
return this.props.label || 'label'; |
|
}, |
|
|
|
keyProp() { |
|
return this.props.key || 'key'; |
|
}, |
|
|
|
disabledProp() { |
|
return this.props.disabled || 'disabled'; |
|
}, |
|
|
|
hasFooter() { |
|
return !!this.$slots.default; |
|
} |
|
}, |
|
|
|
methods: { |
|
updateAllChecked() { |
|
const checkableDataKeys = this.checkableData.map(item => item[this.keyProp]); |
|
this.allChecked = checkableDataKeys.length > 0 && |
|
checkableDataKeys.every(item => this.checked.indexOf(item) > -1); |
|
}, |
|
|
|
handleAllCheckedChange(value) { |
|
this.checked = value |
|
? this.checkableData.map(item => item[this.keyProp]) |
|
: []; |
|
}, |
|
|
|
clearQuery() { |
|
if (this.inputIcon === 'circle-close') { |
|
this.query = ''; |
|
} |
|
} |
|
} |
|
}; |
|
</script>
|
|
|