Initial commit: web_hghl_server
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
package srv_playlet
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
"videoweb/pub/common/response"
|
||||
"videoweb/pub/common/slugx"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/common/utils"
|
||||
"videoweb/pub/models/playletcategorymod"
|
||||
"videoweb/pub/models/playletmod"
|
||||
"videoweb/web/api/proto"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
var playletCategoryWebProjection = bson.D{
|
||||
{Key: playletcategorymod.FN.PlayletCategory.Id, Value: 1},
|
||||
{Key: playletcategorymod.FN.PlayletCategory.Name, Value: 1},
|
||||
{Key: playletcategorymod.FN.PlayletCategory.Slug, Value: 1},
|
||||
{Key: playletcategorymod.FN.PlayletCategory.Icon, Value: 1},
|
||||
{Key: playletcategorymod.FN.PlayletCategory.Status, Value: 1},
|
||||
{Key: playletcategorymod.FN.PlayletCategory.Rank, Value: 1},
|
||||
{Key: playletcategorymod.FN.PlayletCategory.Remark, Value: 1},
|
||||
{Key: playletcategorymod.FN.PlayletCategory.SeoInfo.Title, Value: 1},
|
||||
{Key: playletcategorymod.FN.PlayletCategory.SeoInfo.Description, Value: 1},
|
||||
{Key: playletcategorymod.FN.PlayletCategory.SeoInfo.Keyworld, Value: 1},
|
||||
{Key: playletcategorymod.FN.PlayletCategory.CreatedAt, Value: 1},
|
||||
{Key: playletcategorymod.FN.PlayletCategory.UpdatedAt, Value: 1},
|
||||
}
|
||||
|
||||
// ListPlayletCategory 分页查询短剧分类列表
|
||||
func ListPlayletCategory(ctx context.Context, req *proto.PlayletCategoryListReq) (*proto.PlayletCategoryListPageResp, *srvdef.SrvErr) {
|
||||
if req == nil {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "", "")
|
||||
}
|
||||
filter := bson.M{}
|
||||
if req.Id != nil && *req.Id > 0 {
|
||||
filter[playletcategorymod.FN.PlayletCategory.Id] = *req.Id
|
||||
}
|
||||
if req.Status != nil {
|
||||
filter[playletcategorymod.FN.PlayletCategory.Status] = *req.Status
|
||||
}
|
||||
if name := strings.TrimSpace(req.Name); name != "" {
|
||||
filter[playletcategorymod.FN.PlayletCategory.Name] = bson.M{"$regex": regexp.QuoteMeta(name)}
|
||||
}
|
||||
pageNum, pageSize := normalizePage(req.PageNum, req.PageSize)
|
||||
totalCount, err := playletcategorymod.CountPlayletCategory(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp := &proto.PlayletCategoryListPageResp{
|
||||
BasePageResp: response.BasePageResp{
|
||||
TotalCount: totalCount,
|
||||
PageSize: int(pageSize),
|
||||
PageNum: int(pageNum),
|
||||
List: make([]*proto.PlayletCategoryListResp, 0),
|
||||
},
|
||||
}
|
||||
if totalCount == 0 {
|
||||
return resp, nil
|
||||
}
|
||||
list, err := playletcategorymod.FindManyPlayletCategory(ctx, filter, options.Find().
|
||||
SetProjection(playletCategoryWebProjection).
|
||||
SetSort(bson.D{
|
||||
{Key: playletcategorymod.FN.PlayletCategory.Rank, Value: -1},
|
||||
{Key: playletcategorymod.FN.PlayletCategory.Id, Value: -1},
|
||||
}).
|
||||
SetSkip((pageNum-1)*pageSize).
|
||||
SetLimit(pageSize))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items := make([]*proto.PlayletCategoryListResp, 0, len(list))
|
||||
for _, item := range list {
|
||||
if item == nil {
|
||||
continue
|
||||
}
|
||||
items = append(items, &proto.PlayletCategoryListResp{
|
||||
Id: item.Id,
|
||||
Name: item.Name,
|
||||
Slug: item.Slug,
|
||||
Icon: item.Icon,
|
||||
Status: item.Status,
|
||||
Rank: item.Rank,
|
||||
Remark: item.Remark,
|
||||
SeoInfo: normalizeSeoValue(item.SeoInfo),
|
||||
CreatedAt: item.CreatedAt,
|
||||
UpdatedAt: item.UpdatedAt,
|
||||
})
|
||||
}
|
||||
resp.List = items
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// AddPlayletCategory 新增短剧分类
|
||||
func AddPlayletCategory(ctx context.Context, req *proto.PlayletCategoryAddReq) (*proto.PlayletCategoryAddResp, *srvdef.SrvErr) {
|
||||
if req == nil || strings.TrimSpace(req.Name) == "" {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "分类名称不能为空", "")
|
||||
}
|
||||
doc := &playletcategorymod.PlayletCategory{
|
||||
Name: strings.TrimSpace(req.Name),
|
||||
Slug: req.Slug,
|
||||
Icon: strings.TrimSpace(req.Icon),
|
||||
Status: req.Status,
|
||||
Rank: req.Rank,
|
||||
Remark: strings.TrimSpace(req.Remark),
|
||||
SeoInfo: normalizeSeoValue(req.SeoInfo),
|
||||
}
|
||||
exists := func(s string) bool {
|
||||
item, _ := playletcategorymod.FindOnePlayletCategory(ctx, slugx.Filter(
|
||||
playletcategorymod.FN.PlayletCategory.Slug, playletcategorymod.FN.PlayletCategory.Id, s, 0))
|
||||
return item != nil
|
||||
}
|
||||
if serr := slugx.Ensure(&doc.Slug, utils.SlugSourceFromKeywordsOrTitle(doc.SeoInfo.Keyworld, doc.Name), exists); serr != nil {
|
||||
return nil, serr
|
||||
}
|
||||
if err := playletcategorymod.InsertOnePlayletCategory(ctx, doc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clearAppPlayletHomeCache()
|
||||
return &proto.PlayletCategoryAddResp{Id: doc.Id}, nil
|
||||
}
|
||||
|
||||
// UpdatePlayletCategory 更新短剧分类
|
||||
func UpdatePlayletCategory(ctx context.Context, req *proto.PlayletCategoryUpdateReq) *srvdef.SrvErr {
|
||||
if req == nil || req.Id <= 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "分类ID无效", "")
|
||||
}
|
||||
current, err := playletcategorymod.FindOnePlayletCategory(ctx, bson.M{
|
||||
playletcategorymod.FN.PlayletCategory.Id: req.Id,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
setDoc := bson.M{playletcategorymod.FN.PlayletCategory.UpdatedAt: time.Now()}
|
||||
if req.Name != nil {
|
||||
name := strings.TrimSpace(*req.Name)
|
||||
if name == "" {
|
||||
return srvdef.New(srvdef.ErrParamError, "分类名称不能为空", "")
|
||||
}
|
||||
setDoc[playletcategorymod.FN.PlayletCategory.Name] = name
|
||||
}
|
||||
if req.Icon != nil {
|
||||
setDoc[playletcategorymod.FN.PlayletCategory.Icon] = strings.TrimSpace(*req.Icon)
|
||||
}
|
||||
if req.Status != nil {
|
||||
setDoc[playletcategorymod.FN.PlayletCategory.Status] = *req.Status
|
||||
}
|
||||
if req.Rank != nil {
|
||||
setDoc[playletcategorymod.FN.PlayletCategory.Rank] = *req.Rank
|
||||
}
|
||||
if req.Remark != nil {
|
||||
setDoc[playletcategorymod.FN.PlayletCategory.Remark] = strings.TrimSpace(*req.Remark)
|
||||
}
|
||||
if req.SeoInfo != nil {
|
||||
setDoc["seoInfo"] = normalizeSeoValue(*req.SeoInfo)
|
||||
}
|
||||
name := current.Name
|
||||
if req.Name != nil {
|
||||
name = strings.TrimSpace(*req.Name)
|
||||
}
|
||||
keywords := current.SeoInfo.Keyworld
|
||||
if req.SeoInfo != nil {
|
||||
keywords = normalizeSeoValue(*req.SeoInfo).Keyworld
|
||||
}
|
||||
exists := func(s string) bool {
|
||||
item, _ := playletcategorymod.FindOnePlayletCategory(ctx, slugx.Filter(
|
||||
playletcategorymod.FN.PlayletCategory.Slug, playletcategorymod.FN.PlayletCategory.Id, s, req.Id))
|
||||
return item != nil
|
||||
}
|
||||
slug, changed, serr := slugx.PrepareOnUpdate(current.Slug, req.Slug,
|
||||
utils.SlugSourceFromKeywordsOrTitle(keywords, name), exists)
|
||||
if serr != nil {
|
||||
return serr
|
||||
}
|
||||
if changed {
|
||||
setDoc[playletcategorymod.FN.PlayletCategory.Slug] = slug
|
||||
}
|
||||
if len(setDoc) <= 1 {
|
||||
return srvdef.New(srvdef.ErrParamError, "没有可更新字段", "")
|
||||
}
|
||||
if err := playletcategorymod.UpdateOnePlayletCategory(ctx,
|
||||
bson.M{playletcategorymod.FN.PlayletCategory.Id: req.Id},
|
||||
bson.M{"$set": setDoc},
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
clearAppPlayletHomeCache()
|
||||
return nil
|
||||
}
|
||||
|
||||
// DelPlayletCategory 删除短剧分类,被短剧引用时禁止删除
|
||||
func DelPlayletCategory(ctx context.Context, id int64) *srvdef.SrvErr {
|
||||
if id <= 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "分类ID无效", "")
|
||||
}
|
||||
usedCount, err := playletmod.CountPlaylet(ctx, bson.M{
|
||||
playletmod.FN.Playlet.CategoryIds: bson.M{"$in": []int64{id}},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if usedCount > 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "分类已被短剧引用,无法删除", "")
|
||||
}
|
||||
count, err := playletcategorymod.DelOnePlayletCategory(ctx, bson.M{playletcategorymod.FN.PlayletCategory.Id: id})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count == 0 {
|
||||
return srvdef.New(srvdef.ErrNoData, "", "")
|
||||
}
|
||||
clearAppPlayletHomeCache()
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package srv_playlet
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"videoweb/pub/common/playletcache"
|
||||
"videoweb/pub/pubdef"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultPageSize int64 = 10
|
||||
maxPageSize int64 = 100
|
||||
)
|
||||
|
||||
func normalizePage(pageNum, pageSize int64) (int64, int64) {
|
||||
if pageNum <= 0 {
|
||||
pageNum = 1
|
||||
}
|
||||
if pageSize <= 0 {
|
||||
pageSize = defaultPageSize
|
||||
}
|
||||
if pageSize > maxPageSize {
|
||||
pageSize = maxPageSize
|
||||
}
|
||||
return pageNum, pageSize
|
||||
}
|
||||
|
||||
// normalizeSeoValue 规范化 SEO 字段,避免 keywords 为 null
|
||||
func normalizeSeoValue(seo pubdef.SeoValue) pubdef.SeoValue {
|
||||
seo.Title = strings.TrimSpace(seo.Title)
|
||||
seo.Description = strings.TrimSpace(seo.Description)
|
||||
if seo.Keyworld == nil {
|
||||
seo.Keyworld = make([]string, 0)
|
||||
return seo
|
||||
}
|
||||
words := make([]string, 0, len(seo.Keyworld))
|
||||
for _, word := range seo.Keyworld {
|
||||
word = strings.TrimSpace(word)
|
||||
if word == "" {
|
||||
continue
|
||||
}
|
||||
words = append(words, word)
|
||||
}
|
||||
seo.Keyworld = words
|
||||
return seo
|
||||
}
|
||||
|
||||
func clearAppPlayletHomeCache() {
|
||||
playletcache.ClearHomeCache()
|
||||
}
|
||||
@@ -0,0 +1,651 @@
|
||||
package srv_playlet
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
"videoweb/pub/common/response"
|
||||
"videoweb/pub/common/slugx"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/common/utils"
|
||||
"videoweb/pub/models/playlethomeconfigmod"
|
||||
"videoweb/pub/models/playletthememod"
|
||||
"videoweb/pub/models/videocategorymod"
|
||||
"videoweb/web/api/proto"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
// ListPlayletHomeConfig 分页查询首页配置列表
|
||||
func ListPlayletHomeConfig(ctx context.Context, req *proto.PlayletHomeConfigListReq) (*proto.PlayletHomeConfigListPageResp, *srvdef.SrvErr) {
|
||||
if req == nil {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "", "")
|
||||
}
|
||||
filter, err := buildPlayletHomeConfigFilter(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pageNum, pageSize := normalizePage(req.PageNum, req.PageSize)
|
||||
totalCount, err := playlethomeconfigmod.CountPlayletHomeConfig(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp := &proto.PlayletHomeConfigListPageResp{
|
||||
BasePageResp: response.BasePageResp{
|
||||
TotalCount: totalCount,
|
||||
PageSize: int(pageSize),
|
||||
PageNum: int(pageNum),
|
||||
List: make([]*proto.PlayletHomeConfigListResp, 0),
|
||||
},
|
||||
}
|
||||
if totalCount == 0 {
|
||||
return resp, nil
|
||||
}
|
||||
list, err := playlethomeconfigmod.FindManyPlayletHomeConfig(ctx, filter, options.Find().
|
||||
SetSort(bson.D{
|
||||
{Key: playlethomeconfigmod.FN.PlayletHomeConfig.Rank, Value: -1},
|
||||
{Key: playlethomeconfigmod.FN.PlayletHomeConfig.Id, Value: -1},
|
||||
}).
|
||||
SetSkip((pageNum-1)*pageSize).
|
||||
SetLimit(pageSize))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items := make([]*proto.PlayletHomeConfigListResp, 0, len(list))
|
||||
for _, item := range list {
|
||||
if item == nil {
|
||||
continue
|
||||
}
|
||||
items = append(items, playletHomeConfigToResp(item))
|
||||
}
|
||||
resp.List = items
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// ListPlayletHomeTopicOptions 分页查询未被其他启用模块占用的题材或视频分类
|
||||
func ListPlayletHomeTopicOptions(ctx context.Context, req *proto.PlayletHomeTopicOptionsReq) (*proto.PlayletHomeTopicOptionsResp, *srvdef.SrvErr) {
|
||||
if req == nil || (req.DataType != playlethomeconfigmod.DataTypeAll && req.DataType != playlethomeconfigmod.DataTypeVideo) {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "数据类型仅支持1短剧题材、2视频分类", "")
|
||||
}
|
||||
if req.ConfigId < 0 {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "配置ID无效", "")
|
||||
}
|
||||
pageNum, pageSize := normalizePage(req.PageNum, req.PageSize)
|
||||
resp := &proto.PlayletHomeTopicOptionsResp{
|
||||
List: make([]*proto.PlayletHomeTopicOption, 0),
|
||||
SelectedList: make([]*proto.PlayletHomeTopicOption, 0),
|
||||
PageNum: pageNum,
|
||||
PageSize: pageSize,
|
||||
}
|
||||
var selectedIDs []int64
|
||||
if req.ConfigId > 0 {
|
||||
current, err := playlethomeconfigmod.FindOnePlayletHomeConfig(ctx, bson.M{playlethomeconfigmod.FN.PlayletHomeConfig.Id: req.ConfigId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if current.ModuleType != playlethomeconfigmod.ModuleTypeTopic || current.DataType != req.DataType {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "当前配置不是指定数据类型的专题模块", "")
|
||||
}
|
||||
selectedIDs = current.TopicIds
|
||||
}
|
||||
// 已启用的其他专题模块占用的ID不再出现在可选列表中
|
||||
configFilter := bson.M{
|
||||
playlethomeconfigmod.FN.PlayletHomeConfig.Enabled: true,
|
||||
playlethomeconfigmod.FN.PlayletHomeConfig.ModuleType: playlethomeconfigmod.ModuleTypeTopic,
|
||||
playlethomeconfigmod.FN.PlayletHomeConfig.DataType: req.DataType,
|
||||
}
|
||||
if req.ConfigId > 0 {
|
||||
configFilter[playlethomeconfigmod.FN.PlayletHomeConfig.Id] = bson.M{"$ne": req.ConfigId}
|
||||
}
|
||||
configs, err := playlethomeconfigmod.FindManyPlayletHomeConfig(ctx, configFilter,
|
||||
options.Find().SetProjection(bson.M{playlethomeconfigmod.FN.PlayletHomeConfig.TopicIds: 1}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
occupied := make(map[int64]struct{})
|
||||
for _, config := range configs {
|
||||
if config == nil {
|
||||
continue
|
||||
}
|
||||
for _, id := range config.TopicIds {
|
||||
occupied[id] = struct{}{}
|
||||
}
|
||||
}
|
||||
skip := (pageNum - 1) * pageSize
|
||||
if req.DataType == playlethomeconfigmod.DataTypeVideo {
|
||||
filter := bson.M{videocategorymod.FN.VideoCategory.Status: true}
|
||||
if len(occupied) > 0 {
|
||||
ids := make([]int64, 0, len(occupied))
|
||||
for id := range occupied {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
filter[videocategorymod.FN.VideoCategory.Id] = bson.M{"$nin": ids}
|
||||
}
|
||||
resp.TotalCount, err = videocategorymod.CountVideoCategorys(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list, err := videocategorymod.FindManyVideoCategorys(ctx, filter, options.Find().
|
||||
SetProjection(bson.M{videocategorymod.FN.VideoCategory.Id: 1, videocategorymod.FN.VideoCategory.Name: 1, videocategorymod.FN.VideoCategory.Status: 1}).
|
||||
SetSort(bson.D{{Key: videocategorymod.FN.VideoCategory.Rank, Value: -1}, {Key: videocategorymod.FN.VideoCategory.Id, Value: -1}}).
|
||||
SetSkip(skip).SetLimit(pageSize))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, item := range list {
|
||||
if item != nil {
|
||||
resp.List = append(resp.List, &proto.PlayletHomeTopicOption{Id: item.Id, Name: item.Name, Status: item.Status})
|
||||
}
|
||||
}
|
||||
if len(selectedIDs) > 0 {
|
||||
selected, err := videocategorymod.FindManyVideoCategorys(ctx, bson.M{videocategorymod.FN.VideoCategory.Id: bson.M{"$in": selectedIDs}},
|
||||
options.Find().SetProjection(bson.M{videocategorymod.FN.VideoCategory.Id: 1, videocategorymod.FN.VideoCategory.Name: 1, videocategorymod.FN.VideoCategory.Status: 1}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
byID := make(map[int64]*proto.PlayletHomeTopicOption, len(selected))
|
||||
for _, item := range selected {
|
||||
if item != nil {
|
||||
byID[item.Id] = &proto.PlayletHomeTopicOption{Id: item.Id, Name: item.Name, Status: item.Status}
|
||||
}
|
||||
}
|
||||
for _, id := range selectedIDs {
|
||||
if item := byID[id]; item != nil {
|
||||
resp.SelectedList = append(resp.SelectedList, item)
|
||||
} else {
|
||||
resp.SelectedList = append(resp.SelectedList, &proto.PlayletHomeTopicOption{Id: id})
|
||||
}
|
||||
}
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
filter := bson.M{playletthememod.FN.PlayletTheme.Status: true}
|
||||
if len(occupied) > 0 {
|
||||
ids := make([]int64, 0, len(occupied))
|
||||
for id := range occupied {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
filter[playletthememod.FN.PlayletTheme.Id] = bson.M{"$nin": ids}
|
||||
}
|
||||
resp.TotalCount, err = playletthememod.CountPlayletTheme(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list, err := playletthememod.FindManyPlayletTheme(ctx, filter, options.Find().
|
||||
SetProjection(bson.M{playletthememod.FN.PlayletTheme.Id: 1, playletthememod.FN.PlayletTheme.Name: 1, playletthememod.FN.PlayletTheme.Status: 1}).
|
||||
SetSort(bson.D{{Key: playletthememod.FN.PlayletTheme.Rank, Value: -1}, {Key: playletthememod.FN.PlayletTheme.Id, Value: -1}}).
|
||||
SetSkip(skip).SetLimit(pageSize))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, item := range list {
|
||||
if item != nil {
|
||||
resp.List = append(resp.List, &proto.PlayletHomeTopicOption{Id: item.Id, Name: item.Name, Status: item.Status})
|
||||
}
|
||||
}
|
||||
if len(selectedIDs) > 0 {
|
||||
selected, err := playletthememod.FindManyPlayletTheme(ctx, bson.M{playletthememod.FN.PlayletTheme.Id: bson.M{"$in": selectedIDs}},
|
||||
options.Find().SetProjection(bson.M{playletthememod.FN.PlayletTheme.Id: 1, playletthememod.FN.PlayletTheme.Name: 1, playletthememod.FN.PlayletTheme.Status: 1}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
byID := make(map[int64]*proto.PlayletHomeTopicOption, len(selected))
|
||||
for _, item := range selected {
|
||||
if item != nil {
|
||||
byID[item.Id] = &proto.PlayletHomeTopicOption{Id: item.Id, Name: item.Name, Status: item.Status}
|
||||
}
|
||||
}
|
||||
for _, id := range selectedIDs {
|
||||
if item := byID[id]; item != nil {
|
||||
resp.SelectedList = append(resp.SelectedList, item)
|
||||
} else {
|
||||
resp.SelectedList = append(resp.SelectedList, &proto.PlayletHomeTopicOption{Id: id})
|
||||
}
|
||||
}
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// AddPlayletHomeConfig 新增首页配置
|
||||
func AddPlayletHomeConfig(ctx context.Context, req *proto.PlayletHomeConfigAddReq) (*proto.PlayletHomeConfigAddResp, *srvdef.SrvErr) {
|
||||
if req == nil {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "", "")
|
||||
}
|
||||
title, style, moduleType, dataType, recommendType, limit, err := normalizePlayletHomeConfig(req.Title, req.Style, req.ModuleType, req.DataType, req.RecommendType, req.Limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
doc := &playlethomeconfigmod.PlayletHomeConfig{
|
||||
Title: title,
|
||||
Slug: req.Slug,
|
||||
Desc: strings.TrimSpace(req.Desc),
|
||||
Label: strings.TrimSpace(req.Label),
|
||||
Style: style,
|
||||
CardBackgroundImage: strings.TrimSpace(req.CardBackgroundImage),
|
||||
ModuleType: moduleType,
|
||||
DataType: dataType,
|
||||
RecommendType: recommendType,
|
||||
CategoryId: req.CategoryId,
|
||||
TopicIds: req.TopicIds,
|
||||
Rank: req.Rank,
|
||||
Enabled: req.Enabled,
|
||||
Limit: limit,
|
||||
}
|
||||
if err := validateHomeConfigTopics(ctx, doc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
exists := func(s string) bool {
|
||||
item, _ := playlethomeconfigmod.FindOnePlayletHomeConfig(ctx, slugx.Filter(
|
||||
playlethomeconfigmod.FN.PlayletHomeConfig.Slug, playlethomeconfigmod.FN.PlayletHomeConfig.Id, s, 0))
|
||||
return item != nil
|
||||
}
|
||||
if serr := slugx.Ensure(&doc.Slug, utils.SlugSourceFromKeywordsOrTitle(nil, title), exists); serr != nil {
|
||||
return nil, serr
|
||||
}
|
||||
if err := playlethomeconfigmod.InsertOnePlayletHomeConfig(ctx, doc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clearAppPlayletHomeCache()
|
||||
return &proto.PlayletHomeConfigAddResp{Id: doc.Id}, nil
|
||||
}
|
||||
|
||||
// UpdatePlayletHomeConfig 更新首页配置
|
||||
func UpdatePlayletHomeConfig(ctx context.Context, req *proto.PlayletHomeConfigUpdateReq) *srvdef.SrvErr {
|
||||
if req == nil || req.Id <= 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "id无效", "")
|
||||
}
|
||||
setDoc := bson.M{playlethomeconfigmod.FN.PlayletHomeConfig.UpdatedAt: time.Now()}
|
||||
current, err := playlethomeconfigmod.FindOnePlayletHomeConfig(ctx, bson.M{playlethomeconfigmod.FN.PlayletHomeConfig.Id: req.Id})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if req.Title != nil {
|
||||
title := strings.TrimSpace(*req.Title)
|
||||
if title == "" {
|
||||
return srvdef.New(srvdef.ErrParamError, "模块标题不能为空", "")
|
||||
}
|
||||
setDoc[playlethomeconfigmod.FN.PlayletHomeConfig.Title] = title
|
||||
}
|
||||
if req.Desc != nil {
|
||||
setDoc[playlethomeconfigmod.FN.PlayletHomeConfig.Desc] = strings.TrimSpace(*req.Desc)
|
||||
}
|
||||
if req.Label != nil {
|
||||
setDoc[playlethomeconfigmod.FN.PlayletHomeConfig.Label] = strings.TrimSpace(*req.Label)
|
||||
}
|
||||
if req.Style != nil {
|
||||
style, err := normalizePlayletHomeConfigStyle(*req.Style)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
setDoc[playlethomeconfigmod.FN.PlayletHomeConfig.Style] = style
|
||||
}
|
||||
if req.CardBackgroundImage != nil {
|
||||
setDoc[playlethomeconfigmod.FN.PlayletHomeConfig.CardBackgroundImage] = strings.TrimSpace(*req.CardBackgroundImage)
|
||||
}
|
||||
if req.ModuleType != nil {
|
||||
moduleType, err := normalizePlayletHomeModuleType(*req.ModuleType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
setDoc[playlethomeconfigmod.FN.PlayletHomeConfig.ModuleType] = moduleType
|
||||
}
|
||||
if req.DataType != nil {
|
||||
dataType, err := normalizePlayletHomeDataType(*req.DataType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
setDoc[playlethomeconfigmod.FN.PlayletHomeConfig.DataType] = dataType
|
||||
}
|
||||
if req.RecommendType != nil {
|
||||
if err := validatePlayletHomeRecommendType(*req.RecommendType); err != nil {
|
||||
return err
|
||||
}
|
||||
setDoc[playlethomeconfigmod.FN.PlayletHomeConfig.RecommendType] = *req.RecommendType
|
||||
}
|
||||
if req.CategoryId != nil {
|
||||
setDoc[playlethomeconfigmod.FN.PlayletHomeConfig.CategoryId] = *req.CategoryId
|
||||
}
|
||||
if req.TopicIds != nil {
|
||||
current.TopicIds = *req.TopicIds
|
||||
}
|
||||
if req.ModuleType != nil {
|
||||
current.ModuleType = *req.ModuleType
|
||||
}
|
||||
if req.DataType != nil {
|
||||
current.DataType = *req.DataType
|
||||
}
|
||||
if req.Enabled != nil {
|
||||
current.Enabled = *req.Enabled
|
||||
}
|
||||
if req.TopicIds != nil || req.ModuleType != nil || req.DataType != nil || req.Enabled != nil {
|
||||
if err := validateHomeConfigTopics(ctx, current); err != nil {
|
||||
return err
|
||||
}
|
||||
if req.TopicIds != nil {
|
||||
setDoc[playlethomeconfigmod.FN.PlayletHomeConfig.TopicIds] = current.TopicIds
|
||||
}
|
||||
}
|
||||
if req.Rank != nil {
|
||||
setDoc[playlethomeconfigmod.FN.PlayletHomeConfig.Rank] = *req.Rank
|
||||
}
|
||||
if req.Enabled != nil {
|
||||
setDoc[playlethomeconfigmod.FN.PlayletHomeConfig.Enabled] = *req.Enabled
|
||||
}
|
||||
if req.Limit != nil {
|
||||
setDoc[playlethomeconfigmod.FN.PlayletHomeConfig.Limit] = normalizePlayletHomeConfigLimit(*req.Limit)
|
||||
}
|
||||
title := current.Title
|
||||
if req.Title != nil {
|
||||
title = strings.TrimSpace(*req.Title)
|
||||
}
|
||||
exists := func(s string) bool {
|
||||
item, _ := playlethomeconfigmod.FindOnePlayletHomeConfig(ctx, slugx.Filter(
|
||||
playlethomeconfigmod.FN.PlayletHomeConfig.Slug, playlethomeconfigmod.FN.PlayletHomeConfig.Id, s, req.Id))
|
||||
return item != nil
|
||||
}
|
||||
slug, changed, serr := slugx.PrepareOnUpdate(current.Slug, req.Slug,
|
||||
utils.SlugSourceFromKeywordsOrTitle(nil, title), exists)
|
||||
if serr != nil {
|
||||
return serr
|
||||
}
|
||||
if changed {
|
||||
setDoc[playlethomeconfigmod.FN.PlayletHomeConfig.Slug] = slug
|
||||
}
|
||||
if len(setDoc) <= 1 {
|
||||
return srvdef.New(srvdef.ErrParamError, "没有可更新字段", "")
|
||||
}
|
||||
if err := playlethomeconfigmod.UpdateOnePlayletHomeConfig(ctx,
|
||||
bson.M{playlethomeconfigmod.FN.PlayletHomeConfig.Id: req.Id},
|
||||
bson.M{"$set": setDoc},
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
clearAppPlayletHomeCache()
|
||||
return nil
|
||||
}
|
||||
|
||||
// DelPlayletHomeConfig 删除首页配置
|
||||
func DelPlayletHomeConfig(ctx context.Context, req *proto.PlayletHomeConfigDelReq) *srvdef.SrvErr {
|
||||
if req == nil || len(req.Ids) == 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "配置ID不能为空", "")
|
||||
}
|
||||
ids := make([]int64, 0, len(req.Ids))
|
||||
seen := make(map[int64]struct{}, len(req.Ids))
|
||||
for _, id := range req.Ids {
|
||||
if id <= 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "配置ID无效", "")
|
||||
}
|
||||
if _, ok := seen[id]; ok {
|
||||
continue
|
||||
}
|
||||
seen[id] = struct{}{}
|
||||
ids = append(ids, id)
|
||||
}
|
||||
count, err := playlethomeconfigmod.DelManyPlayletHomeConfig(ctx, bson.M{
|
||||
playlethomeconfigmod.FN.PlayletHomeConfig.Id: bson.M{"$in": ids},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count == 0 {
|
||||
return srvdef.New(srvdef.ErrNoData, "", "")
|
||||
}
|
||||
clearAppPlayletHomeCache()
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildPlayletHomeConfigFilter(req *proto.PlayletHomeConfigListReq) (bson.M, *srvdef.SrvErr) {
|
||||
filter := bson.M{}
|
||||
if req.Id != nil && *req.Id > 0 {
|
||||
filter[playlethomeconfigmod.FN.PlayletHomeConfig.Id] = *req.Id
|
||||
}
|
||||
if slug := strings.TrimSpace(req.Slug); slug != "" {
|
||||
filter[playlethomeconfigmod.FN.PlayletHomeConfig.Slug] = slug
|
||||
}
|
||||
if title := strings.TrimSpace(req.Title); title != "" {
|
||||
filter[playlethomeconfigmod.FN.PlayletHomeConfig.Title] = bson.M{"$regex": regexp.QuoteMeta(title)}
|
||||
}
|
||||
if desc := strings.TrimSpace(req.Desc); desc != "" {
|
||||
filter[playlethomeconfigmod.FN.PlayletHomeConfig.Desc] = bson.M{"$regex": regexp.QuoteMeta(desc)}
|
||||
}
|
||||
if label := strings.TrimSpace(req.Label); label != "" {
|
||||
filter[playlethomeconfigmod.FN.PlayletHomeConfig.Label] = bson.M{"$regex": regexp.QuoteMeta(label)}
|
||||
}
|
||||
if style := strings.TrimSpace(req.Style); style != "" {
|
||||
normalizedStyle, err := normalizePlayletHomeConfigStyle(style)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filter[playlethomeconfigmod.FN.PlayletHomeConfig.Style] = normalizedStyle
|
||||
}
|
||||
if req.ModuleType != nil {
|
||||
moduleType, err := normalizePlayletHomeModuleType(*req.ModuleType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if moduleType == playlethomeconfigmod.ModuleTypePlaylet {
|
||||
filter[playlethomeconfigmod.FN.PlayletHomeConfig.ModuleType] = bson.M{"$in": []interface{}{nil, int64(0), playlethomeconfigmod.ModuleTypePlaylet}}
|
||||
} else {
|
||||
filter[playlethomeconfigmod.FN.PlayletHomeConfig.ModuleType] = moduleType
|
||||
}
|
||||
}
|
||||
if req.DataType != nil {
|
||||
dataType, err := normalizePlayletHomeDataType(*req.DataType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if dataType == playlethomeconfigmod.DataTypeAll {
|
||||
filter[playlethomeconfigmod.FN.PlayletHomeConfig.DataType] = bson.M{"$in": []interface{}{nil, int64(0), playlethomeconfigmod.DataTypeAll}}
|
||||
} else {
|
||||
filter[playlethomeconfigmod.FN.PlayletHomeConfig.DataType] = dataType
|
||||
}
|
||||
}
|
||||
if req.RecommendType != nil {
|
||||
if err := validatePlayletHomeRecommendType(*req.RecommendType); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filter[playlethomeconfigmod.FN.PlayletHomeConfig.RecommendType] = *req.RecommendType
|
||||
}
|
||||
if req.CategoryId != nil && *req.CategoryId > 0 {
|
||||
filter[playlethomeconfigmod.FN.PlayletHomeConfig.CategoryId] = *req.CategoryId
|
||||
}
|
||||
if req.Enabled != nil {
|
||||
filter[playlethomeconfigmod.FN.PlayletHomeConfig.Enabled] = *req.Enabled
|
||||
}
|
||||
return filter, nil
|
||||
}
|
||||
|
||||
func playletHomeConfigToResp(item *playlethomeconfigmod.PlayletHomeConfig) *proto.PlayletHomeConfigListResp {
|
||||
if item == nil {
|
||||
return nil
|
||||
}
|
||||
return &proto.PlayletHomeConfigListResp{
|
||||
Id: item.Id,
|
||||
Slug: item.Slug,
|
||||
Title: item.Title,
|
||||
Desc: item.Desc,
|
||||
Label: item.Label,
|
||||
Style: item.Style,
|
||||
CardBackgroundImage: item.CardBackgroundImage,
|
||||
ModuleType: normalizePlayletHomeModuleTypeForResp(item.ModuleType),
|
||||
DataType: normalizePlayletHomeDataTypeForResp(item.DataType),
|
||||
RecommendType: item.RecommendType,
|
||||
CategoryId: item.CategoryId,
|
||||
TopicIds: item.TopicIds,
|
||||
Rank: item.Rank,
|
||||
Enabled: item.Enabled,
|
||||
Limit: item.Limit,
|
||||
CreatedAt: item.CreatedAt,
|
||||
UpdatedAt: item.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
// validateHomeConfigTopics 校验专题归属和已启用模块间的专题唯一性
|
||||
func validateHomeConfigTopics(ctx context.Context, doc *playlethomeconfigmod.PlayletHomeConfig) *srvdef.SrvErr {
|
||||
if doc.ModuleType != playlethomeconfigmod.ModuleTypeTopic {
|
||||
if len(doc.TopicIds) > 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "列表模块不能配置专题ID", "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
seen := make(map[int64]struct{}, len(doc.TopicIds))
|
||||
ids := make([]int64, 0, len(doc.TopicIds))
|
||||
for _, id := range doc.TopicIds {
|
||||
if id <= 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "专题ID必须大于0", "")
|
||||
}
|
||||
if _, ok := seen[id]; ok {
|
||||
continue
|
||||
}
|
||||
seen[id] = struct{}{}
|
||||
ids = append(ids, id)
|
||||
}
|
||||
doc.TopicIds = ids
|
||||
if !doc.Enabled {
|
||||
return nil
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "启用的专题模块必须配置专题ID", "")
|
||||
}
|
||||
if doc.DataType == playlethomeconfigmod.DataTypeVideo {
|
||||
categories, err := videocategorymod.FindManyVideoCategorys(ctx, bson.M{
|
||||
videocategorymod.FN.VideoCategory.Id: bson.M{"$in": ids},
|
||||
videocategorymod.FN.VideoCategory.Status: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(categories) != len(ids) {
|
||||
return srvdef.New(srvdef.ErrParamError, "视频分类不存在或未上架", "")
|
||||
}
|
||||
} else {
|
||||
themes, err := playletthememod.FindManyPlayletTheme(ctx, bson.M{
|
||||
playletthememod.FN.PlayletTheme.Id: bson.M{"$in": ids},
|
||||
playletthememod.FN.PlayletTheme.Status: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(themes) != len(ids) {
|
||||
return srvdef.New(srvdef.ErrParamError, "短剧题材不存在或未上架", "")
|
||||
}
|
||||
}
|
||||
configs, err := playlethomeconfigmod.FindManyPlayletHomeConfig(ctx, bson.M{
|
||||
playlethomeconfigmod.FN.PlayletHomeConfig.Enabled: true,
|
||||
playlethomeconfigmod.FN.PlayletHomeConfig.ModuleType: playlethomeconfigmod.ModuleTypeTopic,
|
||||
playlethomeconfigmod.FN.PlayletHomeConfig.DataType: doc.DataType,
|
||||
playlethomeconfigmod.FN.PlayletHomeConfig.TopicIds: bson.M{"$in": ids},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, other := range configs {
|
||||
if other != nil && other.Id != doc.Id {
|
||||
return srvdef.New(srvdef.ErrParamError, "专题已分配给其他启用的首页模块", "")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func normalizePlayletHomeConfig(title string, style string, moduleType int64, dataType int64, recommendType int64, limit int64) (string, string, int64, int64, int64, int64, *srvdef.SrvErr) {
|
||||
title = strings.TrimSpace(title)
|
||||
if title == "" {
|
||||
return "", "", 0, 0, 0, 0, srvdef.New(srvdef.ErrParamError, "模块标题不能为空", "")
|
||||
}
|
||||
normalizedStyle, err := normalizePlayletHomeConfigStyle(style)
|
||||
if err != nil {
|
||||
return "", "", 0, 0, 0, 0, err
|
||||
}
|
||||
normalizedModuleType, err := normalizePlayletHomeModuleType(moduleType)
|
||||
if err != nil {
|
||||
return "", "", 0, 0, 0, 0, err
|
||||
}
|
||||
normalizedDataType, err := normalizePlayletHomeDataType(dataType)
|
||||
if err != nil {
|
||||
return "", "", 0, 0, 0, 0, err
|
||||
}
|
||||
if err := validatePlayletHomeRecommendType(recommendType); err != nil {
|
||||
return "", "", 0, 0, 0, 0, err
|
||||
}
|
||||
return title, normalizedStyle, normalizedModuleType, normalizedDataType, recommendType, normalizePlayletHomeConfigLimit(limit), nil
|
||||
}
|
||||
|
||||
func normalizePlayletHomeConfigStyle(style string) (string, *srvdef.SrvErr) {
|
||||
style = strings.ToUpper(strings.TrimSpace(style))
|
||||
switch style {
|
||||
case playlethomeconfigmod.StyleA,
|
||||
playlethomeconfigmod.StyleB,
|
||||
playlethomeconfigmod.StyleC,
|
||||
playlethomeconfigmod.StyleD,
|
||||
playlethomeconfigmod.StyleE,
|
||||
playlethomeconfigmod.StyleF,
|
||||
playlethomeconfigmod.StyleG,
|
||||
playlethomeconfigmod.StyleH:
|
||||
return style, nil
|
||||
default:
|
||||
return "", srvdef.New(srvdef.ErrParamError, "样式无效,仅支持A-H", "")
|
||||
}
|
||||
}
|
||||
|
||||
func validatePlayletHomeRecommendType(recommendType int64) *srvdef.SrvErr {
|
||||
switch recommendType {
|
||||
case playlethomeconfigmod.RecommendTypeUpdated,
|
||||
playlethomeconfigmod.RecommendTypeLike,
|
||||
playlethomeconfigmod.RecommendTypeBrowse,
|
||||
playlethomeconfigmod.RecommendTypeHeat,
|
||||
playlethomeconfigmod.RecommendTypeCategory:
|
||||
return nil
|
||||
default:
|
||||
return srvdef.New(srvdef.ErrParamError, "推荐类型无效,仅支持1按更新、2按点赞、3按观看、4按热度、5按分类", "")
|
||||
}
|
||||
}
|
||||
|
||||
func normalizePlayletHomeModuleType(moduleType int64) (int64, *srvdef.SrvErr) {
|
||||
if moduleType == 0 {
|
||||
return playlethomeconfigmod.ModuleTypePlaylet, nil
|
||||
}
|
||||
switch moduleType {
|
||||
case playlethomeconfigmod.ModuleTypePlaylet, playlethomeconfigmod.ModuleTypeTopic:
|
||||
return moduleType, nil
|
||||
default:
|
||||
return 0, srvdef.New(srvdef.ErrParamError, "模块类型无效,仅支持1短剧列表、2专题", "")
|
||||
}
|
||||
}
|
||||
|
||||
func normalizePlayletHomeModuleTypeForResp(moduleType int64) int64 {
|
||||
if moduleType == playlethomeconfigmod.ModuleTypeTopic {
|
||||
return playlethomeconfigmod.ModuleTypeTopic
|
||||
}
|
||||
return playlethomeconfigmod.ModuleTypePlaylet
|
||||
}
|
||||
|
||||
func normalizePlayletHomeDataType(dataType int64) (int64, *srvdef.SrvErr) {
|
||||
if dataType == 0 {
|
||||
return playlethomeconfigmod.DataTypeAll, nil
|
||||
}
|
||||
switch dataType {
|
||||
case playlethomeconfigmod.DataTypeAll, playlethomeconfigmod.DataTypeVideo:
|
||||
return dataType, nil
|
||||
default:
|
||||
return 0, srvdef.New(srvdef.ErrParamError, "数据类型无效,仅支持1全部上架短剧、2全部上架视频", "")
|
||||
}
|
||||
}
|
||||
|
||||
func normalizePlayletHomeDataTypeForResp(dataType int64) int64 {
|
||||
if dataType == playlethomeconfigmod.DataTypeVideo {
|
||||
return playlethomeconfigmod.DataTypeVideo
|
||||
}
|
||||
return playlethomeconfigmod.DataTypeAll
|
||||
}
|
||||
|
||||
func normalizePlayletHomeConfigLimit(limit int64) int64 {
|
||||
if limit <= 0 {
|
||||
return playlethomeconfigmod.DefaultLimit
|
||||
}
|
||||
if limit > playlethomeconfigmod.MaxLimit {
|
||||
return playlethomeconfigmod.MaxLimit
|
||||
}
|
||||
return limit
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,152 @@
|
||||
package srv_playlet
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
"videoweb/pub/common/response"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/models/playletmod"
|
||||
"videoweb/pub/models/playlettagmod"
|
||||
"videoweb/web/api/proto"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
// ListPlayletTag 分页查询标签列表
|
||||
func ListPlayletTag(ctx context.Context, req *proto.PlayletTagListReq) (*proto.PlayletTagListPageResp, *srvdef.SrvErr) {
|
||||
if req == nil {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "", "")
|
||||
}
|
||||
filter := bson.M{}
|
||||
if req.Id != nil && *req.Id > 0 {
|
||||
filter[playlettagmod.FN.PlayletTag.Id] = *req.Id
|
||||
}
|
||||
if req.Status != nil {
|
||||
filter[playlettagmod.FN.PlayletTag.Status] = *req.Status
|
||||
}
|
||||
if name := strings.TrimSpace(req.Name); name != "" {
|
||||
filter[playlettagmod.FN.PlayletTag.Name] = bson.M{"$regex": regexp.QuoteMeta(name)}
|
||||
}
|
||||
pageNum, pageSize := normalizePage(req.PageNum, req.PageSize)
|
||||
totalCount, err := playlettagmod.CountPlayletTag(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp := &proto.PlayletTagListPageResp{
|
||||
BasePageResp: response.BasePageResp{
|
||||
TotalCount: totalCount,
|
||||
PageSize: int(pageSize),
|
||||
PageNum: int(pageNum),
|
||||
List: make([]*proto.PlayletTagListResp, 0),
|
||||
},
|
||||
}
|
||||
if totalCount == 0 {
|
||||
return resp, nil
|
||||
}
|
||||
list, err := playlettagmod.FindManyPlayletTag(ctx, filter, options.Find().
|
||||
SetSort(bson.D{
|
||||
{Key: playlettagmod.FN.PlayletTag.Rank, Value: -1},
|
||||
{Key: playlettagmod.FN.PlayletTag.Id, Value: -1},
|
||||
}).
|
||||
SetSkip((pageNum-1)*pageSize).
|
||||
SetLimit(pageSize))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items := make([]*proto.PlayletTagListResp, 0, len(list))
|
||||
for _, item := range list {
|
||||
if item == nil {
|
||||
continue
|
||||
}
|
||||
items = append(items, &proto.PlayletTagListResp{
|
||||
Id: item.Id,
|
||||
Name: item.Name,
|
||||
Status: item.Status,
|
||||
Rank: item.Rank,
|
||||
SeoInfo: normalizeSeoValue(item.SeoInfo),
|
||||
CreatedAt: item.CreatedAt,
|
||||
UpdatedAt: item.UpdatedAt,
|
||||
})
|
||||
}
|
||||
resp.List = items
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// AddPlayletTag 新增标签
|
||||
func AddPlayletTag(ctx context.Context, req *proto.PlayletTagAddReq) (*proto.PlayletTagAddResp, *srvdef.SrvErr) {
|
||||
if req == nil || strings.TrimSpace(req.Name) == "" {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "标签名称不能为空", "")
|
||||
}
|
||||
doc := &playlettagmod.PlayletTag{
|
||||
Name: strings.TrimSpace(req.Name),
|
||||
Status: req.Status,
|
||||
Rank: req.Rank,
|
||||
SeoInfo: normalizeSeoValue(req.SeoInfo),
|
||||
}
|
||||
if err := playlettagmod.InsertOnePlayletTag(ctx, doc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clearAppPlayletHomeCache()
|
||||
return &proto.PlayletTagAddResp{Id: doc.Id}, nil
|
||||
}
|
||||
|
||||
// UpdatePlayletTag 更新标签
|
||||
func UpdatePlayletTag(ctx context.Context, req *proto.PlayletTagUpdateReq) *srvdef.SrvErr {
|
||||
if req == nil || req.Id <= 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "id无效", "")
|
||||
}
|
||||
setDoc := bson.M{playlettagmod.FN.PlayletTag.UpdatedAt: time.Now()}
|
||||
if req.Name != nil {
|
||||
name := strings.TrimSpace(*req.Name)
|
||||
if name == "" {
|
||||
return srvdef.New(srvdef.ErrParamError, "标签名称不能为空", "")
|
||||
}
|
||||
setDoc[playlettagmod.FN.PlayletTag.Name] = name
|
||||
}
|
||||
if req.Status != nil {
|
||||
setDoc[playlettagmod.FN.PlayletTag.Status] = *req.Status
|
||||
}
|
||||
if req.Rank != nil {
|
||||
setDoc[playlettagmod.FN.PlayletTag.Rank] = *req.Rank
|
||||
}
|
||||
if req.SeoInfo != nil {
|
||||
setDoc["seoInfo"] = normalizeSeoValue(*req.SeoInfo)
|
||||
}
|
||||
if len(setDoc) <= 1 {
|
||||
return srvdef.New(srvdef.ErrParamError, "没有可更新字段", "")
|
||||
}
|
||||
if err := playlettagmod.UpdateOnePlayletTag(ctx,
|
||||
bson.M{playlettagmod.FN.PlayletTag.Id: req.Id},
|
||||
bson.M{"$set": setDoc},
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
clearAppPlayletHomeCache()
|
||||
return nil
|
||||
}
|
||||
|
||||
// DelPlayletTag 删除标签(被短剧引用时禁止删除)
|
||||
func DelPlayletTag(ctx context.Context, id int64) *srvdef.SrvErr {
|
||||
if id <= 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "id无效", "")
|
||||
}
|
||||
usedCount, err := playletmod.CountPlaylet(ctx, bson.M{playletmod.FN.Playlet.TagIds: id})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if usedCount > 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "标签已被短剧引用,无法删除", "")
|
||||
}
|
||||
count, err := playlettagmod.DelOnePlayletTag(ctx, bson.M{playlettagmod.FN.PlayletTag.Id: id})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count == 0 {
|
||||
return srvdef.New(srvdef.ErrNoData, "", "")
|
||||
}
|
||||
clearAppPlayletHomeCache()
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
package srv_playlet
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
"videoweb/pub/common/response"
|
||||
"videoweb/pub/common/slugx"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/common/utils"
|
||||
"videoweb/pub/models/playletmod"
|
||||
"videoweb/pub/models/playletthememod"
|
||||
"videoweb/web/api/proto"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
var playletThemeWebProjection = bson.D{
|
||||
{Key: playletthememod.FN.PlayletTheme.Id, Value: 1},
|
||||
{Key: playletthememod.FN.PlayletTheme.Name, Value: 1},
|
||||
{Key: playletthememod.FN.PlayletTheme.Slug, Value: 1},
|
||||
{Key: playletthememod.FN.PlayletTheme.Icon, Value: 1},
|
||||
{Key: playletthememod.FN.PlayletTheme.Status, Value: 1},
|
||||
{Key: playletthememod.FN.PlayletTheme.Rank, Value: 1},
|
||||
{Key: playletthememod.FN.PlayletTheme.SeoInfo.Title, Value: 1},
|
||||
{Key: playletthememod.FN.PlayletTheme.SeoInfo.Description, Value: 1},
|
||||
{Key: playletthememod.FN.PlayletTheme.SeoInfo.Keyworld, Value: 1},
|
||||
{Key: playletthememod.FN.PlayletTheme.CreatedAt, Value: 1},
|
||||
{Key: playletthememod.FN.PlayletTheme.UpdatedAt, Value: 1},
|
||||
}
|
||||
|
||||
// ListPlayletTheme 分页查询题材列表
|
||||
func ListPlayletTheme(ctx context.Context, req *proto.PlayletThemeListReq) (*proto.PlayletThemeListPageResp, *srvdef.SrvErr) {
|
||||
if req == nil {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "", "")
|
||||
}
|
||||
filter := bson.M{}
|
||||
if req.Id != nil && *req.Id > 0 {
|
||||
filter[playletthememod.FN.PlayletTheme.Id] = *req.Id
|
||||
}
|
||||
if req.Status != nil {
|
||||
filter[playletthememod.FN.PlayletTheme.Status] = *req.Status
|
||||
}
|
||||
if name := strings.TrimSpace(req.Name); name != "" {
|
||||
filter[playletthememod.FN.PlayletTheme.Name] = bson.M{"$regex": regexp.QuoteMeta(name)}
|
||||
}
|
||||
pageNum, pageSize := normalizePage(req.PageNum, req.PageSize)
|
||||
totalCount, err := playletthememod.CountPlayletTheme(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp := &proto.PlayletThemeListPageResp{
|
||||
BasePageResp: response.BasePageResp{
|
||||
TotalCount: totalCount,
|
||||
PageSize: int(pageSize),
|
||||
PageNum: int(pageNum),
|
||||
List: make([]*proto.PlayletThemeListResp, 0),
|
||||
},
|
||||
}
|
||||
if totalCount == 0 {
|
||||
return resp, nil
|
||||
}
|
||||
list, err := playletthememod.FindManyPlayletTheme(ctx, filter, options.Find().
|
||||
SetProjection(playletThemeWebProjection).
|
||||
SetSort(bson.D{
|
||||
{Key: playletthememod.FN.PlayletTheme.Rank, Value: -1},
|
||||
{Key: playletthememod.FN.PlayletTheme.Id, Value: -1},
|
||||
}).
|
||||
SetSkip((pageNum-1)*pageSize).
|
||||
SetLimit(pageSize))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items := make([]*proto.PlayletThemeListResp, 0, len(list))
|
||||
for _, item := range list {
|
||||
if item == nil {
|
||||
continue
|
||||
}
|
||||
items = append(items, &proto.PlayletThemeListResp{
|
||||
Id: item.Id,
|
||||
Name: item.Name,
|
||||
Slug: item.Slug,
|
||||
Icon: item.Icon,
|
||||
Status: item.Status,
|
||||
Rank: item.Rank,
|
||||
SeoInfo: normalizeSeoValue(item.SeoInfo),
|
||||
CreatedAt: item.CreatedAt,
|
||||
UpdatedAt: item.UpdatedAt,
|
||||
})
|
||||
}
|
||||
resp.List = items
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// AddPlayletTheme 新增题材
|
||||
func AddPlayletTheme(ctx context.Context, req *proto.PlayletThemeAddReq) (*proto.PlayletThemeAddResp, *srvdef.SrvErr) {
|
||||
if req == nil || strings.TrimSpace(req.Name) == "" {
|
||||
return nil, srvdef.New(srvdef.ErrParamError, "题材名称不能为空", "")
|
||||
}
|
||||
doc := &playletthememod.PlayletTheme{
|
||||
Name: strings.TrimSpace(req.Name),
|
||||
Slug: req.Slug,
|
||||
Icon: strings.TrimSpace(req.Icon),
|
||||
Status: req.Status,
|
||||
Rank: req.Rank,
|
||||
SeoInfo: normalizeSeoValue(req.SeoInfo),
|
||||
}
|
||||
exists := func(s string) bool {
|
||||
item, _ := playletthememod.FindOnePlayletTheme(ctx, slugx.Filter(
|
||||
playletthememod.FN.PlayletTheme.Slug, playletthememod.FN.PlayletTheme.Id, s, 0))
|
||||
return item != nil
|
||||
}
|
||||
if serr := slugx.Ensure(&doc.Slug, utils.SlugSourceFromKeywordsOrTitle(doc.SeoInfo.Keyworld, doc.Name), exists); serr != nil {
|
||||
return nil, serr
|
||||
}
|
||||
if err := playletthememod.InsertOnePlayletTheme(ctx, doc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clearAppPlayletHomeCache()
|
||||
return &proto.PlayletThemeAddResp{Id: doc.Id}, nil
|
||||
}
|
||||
|
||||
// UpdatePlayletTheme 更新题材
|
||||
func UpdatePlayletTheme(ctx context.Context, req *proto.PlayletThemeUpdateReq) *srvdef.SrvErr {
|
||||
if req == nil || req.Id <= 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "题材ID无效", "")
|
||||
}
|
||||
current, err := playletthememod.FindOnePlayletTheme(ctx, bson.M{
|
||||
playletthememod.FN.PlayletTheme.Id: req.Id,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
setDoc := bson.M{playletthememod.FN.PlayletTheme.UpdatedAt: time.Now()}
|
||||
if req.Name != nil {
|
||||
name := strings.TrimSpace(*req.Name)
|
||||
if name == "" {
|
||||
return srvdef.New(srvdef.ErrParamError, "题材名称不能为空", "")
|
||||
}
|
||||
setDoc[playletthememod.FN.PlayletTheme.Name] = name
|
||||
}
|
||||
if req.Icon != nil {
|
||||
setDoc[playletthememod.FN.PlayletTheme.Icon] = strings.TrimSpace(*req.Icon)
|
||||
}
|
||||
if req.Status != nil {
|
||||
setDoc[playletthememod.FN.PlayletTheme.Status] = *req.Status
|
||||
}
|
||||
if req.Rank != nil {
|
||||
setDoc[playletthememod.FN.PlayletTheme.Rank] = *req.Rank
|
||||
}
|
||||
if req.SeoInfo != nil {
|
||||
setDoc["seoInfo"] = normalizeSeoValue(*req.SeoInfo)
|
||||
}
|
||||
name := current.Name
|
||||
if req.Name != nil {
|
||||
name = strings.TrimSpace(*req.Name)
|
||||
}
|
||||
keywords := current.SeoInfo.Keyworld
|
||||
if req.SeoInfo != nil {
|
||||
keywords = normalizeSeoValue(*req.SeoInfo).Keyworld
|
||||
}
|
||||
exists := func(s string) bool {
|
||||
item, _ := playletthememod.FindOnePlayletTheme(ctx, slugx.Filter(
|
||||
playletthememod.FN.PlayletTheme.Slug, playletthememod.FN.PlayletTheme.Id, s, req.Id))
|
||||
return item != nil
|
||||
}
|
||||
slug, changed, serr := slugx.PrepareOnUpdate(current.Slug, req.Slug,
|
||||
utils.SlugSourceFromKeywordsOrTitle(keywords, name), exists)
|
||||
if serr != nil {
|
||||
return serr
|
||||
}
|
||||
if changed {
|
||||
setDoc[playletthememod.FN.PlayletTheme.Slug] = slug
|
||||
}
|
||||
if len(setDoc) <= 1 {
|
||||
return srvdef.New(srvdef.ErrParamError, "没有可更新字段", "")
|
||||
}
|
||||
if err := playletthememod.UpdateOnePlayletTheme(ctx,
|
||||
bson.M{playletthememod.FN.PlayletTheme.Id: req.Id},
|
||||
bson.M{"$set": setDoc},
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
clearAppPlayletHomeCache()
|
||||
return nil
|
||||
}
|
||||
|
||||
// DelPlayletTheme 删除题材,被短剧引用时禁止删除
|
||||
func DelPlayletTheme(ctx context.Context, id int64) *srvdef.SrvErr {
|
||||
if id <= 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "题材ID无效", "")
|
||||
}
|
||||
usedCount, err := playletmod.CountPlaylet(ctx, bson.M{
|
||||
playletmod.FN.Playlet.ThemeIds: bson.M{"$in": []int64{id}},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if usedCount > 0 {
|
||||
return srvdef.New(srvdef.ErrParamError, "题材已被短剧引用,无法删除", "")
|
||||
}
|
||||
count, err := playletthememod.DelOnePlayletTheme(ctx, bson.M{playletthememod.FN.PlayletTheme.Id: id})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count == 0 {
|
||||
return srvdef.New(srvdef.ErrNoData, "", "")
|
||||
}
|
||||
clearAppPlayletHomeCache()
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user