适配气站工作人员与用户受保护头像

This commit is contained in:
czl231
2026-08-18 20:28:01 +08:00
parent 084eccc3ec
commit fd2a2b38e3
11 changed files with 228 additions and 49 deletions

View File

@@ -7,6 +7,7 @@ import (
"git.apinb.com/bsm-sdk/core/infra"
"git.apinb.com/heqiapp/platforms/backend/api/internal/impl"
"git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common"
"git.apinb.com/heqiapp/platforms/backend/api/internal/logic/upload"
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
"github.com/gin-gonic/gin"
)
@@ -52,15 +53,31 @@ func GetStaff(ctx *gin.Context) {
Where("identity = ? AND gas_basic_id = ?", ctx.Param("identity"), station.ID), &models.StaffAccount{})
}
// GetStaffAvatar 返回当前气站范围内工作人员的受保护头像。
func GetStaffAvatar(ctx *gin.Context) {
station, ok := currentGas(ctx)
if !ok {
return
}
var account models.StaffAccount
if err := common.ActiveRecords(impl.DBService).Select("avatar").
Where("identity = ? AND gas_basic_id = ?", ctx.Param("identity"), station.ID).
First(&account).Error; err != nil {
common.RespondRecordError(ctx, err)
return
}
upload.ServeAvatar(ctx, account.Avatar)
}
type staffRequest struct {
Username string `json:"username"`
Password string `json:"password"`
Name string `json:"name" binding:"required,max=64"`
Phone string `json:"phone" binding:"max=32"`
Avatar string `json:"avatar" binding:"max=512"`
RoleCode string `json:"role_code" binding:"required"`
DeliveryBasicIdentity string `json:"delivery_basic_identity"`
WorkStatus string `json:"work_status" binding:"required"`
Username string `json:"username"`
Password string `json:"password"`
Name string `json:"name" binding:"required,max=64"`
Phone string `json:"phone" binding:"max=32"`
Avatar *string `json:"avatar" binding:"omitempty,max=512"`
RoleCode string `json:"role_code" binding:"required"`
DeliveryBasicIdentity string `json:"delivery_basic_identity"`
WorkStatus string `json:"work_status" binding:"required"`
}
func CreateStaff(ctx *gin.Context) {
@@ -87,9 +104,13 @@ func CreateStaff(ctx *gin.Context) {
infra.Response.Error(ctx, err)
return
}
avatar := ""
if request.Avatar != nil {
avatar = *request.Avatar
}
staff := models.StaffAccount{
Entity: common.NewEntity(common.StatusEnable), Username: request.Username, PasswordHash: hash,
Name: request.Name, Phone: request.Phone, Avatar: request.Avatar, RoleCode: request.RoleCode,
Name: request.Name, Phone: request.Phone, Avatar: avatar, RoleCode: request.RoleCode,
GasBasicID: station.ID, DeliveryBasicID: deliveryID, WorkStatus: request.WorkStatus,
}
if err := common.CreateStaffRecord(&staff); err != nil {
@@ -120,10 +141,15 @@ func UpdateStaff(ctx *gin.Context) {
}
deliveryID = delivery.ID
}
common.UpdateAllowedByIdentityWithError(ctx, &models.StaffAccount{}, gin.H{
"name": request.Name, "phone": request.Phone, "avatar": request.Avatar, "role_code": request.RoleCode,
values := gin.H{
"name": request.Name, "phone": request.Phone, "role_code": request.RoleCode,
"delivery_basic_id": deliveryID, "work_status": request.WorkStatus,
}, []string{"name", "phone", "avatar", "role_code", "delivery_basic_id", "work_status"}, common.StaffWriteError)
}
// 未选择新头像时不提交 avatar避免编辑基础资料误清空现有头像。
if request.Avatar != nil {
values["avatar"] = *request.Avatar
}
common.UpdateAllowedByIdentityWithError(ctx, &models.StaffAccount{}, values, []string{"name", "phone", "avatar", "role_code", "delivery_basic_id", "work_status"}, common.StaffWriteError)
}
func UpdateStaffStatus(ctx *gin.Context) {

View File

@@ -5,6 +5,7 @@ import (
"git.apinb.com/bsm-sdk/core/infra"
"git.apinb.com/heqiapp/platforms/backend/api/internal/impl"
"git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common"
"git.apinb.com/heqiapp/platforms/backend/api/internal/logic/upload"
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
@@ -57,14 +58,27 @@ func GetUser(ctx *gin.Context) {
infra.Response.Success(ctx, response)
}
// GetUserAvatar 返回与当前气站存在服务关系的用户受保护头像。
func GetUserAvatar(ctx *gin.Context) {
station, ok := currentGas(ctx)
if !ok {
return
}
user, _, ok := requireUser(ctx, ctx.Param("identity"), station.ID)
if !ok {
return
}
upload.ServeAvatar(ctx, user.Avatar)
}
type userRequest struct {
Username string `json:"username"`
Password string `json:"password"`
Name string `json:"name" binding:"required,max=64"`
Phone string `json:"phone" binding:"max=32"`
Avatar string `json:"avatar" binding:"max=512"`
RealName string `json:"real_name" binding:"max=64"`
DeliveryBasicIdentity string `json:"delivery_basic_identity" binding:"required"`
Username string `json:"username"`
Password string `json:"password"`
Name string `json:"name" binding:"required,max=64"`
Phone string `json:"phone" binding:"max=32"`
Avatar *string `json:"avatar" binding:"omitempty,max=512"`
RealName string `json:"real_name" binding:"max=64"`
DeliveryBasicIdentity string `json:"delivery_basic_identity" binding:"required"`
}
func CreateUser(ctx *gin.Context) {
@@ -86,9 +100,13 @@ func CreateUser(ctx *gin.Context) {
infra.Response.Error(ctx, err)
return
}
avatar := ""
if request.Avatar != nil {
avatar = *request.Avatar
}
user := models.UserAccount{
Entity: common.NewEntity(common.StatusEnable), Username: request.Username, PasswordHash: hash,
Name: request.Name, Phone: request.Phone, Avatar: request.Avatar, RealName: request.RealName,
Name: request.Name, Phone: request.Phone, Avatar: avatar, RealName: request.RealName,
}
relation := models.UserServiceRelation{Entity: common.NewEntity(common.StatusEnable), GasBasicID: station.ID, DeliveryBasicID: delivery.ID}
if err := impl.DBService.Transaction(func(tx *gorm.DB) error {
@@ -123,9 +141,14 @@ func UpdateUser(ctx *gin.Context) {
return
}
if err := impl.DBService.Transaction(func(tx *gorm.DB) error {
if err := tx.Model(&user).Updates(map[string]any{
"name": request.Name, "phone": request.Phone, "avatar": request.Avatar, "real_name": request.RealName,
}).Error; err != nil {
values := map[string]any{
"name": request.Name, "phone": request.Phone, "real_name": request.RealName,
}
// 未选择新头像时不提交 avatar避免编辑基础资料误清空现有头像。
if request.Avatar != nil {
values["avatar"] = *request.Avatar
}
if err := tx.Model(&user).Updates(values).Error; err != nil {
return err
}
return tx.Model(&relation).Update("delivery_basic_id", delivery.ID).Error

View File

@@ -30,6 +30,7 @@ func registerGasBusinessRoutes(group *gin.RouterGroup) {
staff.GET("", gaslogic.ListStaff)
staff.POST("", gaslogic.CreateStaff)
staff.GET("/:identity", gaslogic.GetStaff)
staff.GET("/:identity/avatar", gaslogic.GetStaffAvatar)
staff.PUT("/:identity", gaslogic.UpdateStaff)
staff.PUT("/:identity/password", gaslogic.ResetStaffPassword)
staff.PATCH("/:identity/status", gaslogic.UpdateStaffStatus)
@@ -47,6 +48,7 @@ func registerGasBusinessRoutes(group *gin.RouterGroup) {
user.GET("", gaslogic.ListUser)
user.POST("", gaslogic.CreateUser)
user.GET("/:identity", gaslogic.GetUser)
user.GET("/:identity/avatar", gaslogic.GetUserAvatar)
user.PUT("/:identity", gaslogic.UpdateUser)
user.PUT("/:identity/password", gaslogic.ResetUserPassword)
user.PATCH("/:identity/status", gaslogic.UpdateUserStatus)

View File

@@ -81,3 +81,22 @@ func TestGasReadonlyDetailRoutes(t *testing.T) {
}
}
}
// TestGasAvatarRoutes 验证工作人员与用户头像只能通过气站鉴权路由读取。
func TestGasAvatarRoutes(t *testing.T) {
gin.SetMode(gin.TestMode)
engine := gin.New()
RegisterGas("heqi", engine)
routes := map[string]bool{}
for _, route := range engine.Routes() {
routes[route.Method+" "+route.Path] = true
}
for _, path := range []string{
"GET /heqi/gas/v1/staff_account/:identity/avatar",
"GET /heqi/gas/v1/user_account/:identity/avatar",
} {
if !routes[path] {
t.Fatalf("missing gas avatar route %s", path)
}
}
}