@cainiaofe/cn-ui-m
Version:
317 lines (316 loc) • 16.8 kB
JavaScript
import { __assign, __spreadArray } from "tslib";
import $i18n from "../../../../locales/i18n";
import React, { useMemo, useState, useEffect, useRef } from 'react';
import classNames from 'classnames';
import { SelectDrawer } from "../../../select-drawer";
import { CnTab, CnTabItem } from "../../../cn-tab";
import { CnSearch } from "../../../cn-search";
import { CnBox } from "../../../cn-box";
import { CnSelectTag } from "../../../cn-tag";
import { CnReadOnly } from "../../../cn-read-only";
import { CascaderList } from './cascader-list';
import { selectNodeInTree, updateParentNodeInTree, getNodeByPos, getSubmitData, getNodeAndParentsByPos, sortNodesByPos, scrollIntoViewByText, getNewDataSource, getFilterOptions, getMergedValue, } from '../../utils';
import { useControlled } from '@cainiaofe/cn-ui-common';
import { handleRequestService } from "../../../cn-cascader-select/service";
import { useRequest } from 'ahooks';
import { getInvalidValue } from '../../utils/multi-select/get-invalid-value';
var clsPrefix = 'cn-ui-m-cascader';
// 多选默认以","分割,暂时不支持自定义
var separator = ',';
// 避免多次生成新数组导致的性能问题
var emptyList = [];
export var CnCascaderSelectMultiply = function (props) {
var _a, _b;
var propDataSource = props.dataSource, className = props.className, drawerClassName = props.drawerClassName, hasClear = props.hasClear, _c = props.rootTipText, rootTipText = _c === void 0 ? $i18n.get({ id: 'PleaseSelect', dm: '请选择' }) : _c, isPreview = props.isPreview, readOnly = props.readOnly, _d = props.size, size = _d === void 0 ? 'medium' : _d, multiple = props.multiple, placeholder = props.placeholder, disabled = props.disabled, loadData = props.loadData, onSelect = props.onSelect, showSearch = props.showSearch, renderContent = props.renderContent, insideFilter = props.insideFilter, insideForm = props.insideForm, requestConfig = props.requestConfig;
// 请求服务封装
var requestService = handleRequestService(requestConfig);
var isRemoteDataSource = !!((requestConfig === null || requestConfig === void 0 ? void 0 : requestConfig.url) || (requestConfig === null || requestConfig === void 0 ? void 0 : requestConfig.service));
var _e = useRequest(requestService, __assign({ ready: isRemoteDataSource }, requestConfig)).data, data = _e === void 0 ? emptyList : _e;
var dataSource = React.useMemo(function () { return (isRemoteDataSource ? data : propDataSource); }, [data, isRemoteDataSource, propDataSource]);
// 有效数据源(树):所有数据的更新都是变更该数据,其他均由其计算得到(navList)
var _f = useState([]), currentDataSource = _f[0], setCurrentDataSource = _f[1];
// 顶部导航+ 当前页数据: label是tab的标题,value是tab的key, parentPos用于定位父节点,children就是当前tab的数据
var _g = useState([]), navList = _g[0], setNavList = _g[1];
// 搜索关键字
var _h = useState(''), searchKey = _h[0], setSearchKey = _h[1];
// 底部显示标识
var _j = useState(false), isShowSeletedTags = _j[0], setIsShowSelectedTags = _j[1];
// 初始数据源ref
var initDataSourceRef = useRef([]);
// 实时更新数据源(用于loadData时使用)
var updateDataSourceRef = useRef([]);
var _k = useControlled(props), value = _k[0], onChange = _k[1];
useEffect(function () {
var newDataSource = getNewDataSource(dataSource, value);
setCurrentDataSource(newDataSource);
setNavList([
{
label: rootTipText,
value: 'placeholder',
parentPos: 'root',
children: newDataSource,
},
]);
return function () {
window.sessionStorage.setItem('CnCascaderSelect_touchOrder', '0');
};
}, []);
useEffect(function () {
var _a, _b;
var newDataSource = getNewDataSource(dataSource, value);
initDataSourceRef.current = newDataSource;
if (!loadData || ((_a = updateDataSourceRef.current) === null || _a === void 0 ? void 0 : _a.length) === 0) {
setNavList([
{
label: rootTipText,
value: 'placeholder',
parentPos: 'root',
children: newDataSource,
},
]);
// 重置点击顺序
window.sessionStorage.setItem('CnCascaderSelect_touchOrder', '0');
}
if (loadData && ((_b = updateDataSourceRef.current) === null || _b === void 0 ? void 0 : _b.length) !== 0) {
// 原本选中的还需要选中
var values = getSubmitData(currentDataSource).values;
var curValues_1 = __spreadArray([], values, true);
if (Array.isArray(value)) {
value.forEach(function (item) {
if (!curValues_1.includes(item)) {
curValues_1.push(item);
}
});
}
newDataSource = getNewDataSource(dataSource, curValues_1);
}
setCurrentDataSource(newDataSource);
updateDataSourceRef.current = newDataSource;
}, [dataSource, value]);
// 初始值
var initSelectedList = useMemo(function () {
var newDataSource = getNewDataSource(dataSource, value);
var _a = getSubmitData(newDataSource), records = _a.records, values = _a.values;
var curValues = getMergedValue(values, value);
var invalidValues = getInvalidValue(newDataSource, curValues);
sortNodesByPos(records);
var list = __spreadArray([], records, true);
// 如果存在无效值,则将无效值添加到列表最前面
if (invalidValues.length > 0) {
invalidValues.forEach(function (item) {
list.unshift({
label: item,
value: item,
});
});
}
return list;
}, [dataSource, value]);
// 选中回调 -> 改变数据源状态
var handleSelect = function (checked, curData) {
var updatedTreeData = selectNodeInTree(currentDataSource, curData === null || curData === void 0 ? void 0 : curData.pos, checked);
updateParentNodeInTree(updatedTreeData, curData === null || curData === void 0 ? void 0 : curData.pos);
setCurrentDataSource(updatedTreeData);
updateDataSourceRef.current = updatedTreeData;
var newNavList = getNewNavList(updatedTreeData);
setNavList(newNavList);
};
// 更新显示数据
var getNewNavList = function (curData) {
return __spreadArray([], navList, true).map(function (item) {
if (item.parentPos === 'root') {
return __assign(__assign({}, item), { children: curData });
}
else {
var targetNode = getNodeByPos(curData, item.parentPos);
return __assign(__assign({}, item), { children: targetNode.children });
}
});
};
// 取消
var handleCancel = function () {
setSearchKey('');
setCurrentDataSource(initDataSourceRef.current);
updateDataSourceRef.current = initDataSourceRef.current;
setNavList([
{
label: rootTipText,
value: 'placeholder',
parentPos: 'root',
children: initDataSourceRef.current,
},
]);
};
// 清空
var handleClear = function () {
setSearchKey('');
onChange(undefined);
var newDataSource = getNewDataSource(dataSource, []);
setNavList([
{
label: rootTipText,
value: 'placeholder',
parentPos: 'root',
children: newDataSource,
},
]);
setCurrentDataSource(newDataSource);
initDataSourceRef.current = newDataSource;
updateDataSourceRef.current = newDataSource;
// 重置点击顺序
window.sessionStorage.setItem('CnCascaderSelect_touchOrder', '0');
};
if (isPreview || readOnly) {
return (React.createElement(CnReadOnly, null, initSelectedList.map(function (node) { return node.label; }).join(separator)));
}
// 点击tag,快速跳转
var handleNavByTag = function (item) {
var _a, _b, _c;
var pos = item.pos, label = item.label;
var res = getNodeAndParentsByPos(currentDataSource, pos);
var parents = res.parents;
var newNavList = [];
if (parents === null || parents === void 0 ? void 0 : parents.length) {
newNavList.push({
label: (_a = parents[0]) === null || _a === void 0 ? void 0 : _a.label,
value: (_b = parents[0]) === null || _b === void 0 ? void 0 : _b.value,
pos: (_c = parents[0]) === null || _c === void 0 ? void 0 : _c.pos,
parentPos: 'root',
children: currentDataSource,
});
}
else if ((parents === null || parents === void 0 ? void 0 : parents.length) === 0) {
newNavList.push({
label: rootTipText,
value: 'placeholder',
parentPos: 'root',
children: currentDataSource,
});
}
parents.forEach(function (ele, index) {
var _a, _b, _c;
if (index === parents.length - 1) {
newNavList.push({
label: rootTipText,
value: 'placeholder',
parentPos: ele === null || ele === void 0 ? void 0 : ele.pos,
children: ele === null || ele === void 0 ? void 0 : ele.children,
});
return;
}
newNavList.push({
label: (_a = parents[index + 1]) === null || _a === void 0 ? void 0 : _a.label,
value: (_b = parents[index + 1]) === null || _b === void 0 ? void 0 : _b.value,
pos: (_c = parents[index + 1]) === null || _c === void 0 ? void 0 : _c.pos,
parentPos: ele === null || ele === void 0 ? void 0 : ele.pos,
children: ele === null || ele === void 0 ? void 0 : ele.children,
});
});
setNavList(newNavList);
// 滚动到可视范围
setTimeout(function () {
scrollIntoViewByText(label);
}, 100);
};
// 渲染底部已选信息
var renderStatusTag = function (curDataSource) {
if (!curDataSource) {
isShowSeletedTags && setIsShowSelectedTags(false);
return null;
}
var tagElementList = [];
var traverseDataSource = function (curList) {
for (var _i = 0, curList_1 = curList; _i < curList_1.length; _i++) {
var item = curList_1[_i];
if (item.checked) {
tagElementList.push(item);
}
else if (item.children) {
traverseDataSource(item.children);
}
}
};
traverseDataSource(curDataSource);
// 对tagElementList进行排序
sortNodesByPos(tagElementList);
if ((tagElementList === null || tagElementList === void 0 ? void 0 : tagElementList.length) && !isShowSeletedTags) {
setIsShowSelectedTags(true);
}
else if (!(tagElementList === null || tagElementList === void 0 ? void 0 : tagElementList.length) && isShowSeletedTags) {
setIsShowSelectedTags(false);
}
return tagElementList.map(function (item) { return (React.createElement(CnSelectTag, { type: "secondary", checked: true, key: item.pos, onClick: function () { return handleNavByTag(item); } },
React.createElement("span", { className: "".concat(clsPrefix, "-bottom-label") }, item.label))); });
};
// 搜索
var search = showSearch ? (React.createElement("div", { className: "".concat(clsPrefix, "-multiply-search-wrapper") },
React.createElement(CnSearch, { value: searchKey, hasClear: true, onChange: function (val) { return setSearchKey(val); }, onClear: function () { return setSearchKey(''); } }))) : null;
// 处理确定按钮点击
var handleOk = function () {
var _a = getSubmitData(currentDataSource), values = _a.values, records = _a.records, details = _a.details;
var curValues = getMergedValue(values, value);
var invalidValues = getInvalidValue(currentDataSource, curValues);
setSearchKey('');
onChange(__spreadArray(__spreadArray([], invalidValues, true), values, true), records, details);
setNavList([
{
label: rootTipText,
value: 'placeholder',
parentPos: 'root',
children: currentDataSource,
},
]);
};
var handleClick = function (subItem) {
var _a;
var currentSubItem = getNodeByPos(updateDataSourceRef.current, subItem === null || subItem === void 0 ? void 0 : subItem.pos);
if (currentSubItem === null || currentSubItem === void 0 ? void 0 : currentSubItem.disabled) {
return;
}
// if 中间节点 then 跳转
if ((_a = currentSubItem === null || currentSubItem === void 0 ? void 0 : currentSubItem.children) === null || _a === void 0 ? void 0 : _a.length) {
var clickPos = currentSubItem.pos;
var newNavList = __spreadArray([], navList, true);
newNavList[newNavList.length - 1].label = currentSubItem.label;
newNavList[newNavList.length - 1].value = currentSubItem.value;
newNavList[newNavList.length - 1].pos = clickPos;
var clickNode = getNodeByPos(updateDataSourceRef.current, clickPos);
newNavList.push({
label: rootTipText,
value: 'placeholder',
parentPos: clickPos,
children: clickNode === null || clickNode === void 0 ? void 0 : clickNode.children,
});
setNavList(newNavList);
}
else {
// if 末节点 then 改变末节点选中态
handleSelect(!(currentSubItem === null || currentSubItem === void 0 ? void 0 : currentSubItem.checked), currentSubItem);
}
onSelect === null || onSelect === void 0 ? void 0 : onSelect(currentSubItem.value, currentSubItem);
};
return (React.createElement(SelectDrawer, { placeholder: placeholder, disabled: disabled, hasClear: hasClear, size: size, className: classNames(clsPrefix, className), insideFilter: insideFilter, insideForm: insideForm, content: renderContent
? renderContent(initSelectedList, separator)
: initSelectedList.map(function (item) { return item.label; }).join(separator), drawerClassName: classNames("".concat(clsPrefix, "-container"), drawerClassName), onOk: handleOk, onCancel: handleCancel, onClear: handleClear, buttonPosition: "bottom" },
React.createElement(CnTab, { className: "".concat(clsPrefix, "-nav"), activeKey: "placeholder", contentClassName: classNames("".concat(clsPrefix, "-content"), (_a = {},
_a["".concat(clsPrefix, "-content-selected")] = isShowSeletedTags,
_a)), tabAlign: "left" }, navList.map(function (item, i) {
var children = __spreadArray([], item.children, true) || [];
var options = getFilterOptions(children, showSearch, searchKey);
return (React.createElement(CnTabItem, { key: "".concat(item.value), itemKey: item.value, title: item.label || rootTipText, onClick: function () {
if (item.value === 'placeholder')
return;
var updateNavList = getNewNavList(currentDataSource);
var newNavList = __spreadArray([], updateNavList.slice(0, i + 1), true);
newNavList[newNavList.length - 1].label = rootTipText;
newNavList[newNavList.length - 1].value = 'placeholder';
setNavList(newNavList);
} },
search,
React.createElement(CascaderList, { options: options, value: item.value, loadData: loadData, onClick: handleClick, multiple: multiple, handleSelect: handleSelect })));
})),
React.createElement(CnBox, { direction: "row", spacing: 8, className: classNames("".concat(clsPrefix, "-bottom"), (_b = {},
_b["".concat(clsPrefix, "-bottom-show")] = isShowSeletedTags,
_b)) }, renderStatusTag(currentDataSource))));
};
CnCascaderSelectMultiply.displayName = 'CnCascaderSelect';