修复个人中心问题

This commit is contained in:
2026-09-29 18:25:09 +08:00
parent 0dc5c2f075
commit ca4220f92c
44 changed files with 1793 additions and 310 deletions
+131 -7
View File
@@ -16,6 +16,7 @@ import (
"server/services"
"github.com/beego/beego/v2/client/orm"
"github.com/beego/beego/v2/core/logs"
beego "github.com/beego/beego/v2/server/web"
)
@@ -908,16 +909,139 @@ func (c *BackendFileController) BatchDeleteFilesPermanently() {
_ = c.ServeJSON()
}
// UploadAvatar POST /backend/uploadavatar(占位)
func (c *BackendFileController) UploadAvatar() {
c.Data["json"] = map[string]interface{}{"code": 501, "msg": "上传头像暂未实现"}
_ = c.ServeJSON()
// avatarUploadMaxMB 头像大小上限:头像场景 2MB 足够
const avatarUploadMaxMB = 2
const avatarUploadMaxBytes = avatarUploadMaxMB * 1024 * 1024
// avatarAllowedExts 头像允许的图片格式
var avatarAllowedExts = map[string]bool{
"jpg": true, "jpeg": true, "png": true, "gif": true, "webp": true, "bmp": true,
}
// UpdateAvatar POST /backend/uploadavatar/:id(占位)
// UploadAvatar POST /backend/uploadavatar
// 上传并设置「当前登录用户」头像:
// 复用文件存储链路(Stage → 查重 → Commit → 落文件表),
// 并把最终 URL 写入 yz_auth_identity.avatar 供认证中心 userinfo 下发。
func (c *BackendFileController) UploadAvatar() {
claims, err := c.backendClaims()
if err != nil {
c.jsonErr(401, 401, err.Error())
return
}
if err := c.Ctx.Request.ParseMultipartForm(avatarUploadMaxBytes); err != nil {
c.jsonErr(400, 400, "解析上传失败: "+err.Error())
return
}
fh, header, err := c.GetFile("file")
if err != nil || fh == nil {
c.jsonErr(400, 400, "请选择要上传的头像")
return
}
defer fh.Close()
if header != nil && header.Size > avatarUploadMaxBytes {
c.jsonErr(400, 400, fmt.Sprintf("头像大小不能超过%dMB", avatarUploadMaxMB))
return
}
ext := strings.ToLower(services.FileExt(header.Filename))
if !avatarAllowedExts[ext] {
c.jsonErr(400, 400, "头像仅支持 jpg / png / gif / webp 格式")
return
}
storageService, err := services.GetStorageService()
if err != nil {
c.jsonErr(500, 500, "获取存储服务失败: "+err.Error())
return
}
staged, err := storageService.Stage(fh, header)
if err != nil {
c.jsonErr(500, 500, "读取上传文件失败: "+err.Error())
return
}
committed := false
defer func() {
// 去重命中或出错时清理临时文件,避免产生垃圾
if !committed && staged != nil {
_ = storageService.Discard(staged)
}
}()
tid := c.effectiveTid(claims)
// 头像固定归入「我的个人文件」目录:既不会混进租户共享文件列表,
// 又能让本人在文件管理里找到自己上传过的头像。
tuid := uint64(claims.UserID)
upCtx := services.UploadContext{Source: services.SourceBackend, Tid: tid, Tuid: tuid}
// 同一张图重复上传:直接复用已有文件,不再占一份空间
if exist, e := services.FindDuplicate(services.SourceBackend, upCtx.Scope(), tid, tuid, staged.MD5); e == nil && exist != nil {
c.saveAvatarAndReply(claims.UserID, exist.Src, exist.Name)
return
}
result, err := storageService.Commit(staged, upCtx)
if err != nil {
c.jsonErr(500, 500, "上传头像失败: "+err.Error())
return
}
committed = true
// 文件台账落库失败不阻断头像设置(头像可用优先)
if _, e := services.CreateFileRecord(services.FileUploadParams{
Source: services.SourceBackend,
Scope: upCtx.Scope(),
Tid: tid,
Tuid: tuid,
Uid: uint64(claims.UserID),
Name: header.Filename,
Ext: ext,
Size: uint64(result.Size),
Src: result.URL,
ObjectKey: result.Key,
Storage: storageService.Type(),
MD5: result.MD5,
}); e != nil {
logs.Warn("[avatar] 头像文件落库失败: %v", e)
}
c.saveAvatarAndReply(claims.UserID, result.URL, header.Filename)
}
// saveAvatarAndReply 写入身份头像并返回结果
func (c *BackendFileController) saveAvatarAndReply(identityID int, url, name string) {
if err := services.UpdateIdentityAvatar(uint64(identityID), url); err != nil {
c.jsonErr(500, 500, "保存头像失败: "+err.Error())
return
}
c.jsonOK(map[string]interface{}{"url": url, "name": name})
}
// UpdateAvatar POST /backend/uploadavatar/:id
// 兼容旧调用:把指定文件的地址设为当前登录用户头像(不重新上传文件)。
func (c *BackendFileController) UpdateAvatar() {
c.Data["json"] = map[string]interface{}{"code": 501, "msg": "更新头像暂未实现"}
_ = c.ServeJSON()
claims, err := c.backendClaims()
if err != nil {
c.jsonErr(401, 401, err.Error())
return
}
idStr := c.Ctx.Input.Param(":id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil || id == 0 {
c.jsonErr(400, 400, "无效的文件ID")
return
}
var f models.SystemFile
if err := models.Orm.QueryTable(new(models.SystemFile)).
Filter("id", id).
Filter("tid", c.effectiveTid(claims)).
Filter("delete_time__isnull", true).
One(&f); err != nil {
c.jsonErr(404, 404, "文件不存在")
return
}
c.saveAvatarAndReply(claims.UserID, f.Src, f.Name)
}
// BatchMoveFiles POST /backend/batchMoveFiles