🎨 重构用户端前端为vue开发,完善基础类和角色相关接口
This commit is contained in:
392
server/api/v1/app/character.go
Normal file
392
server/api/v1/app/character.go
Normal file
@@ -0,0 +1,392 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"git.echol.cn/loser/st/server/global"
|
||||
"git.echol.cn/loser/st/server/middleware"
|
||||
"git.echol.cn/loser/st/server/model/app/request"
|
||||
"git.echol.cn/loser/st/server/model/common/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
"io"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type CharacterApi struct{}
|
||||
|
||||
// GetPublicCharacterList 获取公开角色卡列表(无需鉴权)
|
||||
// @Summary 获取公开角色卡列表
|
||||
// @Tags 角色卡
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param page query int false "页码" default(1)
|
||||
// @Param pageSize query int false "每页数量" default(20)
|
||||
// @Param keyword query string false "关键词"
|
||||
// @Param sortBy query string false "排序方式: newest, popular, mostChats, mostLikes"
|
||||
// @Success 200 {object} response.Response{data=response.CharacterListResponse}
|
||||
// @Router /app/character/public [get]
|
||||
func (ca *CharacterApi) GetPublicCharacterList(c *gin.Context) {
|
||||
var req request.CharacterListRequest
|
||||
req.Page, _ = strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
req.PageSize, _ = strconv.Atoi(c.DefaultQuery("pageSize", "20"))
|
||||
req.Keyword = c.Query("keyword")
|
||||
req.SortBy = c.Query("sortBy")
|
||||
|
||||
if req.Page < 1 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.PageSize < 1 || req.PageSize > 100 {
|
||||
req.PageSize = 20
|
||||
}
|
||||
|
||||
// 尝试获取当前用户ID(如果已登录)
|
||||
userID := middleware.GetOptionalAppUserID(c)
|
||||
|
||||
list, err := characterService.GetPublicCharacterList(req, userID)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取公开角色卡列表失败", zap.Error(err))
|
||||
response.FailWithMessage("获取列表失败", c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithData(list, c)
|
||||
}
|
||||
|
||||
// GetMyCharacterList 获取我的角色卡列表
|
||||
// @Summary 获取我的角色卡列表
|
||||
// @Tags 角色卡
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param page query int false "页码" default(1)
|
||||
// @Param pageSize query int false "每页数量" default(20)
|
||||
// @Param keyword query string false "关键词"
|
||||
// @Param sortBy query string false "排序方式"
|
||||
// @Success 200 {object} response.Response{data=response.CharacterListResponse}
|
||||
// @Router /app/character/my [get]
|
||||
// @Security ApiKeyAuth
|
||||
func (ca *CharacterApi) GetMyCharacterList(c *gin.Context) {
|
||||
userID := middleware.GetAppUserID(c)
|
||||
|
||||
var req request.CharacterListRequest
|
||||
req.Page, _ = strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
req.PageSize, _ = strconv.Atoi(c.DefaultQuery("pageSize", "20"))
|
||||
req.Keyword = c.Query("keyword")
|
||||
req.SortBy = c.Query("sortBy")
|
||||
|
||||
if req.Page < 1 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.PageSize < 1 || req.PageSize > 100 {
|
||||
req.PageSize = 20
|
||||
}
|
||||
|
||||
list, err := characterService.GetMyCharacterList(req, userID)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取我的角色卡列表失败", zap.Error(err))
|
||||
response.FailWithMessage("获取列表失败", c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithData(list, c)
|
||||
}
|
||||
|
||||
// GetCharacterDetail 获取角色卡详情
|
||||
// @Summary 获取角色卡详情
|
||||
// @Tags 角色卡
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "角色卡ID"
|
||||
// @Success 200 {object} response.Response{data=response.CharacterResponse}
|
||||
// @Router /app/character/:id [get]
|
||||
func (ca *CharacterApi) GetCharacterDetail(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
response.FailWithMessage("无效的ID", c)
|
||||
return
|
||||
}
|
||||
|
||||
// 尝试获取当前用户ID(如果已登录)
|
||||
userID := middleware.GetOptionalAppUserID(c)
|
||||
|
||||
character, err := characterService.GetCharacterDetail(uint(id), userID)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取角色卡详情失败", zap.Error(err))
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithData(character, c)
|
||||
}
|
||||
|
||||
// CreateCharacter 创建角色卡
|
||||
// @Summary 创建角色卡
|
||||
// @Tags 角色卡
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body request.CreateCharacterRequest true "角色卡信息"
|
||||
// @Success 200 {object} response.Response{data=response.CharacterResponse}
|
||||
// @Router /app/character [post]
|
||||
// @Security ApiKeyAuth
|
||||
func (ca *CharacterApi) CreateCharacter(c *gin.Context) {
|
||||
userID := middleware.GetAppUserID(c)
|
||||
|
||||
var req request.CreateCharacterRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
character, err := characterService.CreateCharacter(req, userID)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("创建角色卡失败", zap.Error(err))
|
||||
response.FailWithMessage("创建失败", c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithData(character, c)
|
||||
}
|
||||
|
||||
// UpdateCharacter 更新角色卡
|
||||
// @Summary 更新角色卡
|
||||
// @Tags 角色卡
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body request.UpdateCharacterRequest true "角色卡信息"
|
||||
// @Success 200 {object} response.Response{data=response.CharacterResponse}
|
||||
// @Router /app/character [put]
|
||||
// @Security ApiKeyAuth
|
||||
func (ca *CharacterApi) UpdateCharacter(c *gin.Context) {
|
||||
userID := middleware.GetAppUserID(c)
|
||||
|
||||
var req request.UpdateCharacterRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
character, err := characterService.UpdateCharacter(req, userID)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("更新角色卡失败", zap.Error(err))
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithData(character, c)
|
||||
}
|
||||
|
||||
// DeleteCharacter 删除角色卡
|
||||
// @Summary 删除角色卡
|
||||
// @Tags 角色卡
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "角色卡ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /app/character/:id [delete]
|
||||
// @Security ApiKeyAuth
|
||||
func (ca *CharacterApi) DeleteCharacter(c *gin.Context) {
|
||||
userID := middleware.GetAppUserID(c)
|
||||
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
response.FailWithMessage("无效的ID", c)
|
||||
return
|
||||
}
|
||||
|
||||
err = characterService.DeleteCharacter(uint(id), userID)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("删除角色卡失败", zap.Error(err))
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithMessage("删除成功", c)
|
||||
}
|
||||
|
||||
// ToggleFavorite 切换收藏状态
|
||||
// @Summary 切换收藏状态
|
||||
// @Tags 角色卡
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body request.CharacterActionRequest true "角色卡ID"
|
||||
// @Success 200 {object} response.Response{data=map[string]bool}
|
||||
// @Router /app/character/favorite [post]
|
||||
// @Security ApiKeyAuth
|
||||
func (ca *CharacterApi) ToggleFavorite(c *gin.Context) {
|
||||
userID := middleware.GetAppUserID(c)
|
||||
|
||||
var req request.CharacterActionRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
isFavorited, err := characterService.ToggleFavorite(req.CharacterID, userID)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("切换收藏失败", zap.Error(err))
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithData(gin.H{"isFavorited": isFavorited}, c)
|
||||
}
|
||||
|
||||
// LikeCharacter 点赞角色卡
|
||||
// @Summary 点赞角色卡
|
||||
// @Tags 角色卡
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body request.CharacterActionRequest true "角色卡ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /app/character/like [post]
|
||||
func (ca *CharacterApi) LikeCharacter(c *gin.Context) {
|
||||
var req request.CharacterActionRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
err := characterService.LikeCharacter(req.CharacterID)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("点赞失败", zap.Error(err))
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
response.OkWithMessage("点赞成功", c)
|
||||
}
|
||||
|
||||
// ExportCharacter 导出角色卡为 JSON
|
||||
// @Summary 导出角色卡为 JSON
|
||||
// @Tags 角色卡
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "角色卡ID"
|
||||
// @Success 200 {object} map[string]interface{}
|
||||
// @Router /app/character/:id/export [get]
|
||||
func (ca *CharacterApi) ExportCharacter(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
response.FailWithMessage("无效的ID", c)
|
||||
return
|
||||
}
|
||||
|
||||
// 尝试获取当前用户ID(如果已登录)
|
||||
userID := middleware.GetOptionalAppUserID(c)
|
||||
|
||||
exportData, err := characterService.ExportCharacter(uint(id), userID)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("导出角色卡失败", zap.Error(err))
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
// 设置下载文件头
|
||||
c.Header("Content-Type", "application/json")
|
||||
c.Header("Content-Disposition", "attachment; filename=character.json")
|
||||
c.JSON(200, exportData)
|
||||
}
|
||||
|
||||
// ExportCharacterAsPNG 导出角色卡为 PNG
|
||||
// @Summary 导出角色卡为 PNG
|
||||
// @Tags 角色卡
|
||||
// @Accept json
|
||||
// @Produce octet-stream
|
||||
// @Param id path int true "角色卡ID"
|
||||
// @Success 200 {file} binary
|
||||
// @Router /app/character/:id/export/png [get]
|
||||
func (ca *CharacterApi) ExportCharacterAsPNG(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
response.FailWithMessage("无效的ID", c)
|
||||
return
|
||||
}
|
||||
|
||||
// 尝试获取当前用户ID(如果已登录)
|
||||
userID := middleware.GetOptionalAppUserID(c)
|
||||
|
||||
pngData, err := characterService.ExportCharacterAsPNG(uint(id), userID)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("导出 PNG 角色卡失败", zap.Error(err))
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
// 设置下载文件头
|
||||
c.Header("Content-Type", "image/png")
|
||||
c.Header("Content-Disposition", "attachment; filename=character.png")
|
||||
c.Data(200, "image/png", pngData)
|
||||
}
|
||||
|
||||
// ImportCharacter 导入角色卡
|
||||
// @Summary 导入角色卡(支持 PNG 和 JSON)
|
||||
// @Tags 角色卡
|
||||
// @Accept multipart/form-data
|
||||
// @Produce json
|
||||
// @Param file formData file true "角色卡文件(PNG 或 JSON)"
|
||||
// @Param isPublic formData bool false "是否公开"
|
||||
// @Success 200 {object} response.Response{data=response.CharacterResponse}
|
||||
// @Router /app/character/import [post]
|
||||
// @Security ApiKeyAuth
|
||||
func (ca *CharacterApi) ImportCharacter(c *gin.Context) {
|
||||
userID := middleware.GetAppUserID(c)
|
||||
|
||||
// 获取上传的文件
|
||||
file, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取上传文件失败", zap.Error(err))
|
||||
response.FailWithMessage("请上传文件", c)
|
||||
return
|
||||
}
|
||||
|
||||
// 检查文件大小(最大 10MB)
|
||||
maxSize := int64(10 * 1024 * 1024)
|
||||
if file.Size > maxSize {
|
||||
response.FailWithMessage("文件大小不能超过 10MB", c)
|
||||
return
|
||||
}
|
||||
|
||||
global.GVA_LOG.Info("接收到文件上传",
|
||||
zap.String("filename", file.Filename),
|
||||
zap.Int64("size", file.Size))
|
||||
|
||||
// 读取文件内容
|
||||
src, err := file.Open()
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("打开文件失败", zap.Error(err))
|
||||
response.FailWithMessage("读取文件失败", c)
|
||||
return
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
// 使用 io.ReadAll 读取完整文件内容
|
||||
fileData, err := io.ReadAll(src)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("读取文件内容失败", zap.Error(err))
|
||||
response.FailWithMessage("读取文件内容失败: "+err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
global.GVA_LOG.Info("文件读取成功", zap.Int("bytes", len(fileData)))
|
||||
|
||||
// 获取是否公开参数
|
||||
isPublic := c.DefaultPostForm("isPublic", "false") == "true"
|
||||
|
||||
// 导入角色卡
|
||||
character, err := characterService.ImportCharacter(fileData, file.Filename, userID, isPublic)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("导入角色卡失败",
|
||||
zap.Error(err),
|
||||
zap.String("filename", file.Filename))
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
global.GVA_LOG.Info("角色卡导入成功",
|
||||
zap.Uint("characterId", character.ID),
|
||||
zap.String("name", character.Name))
|
||||
|
||||
response.OkWithData(character, c)
|
||||
}
|
||||
Reference in New Issue
Block a user