35 lines
1.4 KiB
TypeScript
35 lines
1.4 KiB
TypeScript
import { z } from "zod";
|
|
|
|
const numberInput = z.union([z.string(), z.number()]);
|
|
const optionalNumberInput = numberInput.optional();
|
|
const achievementTypeSchema = z.enum(["ordinary", "activity_limited"]);
|
|
|
|
export const achievementFormSchema = z
|
|
.object({
|
|
achievementType: achievementTypeSchema,
|
|
description: z.string().trim().max(240, "描述不能超过 240 个字符").optional(),
|
|
primaryBadgeResourceId: optionalNumberInput,
|
|
title: z.string().trim().min(1, "请输入成就名称").max(64, "成就名称不能超过 64 个字符"),
|
|
})
|
|
.superRefine((value, context) => {
|
|
validateRequiredId(context, "primaryBadgeResourceId", value.primaryBadgeResourceId, "请选择徽章资源");
|
|
});
|
|
|
|
export type AchievementForm = z.infer<typeof achievementFormSchema>;
|
|
|
|
function validatePositiveInteger(context: z.RefinementCtx, path: string, value: unknown, message: string) {
|
|
const numeric = Number(value);
|
|
if (!Number.isInteger(numeric) || numeric <= 0) {
|
|
context.addIssue({ code: "custom", message, path: path.split(".") });
|
|
}
|
|
}
|
|
|
|
function validateRequiredId(context: z.RefinementCtx, path: string, value: unknown, message: string) {
|
|
const raw = String(value ?? "").trim();
|
|
if (!raw) {
|
|
context.addIssue({ code: "custom", message, path: [path] });
|
|
return;
|
|
}
|
|
validatePositiveInteger(context, path, raw, message);
|
|
}
|