mirror of
https://github.com/Buriburizaem0n/admin-frontend-domain.git
synced 2026-09-19 09:40:13 +00:00
feat: server transfer rotation
This commit is contained in:
@@ -36,7 +36,7 @@ import { ModelAlertRule } from "@/types"
|
||||
import { triggerModes } from "@/types"
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { useEffect, useState } from "react"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { useForm, useWatch } from "react-hook-form"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { toast } from "sonner"
|
||||
import { KeyedMutator } from "swr"
|
||||
@@ -50,13 +50,15 @@ interface AlertRuleCardProps {
|
||||
mutate: KeyedMutator<ModelAlertRule[]>
|
||||
}
|
||||
|
||||
const cycleUnitSchema = z.enum(["hour", "day", "week", "month", "year"])
|
||||
|
||||
const ruleSchema = z.object({
|
||||
type: z.string(),
|
||||
min: z.number().optional(),
|
||||
max: z.number().optional(),
|
||||
cycle_start: z.string().optional(),
|
||||
cycle_interval: z.number().optional(),
|
||||
cycle_unit: z.enum(["hour", "day", "week", "month", "year"]).optional(),
|
||||
cycle_unit: cycleUnitSchema.optional(),
|
||||
duration: z.number().optional(),
|
||||
cover: z.number().int().min(0),
|
||||
ignore: z.record(z.string(), z.boolean()).optional(),
|
||||
@@ -71,7 +73,7 @@ const alertRuleFormSchema = z.object({
|
||||
try {
|
||||
JSON.parse(val)
|
||||
return true
|
||||
} catch (e) {
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
},
|
||||
@@ -92,28 +94,30 @@ const alertRuleFormSchema = z.object({
|
||||
export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
type AlertRuleFormData = z.infer<typeof alertRuleFormSchema>
|
||||
type AlertRuleEntry = z.output<typeof ruleSchema>
|
||||
type AlertRuleFormInput = z.input<typeof alertRuleFormSchema>
|
||||
type AlertRuleFormData = z.output<typeof alertRuleFormSchema>
|
||||
|
||||
const form = useForm({
|
||||
resolver: zodResolver(alertRuleFormSchema) as any,
|
||||
const form = useForm<AlertRuleFormInput, unknown, AlertRuleFormData>({
|
||||
resolver: zodResolver(alertRuleFormSchema),
|
||||
defaultValues: data
|
||||
? {
|
||||
...data,
|
||||
rules_raw: JSON.stringify(data.rules),
|
||||
fail_trigger_tasks_raw: conv.arrToStr(data.fail_trigger_tasks),
|
||||
recover_trigger_tasks_raw: conv.arrToStr(data.recover_trigger_tasks),
|
||||
}
|
||||
...data,
|
||||
rules_raw: JSON.stringify(data.rules),
|
||||
fail_trigger_tasks_raw: conv.arrToStr(data.fail_trigger_tasks),
|
||||
recover_trigger_tasks_raw: conv.arrToStr(data.recover_trigger_tasks),
|
||||
}
|
||||
: {
|
||||
name: "",
|
||||
rules_raw: "",
|
||||
rules: [],
|
||||
fail_trigger_tasks: [],
|
||||
fail_trigger_tasks_raw: "",
|
||||
recover_trigger_tasks: [],
|
||||
recover_trigger_tasks_raw: "",
|
||||
notification_group_id: 0,
|
||||
trigger_mode: 0,
|
||||
},
|
||||
name: "",
|
||||
rules_raw: "",
|
||||
rules: [],
|
||||
fail_trigger_tasks: [],
|
||||
fail_trigger_tasks_raw: "",
|
||||
recover_trigger_tasks: [],
|
||||
recover_trigger_tasks_raw: "",
|
||||
notification_group_id: 0,
|
||||
trigger_mode: 0,
|
||||
},
|
||||
resetOptions: {
|
||||
keepDefaultValues: false,
|
||||
},
|
||||
@@ -124,14 +128,16 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
|
||||
// 结构化规则编辑状态:从已有数据或 rules_raw 初始化
|
||||
const initialRules = (() => {
|
||||
try {
|
||||
if (data?.rules) return data.rules as any[]
|
||||
if (data?.rules) return data.rules
|
||||
const raw = form.getValues("rules_raw")
|
||||
return raw ? JSON.parse(raw) : []
|
||||
if (!raw) return []
|
||||
const parsed: unknown = JSON.parse(raw)
|
||||
return z.array(ruleSchema).parse(parsed)
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
})()
|
||||
const [rulesUI, setRulesUI] = useState<any[]>(initialRules)
|
||||
const [rulesUI, setRulesUI] = useState<AlertRuleEntry[]>(initialRules)
|
||||
|
||||
// 同步到 rules_raw(提交仍走 JSON 字符串)
|
||||
useEffect(() => {
|
||||
@@ -140,17 +146,22 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}, [rulesUI])
|
||||
}, [form, rulesUI])
|
||||
|
||||
const rulesRaw = useWatch({ control: form.control, name: "rules_raw" })
|
||||
|
||||
const onSubmit = async (values: AlertRuleFormData) => {
|
||||
values.rules = JSON.parse(values.rules_raw)
|
||||
values.rules = z.array(ruleSchema).parse(JSON.parse(values.rules_raw))
|
||||
values.fail_trigger_tasks = conv.strToArr(values.fail_trigger_tasks_raw).map(Number)
|
||||
values.recover_trigger_tasks = conv.strToArr(values.recover_trigger_tasks_raw).map(Number)
|
||||
const { rules_raw, ...requiredFields } = values
|
||||
const requiredFields = { ...values }
|
||||
delete (requiredFields as Record<string, unknown>).rules_raw
|
||||
try {
|
||||
data?.id
|
||||
? await updateAlertRule(data.id, requiredFields)
|
||||
: await createAlertRule(requiredFields)
|
||||
if (data?.id) {
|
||||
await updateAlertRule(data.id, requiredFields)
|
||||
} else {
|
||||
await createAlertRule(requiredFields)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
toast(t("Error"), {
|
||||
@@ -185,7 +196,7 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
|
||||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmit as any)}
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className="space-y-2 my-2"
|
||||
>
|
||||
<FormField
|
||||
@@ -358,9 +369,9 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
|
||||
...next[idx],
|
||||
min: e.target.value
|
||||
? Number(
|
||||
e.target
|
||||
.value,
|
||||
)
|
||||
e.target
|
||||
.value,
|
||||
)
|
||||
: undefined,
|
||||
}
|
||||
setRulesUI(next)
|
||||
@@ -381,9 +392,9 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
|
||||
...next[idx],
|
||||
max: e.target.value
|
||||
? Number(
|
||||
e.target
|
||||
.value,
|
||||
)
|
||||
e.target
|
||||
.value,
|
||||
)
|
||||
: undefined,
|
||||
}
|
||||
setRulesUI(next)
|
||||
@@ -445,8 +456,8 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
|
||||
try {
|
||||
return r.ignore
|
||||
? JSON.stringify(
|
||||
r.ignore,
|
||||
)
|
||||
r.ignore,
|
||||
)
|
||||
: ""
|
||||
} catch {
|
||||
return ""
|
||||
@@ -457,8 +468,8 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
|
||||
try {
|
||||
const obj = e.target.value
|
||||
? JSON.parse(
|
||||
e.target.value,
|
||||
)
|
||||
e.target.value,
|
||||
)
|
||||
: undefined
|
||||
next[idx] = {
|
||||
...next[idx],
|
||||
@@ -512,9 +523,9 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
|
||||
cycle_interval: e.target
|
||||
.value
|
||||
? Number(
|
||||
e.target
|
||||
.value,
|
||||
)
|
||||
e.target
|
||||
.value,
|
||||
)
|
||||
: undefined,
|
||||
}
|
||||
setRulesUI(next)
|
||||
@@ -531,7 +542,10 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
|
||||
const next = [...rulesUI]
|
||||
next[idx] = {
|
||||
...next[idx],
|
||||
cycle_unit: val,
|
||||
cycle_unit:
|
||||
cycleUnitSchema.parse(
|
||||
val,
|
||||
),
|
||||
}
|
||||
setRulesUI(next)
|
||||
}}
|
||||
@@ -603,7 +617,7 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
|
||||
<FormControl>
|
||||
<Textarea
|
||||
className="resize-y"
|
||||
value={form.watch("rules_raw")}
|
||||
value={rulesRaw}
|
||||
onChange={(e) => {
|
||||
// 同步到结构化编辑器
|
||||
form.setValue("rules_raw", e.target.value, {
|
||||
@@ -630,7 +644,7 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
|
||||
placeholder={t("Search")}
|
||||
options={ngroupList}
|
||||
onValueChange={field.onChange}
|
||||
defaultValue={field.value.toString()}
|
||||
defaultValue={String(field.value ?? "")}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
|
||||
Reference in New Issue
Block a user