package utils import ( "errors" "strings" "github.com/gin-gonic/gin" "github.com/go-playground/validator/v10" "psi/models/response" ) // HandleValidationError 处理验证错误并返回自定义JSON响应 // 将 validator 的验证错误转换为友好的中文提示 func HandleValidationError(c *gin.Context, err error) { if err == nil { return } // 如果是 validator.ValidationErrors 类型 var validationErrors validator.ValidationErrors if errors.As(err, &validationErrors) { // 提取所有验证错误信息 errorMessages := make([]string, 0, len(validationErrors)) for _, e := range validationErrors { errorMessages = append(errorMessages, formatValidationError(e)) } // 返回第一个错误信息(或者可以返回所有错误) msg := strings.Join(errorMessages, "; ") response.FailWithValidateMessage(msg, c) return } // 其他类型的错误,直接返回错误信息 response.FailWithValidateMessage("参数错误: "+err.Error(), c) } // formatValidationError 格式化单个验证错误为友好的中文提示 func formatValidationError(e validator.FieldError) string { field := e.Field() tag := e.Tag() param := e.Param() switch tag { case "required": return getFieldChineseName(field) + "不能为空" case "min": kind := e.Kind().String() if kind == "slice" || kind == "array" { return getFieldChineseName(field) + "至少需要" + param + "个元素" } return getFieldChineseName(field) + "最小值为" + param case "max": kind := e.Kind().String() if kind == "slice" || kind == "array" { return getFieldChineseName(field) + "最多只能有" + param + "个元素" } return getFieldChineseName(field) + "最大值为" + param case "email": return getFieldChineseName(field) + "邮箱格式不正确" case "url": return getFieldChineseName(field) + "URL格式不正确" case "numeric": return getFieldChineseName(field) + "必须是数字" case "alpha": return getFieldChineseName(field) + "只能是字母" case "alphanum": return getFieldChineseName(field) + "只能是字母和数字" case "oneof": return getFieldChineseName(field) + "必须是以下值之一: " + param case "gt": return getFieldChineseName(field) + "必须大于" + param case "gte": return getFieldChineseName(field) + "必须大于等于" + param case "lt": return getFieldChineseName(field) + "必须小于" + param case "lte": return getFieldChineseName(field) + "必须小于等于" + param case "len": kind := e.Kind().String() if kind == "slice" || kind == "array" { return getFieldChineseName(field) + "必须有" + param + "个元素" } return getFieldChineseName(field) + "长度必须为" + param case "ne": return getFieldChineseName(field) + "不能等于" + param case "eq": return getFieldChineseName(field) + "必须等于" + param case "contains": return getFieldChineseName(field) + "必须包含" + param case "excludes": return getFieldChineseName(field) + "不能包含" + param case "startswith": return getFieldChineseName(field) + "必须以" + param + "开头" case "endswith": return getFieldChineseName(field) + "必须以" + param + "结尾" default: return getFieldChineseName(field) + "验证失败" } } // getFieldChineseName 获取字段的中文名称映射 func getFieldChineseName(field string) string { fieldMap := map[string]string{ //Barcode 相关 "Content": "条形码内容", // Book 相关 "Isbn": "ISBN", "BookName": "书名", "Author": "作者", "Publisher": "出版社", "PublicationTime": "出版时间", "BindingLayout": "装帧方式", "FixPrice": "定价", // Car 相关 "Appearance": "品相", "PushType": "推送类型", // Employee 相关 "Username": "账号", "Password": "密码", "EmpId": "员工ID", "Level": "等级", "PayTime": "支付时间", "OperationType": "操作类型", "ExpireTime": "过期时间", // Inventory 相关 "ProductID": "商品ID", "StockCheckID": "盘库ID", // Location 相关 "WarehouseID": "仓库ID", "Code": "编码", "Type": "类型", "Capacity": "容量", "Status": "状态", // Process 相关 "CarID": "小车ID", "CarCode": "小车编号", "Quantity": "数量", "UnitPrice": "单价", "WaveID": "波次ID", "RelatedOrderID": "关联订单ID", "WaveNo": "波次号", "Operator": "操作人", "OperatorID": "操作人ID", "ReceivingOrderID": "入库单ID", "WaveTaskID": "波次任务ID", "AssociationOrderID": "关联平台订单ID", "AssociationOrderNo": "关联平台订单号", "OutboundOrderID": "出库单ID", "ShippingOrderID": "发货单ID", "SalesOrderItemID": "销售单明细ID", "LogisticsCompany": "物流公司", "LogisticsNo": "物流运单号", "OrderID": "订单ID", "LocationID": "货位ID", "AdjustType": "调整类型", "SalesOrderID": "销售订单ID", // Product 相关 "CategoryID": "分类ID", "ProductName": "商品名称", "Barcode": "条形码", "Price": "单价", "UserID": "用户ID", "SalePrice": "售价", "OutTaskID": "外部任务ID", // Warehouse 相关 "Name": "名称", "ContactPerson": "联系人", "ContactPhone": "联系电话", "Province": "省份", "City": "城市", "District": "区县", "Address": "详细地址", // 通用字段 "Page": "页码", "PageSize": "每页数量", "Keyword": "关键词", "ID": "ID", } if chineseName, ok := fieldMap[field]; ok { return chineseName } // 如果没有映射,返回原字段名 return field }