``
import { useCallback, useContext, useImperativeHandle, useState } from 'react';
import { SpellGroup, SpellNode, FileType } from '@/utils/api';
import './SpellTree.scss';
import React from 'react';
import { deepCopy, findGroup } from '@/utils/data';
import { sendMaterialMessage } from '@/utils/native/index';
interface GroupProps extends SpellGroup {
isExpand?: boolean
isHide?: boolean
}
interface NodeProps extends SpellNode {
isHide?: boolean
}
type SpellContextInit = {
groupItemClick?: (groupId: number, isExpand: boolean) => void
nodeItemClick?: (node: NodeProps) => void
};
interface SpellTreeProps {
data: GroupProps[]
}
export interface SpellTreeComponent {
refreshTree: () => void
query: (value: string) => void
}
const SpellFun = React.createContext<SpellContextInit>({});
function Node(props: NodeProps) {
const classMap: Record<FileType, string> = {
1: 'word-icon',
2: 'image-icon',
3: 'video-icon',
4: 'pdf-icon',
5: 'article-icon',
6: 'excel-icon',
7: 'word-icon'
};
const { nodeItemClick } = useContext(SpellFun);
if (props.isHide) return null;
return (
<div onClick={() => nodeItemClick!(props)} className="node-item">
<div className="node-type file-type">
<span className={classMap[props.type] + ' icon'}></span>
</div>
<div className="node-content">{props.title || props.itemContent || props.itemTitle}</div>
</div>
);
}
function Group(props: GroupProps) {
const [isExpand, setExpand] = useState(props.isExpand);
const { groupItemClick: contextGroupItemClick } = useContext(SpellFun);
const groupItemClick = useCallback(function () {
setExpand(!isExpand);
contextGroupItemClick!(props.id, !isExpand);
}, [isExpand, contextGroupItemClick]);
if (props.isHide) return null;
return (
<div className="group-wrap">
<div onClick={groupItemClick} className="group-item">
<div className="left-icon">
<span className="folder-icon icon"></span>
</div>
<div className="right-content">
<div className="top-title">{props.name}</div>
<div className="tip">{`${props.children.length}个话术文件夹,${props.contentList.length}条话术`}</div>
</div>
</div>
<div className="sub-group-item" style={{
display: isExpand ? '' : 'none'
}}>
{props.children.map(item => <Group key={item.id} {...item}></Group>)}
{props.contentList.map(item => <Node key={item.id} {...item}></Node>)}
</div>
</div>
);
}
function setNodeStatus(group:NodeProps | GroupProps, mz: boolean) {
group.isHide = !mz;
}
// 筛选相关
function setGroupRecursionStatus(group:GroupProps, mz: boolean) {
group.isHide = !mz;
group.children.forEach(function (item) {
setGroupRecursionStatus(item, mz);
});
group.contentList.forEach(function (item) {
setNodeStatus(item, mz);
});
}
function isMZ(item: SpellGroup | SpellNode, filterFun: (item: SpellGroup | SpellNode) => boolean) {
let mz = filterFun(item);
if (!mz) {
// 如果未命中
if ('pid' in item) {
// 此时为 group
item.children.forEach(function (item) {
if (!mz) {
mz = isMZ(item, filterFun);
}else {
isMZ(item, filterFun);
}
});
item.contentList.forEach(function (item) {
if (!mz) {
mz = isMZ(item, filterFun);
}else {
isMZ(item, filterFun);
}
});
setNodeStatus(item, mz);
return mz;
}
}
// 如果已经命中,则不用再遍历直接标记
if ('pid' in item) {
setGroupRecursionStatus(item, mz);
} else {
setNodeStatus(item, mz);
}
return mz;
}
function queryTreeData(treeData: SpellGroup[], filterFun: (item: SpellGroup | SpellNode) => boolean) {
const copyTreeData = deepCopy(treeData);
copyTreeData.forEach(function (item) {
isMZ(item, filterFun);
});
return copyTreeData;
}
function SpellTree({data: oTree}: SpellTreeProps, ref: React.Ref<SpellTreeComponent> | undefined) {
const [tree, setTree] = useState<SpellGroup[]>(oTree);
function groupItemClick(groupId: number, isExpand: boolean) {
const group: GroupProps = findGroup(tree, groupId)!;
group.isExpand = isExpand;
}
function nodeItemClick(node: NodeProps) {
console.log(node, 'node');
sendMaterialMessage(node);
}
console.log('build');
useImperativeHandle(ref, () => ({
refreshTree: function () {
// setTree(oTree);
},
query: function (value: string) {
if (!value) {
setTree(oTree);
return;
}
const newTree = queryTreeData(tree, function (item) {
if ('pid' in item) {
return item.name.includes(value);
}
return item.title.includes(value);
});
setTree(newTree);
}
}));
return (
<SpellFun.Provider value={{
groupItemClick,
nodeItemClick
}}>
<div className="spell-tree-page">
{
tree.map(item => <Group key={item.id} {...item}></Group>)
}
</div>
</SpellFun.Provider>
);
}
export default React.forwardRef(SpellTree);