🎨 新增批量上传文章功能

This commit is contained in:
2025-09-12 23:54:54 +08:00
parent 57289a24e7
commit f9b37fb1aa
5 changed files with 94 additions and 5 deletions

View File

@@ -8,6 +8,7 @@ import (
"git.echol.cn/loser/lckt/utils/user_jwt" "git.echol.cn/loser/lckt/utils/user_jwt"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"go.uber.org/zap" "go.uber.org/zap"
"strings"
) )
type ArticleApi struct{} type ArticleApi struct{}
@@ -90,6 +91,26 @@ func (ArticleApi) ById(ctx *gin.Context) {
r.OkWithData(article, ctx) r.OkWithData(article, ctx)
} }
// BulkUpload 批量上传文章
func (ArticleApi) BulkUpload(ctx *gin.Context) {
var p request.BulkUpload
if err := ctx.ShouldBind(&p); err != nil {
r.FailWithMessage(err.Error(), ctx)
global.GVA_LOG.Error("参数有误!", zap.Error(err))
return
}
err := articleService.BulkUpload(p)
if err != nil {
global.GVA_LOG.Error("批量上传失败!", zap.Error(err))
// 只要返回部分失败的文件列表 删除前面的"部分文件上传失败: "即可
r.FailWithDetailed(strings.TrimPrefix(err.Error(), "部分文件上传失败: "), "部分文件上传失败:"+strings.TrimPrefix(err.Error(), "部分文件上传失败: "), ctx)
return
}
r.OkWithMessage("批量上传成功", ctx)
}
// ===================================== APP 端接口 ============================
func (ArticleApi) APPGetList(ctx *gin.Context) { func (ArticleApi) APPGetList(ctx *gin.Context) {
var p request.GetList var p request.GetList
if err := ctx.ShouldBind(&p); err != nil { if err := ctx.ShouldBind(&p); err != nil {

View File

@@ -15,3 +15,15 @@ type GetList struct {
type DeleteIds struct { type DeleteIds struct {
Ids []int `json:"ids" form:"ids" binding:"required"` Ids []int `json:"ids" form:"ids" binding:"required"`
} }
type BulkUpload struct {
Files []string `json:"files" form:"files" binding:"required"`
Title string `json:"title" form:"title" binding:"required"`
Desc string `json:"desc" form:"desc" binding:"required"`
Price float64 `json:"price" form:"price" binding:"required"` // 价格,单位分
// 分类ID
CategoryId int `json:"categoryId" form:"categoryId" binding:"required"` // 分类ID
// 发布时间
PublishTime string `json:"publishTime" form:"publishTime"` // 发布时间
IsFree *int `json:"isFree" form:"isFree"` // 是否免费
}

View File

@@ -14,11 +14,12 @@ func (s *ArticleRouter) InitBotRouter(Router *gin.RouterGroup, PublicRouter *gin
articleRouterWithoutAuth := PublicRouter.Group("article") articleRouterWithoutAuth := PublicRouter.Group("article")
appRouter := AppRouter.Group("article") appRouter := AppRouter.Group("article")
{ {
articleRouter.POST("", artApi.Create) // 新建文章 articleRouter.POST("", artApi.Create) // 新建文章
articleRouter.DELETE("", artApi.Delete) // 批量删除文章 articleRouter.DELETE("", artApi.Delete) // 批量删除文章
articleRouter.PUT("", artApi.Update) // 更新文章 articleRouter.PUT("", artApi.Update) // 更新文章
articleRouter.GET("list", artApi.List) // 获取文章列表 articleRouter.GET("list", artApi.List) // 获取文章列表
articleRouter.GET("", artApi.ById) // 文章开放接口 articleRouter.GET("", artApi.ById) // 文章开放接口
articleRouter.POST("bulk", artApi.BulkUpload) // 批量新建文章
} }
{ {
articleRouterWithoutRecord.GET(":id", artApi.ById) // 根据ID获取文章 articleRouterWithoutRecord.GET(":id", artApi.ById) // 根据ID获取文章

View File

@@ -1,12 +1,15 @@
package article package article
import ( import (
"fmt"
"git.echol.cn/loser/lckt/global" "git.echol.cn/loser/lckt/global"
"git.echol.cn/loser/lckt/model/app" "git.echol.cn/loser/lckt/model/app"
"git.echol.cn/loser/lckt/model/article" "git.echol.cn/loser/lckt/model/article"
"git.echol.cn/loser/lckt/model/article/request" "git.echol.cn/loser/lckt/model/article/request"
"git.echol.cn/loser/lckt/model/article/vo" "git.echol.cn/loser/lckt/model/article/vo"
"git.echol.cn/loser/lckt/model/user"
"go.uber.org/zap" "go.uber.org/zap"
"strings"
) )
type ArticleService struct{} type ArticleService struct{}
@@ -200,3 +203,52 @@ func (s ArticleService) AppDelete(id string) error {
} }
return nil return nil
} }
func (s ArticleService) BulkUpload(p request.BulkUpload) (err error) {
var articles []article.Article
var failedFiles []string
for _, a := range p.Files {
teacher := user.User{}
if dbErr := global.GVA_DB.Model(&teacher).Where("nick_name = ?", getTeacherName(a)).First(&teacher).Error; dbErr != nil {
global.GVA_LOG.Error("获取讲师信息失败", zap.Error(dbErr))
failedFiles = append(failedFiles, a)
continue
}
content := "<p><img src=" + a + " alt=\"" + a + "\" data-href=\"\" style=\"width: 100%;height: auto;\"/></p>"
articles = append(articles, article.Article{
Title: p.Title,
Desc: p.Desc,
CategoryId: p.CategoryId,
TeacherId: int(teacher.ID),
TeacherName: teacher.NickName,
CoverImg: teacher.Avatar,
Content: content,
IsFree: p.IsFree,
Price: int64(p.Price),
})
}
if len(articles) > 0 {
if dbErr := global.GVA_DB.Create(&articles).Error; dbErr != nil {
global.GVA_LOG.Error("批量上传文章失败", zap.Error(dbErr))
return dbErr
}
}
if len(failedFiles) > 0 {
global.GVA_LOG.Error("部分文件上传失败", zap.Strings("failedFiles", failedFiles))
return fmt.Errorf("部分文件上传失败: %v", failedFiles)
}
return nil
}
func getTeacherName(url string) string {
lastSlash := strings.LastIndex(url, "/")
underscore := strings.Index(url[lastSlash+1:], "_")
if lastSlash == -1 || underscore == -1 {
return ""
}
return url[lastSlash+1 : lastSlash+1+underscore]
}

View File

@@ -101,6 +101,9 @@ func (e *FileUploadAndDownloadService) UploadFile(header *multipart.FileHeader,
if classId == 2 { if classId == 2 {
header.Filename = utils.GenerateRandomString(12) + "_" + strconv.FormatInt(time.Now().Unix(), 10) + "." + s[len(s)-1] header.Filename = utils.GenerateRandomString(12) + "_" + strconv.FormatInt(time.Now().Unix(), 10) + "." + s[len(s)-1]
} }
if classId == 3 {
header.Filename = s[0] + "_" + utils.GenerateRandomString(12) + "_" + strconv.FormatInt(time.Now().Unix(), 10) + "." + s[len(s)-1]
}
filePath, key, uploadErr := oss.UploadFile(header) filePath, key, uploadErr := oss.UploadFile(header)
if uploadErr != nil { if uploadErr != nil {
return file, uploadErr return file, uploadErr