import { useState } from 'react' import { useNavigate, useParams } from 'react-router' import { useDataProvider, useList, useOne } from '@refinedev/core' import { Alert, Button, Card, CardContent, Checkbox, ConfirmDialog, DetailList, Field, Input, Modal, PageHeader, PageState, StatusPill, conflictMessage, } from './lib/ui.jsx' import { useTitle } from './lib/hooks.js' export function DraftPage() { const { id } = useParams() const navigate = useNavigate() const dataProvider = useDataProvider()('default') const [reviewed, setReviewed] = useState(false) const [confirmOpen, setConfirmOpen] = useState(false) const [busy, setBusy] = useState(false) const [notice, setNotice] = useState(null) const { result, error, isPending, query } = useOne({ resource: 'drafts', id, queryOptions: { retry: false } }) const draft = result const { result: bindingResult, query: browsersQuery } = useList({ resource: 'browsers', queryOptions: { retry: false } }) const browsers = bindingResult.data ?? [] const browsersError = browsersQuery.error const refetchBrowsers = browsersQuery.refetch useTitle('CreatorHub · 草稿核对') if (isPending) return if (error || !draft) return {error?.message || '草稿不存在'} const versions = draft.versions || [] const confirmations = draft.confirmations || [] const tasks = draft.tasks || [] const latestVersion = versions[0]?.version || draft.version const isLatest = draft.version === latestVersion const confirmation = confirmations.find(item => item.account_version === draft.account.version && item.draft_version === draft.version) const binding = browsersError ? undefined : browsers.find(item => item.account_id === draft.account_id) const readiness = draftReadiness(draft, binding, !!browsersError) const canConfirm = isLatest && !!binding && !browsersError const canEnqueue = !!confirmation && isLatest && readiness.ready async function confirmSnapshot() { setBusy(true) setNotice(null) try { await dataProvider.confirmDraft(draft.id, draft.account.version, draft.version) await query.refetch() setConfirmOpen(false) setNotice({ variant: 'success', text: '确认快照已保存,可回溯账号、草稿与当前固定资源版本。' }) } catch (reason) { setConfirmOpen(false) setNotice({ variant: 'destructive', text: conflictMessage(reason) }) await Promise.all([query.refetch(), refetchBrowsers()]) } finally { setBusy(false) } } async function enqueue() { if (!confirmation) return setBusy(true) setNotice(null) try { const task = await dataProvider.enqueueConfirmation(confirmation.id) await query.refetch() setNotice({ variant: 'success', text: `任务已排队:${task.id}。重复提交会返回同一任务。` }) } catch (reason) { setNotice({ variant: 'destructive', text: conflictMessage(reason) }) await Promise.all([query.refetch(), refetchBrowsers()]) } finally { setBusy(false) } } return (
{draft.account.platform_account_key} · 草稿版本 {draft.version}}> {notice ? {notice.text} : null} {browsersError ? 环境不可用:当前运行环境与网络出口状态未知,不能确认或排队。 : null} {!isLatest ? ( 当前只读快照已不是最新草稿版本,请刷新到版本 {latestVersion} 后重新核对。 ) : null}

只读内容快照

{draft.content}

版本与当前资源

版本链

{versions.map(item => item.id === draft.id ? (

版本 {item.version}(当前快照)

) : ( ))}

显式核对与入队

我已核对当前账号、草稿内容、运行环境和网络出口
{confirmation ? null :

保存有效确认后才可加入队列。

} {confirmation ? (

确认快照 v{confirmation.version}

账号版本 {confirmation.account_version} · 草稿版本 {confirmation.draft_version}

环境:{confirmation.browser_env_alias || '未记录'} · 出口:{confirmation.network_exit_id || '未记录'} · 绑定版本:{confirmation.binding_version || '未记录'}

) : null}

关联任务

{tasks.length === 0 ?

尚未入队。

: (
{tasks.map(task => (

{task.id}

任务状态:{task.state}

))}
)}
setConfirmOpen(false)} title="确认草稿版本" size="sm" labelledBy="confirm-draft-title" footer={<> }>

将保存账号版本 {draft.account.version}、草稿版本 {draft.version}、运行环境 {binding?.alias} 与网络出口 {binding?.network_exit_id || '当前机器直连'} 的只读确认快照。版本变化后必须重新确认。

) } // 与账号 readiness 同构的草稿侧判定:只依赖绑定健康与调度状态。 function draftReadiness(draft, binding, bindingsError = false) { if (draft.account.authorization_status !== 'authorized') return { label: '授权已撤销', ready: false } if (bindingsError) return { label: '环境状态未知', ready: false } if (!binding) return { label: '未绑定运行环境', ready: false } if (binding.network_exit_id && binding.network_exit_health !== 'healthy') return { label: '固定出口不健康', ready: false } const schedule = binding.schedule_block_reason || '' return { label: schedule ? `不可调度:${schedule}` : '可调度', ready: !schedule } }