import React, { useState, useEffect } from 'react';
import { ProCard, PageContainer } from '@ant-design/pro-components';
import {Form, Radio, Tree, Row, Col, message, List, Card, Tag, Typography, Space} from 'antd';
import {request} from "@@/plugin-request/request";
import CustomPagination from "./CustomPagination";
const { Title, Text, Paragraph } = Typography;
interface SearchResultListProps {
keyword?: string;
}
interface AssetsItem {
id: string;
dsName: string;
dsTableName: string;
dsType: string;
areaId: string;
areaName: string;
sysId: string;
sysName: string;
bussinessObjName: string;
bussinessObjId: string;
processPointName: string;
dsOwnerName: string;
dsOwnerNum: string;
isConfirm: string; // 后端返回的是字符串 "true"/"false"
dsMemo: string;
dsRange: string;
tags: string;
demoData: string;
createUser: string;
createTime: number; // 时间戳
updateUser: string;
updateTime: number; // 时间戳
deleted: number; // 删除标志,0表示未删除
demoFileName: string;
demoFilePath: string;
demoOssFilePath: string;
}
// 树形结构组件
const SearchResultList: React.FC<SearchResultListProps> = ({keyword}) => {
const [treeData, setTreeData] = useState<any[]>([]);
const [assetsData, setAssetsData] = useState<AssetsItem[]>([]);
const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
// ✅ 新增两个筛选状态
const [isEmpty, setIsEmpty] = useState<boolean>(false);
const [dsType, setDsType] = useState<string>('');
const [isConfirm, setIsConfirm] = useState<string>('');
//数据资产分页
const [pageNum, setPageNum] = useState<number>(1);
const [totalItems, setTotalItems] = useState<number>(5); // 从接口获取
// 组件加载时自动请求一次树数据
useEffect(() => {
const loadInitialData = async () => {
// 更新 requestAssetsParam
// 请求树结构
const treeData = await fetchTreeData({
keyWord: keyword ?? '',
dsType: dsType,
isConfirm: isConfirm
});
if(treeData){
setTreeData(treeData);
}else{
message.error("查询数据为空")
}
// 请求数据资产
const assetsData = await fetchAssetsData({
keyWord: keyword,
dsType: dsType,
isConfirm: isConfirm,
pageNum:pageNum,
pageSize:10
});
if(assetsData){
setAssetsData(assetsData);
}
};
loadInitialData();
}, [keyword, dsType, isConfirm ,pageNum]); // 当筛选条件变化时重新请求
// 树形数据处理函数,遍历节点 将节点的名称进行拼接
// @ts-ignore
const filterTreeData = (nodes: any[], level = 1) =>
nodes.map((node) => {
if (node.count <= 0 || node.count == null) {
node.title = node.title.replace(/[\s\(\(]*$$(\d+)$$[\s\)\)]*/g, '').trim();
}
return {
...node,
isLink: level === 1, // 第一层节点添加 isLink
children: node.children ? filterTreeData(node.children, level + 1) : [],
};
});
// 获取树形结构数据的函数
const fetchTreeData = async (param: { keyWord: string; dsType: string; isConfirm: string; }) => {
const res = await request('/ds/dsbaseinfo/searchAssetsTree', {
method: 'POST',
data:param
});
if(res && res.length>0){
return filterTreeData(res || []);
}
return []
};
// 获取资产详情的函数,
const fetchAssetsData = async (param: { keyWord: any; dsType: string; isConfirm: string; pageNum: number; pageSize: number; areaName?: any; }) => {
try {
const res = await request('/ds/dsbaseinfo/globalSearchAssets', {
method: 'POST',
data: param,
});
if (res && res.list) {
setIsEmpty(res.list.length === 0);
setTotalItems(res.list.length)
return res.list as AssetsItem[];
} else {
setIsEmpty(true);
return [];
}
} catch (err) {
setIsEmpty(true);
message.error('请求失败');
return [];
}
}
const showModal = (areaName: string) => {
// 模拟从后端获取领域清单数据
const list = [
{ name: '销售领域', count: 120 },
{ name: '财务领域', count: 80 },
{ name: '人力资源领域', count: 95 },
{ name: '供应链领域', count: 70 },
];
};
//翻页函数
const handlePageChange = (page: number) => {
setPageNum(page);
};
// 高亮关键词函数
const highlightKeyword = (text: string, keyword: string | null | undefined): React.ReactNode => {
if (!keyword || !text || typeof text !== 'string') return text;
const regex = new RegExp(`(${keyword})`, 'gi'); // 忽略大小写匹配
const parts = text.split(regex);
return parts.map((part, index) =>
part.toLowerCase() === keyword.toLowerCase() ? (
<span key={index} style={{color: 'red', fontWeight: 'bold'}}>
{part}
</span>
) : (
part
)
);
};
// 预览文件函数
const handlePreview = (url: string) => {
if (url) {
const base64Url = btoa(unescape(encodeURIComponent(url)));
window.open('http://10.255.96.51:8012/onlinePreview?url=' + encodeURIComponent(base64Url));
} else {
message.error('无法预览文件');
}
};
// 点击树节点时触发
const onSelect = async (selectedKeys: string[], info: any) => {
const selectedNode = info.node;
// ✅ 判断是否是叶子节点或倒数第二层节点
const isLeafNode = selectedNode.isLeaf || !selectedNode.children?.length;
const isPenultimateNode =
selectedNode.children?.length > 0 &&
selectedNode.children.every((child: any) => child.isLeaf || !child.children?.length);
let param = {
keyWord:keyword,
pageNum:pageNum,
pageSize:10,
dsType:dsType,
isConfirm:isConfirm,
areaName: selectedNode.key.split('_')[0],
}
if (isLeafNode){
param = {
...param,
// @ts-ignore
dsName:selectedNode.title
}
}
if (isPenultimateNode) {
if(selectedNode.key.includes("系统")){
// @ts-ignore
param = {...param,sysName:selectedNode.key.split('_')[2]}
}
if (selectedNode.key.includes("对象")){
// @ts-ignore
param = {...param,bussinessObjName:selectedNode.key.split('_')[2]}
}
if (selectedNode.key.includes("流程")){
// @ts-ignore
param = {...param,processPointName:selectedNode.key.split('_')[2]}
}
}
const assetsData = await fetchAssetsData(param);
setAssetsData(assetsData);
}
// 控制树节点展开
const onExpand = (keys: React.Key[]) => {
setExpandedKeys(keys as string[]);
};
// ✅ 处理筛选项变化
const handleDsTypeChange = (e: any) => {
setDsType(e.target.value)
};
const handleIsConfirmChange = (e: any) => {
if(e.target.value == '是'){
setIsConfirm('true')
}else if (e.target.value == '否'){
setIsConfirm('false')
}else{
setIsConfirm('')
}
};
return (
<PageContainer style={{marginTop: 5}}>
<ProCard style={{margin: '0 auto', width: 1300, border: 1}}>
<Form layout="inline" style={{padding: 3, flexDirection: 'column'}}>
{/* 数据类型 */}
<Form.Item label="数据类型" style={{marginBottom: 16}}>
<Radio.Group defaultValue={''} onChange={handleDsTypeChange}>
<Radio value="">不限</Radio>
<Radio value="原始数据">原始数据</Radio>
<Radio value="清洗后数据">清洗后数据</Radio>
</Radio.Group>
</Form.Item>
{/* 是否认证 */}
<Form.Item label="是否认证" style={{marginBottom: 16}}>
<Radio.Group defaultValue={''} onChange={handleIsConfirmChange}>
<Radio value="">不限</Radio>
<Radio value="是">是</Radio>
<Radio value="否">否</Radio>
</Radio.Group>
</Form.Item>
</Form>
</ProCard>
<Row gutter={5} style={{marginTop: 5}}>
<Col span={5}>
<ProCard title="各领域树状结构">
<Tree
showLine
treeData={treeData}
// @ts-ignore
onSelect={onSelect}
expandedKeys={expandedKeys}
onExpand={onExpand}
title={(node) => {
if (node.isFirstLevel) {
return (
<span>
<span>{node.title}</span>
<button
type="button"
style={{
marginLeft: 10,
padding: '2px 8px',
fontSize: 12,
color: '#1890ff',
background: 'none',
border: '1px solid #1890ff',
borderRadius: 4,
cursor: 'pointer',
}}
onClick={(e) => {
e.preventDefault();
e.stopPropagation(); // 阻止触发 onSelect
showModal(node.title);
}}
>
领域清单
</button>
</span>
);
}
return <span>{node.title}</span>;
}}
/>
</ProCard>
</Col>
<Col span={19}>
<ProCard title="数据资产列表">
<div>
{isEmpty ? (
<div style={{
textAlign: 'center',
padding: '50px 20px',
color: '#999',
fontSize: '16px',
}}>
提示您搜索的关键词暂无相关数据资产
</div>
) : (
<List
dataSource={assetsData}
renderItem={(item) => (
<List.Item style={{marginBottom: -5}} key={item.id}>
<Card style={{width: '100%', padding: 10}} bodyStyle={{padding: 5}}>
<Title level={4}>
<a href="#">{highlightKeyword(item.dsName, keyword)}</a>
{item.isConfirm === 'true' ? (
<Tag color="red" key={item.id}>
数据已确认
</Tag>
) : null}
{item.tags.split(',').map((tag, index) => (
<Tag color="blue" key={index}>
{highlightKeyword(tag, keyword)}
</Tag>
))}
</Title>
<Text type="secondary">{highlightKeyword(item.dsTableName, keyword)}</Text>
<Paragraph>{highlightKeyword(item.dsMemo, keyword)}</Paragraph>
<Space direction="vertical" size="small">
<Text>
领域:<Text strong>{highlightKeyword(item.areaName, keyword)}</Text>
系统:<Text strong>{highlightKeyword(item.sysName, keyword)}</Text>
对象:<Text
strong>{highlightKeyword(item.bussinessObjName, keyword)}</Text>
流程:<Text strong>{highlightKeyword(item.processPointName, keyword)}</Text>
</Text>
{/* 如果有样例文件则显示 */}
{item.demoFileName && item.demoFileName !== '' ? (
<Text>
样例数据:{' '}
<a href="#">{highlightKeyword(item.demoFileName, keyword)}</a>
<span
onClick={() => handlePreview(item.demoOssFilePath)}
style={{color: 'blue', cursor: 'pointer', marginRight: 10}}
>
预览
</span>
<span>
<a href={item.demoOssFilePath}>下载</a>
</span>
</Text>
) : null}
</Space>
</Card>
</List.Item>
)}
/>
)}
<CustomPagination
current={pageNum}
total={totalItems}
pageSize={10}
onPageChange={handlePageChange}
/>
</div>
</ProCard>
</Col>
</Row>
</PageContainer>
);
}
export default SearchResultList;
我这么写 为啥么有显示出链接
最新发布