| <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> |