index.tsx.backup.final 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. import * as React from 'react';
  2. import { useNavigate } from 'react-router-dom';
  3. import { Button, Table, TableColumnsType, TablePaginationConfig, Input, Space, Tabs, message, Tooltip } from 'antd';
  4. import { PlusOutlined, SearchOutlined, EditFilled, FileWordFilled, FileMarkdownFilled, DeleteFilled } from '@ant-design/icons';
  5. import { GuideTips, FilterBar } from '@/components/common';
  6. import InfoModal from './components/InfoModal';
  7. import { useKnowledgeLibListStore } from './store';
  8. import { Record } from './types';
  9. import './style.less';
  10. import LocalStorage from '@/LocalStorage';
  11. import dayjs from 'dayjs';
  12. // 导入 GuideTips 配置
  13. import { getGuideTipsConfig } from '@/config/guideTips';
  14. const KnowledgeLibList: React.FC = () => {
  15. const navigate = useNavigate();
  16. const {
  17. listLoading,
  18. list,
  19. infoModalId,
  20. infoModalOpen,
  21. page,
  22. setListLoading,
  23. setList,
  24. setInfoModalId,
  25. setInfoModalOpen,
  26. setPage,
  27. fetchKnowledgeLibList,
  28. onCreateKnowledgeLib,
  29. onModifyKnowledgeLib,
  30. onDeleteKnowledgeLib,
  31. onInfoModalOpenChange,
  32. init,
  33. reset,
  34. } = useKnowledgeLibListStore();
  35. const [activeTab, setActiveTab] = React.useState('all'); // 'all' | 'mine'
  36. const [searchName, setSearchName] = React.useState('');
  37. const [currentPage, setCurrentPage] = React.useState(1);
  38. const [pageSize, setPageSize] = React.useState(10);
  39. const userInfoAll = LocalStorage.getUserInfo();
  40. const listFlag = LocalStorage.getStatusFlag('knowledge:knowledgeLib:list');
  41. const updateFlag = LocalStorage.getStatusFlag('knowledge:knowledgeLib:update');
  42. const downloadOriginal = LocalStorage.getStatusFlag('knowledge:knowledgeLib:downloadOriginal');
  43. const downloadMd = LocalStorage.getStatusFlag('knowledge:knowledgeLib:downloadMd');
  44. // 初始化加载数据
  45. React.useEffect(() => {
  46. init();
  47. }, [init]);
  48. // 监听创建事件
  49. React.useEffect(() => {
  50. const handleCreate = () => {
  51. onCreateKnowledgeLibClick();
  52. };
  53. window.addEventListener('knowledgeLibCreate', handleCreate as EventListener);
  54. return () => {
  55. window.removeEventListener('knowledgeLibCreate', handleCreate as EventListener);
  56. };
  57. }, []);
  58. // 处理函数
  59. const onCreateKnowledgeLibClick = () => {
  60. setInfoModalId('');
  61. setInfoModalOpen(true);
  62. message.info('创建知识库');
  63. };
  64. const onClickModify = (record: Record) => {
  65. setInfoModalId(record.knowledgeId);
  66. setInfoModalOpen(true);
  67. message.info('编辑知识库');
  68. };
  69. const infoModalOnClickConfirm = () => {
  70. const data = {
  71. name: '测试知识库',
  72. description: '测试描述',
  73. };
  74. if (infoModalId) {
  75. onModifyKnowledgeLib(infoModalId, data);
  76. } else {
  77. onCreateKnowledgeLib(data);
  78. }
  79. };
  80. const infoModalOnClickCancel = () => {
  81. setInfoModalOpen(false);
  82. setInfoModalId('');
  83. };
  84. const onClickDelete = (record: Record) => {
  85. message.loading('删除中...', 0);
  86. setTimeout(() => {
  87. onDeleteKnowledgeLib(record.knowledgeId);
  88. message.success('删除成功');
  89. }, 500);
  90. };
  91. const onClickDownload = (record: Record) => {
  92. // 下载原始文档
  93. message.info(`下载原始文档:${record.name}`);
  94. // TODO: 调用原始文档下载 API
  95. };
  96. const onClickDownloadMd = (record: Record) => {
  97. // 下载 MD 文档
  98. message.info(`下载 MD 文档:${record.name}`);
  99. // TODO: 调用 MD 文档下载 API
  100. };
  101. // 过滤数据
  102. const filteredList = list.filter(item => {
  103. const matchSearch = !searchName || item.name.toLowerCase().includes(searchName.toLowerCase());
  104. // TAB 过滤:全部 | 我创建的 | 我可以维护的
  105. let matchTab = true;
  106. if (activeTab === 'mine') {
  107. // 我创建的
  108. matchTab = userInfoAll?.id === item.createBy;
  109. } else if (activeTab === 'maintainer') {
  110. // 我可以维护的(创建者或维护者)
  111. matchTab = userInfoAll?.id === item.createBy ||
  112. (item.maintainers && item.maintainers.includes(userInfoAll?.id));
  113. }
  114. return matchSearch && matchTab;
  115. });
  116. // 分页
  117. const paginatedList = filteredList.slice((currentPage - 1) * pageSize, currentPage * pageSize);
  118. // 分页处理
  119. const handlePageChange = (page: number, size: number) => {
  120. setCurrentPage(page);
  121. setPageSize(size);
  122. setPage({ pageNum: page, pageSize: size, total: filteredList.length });
  123. };
  124. // 表格列定义 - 匹配实际 API 字段(紧凑布局)
  125. const columns: TableColumnsType<Record> = [
  126. {
  127. title: '序号',
  128. dataIndex: 'index',
  129. width: 60, // 更紧凑
  130. align: 'center',
  131. render: (_text, _record, index) => {
  132. return ((currentPage - 1) * pageSize) + index + 1;
  133. }
  134. },
  135. {
  136. title: '知识库名称',
  137. dataIndex: 'name',
  138. width: 180, // 更紧凑
  139. render: (text, record) => {
  140. return (
  141. <div>
  142. <p
  143. className='text-primary cursor-pointer'
  144. style={{ fontWeight: 600, fontSize: '@font-base' }}
  145. onClick={() => {
  146. navigate(`/knowledge/knowledgeLib/${record.knowledgeId}/${record.createBy}`);
  147. }}
  148. >
  149. {text}
  150. </p>
  151. <div style={{ color: '#999', fontSize: 11, marginTop: 2 }}>
  152. ID: {record.knowledgeId}
  153. </div>
  154. </div>
  155. );
  156. }
  157. },
  158. {
  159. title: '使用空间',
  160. dataIndex: 'length',
  161. width: 90, // 更紧凑
  162. align: 'center',
  163. render: (text) => text || '--',
  164. },
  165. {
  166. title: '字符数量',
  167. dataIndex: 'wordNum',
  168. width: 100, // 更紧凑
  169. align: 'center',
  170. render: (text) => text && text !== '--' ? text.toLocaleString() : '--',
  171. },
  172. {
  173. title: '文件数量',
  174. dataIndex: 'documentSize',
  175. width: 80, // 更紧凑
  176. align: 'center',
  177. render: (text) => text && text !== '--' ? text : '--',
  178. },
  179. {
  180. title: '切片数量',
  181. dataIndex: 'sliceCount',
  182. width: 80, // 更紧凑
  183. align: 'center',
  184. render: (text) => text && text !== '--' ? text.toLocaleString() : '--',
  185. },
  186. {
  187. title: '是否公开',
  188. dataIndex: 'isOpen',
  189. width: 80, // 更紧凑
  190. align: 'center',
  191. render: (value) => value === 1 ? '公开' : '私有',
  192. },
  193. {
  194. title: '创建时间',
  195. dataIndex: 'createTime',
  196. width: 160, // 更紧凑
  197. align: 'center',
  198. render: (text) => text && text !== '--' ? dayjs(text).format('YYYY-MM-DD HH:mm:ss') : '--',
  199. },
  200. {
  201. title: '更新时间',
  202. dataIndex: 'updateTime',
  203. width: 160, // 更紧凑
  204. align: 'center',
  205. render: (text) => text && text !== '--' ? dayjs(text).format('YYYY-MM-DD HH:mm:ss') : '--',
  206. },
  207. {
  208. title: '操作',
  209. key: 'action',
  210. width: 160, // 适配 Ant Design 图标
  211. fixed: 'right',
  212. align: 'center',
  213. render: (_text, record) => (
  214. <Space size={0}> {/* 无间距,更紧凑 */}
  215. {/* 编辑按钮 */}
  216. <Tooltip title="编辑" placement="top">
  217. <Button
  218. type="text"
  219. size="large"
  220. onClick={() => onClickModify(record)}
  221. className="action-btn"
  222. icon={<EditFilled />}
  223. />
  224. </Tooltip>
  225. {/* 下载原文档按钮 */}
  226. <Tooltip title="下载原文档" placement="top">
  227. <Button
  228. type="text"
  229. size="large"
  230. onClick={() => onClickDownload(record)}
  231. className="action-btn"
  232. icon={<FileWordFilled />}
  233. />
  234. </Tooltip>
  235. {/* 下载 MD 文档按钮 */}
  236. <Tooltip title="下载 MD 文档" placement="top">
  237. <Button
  238. type="text"
  239. size="large"
  240. onClick={() => onClickDownloadMd(record)}
  241. className="action-btn"
  242. icon={<FileMarkdownFilled />}
  243. />
  244. </Tooltip>
  245. {/* 删除按钮 */}
  246. <Tooltip title="删除" placement="top">
  247. <Button
  248. type="text"
  249. size="large"
  250. danger
  251. onClick={() => onClickDelete(record)}
  252. className="action-btn"
  253. icon={<DeleteFilled />}
  254. />
  255. </Tooltip>
  256. </Space>
  257. )
  258. },
  259. ];
  260. // 获取 GuideTips 配置
  261. const guideTipsConfig = getGuideTipsConfig('knowledgeLib');
  262. return (
  263. <div className="page-container">
  264. {/* 标题区域 */}
  265. <div className="list-header with-tips">
  266. <div className='list-header-title'>
  267. <h1>知识库管理</h1>
  268. <p>管理您的所有知识库</p>
  269. </div>
  270. <div className='list-header-actions'>
  271. <Button
  272. type='primary'
  273. icon={<PlusOutlined />}
  274. onClick={onCreateKnowledgeLibClick}
  275. >
  276. 创建
  277. </Button>
  278. </div>
  279. </div>
  280. {/* Tips 提示组件 */}
  281. {guideTipsConfig && (
  282. <GuideTips
  283. visible={true}
  284. title={guideTipsConfig.title}
  285. steps={guideTipsConfig.steps}
  286. />
  287. )}
  288. {/* 筛选区域 - 使用 FilterBar 组件 */}
  289. <FilterBar
  290. tabs={[
  291. { key: 'all', label: '全部' },
  292. { key: 'mine', label: '我创建的' },
  293. { key: 'maintainer', label: '我可以维护的' },
  294. ]}
  295. activeTab={activeTab}
  296. onTabChange={setActiveTab}
  297. searchPlaceholder="请输入知识库名称"
  298. searchValue={searchName}
  299. onSearchChange={setSearchName}
  300. onSearch={async () => {
  301. // 模拟异步搜索
  302. await new Promise(resolve => setTimeout(resolve, 500));
  303. message.info('搜索功能开发中');
  304. }}
  305. searchWidth={300}
  306. />
  307. {/* 表格区域 */}
  308. <div className="content-section">
  309. <Table
  310. rowKey="knowledgeId"
  311. loading={listLoading}
  312. columns={columns}
  313. dataSource={paginatedList}
  314. pagination={{
  315. current: currentPage,
  316. pageSize: pageSize,
  317. total: filteredList.length,
  318. onChange: handlePageChange,
  319. showSizeChanger: true,
  320. showQuickJumper: true,
  321. showTotal: (total) => `共 ${total} 条`,
  322. pageSizeOptions: ['10', '20', '50', '100'],
  323. }}
  324. scroll={{ x: 1200 }}
  325. />
  326. </div>
  327. {/* 创建/编辑弹窗 */}
  328. <InfoModal
  329. id={infoModalId}
  330. open={infoModalOpen}
  331. onClickConfirm={infoModalOnClickConfirm}
  332. onClickCancel={infoModalOnClickCancel}
  333. />
  334. </div>
  335. );
  336. };
  337. export default KnowledgeLibList;