feat: web update vuln list

This commit is contained in:
fan-tastic-z
2025-08-26 18:41:23 +08:00
parent 16910d9f9c
commit 9360314956
4 changed files with 88 additions and 72 deletions

View File

@@ -9,15 +9,16 @@
"preview": "vite preview"
},
"dependencies": {
"@tailwindcss/line-clamp": "^0.4.4",
"@vitejs/plugin-react": "^4.3.1",
"autoprefixer": "^10.4.20",
"axios": "^1.7.4",
"postcss": "^8.4.41",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.26.0",
"axios": "^1.7.4",
"tailwindcss": "^3.4.10",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.41",
"vite": "^5.4.2",
"@vitejs/plugin-react": "^4.3.1"
"vite": "^5.4.2"
},
"devDependencies": {
"@types/react": "^18.3.4",

11
assets/pnpm-lock.yaml generated
View File

@@ -5,6 +5,9 @@ settings:
excludeLinksFromLockfile: false
dependencies:
'@tailwindcss/line-clamp':
specifier: ^0.4.4
version: 0.4.4(tailwindcss@3.4.17)
'@vitejs/plugin-react':
specifier: ^4.3.1
version: 4.7.0(vite@5.4.19)
@@ -671,6 +674,14 @@ packages:
dev: false
optional: true
/@tailwindcss/line-clamp@0.4.4(tailwindcss@3.4.17):
resolution: {integrity: sha512-5U6SY5z8N42VtrCrKlsTAA35gy2VSyYtHWCsg1H87NU1SXnEfekTVlrga9fzUDrrHcGi2Lb5KenUWb4lRQT5/g==}
peerDependencies:
tailwindcss: '>=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1'
dependencies:
tailwindcss: 3.4.17
dev: false
/@types/babel__core@7.20.5:
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
dependencies:

View File

@@ -45,9 +45,9 @@ const VulnerabilityListPage = () => {
const totalPages = Math.ceil(totalCount / pageSize)
return (
<div className="max-w-7xl mx-auto">
<div className="text-center mb-8">
<h1 className="text-3xl font-extrabold text-gray-900 mb-2">
<div className="mx-auto max-w-7xl">
<div className="mb-8 text-center">
<h1 className="mb-2 text-3xl font-extrabold text-gray-900">
漏洞信息列表
</h1>
<p className="text-gray-600">
@@ -64,13 +64,13 @@ const VulnerabilityListPage = () => {
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="搜索漏洞标题或描述..."
className="block w-full pl-4 pr-12 py-2 border border-gray-300 rounded-md leading-5 bg-white placeholder-gray-500 focus:outline-none focus:placeholder-gray-400 focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
className="block w-full py-2 pl-4 pr-12 leading-5 placeholder-gray-500 bg-white border border-gray-300 rounded-md focus:outline-none focus:placeholder-gray-400 focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
/>
<button
type="submit"
className="absolute inset-y-0 right-0 flex items-center pr-3"
>
<svg className="h-5 w-5 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
<svg className="w-5 h-5 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clipRule="evenodd" />
</svg>
</button>
@@ -79,82 +79,84 @@ const VulnerabilityListPage = () => {
</div>
{error && (
<div className="bg-red-50 border border-red-200 rounded-md p-4 mb-6">
<div className="text-red-800 text-sm">
<div className="p-4 mb-6 border border-red-200 rounded-md bg-red-50">
<div className="text-sm text-red-800">
{error}
</div>
</div>
)}
{loading ? (
<div className="flex justify-center items-center h-64">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-indigo-600"></div>
<div className="flex items-center justify-center h-64">
<div className="w-12 h-12 border-b-2 border-indigo-600 rounded-full animate-spin"></div>
</div>
) : (
<>
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
{vulnerabilities.map((vuln) => (
<div key={vuln.id} className="bg-white rounded-xl shadow-lg overflow-hidden hover:shadow-xl transition-shadow duration-300 ease-in-out">
<Link to={`/vulns/${vuln.id}`} className="block h-full">
<div className="p-6 h-full flex flex-col">
<div className="flex justify-between items-start">
<h3 className="text-lg font-bold text-gray-900 truncate">{vuln.title}</h3>
<span className={`ml-2 px-2 py-1 text-xs font-semibold rounded-full ${
vuln.severity === 'Critical' ? 'bg-red-100 text-red-800' :
vuln.severity === 'High' ? 'bg-orange-100 text-orange-800' :
vuln.severity === 'Medium' ? 'bg-yellow-100 text-yellow-800' :
'bg-green-100 text-green-800'
}`}>
{vuln.severity}
</span>
</div>
<p className="mt-3 text-gray-600 text-sm flex-grow">
{vuln.description.substring(0, 120)}...
</p>
<div className="mt-4 flex flex-wrap gap-2">
{vuln.tags && vuln.tags.slice(0, 3).map((tag, index) => (
<span key={index} className="px-2 py-1 bg-indigo-100 text-indigo-800 text-xs font-medium rounded-full">
{tag}
</span>
))}
{vuln.tags && vuln.tags.length > 3 && (
<span className="px-2 py-1 bg-gray-100 text-gray-800 text-xs font-medium rounded-full">
+{vuln.tags.length - 3}
</span>
)}
</div>
<div className="mt-4 flex items-center justify-between text-sm">
<div className="flex items-center">
<svg className="h-4 w-4 text-gray-500 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
</svg>
<span className="text-gray-500">CVE: {vuln.cve || 'N/A'}</span>
<div className="overflow-hidden bg-white shadow sm:rounded-md">
<ul className="divide-y divide-gray-200">
{vulnerabilities.map((vuln) => (
<li key={vuln.id}>
<Link to={`/vulns/${vuln.id}`} className="block hover:bg-gray-50">
<div className="px-4 py-4 sm:px-6">
<div className="flex items-center justify-between">
<p className="text-sm font-medium text-indigo-600 truncate">{vuln.title}</p>
<div className="flex flex-shrink-0 ml-2">
<span className={`px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${
vuln.severity === 'Critical' ? 'bg-red-100 text-red-800' :
vuln.severity === 'High' ? 'bg-orange-100 text-orange-800' :
vuln.severity === 'Medium' ? 'bg-yellow-100 text-yellow-800' :
'bg-green-100 text-green-800'
}`}>
{vuln.severity}
</span>
</div>
</div>
<div className="flex items-center">
<svg className="h-4 w-4 text-gray-500 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span className="text-gray-500">
{vuln.pushed ? '已推送' : '未推送'}
</span>
<div className="mt-2 sm:flex sm:justify-between">
<div className="sm:flex">
<p className="flex items-center text-sm text-gray-500">
CVE: {vuln.cve || 'N/A'}
</p>
<div className="flex flex-wrap gap-2 mt-2 sm:mt-0 sm:ml-6">
{vuln.tags && vuln.tags.slice(0, 5).map((tag, index) => (
<span key={index} className="px-2 py-1 text-xs font-medium text-indigo-800 bg-indigo-100 rounded-full">
{tag}
</span>
))}
{vuln.tags && vuln.tags.length > 5 && (
<span className="px-2 py-1 text-xs font-medium text-gray-800 bg-gray-100 rounded-full">
+{vuln.tags.length - 5}
</span>
)}
</div>
</div>
<div className="flex items-center mt-2 text-sm text-gray-500 sm:mt-0">
<svg className="flex-shrink-0 mr-1.5 h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z" clipRule="evenodd" />
</svg>
<p>
更新时间: <time dateTime={vuln.updated_at}>{new Date(vuln.updated_at).toLocaleDateString('zh-CN')}</time>
</p>
<span className={`ml-4 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${
vuln.pushed ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'
}`}>
{vuln.pushed ? '已推送' : '未推送'}
</span>
</div>
</div>
<div className="mt-2">
<p className="text-sm text-gray-500 line-clamp-2">
{vuln.description}
</p>
</div>
</div>
<div className="mt-3 text-xs text-gray-400">
更新时间: {new Date(vuln.updated_at).toLocaleDateString('zh-CN')}
</div>
</div>
</Link>
</div>
))}
</Link>
</li>
))}
</ul>
</div>
{/* 分页组件 */}
<div className="mt-6 flex items-center justify-between">
<div className="flex items-center justify-between mt-6">
<div className="text-sm text-gray-700">
显示第 {(pageNo - 1) * pageSize + 1} {Math.min(pageNo * pageSize, totalCount)} 条记录
总共 {totalCount} 条记录

View File

@@ -7,5 +7,7 @@ export default {
theme: {
extend: {},
},
plugins: [],
plugins: [
require('@tailwindcss/line-clamp'),
],
}