import { useState } from 'react' import { useQuery, useQueryClient } from '@tanstack/react-query' import { Alert, App, Button, Form, Input, InputNumber, Modal, Switch, Tag, Typography } from 'antd' import { PlusOutlined, ReloadOutlined } from '@ant-design/icons' import { createPushChannel, fetchPushChannels, fetchPushRules, testPushChannel, updatePushChannel, updatePushRule, } from '@/features/admin/api' import { AdminPageHeader } from '@/features/admin/components/AdminPageHeader' import { DataTable } from '@/features/admin/components/DataTable' import type { AdminPushChannel, AdminPushRule } from '@/features/admin/types' import { useAdminSessionStore } from '@/stores/adminSession' import { formatDateTime, formatText } from '@/shared/utils/format' function errorText(error: unknown) { const response = (error as { response?: { data?: { message?: string } } })?.response return response?.data?.message || (error instanceof Error ? error.message : '请求失败') } export function AdminPushPage() { const { message } = App.useApp() const queryClient = useQueryClient() const [form] = Form.useForm<{ name: string; type: string; config: string }>() const [ruleForm] = Form.useForm<{ threshold: number; message_template: string }>() const [open, setOpen] = useState(false) const [ruleTarget, setRuleTarget] = useState() const [submitting, setSubmitting] = useState(false) const permissions = useAdminSessionStore(state => state.admin?.permissions) const canView = Boolean(permissions?.includes('*') || permissions?.includes('system_config:view')) const canManage = Boolean(permissions?.includes('*') || permissions?.includes('system_config:update')) const channelsQuery = useQuery({ queryKey: ['admin-push-channels'], queryFn: fetchPushChannels, enabled: canView, }) const rulesQuery = useQuery({ queryKey: ['admin-push-rules'], queryFn: fetchPushRules, enabled: canView, }) const invalidate = () => Promise.all([ queryClient.invalidateQueries({ queryKey: ['admin-push-channels'] }), queryClient.invalidateQueries({ queryKey: ['admin-push-rules'] }), ]) const channels = Array.isArray(channelsQuery.data) ? channelsQuery.data : [] const rules = Array.isArray(rulesQuery.data) ? rulesQuery.data : [] const create = async () => { const values = await form.validateFields() let config: Record try { config = JSON.parse(values.config || '{}') } catch { message.error('配置必须是合法 JSON') return } setSubmitting(true) try { await createPushChannel({ name: values.name.trim(), type: values.type.trim(), config }) message.success('推送渠道已创建') setOpen(false) await invalidate() } catch (error) { message.error(errorText(error)) } finally { setSubmitting(false) } } if (!canView) { return (
) } return (
渠道 {channels.length} · 规则 {rules.length} } extra={ } />
推送渠道
columns={[ { title: '名称 / 类型', key: 'name', width: 240, render: (_, row) => (
{row.name} {row.type}
), }, { title: '配置', key: 'config', render: (_, row) => ( {JSON.stringify(row.config ?? {})} ), }, { title: '状态', key: 'enabled', width: 110, render: (_, row) => ( { try { await updatePushChannel(row.id, { enabled: checked }) message.success(checked ? '已启用' : '已停用') await invalidate() } catch (error) { message.error(errorText(error)) } }} /> ), }, { title: '更新时间', dataIndex: 'updated_at', width: 170, render: value => formatDateTime(value), }, { title: '操作', key: 'actions', width: 200, render: (_, row) => ( ), }, ]} dataSource={channels} rowKey="id" loading={channelsQuery.isFetching} extra={ } emptyDescription="还没有推送渠道" />
通知规则
columns={[ { title: '事件', dataIndex: 'event', width: 240, render: value => {formatText(value)}, }, { title: '消息模板', dataIndex: 'message_template', render: value => formatText(value), }, { title: '阈值', dataIndex: 'threshold', width: 100, align: 'right', }, { title: '状态', key: 'enabled', width: 110, render: (_, row) => ( { try { await updatePushRule(row.id, { enabled: checked }) await invalidate() } catch (error) { message.error(errorText(error)) } }} /> ), }, { title: '操作', key: 'actions', width: 100, render: (_, row) => ( ), }, ]} dataSource={rules} rowKey="id" loading={rulesQuery.isFetching} emptyDescription="还没有通知规则" /> void create()} onCancel={() => setOpen(false)} >
setRuleTarget(undefined)} onOk={async () => { if (!ruleTarget) return const values = await ruleForm.validateFields() try { await updatePushRule(ruleTarget.id, { threshold: values.threshold, message_template: values.message_template, }) message.success('规则已更新') setRuleTarget(undefined) await invalidate() } catch (error) { message.error(errorText(error)) } }} >
) }