import { z } from 'zod' import { MenuIconKey, MenuType, MenuTypeSchema, StatusSchema, type MenuIconKeyValues } from '@/enum' const MenuIconKeySchema = z.custom( (value) => Object.values(MenuIconKey).includes(value as MenuIconKeyValues), { message: '请选择菜单图标', }, ) export const menuSchema = z.object({ id: z.number().int(), name: z.string(), path: z.string(), component: z.string(), hidden: z.boolean(), sort: z.number(), type: MenuTypeSchema, status: StatusSchema, permission_code: z.string(), parent_id: z.number().int().nullable(), icon: MenuIconKeySchema.nullable(), created_at: z.string(), updated_at: z.string(), }) export type Menu = z.infer export interface MenuTree extends Menu { children?: MenuTree[] } export const menuFormSchema = z .object({ id: z.number().optional(), name: z.string().min(1, '菜单名称不能为空').max(16, '菜单名称不能超过16个字符'), path: z.string().optional(), component: z.string().optional(), hidden: z.boolean(), // https://www.reddit.com/r/reactjs/comments/1mmfnyt/typescript_error_when_using_zcoercenumberstring/ sort: z.coerce.number().int().min(0, '排序值不能小于0'), type: MenuTypeSchema.refine((val) => val !== undefined, { message: '请选择菜单类型', }), status: StatusSchema.refine((val) => val !== undefined, { message: '请选择状态', }), permission_code: z.string().min(1, '权限编码不能为空'), parent_id: z.number().int().nullable().optional(), icon: MenuIconKeySchema.nullable(), }) .superRefine((data, ctx) => { if (data.type === MenuType.menu && !data.component) { ctx.addIssue({ code: 'custom', path: ['component'], message: '组件路径不能为空' }) } }) .transform((data) => { if (data.type !== MenuType.menu) { data.component = '' } return data }) export type MenuForm = z.infer