import { useState, useEffect } from 'react'; import { Table } from '@ctzhian/ui'; import { getSecurityScanningList } from '@/api/SecurityScanning'; import dayjs from 'dayjs'; import Card from '@/components/card'; import { Autocomplete, Box, Stack, TextField, Tooltip } from '@mui/material'; import { ColumnsType } from '@ctzhian/ui/dist/Table'; import { DomainSecurityScanningResult, DomainSecurityScanningRiskResult, DomainUser, } from '@/api/types'; import User from '@/components/user'; import TaskDetail from './taskDetail'; import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline'; import AutoModeIcon from '@mui/icons-material/AutoMode'; import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'; import { getUserSecurityScanningList } from '@/api'; const CodeScanTaskList = ({ admin, users, }: { admin: boolean; users: DomainUser[]; }) => { const [page, setPage] = useState(1); const [size, setSize] = useState(20); const [total, setTotal] = useState(0); const [loading, setLoading] = useState(false); const [dataSource, setDataSource] = useState( [] ); const [detail, setDetail] = useState< DomainSecurityScanningResult | undefined >(); const [filterUser, setFilterUser] = useState(''); const fetchData = async (params: { page?: number; size?: number; work_mode?: string; author?: string; }) => { setLoading(true); const res = await (admin ? getSecurityScanningList : getUserSecurityScanningList)({ page: params.page || page, size: params.size || size, author: params.author || filterUser, }); setLoading(false); setTotal(res.total_count || 0); setDataSource(res.items || []); }; useEffect(() => { setPage(1); fetchData({ page: 1, author: filterUser, }); }, [filterUser]); const columns: ColumnsType = [ { dataIndex: 'name', title: '扫描任务', width: 240, render: (project_name, record) => { return ( {record?.name} {record.status === 'pending' && ( 等待扫描 )} {record.status === 'running' && ( 正在扫描 )} {record.status === 'success' && ( 扫描完成 )} {record.status === 'failed' && ( 扫描失败 )} ); }, }, { title: '项目名称', dataIndex: 'project_name', render: (project_name, record) => { return ( {record?.project_name} {record?.path} ); }, }, { dataIndex: 'risk', title: '扫描结果', width: 260, render(risk: DomainSecurityScanningRiskResult, record) { const hasNoRisk = record.status !== 'pending' && (!risk.severe_count || risk.severe_count <= 0) && (!risk.critical_count || risk.critical_count <= 0) && (!risk.suggest_count || risk.suggest_count <= 0); const tip = []; if (risk.severe_count && risk.severe_count > 0) { tip.push(`严重安全告警 ${risk.severe_count} 个`); } if (risk.critical_count && risk.critical_count > 0) { tip.push(`高风险安全提醒 ${risk.critical_count} 个`); } if (risk.suggest_count && risk.suggest_count > 0) { tip.push(`低风险安全提醒 ${risk.suggest_count} 个`); } return ( { if (!hasNoRisk) { setDetail(record); } }} sx={{ color: '#fff', fontSize: '12px', width: '200px', height: '24px', lineHeight: '24px', background: record.status === 'pending' || record.status === 'running' ? 'repeating-linear-gradient(45deg, #f0f0f0, #f0f0f0 10px, #e0e0e0 10px, #e0e0e0 20px)' : '#F1F2F8', backgroundSize: '30px 30px', animation: 'stripes 1s linear infinite', borderRadius: '4px', overflow: 'hidden', transition: 'box-shadow 0.3s ease', userSelect: 'none', '&:hover': { cursor: 'pointer', boxShadow: hasNoRisk ? '' : '0 0px 8px #FFCF62', }, '@keyframes stripes': { '0%': { backgroundPosition: '0 0', }, '100%': { backgroundPosition: '30px 0', }, }, }} > {(record.status === 'success' || record.status === 'failed') && hasNoRisk ? ( // 如果没有风险,显示"无风险" 暂无风险 ) : ( // 否则,显示原有的风险条 <> {!!risk.severe_count && risk.severe_count > 0 && ( {risk.severe_count} )} {!!risk.critical_count && risk.critical_count > 0 && ( {risk.critical_count} )} {!!risk.suggest_count && risk.suggest_count > 0 && ( {risk.suggest_count} )} )} ); }, }, { dataIndex: 'user', title: '成员', width: 200, render(value: DomainUser) { return ( ); }, }, { title: '扫描时间', dataIndex: 'created_at', width: 160, render: (text) => { return ( {dayjs.unix(text).format('YYYY-MM-DD')} {dayjs.unix(text).format('HH:mm:ss')} ); }, }, ]; return ( {admin && ( option.username || ''} value={users?.find((item) => item.username === filterUser) || null} onChange={(_, newValue) => setFilterUser(newValue ? newValue.username! : '') } isOptionEqualToValue={(option, value) => option.username === value.username } renderInput={(params) => } clearOnEscape /> )} { setPage(page); setSize(size); fetchData({ page: page, size: size, }); }, }} /> setDetail(undefined)} task={detail} admin={admin} /> ); }; export default CodeScanTaskList;