feat(iod): 重构数联网搜索功能

- 新增数联网设置页面
- 优化数联网搜索结果展示
- 添加数据集、科创场景和科技企业等不同类型的搜索结果
- 重构搜索结果卡片组件,支持加载状态和不同展示模式
- 更新数联网搜索相关的国际化文案
This commit is contained in:
zhaoweijie
2025-08-22 17:15:19 +08:00
parent efbf2a3eff
commit 17020e8755
33 changed files with 1321 additions and 773 deletions

View File

@@ -1,40 +1,85 @@
import React, { useState } from "react"
import React, { useMemo, useState } from "react"
import { DataNavigation } from "@/components/Common/DataNavigation.tsx"
import { Card, Drawer, List } from "antd"
import { Card, Drawer, Skeleton } from "antd"
import { IodRegistryEntry } from "@/types/iod.ts"
type ShowCardProps = {
loading: boolean
record: IodRegistryEntry
truncate?: boolean
}
const ShowCard: React.FC<ShowCardProps> = ({
loading,
record,
truncate = true
}) => (
<Card className="[&_.ant-card-body]:!p-2 !bg-[gb(248, 248, 248)] border !border-[#e9e9e9]">
{loading ? (
<Skeleton title={false} active />
) : (
<div className="flex flex-col gap-0.5">
<h3
className={`text-base font-medium mb-1 text-[#222222] break-all ${truncate ? "line-clamp-2" : ""}`}
title={record.name}>
{record.name}
</h3>
<p
className={`text-sm text-[#383838] break-all ${truncate ? "line-clamp-2" : ""}`}
title={record.doId}>
{record.doId}
</p>
<p
className={`text-[#828282] text-xs break-all ${truncate ? "truncate" : ""}`}
title={record.description}>
{record.description}
</p>
</div>
)}
</Card>
)
const defaultData:IodRegistryEntry[] = [
{
name: "上海芯飞睿科技有限公司",
description:
"上海芯飞睿科技有限公司专业从事集成化激光材料与微型化激光器件的研发",
doId: "CSTR:15552.13.05.61.2022.783"
},
{
name: "长三角先进材料研究院",
description: "由江苏省人民政府联合中国科学院、中国钢研科技集团和中国",
doId: "CSTR:15552.12.01.11.2021.528"
},
{
name: "清华大学智能系统实验室",
description: "清华大学",
doId: "CSTR:15552.13.04.91.2021.614",
},
]
export const PlaygroundTeam = () => {
// 模拟数据
const data = [
{
title: "绿色化工工艺项目",
description:
"基于生物基原料采用repeal2.0可降解材料技术,开发新型环保材料。",
demander: "奥赛康药业 供方美国Propella公司"
},
{
title: "智能农业解决方案",
description: "利用物联网技术,实现精准农业管理,提高农作物产量。",
demander: "奥赛康药业 供方美国Propella公司"
},
{
title: "新能源汽车电池技术",
description: "研发高能量密度、长寿命的新型电池材料,推动电动汽车发展。",
demander: "奥赛康药业 供方美国Propella公司"
},
{
title: "碳捕集与封存技术",
description: "开发高效的碳捕集技术,减少工业排放,助力碳中和目标。",
demander: "奥赛康药业 供方美国Propella公司"
}
]
const { messages, iodLoading, currentMessageId, iodSearch } = useMessageOption()
for (let i = 0; i < 10; i++) {
data.push({
title: "开发新型电池材料",
description: "研发高能量密度、长寿命的新型电池材料,推动电动汽车发展。",
demander: "奥赛康药业 供方美国Propella公司"
})
}
const data = useMemo<IodRegistryEntry[]>(() => {
// 确保loading状态时数据大于3
if (iodLoading) {
return defaultData
}
if (messages.length && iodSearch) {
const currentMessage = messages?.find(
(message) => message.id === currentMessageId
)
return currentMessage?.iodSources.organization.data ?? []
}
return defaultData
}, [currentMessageId, messages, iodLoading])
const title = useMemo(() => {
return messages.length > 0 ? "推荐团队" : "热点团队"
}, [messages])
const [open, setOpen] = useState(false)
@@ -72,7 +117,7 @@ export const PlaygroundTeam = () => {
p-id="7274"
fill="#BE0BAC"></path>
</svg>
{title}
</div>
}
onClick={showDrawer}
@@ -80,59 +125,27 @@ export const PlaygroundTeam = () => {
{/* 场景列表 */}
<div className="grid grid-cols-3 gap-3 flex-1 overflow-y-auto">
{data.slice(0, 5).map((item, index) => (
<Card
key={index}
className="[&_.ant-card-body]:!p-2 !bg-[gb(248, 248, 248)] border !border-[#e9e9e9]">
<div className="flex flex-col gap-0.5">
<h3 className="text-base font-medium mb-1 text-[#222222] line-clamp-2">
{item.title}
</h3>
<p className="text-[#828282] text-xs truncate">
{item.description}
</p>
<p className="flex items-center gap-1.5">
<span className="inline-block text-[#BE0BAC] bg-[#be0bac30] h-5 leading-5 mt-1 text-xs rounded-full px-2.5">
</span>
<span className="inline-block text-[#EB1C1C] bg-[#eb1c1c30] h-5 leading-5 mt-1 text-xs rounded-full px-2.5">
</span>
</p>
</div>
</Card>
{data.slice(0, 3).map((item, index) => (
<ShowCard key={item.doId} loading={iodLoading} record={item} />
))}
</div>
</div>
{/* 抽屉 */}
<Drawer
title="相关团队"
title={title}
closable={{ "aria-label": "Close Button" }}
onClose={onClose}
open={open}
width="33.33%">
<div className="grid grid-cols-1 gap-3 overflow-y-auto">
{data.slice(0, 5).map((item, index) => (
<Card
key={index}
hoverable
className="[&_.ant-card-body]:!p-2 !bg-[gb(248, 248, 248)] border !border-[#e9e9e9]">
<div className="flex flex-col gap-0.5">
<h3 className="text-base font-medium mb-1 text-[#222222]">
{item.title}
</h3>
<p className="text-[#828282] text-xs">{item.description}</p>
<p className="flex items-center gap-1.5">
<span className="inline-block text-[#BE0BAC] bg-[#be0bac30] h-5 leading-5 mt-1 text-xs rounded-full px-2.5">
</span>
<span className="inline-block text-[#EB1C1C] bg-[#eb1c1c30] h-5 leading-5 mt-1 text-xs rounded-full px-2.5">
</span>
</p>
</div>
</Card>
{data.map((item, index) => (
<ShowCard
key={item.doId}
loading={iodLoading}
record={item}
truncate={false}
/>
))}
</div>
</Drawer>