import { z } from "zod"; import { EMPLOYEE_STATUS } from "./employee.types"; // 查询参数里的空字符串统一当作“未传”,方便前端表单清空筛选条件。 const emptyStringToUndefined = (value: unknown) => { if (typeof value === "string" && value.trim() === "") { return undefined; } return value; }; const phoneSchema = z .string() .trim() // 这里先按中国大陆手机号做校验;如果你的店里有港澳台或海外员工,可以改成更宽松的规则。 .regex(/^1[3-9]\d{9}$/, "手机号格式不正确"); const roleIdsSchema = z .array(z.coerce.number().int().positive()) // 角色过多通常说明权限模型需要重新设计,这里先给出合理上限。 .max(20, "一个员工不建议绑定过多角色") .default([]); export const idParamSchema = z.object({ id: z.coerce.number().int().positive() }); export const listEmployeesQuerySchema = z.object({ // z.coerce 用于把 query string 转成数字,例如 ?page=1。 storeId: z.preprocess(emptyStringToUndefined, z.coerce.number().int().positive().optional()), status: z.preprocess(emptyStringToUndefined, z.enum(EMPLOYEE_STATUS).optional()), keyword: z.preprocess(emptyStringToUndefined, z.string().trim().min(1).max(100).optional()), page: z.coerce.number().int().min(1).default(1), pageSize: z.coerce.number().int().min(1).max(100).default(20) }); export const createEmployeeBodySchema = z.object({ storeId: z.coerce.number().int().positive(), name: z.string().trim().min(1).max(50), phone: phoneSchema, status: z.enum(EMPLOYEE_STATUS).default("ACTIVE"), remark: z.string().trim().max(500).nullable().optional(), roleIds: roleIdsSchema }); export const updateEmployeeBodySchema = z .object({ storeId: z.coerce.number().int().positive().optional(), name: z.string().trim().min(1).max(50).optional(), phone: phoneSchema.optional(), status: z.enum(EMPLOYEE_STATUS).optional(), remark: z.string().trim().max(500).nullable().optional(), roleIds: roleIdsSchema.optional() }) // PATCH 不允许提交空对象,否则调用方无法判断到底修改了什么。 .refine((value) => Object.keys(value).length > 0, { message: "至少需要提交一个要修改的字段" }); export const updateEmployeeStatusBodySchema = z.object({ status: z.enum(EMPLOYEE_STATUS) });