/** * AI 触发器设置页面。 * * 管理 biz.trigger_jobs 表中 job_type='ai_*' 的所有触发器,支持: * - 启用/禁用 * - 修改 cron 表达式(仅 cron 类型) * - 修改描述 * - 查看事件名、最近运行、下次运行、最后错误 */ import React, { useCallback, useEffect, useState } from "react"; import { Card, Table, Tag, Button, Space, Modal, Input, Switch, message, Typography, Tooltip, Descriptions, } from "antd"; import { ReloadOutlined, EditOutlined } from "@ant-design/icons"; import type { ColumnsType } from "antd/es/table"; import { listTriggers, updateTrigger, type TriggerItem, } from "../api/adminAI"; const { Title, Paragraph } = Typography; const STATUS_COLOR: Record = { enabled: "success", disabled: "default", }; const CONDITION_COLOR: Record = { event: "processing", cron: "warning", interval: "cyan", }; function fmtTime(raw: string | null): string { if (!raw) return "—"; const d = new Date(raw); return Number.isNaN(d.getTime()) ? raw : d.toLocaleString("zh-CN"); } function cronExpr(item: TriggerItem): string { const cfg = item.trigger_config || {}; return String(cfg.cron_expression || cfg.event_name || "—"); } const AITriggers: React.FC = () => { const [items, setItems] = useState([]); const [loading, setLoading] = useState(false); const [editing, setEditing] = useState(null); const [editCron, setEditCron] = useState(""); const [editDesc, setEditDesc] = useState(""); const [saving, setSaving] = useState(false); const load = useCallback(async () => { setLoading(true); try { const res = await listTriggers(); setItems(res); } catch { message.error("加载触发器列表失败"); } finally { setLoading(false); } }, []); useEffect(() => { load(); }, [load]); const handleToggle = async (item: TriggerItem, next: boolean) => { try { await updateTrigger(item.id, { status: next ? "enabled" : "disabled" }); message.success(next ? "已启用" : "已禁用"); load(); } catch { message.error("状态切换失败"); } }; const openEdit = (item: TriggerItem) => { setEditing(item); setEditCron(String(item.trigger_config?.cron_expression || "")); setEditDesc(item.description || ""); }; const handleSave = async () => { if (!editing) return; setSaving(true); try { const body: { cron_expression?: string; description?: string } = {}; if (editing.trigger_condition === "cron" && editCron !== editing.trigger_config?.cron_expression) { body.cron_expression = editCron; } if (editDesc !== (editing.description || "")) { body.description = editDesc; } if (Object.keys(body).length === 0) { message.info("无变更"); setEditing(null); return; } await updateTrigger(editing.id, body); message.success("已保存"); setEditing(null); load(); } catch (err) { const msg = (err as { response?: { data?: { detail?: string } } })?.response?.data?.detail; message.error(`保存失败${msg ? `:${msg}` : ""}`); } finally { setSaving(false); } }; const columns: ColumnsType = [ { title: "ID", dataIndex: "id", key: "id", width: 60 }, { title: "触发器名", dataIndex: "job_name", key: "job_name", width: 200, render: (v: string, r) => (
{v}
{r.description && (
{r.description}
)}
), }, { title: "类型", dataIndex: "trigger_condition", key: "trigger_condition", width: 80, render: (v: string) => {v}, }, { title: "表达式 / 事件", key: "expr", width: 240, render: (_: unknown, r) => ( {cronExpr(r)} ), }, { title: "状态", dataIndex: "status", key: "status", width: 100, render: (v: string, r) => ( handleToggle(r, c)} /> {v} ), }, { title: "最近运行", dataIndex: "last_run_at", key: "last_run_at", width: 160, render: fmtTime }, { title: "下次运行", dataIndex: "next_run_at", key: "next_run_at", width: 160, render: fmtTime }, { title: "最后错误", dataIndex: "last_error", key: "last_error", ellipsis: true, render: (v: string | null) => v ? ( {v.slice(0, 40)}… ) : "—", }, { title: "操作", key: "action", width: 100, fixed: "right", render: (_: unknown, r) => ( ), }, ]; return (
AI 触发器设置 管理 biz.trigger_jobs 中 AI 相关触发器,支持启停与 cron 修改。修改立即生效。
columns={columns} dataSource={items} rowKey="id" loading={loading} pagination={false} size="small" scroll={{ x: 1200 }} /> setEditing(null)} onOk={handleSave} confirmLoading={saving} okText="保存" cancelText="取消" width={600} > {editing && ( <> {editing.job_name} {editing.trigger_condition} {editing.trigger_condition === "event" && ( {String(editing.trigger_config?.event_name || "—")} )} {editing.trigger_condition === "cron" && (
Cron 表达式
setEditCron(e.target.value)} placeholder="标准 5 段 cron,例如 0 10 * * *" /> 格式:分 时 日 月 周。示例:0 10 * * *(每日 10:00)、*/30 * * * *(每 30 分钟)。
)}
描述
setEditDesc(e.target.value)} rows={3} />
)}
); }; export default AITriggers;