@fesjs/fes-design
Version:
fes-design for PC
218 lines (212 loc) • 8.11 kB
JavaScript
import { defineComponent, inject, computed, createVNode, createTextVNode, mergeProps } from 'vue';
import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
import { isNil } from 'lodash-es';
import Tree from '../tree';
import Empty from '../empty';
import { SearchOutlined, CloseCircleOutlined } from '../icon';
import Input from '../input';
import VirtualList from '../virtual-list';
import { COMPONENT_NAME, TRANSFER_INJECT_KEY, COMPONENT_CLASS, COMPONENT_ONE_WAY_CLASS } from './const';
import { TransferCheckbox, calcCheckStatus } from './checkbox';
import { isTree, flattenTree, cls } from './utils';
import { useTreeFilter } from './useTreeFilter';
import { useCheckValueWithCheckbox } from './useCheckValueWithCheckbox';
import { useOptionsFilter } from './useOptionsFilter';
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
const useData = _ref => {
let {
modelValue,
rootProps,
handleChange
} = _ref;
const options = computed(() => rootProps.options);
const {
checkboxStatus,
handleCheckboxChange,
handleCheck
} = useCheckValueWithCheckbox({
checkValue: modelValue,
options,
onCheckboxChange: () => {
handleChange({
nextValue: modelValue.value
});
}
});
return {
treeCheckStatus: checkboxStatus,
handleCheckStatusChange: handleCheckboxChange,
handleTreeCheck: handleCheck
};
};
const OneWayTransfer = defineComponent({
name: COMPONENT_NAME,
setup: () => {
const {
modelValue,
rootProps,
rootStyle,
filter,
renderLabel,
handleChange,
scrollContentHeight
} = inject(TRANSFER_INJECT_KEY);
const {
handleTreeCheck,
treeCheckStatus,
handleCheckStatusChange
} = useData({
modelValue,
rootProps,
handleChange
});
const checkedOptions = computed(() => {
const options = isTree(rootProps.options) ? flattenTree(rootProps.options) : rootProps.options;
return options.filter(o => modelValue.value.includes(o.value));
});
const {
treeRef,
defaultFilterForTree,
filterText: treeFilterText
} = useTreeFilter({
rootProps
});
// 右边 TargetList 需要的 filter
const {
displayOptions: displayCheckedOptions,
filterText: checkedOptionsFilterText
} = useOptionsFilter({
options: checkedOptions,
rootProps,
filter: filter.value
});
const handleClear = () => {
modelValue.value = [];
treeCheckStatus.value = 'none';
handleChange({
nextValue: []
});
};
const removeCheckedOption = optionValue => {
const nextModelValue = [...modelValue.value];
const index = nextModelValue.findIndex(v => v === optionValue);
if (index === -1) {
return;
}
nextModelValue.splice(index, 1);
// 更新值
modelValue.value = nextModelValue;
treeCheckStatus.value = calcCheckStatus(nextModelValue.length, rootProps.options.length);
handleChange({
nextValue: nextModelValue
});
};
const renderFilterInput = filterText => {
if (!rootProps.filterable) {
return undefined;
}
return createVNode(Input, {
"modelValue": filterText.value,
"onUpdate:modelValue": $event => filterText.value = $event,
"class": cls('panel-filter'),
"placeholder": '请输入'
}, {
suffix: () => createVNode(SearchOutlined, null, null)
});
};
const renderSourcePanel = () => {
var _ref2;
// TODO: 在 options 为空的时候,应该也展示 Empty 组件。但是 Tree 组件需要绑定 ref,但是在 if-else 的 JSX 中绑定的 ref 会错乱
const treeOptions = rootProps.options.map(option => _objectSpread(_objectSpread({}, option), {}, {
label: () => renderLabel(option)
}));
const virtualScrollConfig = !isNil(scrollContentHeight.value) ? {
virtualList: true,
style: {
height: `${scrollContentHeight.value}px`
}
} : {};
const filterForTree = rootProps.filterable ? (_ref2 = rootProps.filter // TODO: is not assignable
) !== null && _ref2 !== void 0 ? _ref2 : defaultFilterForTree() : undefined;
return createVNode("div", {
"class": [cls('panel'), cls('source-panel')]
}, [createVNode("div", {
"class": [cls('panel-header')]
}, [createVNode(TransferCheckbox, {
"modelValue": treeCheckStatus.value,
"onUpdate:modelValue": $event => treeCheckStatus.value = $event,
"label": '全选',
"disabled": rootProps.options.length === 0,
"onChange": handleCheckStatusChange
}, null), createVNode("span", {
"class": cls('panel-count')
}, [createTextVNode("\u5171 "), rootProps.options.length, createTextVNode(" \u9879")])]), renderFilterInput(treeFilterText), createVNode(Tree, mergeProps({
'checkedKeys': modelValue.value,
"onUpdate:checkedKeys": $event => modelValue.value = $event,
"ref": treeRef,
"data": treeOptions,
"class": cls('panel-list'),
"checkable": true,
"selectable": false,
"filterMethod": filterForTree,
"onCheck": handleTreeCheck
}, virtualScrollConfig), null)]);
};
const renderCheckedOption = option => {
const labelContent = renderLabel(option);
return createVNode("div", {
"class": [cls('option'), cls('checked-option')]
}, [createVNode("span", {
"class": cls('checked-option-text')
}, [labelContent]), createVNode(CloseCircleOutlined, {
"class": cls('checked-option-remove-button'),
"onClick": () => removeCheckedOption(option.value)
}, null)]);
};
const renderTargetPanel = () => {
const isEmpty = modelValue.value.length === 0;
let content;
if (isEmpty) {
content = createVNode(Empty, {
"class": cls('empty')
}, null);
} else if (!isNil(scrollContentHeight.value)) {
content = createVNode(VirtualList, {
"class": cls('panel-list'),
"style": {
height: `${scrollContentHeight.value}px`
},
"dataSources": displayCheckedOptions.value,
"dataKey": option => option.value
}, {
default: _ref3 => {
let {
source: option
} = _ref3;
return renderCheckedOption(option);
}
});
} else {
content = createVNode("div", {
"class": cls('panel-list')
}, [displayCheckedOptions.value.map(renderCheckedOption)]);
}
return createVNode("div", {
"class": [cls('panel'), cls('target-panel'), isEmpty && cls('empty-panel')]
}, [createVNode("div", {
"class": [cls('panel-header')]
}, [createVNode("span", {
"class": cls('panel-checked-count')
}, [createTextVNode("\u5DF2\u9009 "), modelValue.value.length, createTextVNode(" \u9879")]), createVNode("span", {
"class": cls('panel-clear-button'),
"onClick": handleClear
}, [createTextVNode("\u6E05\u9664")])]), renderFilterInput(checkedOptionsFilterText), content]);
};
return () => createVNode("div", {
"class": [COMPONENT_CLASS, COMPONENT_ONE_WAY_CLASS],
"style": rootStyle.value
}, [renderSourcePanel(), renderTargetPanel()]);
}
});
export { OneWayTransfer as default };