2026-06-23 23:29:21 +08:00

219 lines
9.3 KiB
TypeScript

import { z } from "zod";
const commandBaseSchema = z.object({
commandId: z.string().trim().min(1, "请输入 Command ID").max(120, "Command ID 不能超过 120 个字符"),
reason: z.string().trim().max(200, "原因不能超过 200 个字符").optional().default(""),
});
const commandContactSchema = z.object({
commandId: z.string().trim().min(1, "请输入 Command ID").max(120, "Command ID 不能超过 120 个字符"),
contact: z.string().trim().max(128, "联系方式不能超过 128 个字符").optional().default(""),
reason: z.string().trim().max(200, "原因不能超过 200 个字符").optional().default(""),
});
const userIdSchema = z.preprocess(
(value) => {
if (value === null || value === undefined) {
return "";
}
return String(value).trim();
},
z
.string()
.min(1, "请输入有效用户短 ID")
.regex(/^[1-9]\d*$/, "请输入有效用户短 ID"),
);
const entityIdSchema = z.preprocess(
(value) => {
if (value === null || value === undefined) {
return "";
}
return String(value).trim();
},
z.string().min(1, "请输入有效用户 ID").regex(/^\d+$/, "请输入有效用户 ID"),
);
const optionalUserIdSchema = z.preprocess(
(value) => {
if (value === null || value === undefined) {
return "0";
}
if (typeof value === "string" && value.trim() === "") {
return "0";
}
return String(value).trim();
},
z.string().regex(/^(0|[1-9]\d*)$/, "请输入有效用户短 ID"),
);
const regionIdSchema = z.coerce.number().int().positive("请输入有效区域 ID");
const sortOrderSchema = z.coerce.number().int().min(0, "排序不能小于 0").default(0);
const optionalTextSchema = (max: number, message: string) => z.string().trim().max(max, message).optional().default("");
const codeSchema = (label: string) => z.string().trim().min(1, `请输入${label}`).max(40, `${label}不能超过 40 个字符`);
const countryCodesSchema = z.array(z.string()).transform((values, ctx) => {
const countries = values.map((item) => item.trim().toUpperCase()).filter(Boolean);
if (new Set(countries).size !== countries.length) {
ctx.addIssue({ code: "custom", message: "国家码不能重复" });
}
return countries;
});
const retiredRegionCodes = new Set([
"AUSTRALIA AND NEW ZEALAND",
"CARIBBEAN",
"MELANESIA",
"MICRONESIA",
"POLYNESIA",
"SOUTHERN AFRICA",
"UNSPECIFIED",
]);
const requiredCountryCodesSchema = countryCodesSchema.superRefine((countries, ctx) => {
if (!countries.length) {
ctx.addIssue({ code: "custom", message: "请选择国家码" });
}
});
const regionBaseSchema = z
.object({
countries: countryCodesSchema,
name: z.string().trim().min(1, "请输入区域名称").max(80, "区域名称不能超过 80 个字符"),
regionCode: codeSchema("区域编码").transform((value) => value.toUpperCase()),
sortOrder: sortOrderSchema,
})
.superRefine((value, ctx) => {
if (retiredRegionCodes.has(value.regionCode)) {
ctx.addIssue({ code: "custom", message: "该区域已移除", path: ["regionCode"] });
}
if (value.regionCode !== "GLOBAL" && !value.countries.length) {
ctx.addIssue({ code: "custom", message: "请选择国家码", path: ["countries"] });
}
if (value.regionCode === "GLOBAL" && value.countries.length) {
ctx.addIssue({ code: "custom", message: "GLOBAL 区域不需要选择国家", path: ["countries"] });
}
});
export const createBDLeaderSchema = commandContactSchema.extend({
positionAlias: optionalTextSchema(64, "职位别名不能超过 64 个字符"),
targetUserId: userIdSchema,
});
export const createBDSchema = commandBaseSchema.extend({
parentLeaderUserId: optionalUserIdSchema,
targetUserId: userIdSchema,
});
export const bdStatusSchema = commandBaseSchema.extend({
status: z.string().trim().min(1, "请输入状态").max(40, "状态不能超过 40 个字符"),
targetType: z.enum(["bd", "leader"]),
targetUserId: userIdSchema,
});
export const createCoinSellerSchema = commandContactSchema.extend({
targetUserId: userIdSchema,
});
export const createManagerSchema = z.object({
canAddAdmin: z.boolean().optional().default(true),
canAddBdLeader: z.boolean().optional().default(true),
canAddSuperadmin: z.boolean().optional().default(true),
canBlockUser: z.boolean().optional().default(true),
canGrantAvatarFrame: z.boolean().optional().default(true),
canGrantVehicle: z.boolean().optional().default(true),
canUpdateUserLevel: z.boolean().optional().default(true),
contact: z.string().trim().max(128, "联系方式不能超过 128 个字符").optional().default(""),
targetUserId: userIdSchema,
});
export const coinSellerStatusSchema = commandContactSchema.extend({
status: z.enum(["active", "disabled"]),
targetUserId: entityIdSchema,
});
export const coinSellerStockCreditSchema = z
.object({
coinAmount: z.coerce.number().int().positive("请输入充值金币"),
commandId: z.string().trim().min(1, "请输入 Command ID").max(120, "Command ID 不能超过 120 个字符"),
reason: z.string().trim().max(512, "原因不能超过 512 个字符").optional().default(""),
rechargeAmount: z.string().trim().max(32, "充值金额不能超过 32 个字符").optional().default(""),
type: z.enum(["usdt_purchase", "coin_compensation"]),
})
.superRefine((value, ctx) => {
if (value.type === "usdt_purchase") {
if (!/^(0|[1-9]\d*)(\.\d{1,6})?$/.test(value.rechargeAmount) || Number(value.rechargeAmount) <= 0) {
ctx.addIssue({ code: "custom", message: "请输入最多 6 位小数的 USDT 金额", path: ["rechargeAmount"] });
}
return;
}
if (value.rechargeAmount) {
ctx.addIssue({ code: "custom", message: "金币补偿不能提交充值金额", path: ["rechargeAmount"] });
}
});
export const coinSellerStockDebitSchema = z.object({
coinAmount: z.coerce.number().int().positive("请输入扣除金币"),
commandId: z.string().trim().min(1, "请输入 Command ID").max(120, "Command ID 不能超过 120 个字符"),
rechargeAmount: z
.string()
.trim()
.regex(/^(0|[1-9]\d*)(\.\d{1,6})?$/, "请输入最多 6 位小数的 USDT 数量")
.refine((value) => Number(value) > 0, "请输入扣除USDT数量"),
reason: z.string().trim().min(1, "请输入扣除原因").max(512, "原因不能超过 512 个字符"),
});
export const createAgencySchema = commandBaseSchema.extend({
joinEnabled: z.boolean().default(true),
name: z.string().trim().min(1, "请输入 Agency 名称").max(80, "Agency 名称不能超过 80 个字符"),
ownerUserId: userIdSchema,
parentBdUserId: optionalUserIdSchema,
});
export const agencyCloseSchema = commandBaseSchema.extend({
agencyId: entityIdSchema,
});
export const agencyJoinEnabledSchema = commandBaseSchema.extend({
agencyId: entityIdSchema,
joinEnabled: z.boolean().default(true),
});
export const countryCreateSchema = z.object({
countryCode: z
.string()
.trim()
.regex(/^[A-Za-z]{2,3}$/, "国家码必须是 2-3 位字母")
.transform((value) => value.toUpperCase()),
countryDisplayName: z.string().trim().min(1, "请输入展示名称").max(80, "展示名称不能超过 80 个字符"),
countryName: z.string().trim().min(1, "请输入国家名称").max(80, "国家名称不能超过 80 个字符"),
enabled: z.boolean().default(true),
flag: optionalTextSchema(16, "国旗不能超过 16 个字符"),
isoAlpha3: optionalTextSchema(8, "ISO Alpha-3 不能超过 8 个字符").transform((value) => value.toUpperCase()),
isoNumeric: optionalTextSchema(8, "ISO Numeric 不能超过 8 个字符"),
phoneCountryCode: optionalTextSchema(16, "电话区号不能超过 16 个字符"),
sortOrder: sortOrderSchema,
});
export const countryUpdateSchema = countryCreateSchema.omit({
countryCode: true,
enabled: true,
});
export const regionCreateSchema = regionBaseSchema;
export const regionUpdateSchema = regionBaseSchema;
export const regionCountriesSchema = z.object({
countries: requiredCountryCodesSchema,
});
export type CreateBDLeaderForm = z.infer<typeof createBDLeaderSchema>;
export type CreateBDForm = z.infer<typeof createBDSchema>;
export type BDStatusForm = z.infer<typeof bdStatusSchema>;
export type CreateCoinSellerForm = z.infer<typeof createCoinSellerSchema>;
export type CoinSellerStatusForm = z.infer<typeof coinSellerStatusSchema>;
export type CoinSellerStockCreditForm = z.infer<typeof coinSellerStockCreditSchema>;
export type CoinSellerStockDebitForm = z.infer<typeof coinSellerStockDebitSchema>;
export type CreateAgencyForm = z.infer<typeof createAgencySchema>;
export type AgencyCloseForm = z.infer<typeof agencyCloseSchema>;
export type AgencyJoinEnabledForm = z.infer<typeof agencyJoinEnabledSchema>;
export type CountryCreateForm = z.infer<typeof countryCreateSchema>;
export type CountryUpdateForm = z.infer<typeof countryUpdateSchema>;
export type RegionCreateForm = z.infer<typeof regionCreateSchema>;
export type RegionUpdateForm = z.infer<typeof regionUpdateSchema>;
export type RegionCountriesForm = z.infer<typeof regionCountriesSchema>;