Haixun Patrol
+智慧巡檢 · 任務追蹤 · 即時協作
+巡樓
+{uid || member?.uid}
++ {uid || member?.uid} +
+{subtitle}
+ ) : null} +{message}
+} + +export function CopyableId({ label, value }: { label: string; value: string }) { + const copy = async () => { + if (!value) return + await navigator.clipboard.writeText(value) + } + return ( +{value || '—'}
+ {value ? (
+ {desc}
+ + 前往 → + + + ) +} + +export function StatCard({ + label, + value, + hint, + tone = 'default', +}: { + label: string + value: ReactNode + hint?: string + tone?: 'default' | 'brand' | 'sky' +}) { + const bg = tone === 'brand' ? 'bg-brand-soft' : tone === 'sky' ? 'bg-glow' : 'bg-surface' + return ( +{label}
+{hint}
: null} +{reply || '—'}
+ + Patrol Hub +
++ 任務、排程、AI 助手都在這裡。狀態一眼看懂,不用到處找。 +
+{error}
+ if (!job) return載入中…
+ + return ( +{job.progress.percentage}%
+{JSON.stringify(job, null, 2)}
+ 共 {pagination.total} 筆
: null} +| ID | +Cron | +Template | +Enabled | +操作 | +
|---|---|---|---|---|
| {s.id.slice(0, 8)}… | +{s.cron} | +{s.template_type} | +{s.enabled ? 'yes' : 'no'} | +
+ |
+
{error}
: null} +{t.type} · v{t.version}
+{t.description || '—'}
+
+ {JSON.stringify(t.steps, null, 2)}
+
+ 怎麼知道任務有沒有在跑?
+make run)只會建立預設模板{' '}
+ demo_long_task,不會自動產生執行紀錄。
+ JobWorker.Enabled)。
+ 共 {pagination.total} 筆
+ ) : null} +| ID | +Status | +Progress | +Template | +操作 | +
|---|---|---|---|---|
|
+ {j.id.slice(0, 8)}…
+
+ 查看任務詳情與事件
+
+ |
+ + + {jobStatusLabel(j.status)} + + / {j.phase} + | +
+ {j.progress.percentage}%
+ {j.progress.summary ? (
+ {j.progress.summary}
+ ) : null}
+ |
+ {j.template_type} | +
+ |
+
Email / 密碼驗證
+ ++ 還沒有帳號?{' '} + + 前往註冊 + +
+{error}
: null} +Roles: {roles.join(', ') || '—'}
+| Path | +Methods | +
|---|---|
| {path} | +{methods} | +
已儲存
: null} +建立巡樓管理帳號
+ ++ 已有帳號?{' '} + + 前往登入 + +
+{message}
: null} ++ 共 {pagination.total} 筆 · 第 {pagination.page}/{pagination.totalPages} 頁 +
+ ) : null} +| Key | +Version | +Value | +
|---|---|---|
| {s.key} | +{s.version} | +{JSON.stringify(s.value)} | +