refactor: use original dashboard UI primitives
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
import { useState } from 'react'
|
||||
import { Link, useNavigate, useParams } from '../../shared/router.jsx'
|
||||
import { useDataProvider, useList, useOne } from '../../shared/hooks/dataHooks.js'
|
||||
import {
|
||||
Alert, Button, Card, CardContent, DetailList, Field, PageHeader, PageState, Select, StatusPill,
|
||||
} from '../../shared/ui/ui.jsx'
|
||||
import { Alert } from '../../components/ui/alert'
|
||||
import { Button } from '../../components/ui/button'
|
||||
import { Card, CardContent } from '../../components/ui/card'
|
||||
import { Input } from '../../components/ui/input'
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../components/ui/select'
|
||||
import { DetailList, Field, PageHeader, PageState, StatusPill } from '../../shared/ui/ui.jsx'
|
||||
import { useTitle } from '../../shared/hooks/hooks.js'
|
||||
|
||||
const stateTone = { queued: 'neutral', executing: 'info', succeeded: 'success', failed: 'danger', needs_confirmation: 'warning', policy_hold: 'warning', cancelled: 'neutral' }
|
||||
@@ -34,10 +37,10 @@ function TaskCard({ task }) {
|
||||
<Link to={`/tasks/${task.id}`} className="anywhere font-semibold text-primary hover:underline">{task.id}</Link>
|
||||
<StatusPill tone={stateTone[task.state] || 'neutral'} label={stateLabel(task.state)} />
|
||||
</div>
|
||||
<div className="text-sm"><span className="text-muted">账号:</span><Link to={`/accounts/${task.account_id}`} className="anywhere text-primary hover:underline">{task.account_id}</Link></div>
|
||||
<div className="text-sm"><span className="text-muted">确认:</span><span className="anywhere">{task.confirmation_id || '未确认'}</span></div>
|
||||
<div className="anywhere text-xs text-muted">{holdLabel(task.hold_reason)}</div>
|
||||
<p className="text-xs text-muted">{new Date(task.updated_at || task.created_at).toLocaleString('zh-CN')}</p>
|
||||
<div className="text-sm"><span className="text-muted-foreground">账号:</span><Link to={`/accounts/${task.account_id}`} className="anywhere text-primary hover:underline">{task.account_id}</Link></div>
|
||||
<div className="text-sm"><span className="text-muted-foreground">确认:</span><span className="anywhere">{task.confirmation_id || '未确认'}</span></div>
|
||||
<div className="anywhere text-xs text-muted-foreground">{holdLabel(task.hold_reason)}</div>
|
||||
<p className="text-xs text-muted-foreground">{new Date(task.updated_at || task.created_at).toLocaleString('zh-CN')}</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
@@ -63,11 +66,20 @@ export function TaskList() {
|
||||
<PageHeader icon="ri-task-line" title="任务中心" description="逐条处理暂停、版本变化与未知执行结果;不会自动重试或更换出口" />
|
||||
<div className="mb-5 flex flex-col gap-3 sm:flex-row">
|
||||
<Field id="task-account-filter" label="按账号筛选" className="sm:w-72">
|
||||
<input id="task-account-filter" value={accountFilter} onChange={event => setAccountFilter(event.target.value)} placeholder="账号 ID" className="h-9 w-full rounded-md border border-[#c4ccd9] bg-white px-3 text-sm focus:border-primary focus:outline-none" />
|
||||
<Input id="task-account-filter" value={accountFilter} onChange={event => setAccountFilter(event.target.value)} placeholder="账号 ID" />
|
||||
</Field>
|
||||
<Field id="task-state-filter" label="按状态筛选" className="sm:w-56">
|
||||
<Select id="task-state-filter" value={stateFilter} onChange={event => setStateFilter(event.target.value)}
|
||||
options={Object.entries(stateText).map(([value, label]) => ({ value, label }))} placeholder="全部状态" emptyOption={{ value: '', label: '全部状态' }} />
|
||||
<Select value={stateFilter || "__all__"} onValueChange={value => setStateFilter(value === "__all__" ? "" : value)}>
|
||||
<SelectTrigger id="task-state-filter">
|
||||
<SelectValue placeholder="全部状态" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="__all__">全部状态</SelectItem>
|
||||
{Object.entries(stateText).map(([value, label]) => (
|
||||
<SelectItem key={value} value={value}>{label}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
</div>
|
||||
{error ? <Alert variant="destructive" className="mb-4">{error.message}</Alert> : null}
|
||||
@@ -114,10 +126,13 @@ export function TaskDetail() {
|
||||
return (
|
||||
<div>
|
||||
<PageHeader title="任务详情" description={<span className="anywhere">{task.id}</span>}>
|
||||
<Button icon="ri-arrow-left-line" onClick={() => navigate('/tasks')}>返回任务中心</Button>
|
||||
<Button onClick={() => navigate('/tasks')}>
|
||||
<i className="ri-arrow-left-line" aria-hidden="true" />
|
||||
返回任务中心
|
||||
</Button>
|
||||
</PageHeader>
|
||||
{notice ? <Alert variant={notice.variant} className="mb-4">{notice.text}</Alert> : null}
|
||||
{unknownHold ? <Alert variant="warning" className="mb-4">后端返回了未知停止原因“{task.hold_reason}”;为避免不安全操作,本页不提供恢复动作。</Alert> : null}
|
||||
{notice ? <Alert variant={notice.variant === "destructive" ? "destructive" : "default"} className="mb-4">{notice.text}</Alert> : null}
|
||||
{unknownHold ? <Alert variant="default" className="mb-4">后端返回了未知停止原因“{task.hold_reason}”;为避免不安全操作,本页不提供恢复动作。</Alert> : null}
|
||||
<div className="grid gap-4 lg:grid-cols-2">
|
||||
<Card>
|
||||
<CardContent className="space-y-3">
|
||||
@@ -128,7 +143,7 @@ export function TaskDetail() {
|
||||
['人工核验', task.verification_result || '尚未记录'],
|
||||
]} />
|
||||
<div>
|
||||
<Button size="sm" as={Link} to={`/audit?task_id=${encodeURIComponent(task.id)}`}>查看关联审计</Button>
|
||||
<Button size="sm" asChild><Link to={`/audit?task_id=${encodeURIComponent(task.id)}`}>查看关联审计</Link></Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -141,8 +156,8 @@ export function TaskDetail() {
|
||||
['环境与出口', <span className="anywhere">{confirmation.browser_env_alias || '未记录'} · {confirmation.network_exit_id || '未记录'} · 绑定版本:{confirmation.binding_version || '未记录'}</span>],
|
||||
]} />
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button size="sm" as={Link} to={`/accounts/${task.account_id}`}>查看账号</Button>
|
||||
<Button size="sm" as={Link} to={`/drafts/${task.draft_id}`}>查看草稿</Button>
|
||||
<Button size="sm" asChild><Link to={`/accounts/${task.account_id}`}>查看账号</Link></Button>
|
||||
<Button size="sm" asChild><Link to={`/drafts/${task.draft_id}`}>查看草稿</Link></Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -155,37 +170,40 @@ export function TaskDetail() {
|
||||
['运行实例 / 绑定版本', <span className="anywhere">{task.runtime_instance_id || '未记录'} · {task.binding_version || '未记录'}</span>],
|
||||
]} />
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{task.browser_env_alias ? <Button size="sm" as={Link} to={`/browsers/${encodeURIComponent(task.browser_env_alias)}`}>查看原环境</Button> : null}
|
||||
{task.network_exit_id ? <Button size="sm" as={Link} to={`/network-exits/${encodeURIComponent(task.network_exit_id)}`}>查看原出口</Button> : null}
|
||||
{task.browser_env_alias ? <Button size="sm" asChild><Link to={`/browsers/${encodeURIComponent(task.browser_env_alias)}`}>查看原环境</Link></Button> : null}
|
||||
{task.network_exit_id ? <Button size="sm" asChild><Link to={`/network-exits/${encodeURIComponent(task.network_exit_id)}`}>查看原出口</Link></Button> : null}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardContent className="space-y-3">
|
||||
<h2 className="text-base font-semibold">唯一安全动作</h2>
|
||||
{task.readiness_reason ? <Alert variant="warning">当前仍被阻断:{holdLabel(task.readiness_reason)}。修复原资源并刷新后,才会开放恢复。</Alert> : null}
|
||||
{task.readiness_reason ? <Alert variant="default">当前仍被阻断:{holdLabel(task.readiness_reason)}。修复原资源并刷新后,才会开放恢复。</Alert> : null}
|
||||
{task.allowed_action === 'verify' ? (
|
||||
<>
|
||||
<Alert variant="warning">先在原环境和原出口核验真实结果。选择“未执行”不会立即重试,仍需下一步显式恢复。</Alert>
|
||||
<Alert variant="default">先在原环境和原出口核验真实结果。选择“未执行”不会立即重试,仍需下一步显式恢复。</Alert>
|
||||
<Field id="task-verification" label="人工核验结论">
|
||||
<Select id="task-verification" value={verification} onChange={event => setVerification(event.target.value)} options={[
|
||||
{ value: 'not_executed', label: '确认未执行,可评估恢复' },
|
||||
{ value: 'succeeded', label: '确认已成功' },
|
||||
{ value: 'failed', label: '确认已失败' },
|
||||
]} />
|
||||
<Select value={verification} onValueChange={setVerification}>
|
||||
<SelectTrigger id="task-verification"><SelectValue /></SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="not_executed">确认未执行,可评估恢复</SelectItem>
|
||||
<SelectItem value="succeeded">确认已成功</SelectItem>
|
||||
<SelectItem value="failed">确认已失败</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<Button variant="primary" disabled={busy} onClick={() => runAction('verify', { result: verification })}>记录人工核验</Button>
|
||||
<Button variant="default" disabled={busy} onClick={() => runAction('verify', { result: verification })}>记录人工核验</Button>
|
||||
</>
|
||||
) : null}
|
||||
{task.allowed_action === 'resume' ? <Button variant="primary" disabled={busy} onClick={() => runAction('resume')}>按核验结论恢复排队</Button> : null}
|
||||
{task.allowed_action === 'finish' ? <Button variant="primary" disabled={busy} onClick={() => runAction('finish')}>按核验结论结束任务</Button> : null}
|
||||
{task.allowed_action === 'resume' ? <Button variant="default" disabled={busy} onClick={() => runAction('resume')}>按核验结论恢复排队</Button> : null}
|
||||
{task.allowed_action === 'finish' ? <Button variant="default" disabled={busy} onClick={() => runAction('finish')}>按核验结论结束任务</Button> : null}
|
||||
{task.allowed_action === 'reconfirm' ? (
|
||||
<>
|
||||
<Alert variant="warning">版本已变化,旧确认不可继续使用。</Alert>
|
||||
<Button variant="primary" as={Link} to={`/drafts/${task.draft_id}`}>重新核对并确认草稿</Button>
|
||||
<Alert variant="default">版本已变化,旧确认不可继续使用。</Alert>
|
||||
<Button variant="default" asChild><Link to={`/drafts/${task.draft_id}`}>重新核对并确认草稿</Link></Button>
|
||||
</>
|
||||
) : null}
|
||||
{task.allowed_action ? null : <p className="text-sm text-muted">当前没有可安全执行的动作。</p>}
|
||||
{task.allowed_action ? null : <p className="text-sm text-muted-foreground">当前没有可安全执行的动作。</p>}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
@@ -204,7 +222,7 @@ export function TaskDetail() {
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<Card><CardContent><p className="text-sm text-muted">尚未产生执行尝试。</p></CardContent></Card>
|
||||
<Card><CardContent><p className="text-sm text-muted-foreground">尚未产生执行尝试。</p></CardContent></Card>
|
||||
)}
|
||||
</section>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user