// Package method 业务逻辑方法包,实现反馈相关的业务操作 package method import ( "strings" "bsm/full/module/base/feedback/internal/models" pb "bsm/full/module/base/feedback/pb" "git.apinb.com/bsm-sdk/core/crypto/token" "git.apinb.com/bsm-sdk/core/vars" ) // isAdmin 判断是否为管理端角色,沿用仓库内 <模块>_Admin 的角色命名约定 func isAdmin(auth *token.Claims) bool { role := strings.ToLower(auth.Role) return role == "admin" || strings.HasSuffix(role, "_admin") } // canAccess 判断调用方是否为记录归属人或管理端 func canAccess(auth *token.Claims, passportIdentity string) bool { if isAdmin(auth) { return true } return auth.Identity != "" && passportIdentity != "" && passportIdentity == auth.Identity } // maskEmail 邮箱脱敏,保留首字符与域名 func maskEmail(email string) string { at := strings.Index(email, "@") if at <= 0 { return "***" } return email[:1] + "***" + email[at:] } // maskPhone 手机号脱敏,保留前3位与后4位 func maskPhone(phone string) string { if len(phone) < 7 { return "***" } return phone[:3] + "****" + phone[len(phone)-4:] } // convert 将数据库模型转换为protobuf响应格式 // item: 数据库中的反馈记录模型 // maskPII: 是否对邮箱与手机号脱敏(非本人且非管理端时为 true) // 返回: protobuf格式的反馈记录指针 func convert(item models.FeedbackItem, maskPII bool) *pb.FeedbackItem { reply := &pb.FeedbackItem{ Identity: item.Identity, // 记录唯一标识 UserName: item.UserName, // 用户名 Email: item.Email, // 邮箱 Phone: item.Phone, // 手机号 Status: item.Status, // 状态 Title: item.Title, // 标题 Content: item.Content, // 内容 Remark: item.Remark, // 备注 Category: item.Category, // 分类 CreatedAt: item.CreatedAt.Format(vars.YYYY_MM_DD_HH_MM_SS), // 创建时间 UpdatedAt: item.UpdatedAt.Format(vars.YYYY_MM_DD_HH_MM_SS), // 更新时间 } // 非本人且非管理端时抹除联系方式的完整内容 if maskPII { reply.Email = maskEmail(item.Email) reply.Phone = maskPhone(item.Phone) } // 转换图片信息 for _, image := range item.Images { reply.Images = append(reply.Images, &pb.FeedbackImage{ Identity: image.Identity, // 图片唯一标识 ItemIdentity: image.ItemIdentity, // 关联的反馈记录ID Url: image.URL, // 图片URL }) } // 转换附件信息 for _, accessory := range item.Accessories { reply.Accessories = append(reply.Accessories, &pb.FeedbackAccessory{ Identity: accessory.Identity, // 附件唯一标识 ItemIdentity: accessory.ItemIdentity, // 关联的反馈记录ID Title: accessory.Title, // 附件标题 FilePath: accessory.FilePath, // 附件文件路径 }) } return reply }