UNPKG

@cainiaofe/cn-ui-m

Version:
317 lines (316 loc) 16.8 kB
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';