Commit 99687a26 authored by 375242562@qq.com's avatar 375242562@qq.com

fix: 批量日志补全操作列 — 新增停止按钮

- 表头补全"操作"列(此前数据行有对应单元格但表头缺失导致列不显示)
- 运行中/待启动的任务显示停止按钮(StopCircleIcon),点击后调用
  cancelJob 并刷新日志列表,停止中显示 CircularProgress
- 同步更新当前追踪的 batchJob 状态
- colSpan 更新为 9(含新操作列)
Co-Authored-By: default avatarClaude Sonnet 4.6 <noreply@anthropic.com>
parent e4f59292
...@@ -2,7 +2,7 @@ import { useState, useEffect, useCallback } from 'react' ...@@ -2,7 +2,7 @@ import { useState, useEffect, useCallback } from 'react'
import { import {
Box, Typography, Card, CardContent, CardHeader, Grid, Box, Typography, Card, CardContent, CardHeader, Grid,
FormControl, InputLabel, Select, MenuItem, Stack, FormControl, InputLabel, Select, MenuItem, Stack,
Tabs, Tab, Alert, Divider, LinearProgress, Chip, Button, Tabs, Tab, Alert, Divider, LinearProgress, Chip, Button, CircularProgress,
Table, TableBody, TableCell, TableHead, TableRow, Table, TableBody, TableCell, TableHead, TableRow,
Collapse, IconButton, Tooltip, TablePagination, Collapse, IconButton, Tooltip, TablePagination,
} from '@mui/material' } from '@mui/material'
...@@ -14,6 +14,7 @@ import { PermissionButton } from '../components/auth/PermissionButton' ...@@ -14,6 +14,7 @@ import { PermissionButton } from '../components/auth/PermissionButton'
import PsychologyIcon from '@mui/icons-material/Psychology' import PsychologyIcon from '@mui/icons-material/Psychology'
import BatchPredictionIcon from '@mui/icons-material/BatchPrediction' import BatchPredictionIcon from '@mui/icons-material/BatchPrediction'
import StopIcon from '@mui/icons-material/Stop' import StopIcon from '@mui/icons-material/Stop'
import StopCircleIcon from '@mui/icons-material/StopCircle'
import { MatchingStepper } from '../components/matching/MatchingStepper' import { MatchingStepper } from '../components/matching/MatchingStepper'
import { MatchingResultCard } from '../components/matching/MatchingResultCard' import { MatchingResultCard } from '../components/matching/MatchingResultCard'
import { ReasoningTimeline } from '../components/matching/ReasoningTimeline' import { ReasoningTimeline } from '../components/matching/ReasoningTimeline'
...@@ -74,6 +75,7 @@ export function MatchingPage() { ...@@ -74,6 +75,7 @@ export function MatchingPage() {
const [logTotal, setLogTotal] = useState(0) const [logTotal, setLogTotal] = useState(0)
const [logPage, setLogPage] = useState(0) const [logPage, setLogPage] = useState(0)
const [expandedErrorId, setExpandedErrorId] = useState<string | null>(null) const [expandedErrorId, setExpandedErrorId] = useState<string | null>(null)
const [cancellingJobId, setCancellingJobId] = useState<string | null>(null)
const loadJobHistory = useCallback(async (page = 0) => { const loadJobHistory = useCallback(async (page = 0) => {
// fetch PAGE_SIZE+1 to detect if a next page exists // fetch PAGE_SIZE+1 to detect if a next page exists
...@@ -163,6 +165,21 @@ export function MatchingPage() { ...@@ -163,6 +165,21 @@ export function MatchingPage() {
} }
} }
const handleCancelFromLog = async (job: BatchJob) => {
setCancellingJobId(job.id)
try {
const updated = await batchMatchingService.cancelJob(job.id)
// 如果是当前追踪的 job,同步状态
if (batchJob?.id === job.id) setBatchJob(updated)
loadJobHistory(logPage)
} catch (e: unknown) {
const msg = e instanceof Error ? e.message : '停止失败'
setBatchError(msg)
} finally {
setCancellingJobId(null)
}
}
const handleLogPageChange = (_: unknown, newPage: number) => { const handleLogPageChange = (_: unknown, newPage: number) => {
setLogPage(newPage) setLogPage(newPage)
loadJobHistory(newPage) loadJobHistory(newPage)
...@@ -322,6 +339,7 @@ export function MatchingPage() { ...@@ -322,6 +339,7 @@ export function MatchingPage() {
<TableCell>触发时间</TableCell> <TableCell>触发时间</TableCell>
<TableCell>完成时间</TableCell> <TableCell>完成时间</TableCell>
<TableCell>耗时</TableCell> <TableCell>耗时</TableCell>
<TableCell align="center">操作</TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
...@@ -387,10 +405,28 @@ export function MatchingPage() { ...@@ -387,10 +405,28 @@ export function MatchingPage() {
{formatDuration(job.created_at, job.completed_at)} {formatDuration(job.created_at, job.completed_at)}
</Typography> </Typography>
</TableCell> </TableCell>
<TableCell align="center">
{(job.status === 'running' || job.status === 'pending') && (
<Tooltip title={job.cancel_requested ? '停止中...' : '停止该任务'}>
<span>
<IconButton
size="small"
color="error"
disabled={!!job.cancel_requested || cancellingJobId === job.id}
onClick={() => handleCancelFromLog(job)}
>
{cancellingJobId === job.id
? <CircularProgress size={14} color="error" />
: <StopCircleIcon fontSize="small" />}
</IconButton>
</span>
</Tooltip>
)}
</TableCell>
</TableRow> </TableRow>
{hasError && ( {hasError && (
<TableRow key={`${job.id}-err`}> <TableRow key={`${job.id}-err`}>
<TableCell colSpan={8} sx={{ py: 0 }}> <TableCell colSpan={9} sx={{ py: 0 }}>
<Collapse in={isExpanded}> <Collapse in={isExpanded}>
<Box sx={{ p: 1.5, bgcolor: 'grey.50', borderRadius: 1, my: 0.5 }}> <Box sx={{ p: 1.5, bgcolor: 'grey.50', borderRadius: 1, my: 0.5 }}>
<Typography <Typography
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment