diff --git a/components/DependentTable.tsx b/components/DependentTable.tsx
index e009b0e..5ff92fa 100644
--- a/components/DependentTable.tsx
+++ b/components/DependentTable.tsx
@@ -1,8 +1,8 @@
'use client';
-import React, { useState, useMemo } from 'react';
-import { Table } from 'antd';
-// import { DownOutlined, UpOutlined } from '@ant-design/icons';
-// import { SorterResult } from 'antd/es/table/interface';
+import React, { useState } from 'react';
+import Link from 'next/link';
+import { useParams } from 'next/navigation';
+import Image from 'next/image';
interface DependentItem {
crate_name: string;
@@ -14,80 +14,254 @@ interface DependentTableProps {
data: DependentItem[] | undefined; // 允许为 undefined
}
-const DependencyTable: React.FC
= ({ data }) => {
- const [sortColumn, setSortColumn] = useState(null);
- const [sortDirection, setSortDirection] = useState(null);
+const DependentTable: React.FC = ({ data }) => {
+ const params = useParams();
+ const [searchQuery, setSearchQuery] = useState('');
+ const [currentPage, setCurrentPage] = useState(1);
+ const itemsPerPage = 15; // 每页显示条目数
+ const [sortField, setSortField] = useState(null);
+ const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc');
+ // 处理搜索逻辑
+ const handleSearch = (e: React.ChangeEvent) => {
+ setSearchQuery(e.target.value);
+ setCurrentPage(1); // 搜索时重置到第一页
+ };
- const y = 1;
- if (y <= 0) {
- setSortColumn(null);
- setSortDirection(null);
- console.log(data);
- }
+ // 处理排序
+ const handleSort = (field: string) => {
+ if (sortField === field) {
+ // 如果已经在按这个字段排序,则切换排序方向
+ setSortDirection(sortDirection === 'asc' ? 'desc' : 'asc');
+ } else {
+ // 如果是新的排序字段,设置为升序
+ setSortField(field);
+ setSortDirection('asc');
+ }
+ setCurrentPage(1); // 排序时重置到第一页
+ };
+
+ // 筛选数据
+ const filteredData = data?.filter(item =>
+ item.crate_name.toLowerCase().includes(searchQuery.toLowerCase()) ||
+ item.version.toLowerCase().includes(searchQuery.toLowerCase()) ||
+ item.relation.toLowerCase().includes(searchQuery.toLowerCase())
+ ) || [];
+
+ // 排序数据
+ const sortedData = [...filteredData].sort((a, b) => {
+ if (!sortField) return 0;
+ let valueA, valueB;
- const sortedData = useMemo(() => {
- if (data === null) {
- return [];
+ switch (sortField) {
+ case 'crate_name':
+ valueA = a.crate_name.toLowerCase();
+ valueB = b.crate_name.toLowerCase();
+ break;
+ case 'relation':
+ valueA = a.relation.toLowerCase();
+ valueB = b.relation.toLowerCase();
+ break;
+ default:
+ return 0;
}
- if (!data) {
- return []; // 如果 data 为 undefined 或 null,返回空数组
+
+ if (valueA < valueB) return sortDirection === 'asc' ? -1 : 1;
+ if (valueA > valueB) return sortDirection === 'asc' ? 1 : -1;
+ return 0;
+ });
+
+ // 分页逻辑
+ const totalPages = Math.ceil(sortedData.length / itemsPerPage);
+ const startIndex = (currentPage - 1) * itemsPerPage;
+ const endIndex = startIndex + itemsPerPage;
+ const currentItems = sortedData.slice(startIndex, endIndex);
+
+ // 分页控制函数
+ const goToPage = (page: number) => {
+ if (page >= 1 && page <= totalPages) {
+ setCurrentPage(page);
}
- return sortColumn
- ? data.sort((a: DependentItem, b: DependentItem) => {
- if (a[sortColumn] < b[sortColumn]) return sortDirection === 'ascend' ? -1 : 1;
- if (a[sortColumn] > b[sortColumn]) return sortDirection === 'ascend' ? 1 : -1;
- return 0;
- })
- : data;
- }, [data, sortColumn, sortDirection]);
-
- const columns = [
- {
- title: 'Crate',
- dataIndex: 'crate_name',
- key: 'Crate',
- sorter: true,
- sortDirection: sortDirection,
- render: (text: string | number | bigint | boolean | React.ReactElement> | Iterable | React.ReactPortal | Promise | null | undefined) => {text},
- },
- {
- title: 'Version',
- dataIndex: 'version',
- key: 'Version',
- render: (text: string | number | bigint | boolean | React.ReactElement> | Iterable | React.ReactPortal | Promise | null | undefined) => {text},
- },
- {
- title: 'Relation',
- dataIndex: 'relation',
- key: 'relation',
- sorter: true,
- sortDirection: sortDirection,
- render: (text: string | number | bigint | boolean | React.ReactElement> | Iterable | React.ReactPortal | Promise | null | undefined) => {text},
- },
-
-
- ];
-
- // const handleSort = (column: SorterResult | SorterResult[], direction: React.SetStateAction) => {
- // setSortColumn(column.dataIndex);
- // setSortDirection(direction);
- // };
- const x = 1;
- if (x <= 0) {
- setSortColumn(null);
- setSortDirection(null);
- }
+ };
+
+ // 生成页码按钮
+ const getPageButtons = () => {
+ const pageButtons = [];
+ const maxVisiblePages = 5;
+
+ // 计算要显示的页码范围
+ let startPage = Math.max(1, currentPage - 2);
+ const endPage = Math.min(totalPages, startPage + maxVisiblePages - 1);
+
+ // 调整起始页,确保显示足够的页码
+ if (endPage - startPage + 1 < maxVisiblePages) {
+ startPage = Math.max(1, endPage - maxVisiblePages + 1);
+ }
+
+ for (let i = startPage; i <= endPage; i++) {
+ pageButtons.push(
+
+ );
+ }
+
+ return pageButtons;
+ };
+
return (
- handleSort(sorter, sorter.order)}
- //rowKey={(record) => record.Crate}
- />
+
+ {/* 搜索区域 */}
+
+
+ {/* 表格 */}
+
+
+
+
+ Crate
+
+
+
+ Version
+
+
+ Relation
+
+
+
+
+
+ {currentItems.length > 0 ? (
+ currentItems.map((item, index) => (
+
+
+
+ {item.crate_name}
+
+
+
{item.version}
+
{item.relation}
+
+ ))
+ ) : (
+
+ {searchQuery ? 'No matching results found' : 'No data available'}
+
+ )}
+
+
+
+ {/* 分页控制 */}
+ {sortedData.length > 0 && (
+
+
+
+
+ {getPageButtons()}
+
+
+
+
+ )}
+
);
};
-export default DependencyTable;
\ No newline at end of file
+export default DependentTable;
\ No newline at end of file
diff --git a/components/VersionsTable.tsx b/components/VersionsTable.tsx
index a2e6f31..28adddc 100644
--- a/components/VersionsTable.tsx
+++ b/components/VersionsTable.tsx
@@ -1,7 +1,8 @@
'use client';
-import React, { useEffect, useState } from 'react';
-import { Table } from 'antd';
+import React, { useState, useEffect } from 'react';
+import Link from 'next/link';
import { useParams } from 'next/navigation';
+import Image from 'next/image';
// 假设后端接口返回的类型
interface VersionInfo {
@@ -9,20 +10,24 @@ interface VersionInfo {
dependents: number; // 保持原始字段以便从API获取
updated_at: string; // 新增字段
downloads: string;
-
}
// 新增 PublishDay 接口
-interface FormattedVersionInfo extends VersionInfo {
- updated_at: string; // 新增字段
- downloads: string;
-}
+// interface FormattedVersionInfo extends VersionInfo {
+// updated_at: string; // 新增字段
+// downloads: string;
+// }
const VersionsTable: React.FC = () => {
- const [versionsData, setVersionsData] = useState([]);
+ const params = useParams();
+ const [versionsData, setVersionsData] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
- const params = useParams();
+ const [searchQuery, setSearchQuery] = useState('');
+ const [currentPage, setCurrentPage] = useState(1);
+ const itemsPerPage = 15; // 每页显示条目数
+ const [sortField, setSortField] = useState(null);
+ const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc');
useEffect(() => {
const fetchVersionsData = async () => {
@@ -33,22 +38,14 @@ const VersionsTable: React.FC = () => {
throw new Error(`HTTP error! status: ${response.status}`);
}
- const data: VersionInfo[] = await response.json();
+ const data = await response.json();
// 检查数据是否有效
if (!Array.isArray(data)) {
throw new Error('Invalid data format');
}
- // 将 API 数据转换为 Table 需要的格式
- const formattedData = data.map((item) => ({
- version: item.version,
- dependents: item.dependents, // 保留依赖数
- updated_at: item.updated_at, // 设置默认发布日为 N/A
- downloads: item.downloads, // 设置默认下载数为 N/A
- }));
-
- setVersionsData(formattedData); // 设置获取的数据
+ setVersionsData(data); // 设置获取的数据
} catch (error) {
setError(error instanceof Error ? error.message : 'An unknown error occurred'); // 改进错误处理
console.error('Error fetching data:', error);
@@ -60,44 +57,314 @@ const VersionsTable: React.FC = () => {
fetchVersionsData(); // 调用函数来获取数据
}, [params.nsfront, params.nsbehind, params.name, params.version]); // 依赖项数组
- const columns = [
- {
- title: 'Version',
- dataIndex: 'version',
- key: 'version',
- render: (text: string) => {text},
- },
- {
- title: 'Updated_at',
- dataIndex: 'updated_at', // 修改为使用 publishDay
- key: 'updated_at', // 修改为使用 publishDay
- render: (text: string) => {text},
- },
- {
- title: 'Downloads',
- dataIndex: 'downloads', // 修改为使用 publishDay
- key: 'downloads', // 修改为使用 publishDay
- render: (text: string) => {text},
- },
- {
- title: 'Dependents',
- dataIndex: 'dependents',
- key: 'dependents',
- render: (text: number) => {text},
- },
- ];
-
- if (loading) return Loading...
;
+ // 处理搜索逻辑
+ const handleSearch = (e: React.ChangeEvent) => {
+ setSearchQuery(e.target.value);
+ setCurrentPage(1); // 搜索时重置到第一页
+ };
+
+ // 处理排序
+ const handleSort = (field: string) => {
+ if (sortField === field) {
+ // 如果已经在按这个字段排序,则切换排序方向
+ setSortDirection(sortDirection === 'asc' ? 'desc' : 'asc');
+ } else {
+ // 如果是新的排序字段,设置为升序
+ setSortField(field);
+ setSortDirection('asc');
+ }
+ setCurrentPage(1); // 排序时重置到第一页
+ };
+
+ // 筛选数据
+ const filteredData = versionsData.filter(item =>
+ item.version.toLowerCase().includes(searchQuery.toLowerCase()) ||
+ item.updated_at.toLowerCase().includes(searchQuery.toLowerCase()) ||
+ item.downloads.toLowerCase().includes(searchQuery.toLowerCase()) ||
+ String(item.dependents).includes(searchQuery)
+ );
+
+ // 辅助函数:将下载量字符串转换为数字
+ const parseDownloadsToNumber = (downloadsStr: string): number => {
+ // 如果为空,返回0
+ if (!downloadsStr) return 0;
+
+ // 移除所有逗号
+ const cleanStr = downloadsStr.replace(/,/g, '');
+
+ // 处理带单位的数字,如"1.2M"、"3.4K"等
+ if (cleanStr.endsWith('K') || cleanStr.endsWith('k')) {
+ return parseFloat(cleanStr) * 1000;
+ } else if (cleanStr.endsWith('M') || cleanStr.endsWith('m')) {
+ return parseFloat(cleanStr) * 1000000;
+ } else if (cleanStr.endsWith('B') || cleanStr.endsWith('b')) {
+ return parseFloat(cleanStr) * 1000000000;
+ }
+
+ // 尝试直接解析为数字
+ return parseFloat(cleanStr) || 0;
+ };
+
+ // 辅助函数:比较版本号
+ const compareVersions = (versionA: string, versionB: string): number => {
+ // 分割版本号为组件部分
+ const partsA = versionA.split('.').map(part => parseInt(part) || 0);
+ const partsB = versionB.split('.').map(part => parseInt(part) || 0);
+
+ // 确保两个版本号数组长度相同
+ const maxLength = Math.max(partsA.length, partsB.length);
+ while (partsA.length < maxLength) partsA.push(0);
+ while (partsB.length < maxLength) partsB.push(0);
+
+ // 逐部分比较
+ for (let i = 0; i < maxLength; i++) {
+ if (partsA[i] > partsB[i]) return 1;
+ if (partsA[i] < partsB[i]) return -1;
+ }
+
+ return 0; // 版本号相等
+ };
+
+ // 排序数据
+ const sortedData = [...filteredData].sort((a, b) => {
+ if (!sortField) return 0;
+
+ let valueA, valueB;
+
+ switch (sortField) {
+ case 'version':
+ // 使用版本号比较函数
+ return sortDirection === 'asc'
+ ? compareVersions(a.version, b.version)
+ : compareVersions(b.version, a.version);
+ case 'downloads':
+ // 将下载量字符串转换为数字进行排序
+ valueA = parseDownloadsToNumber(a.downloads);
+ valueB = parseDownloadsToNumber(b.downloads);
+ break;
+ case 'dependents':
+ valueA = a.dependents;
+ valueB = b.dependents;
+ break;
+ default:
+ return 0;
+ }
+
+ if (valueA < valueB) return sortDirection === 'asc' ? -1 : 1;
+ if (valueA > valueB) return sortDirection === 'asc' ? 1 : -1;
+ return 0;
+ });
+
+ // 分页逻辑
+ const totalPages = Math.ceil(sortedData.length / itemsPerPage);
+ const startIndex = (currentPage - 1) * itemsPerPage;
+ const endIndex = startIndex + itemsPerPage;
+ const currentItems = sortedData.slice(startIndex, endIndex);
+
+ // 分页控制函数
+ const goToPage = (page: number) => {
+ if (page >= 1 && page <= totalPages) {
+ setCurrentPage(page);
+ }
+ };
+
+ // 生成页码按钮
+ const getPageButtons = () => {
+ const pageButtons = [];
+ const maxVisiblePages = 5;
+
+ // 计算要显示的页码范围
+ let startPage = Math.max(1, currentPage - 2);
+ const endPage = Math.min(totalPages, startPage + maxVisiblePages - 1);
+
+ // 调整起始页,确保显示足够的页码
+ if (endPage - startPage + 1 < maxVisiblePages) {
+ startPage = Math.max(1, endPage - maxVisiblePages + 1);
+ }
+
+ for (let i = startPage; i <= endPage; i++) {
+ pageButtons.push(
+
+ );
+ }
+
+ return pageButtons;
+ };
+
+ if (loading) return Loading...
;
if (error) return Error: {error}
;
return (
-
+
+ {/* 搜索区域 */}
+
+
+ {/* 表格 */}
+
+
+
+
+ Version
+
+
+
+ Updated At
+
+
+ Downloads
+
+
+
+ Dependents
+
+
+
+
+
+ {currentItems.length > 0 ? (
+ currentItems.map((item, index) => (
+
+
+
+ {item.version}
+
+
+
{item.updated_at}
+
{item.downloads}
+
{item.dependents}
+
+ ))
+ ) : (
+
+ {searchQuery ? 'No matching results found' : 'No data available'}
+
+ )}
+
+
+
+ {/* 分页控制 */}
+ {sortedData.length > 0 && (
+
+
+
+
+ {getPageButtons()}
+
+
+
+
+ )}
+
);
};